1 //
2 // Copyright (c) 2010-2025 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using Endianess = ELFSharp.ELF.Endianess;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Utilities.Binding;
11 using Antmicro.Renode.Exceptions;
12 using Antmicro.Renode.Peripherals.IRQControllers;
13 using System;
14 using System.Collections.Generic;
15 
16 namespace Antmicro.Renode.Peripherals.CPU
17 {
18     [GPIO(NumberOfInputs = 1)]
19     public abstract class BaseX86 : TranslationCPU
20     {
BaseX86(string cpuType, IMachine machine, LAPIC lapic, CpuBitness bitness)21         public BaseX86(string cpuType, IMachine machine, LAPIC lapic, CpuBitness bitness): base(cpuType, machine, Endianess.LittleEndian, bitness)
22         {
23             Lapic = lapic;
24         }
25 
SetDescriptor(SegmentDescriptor descriptor, uint selector, uint baseAddress, uint limit, uint flags)26         public void SetDescriptor(SegmentDescriptor descriptor, uint selector, uint baseAddress, uint limit, uint flags)
27         {
28             switch(descriptor)
29             {
30                 case SegmentDescriptor.CS:
31                     TlibSetCsDescriptor(selector, baseAddress, limit, flags);
32                     break;
33                 default:
34                     throw new RecoverableException($"Setting the {descriptor} descriptor is not implemented");
35             }
36         }
37 
38         public bool HltAsNop
39         {
40             get => neverWaitForInterrupt;
41             set
42             {
43                 neverWaitForInterrupt = value;
44             }
45         }
46 
47         public LAPIC Lapic { get; }
48 
DecodeInterrupt(int number)49         protected override Interrupt DecodeInterrupt(int number)
50         {
51             if(number == 0)
52             {
53                 return Interrupt.Hard;
54             }
55             throw InvalidInterruptNumberException;
56         }
57 
GetExceptionDescription(ulong exceptionIndex)58         protected override string GetExceptionDescription(ulong exceptionIndex)
59         {
60             return ExceptionDescriptionsMap.TryGetValue(exceptionIndex, out var result)
61                 ? result
62                 : base.GetExceptionDescription(exceptionIndex);
63         }
64 
65         [Export]
ReadByteFromPort(uint address)66         private uint ReadByteFromPort(uint address)
67         {
68             return (uint)ReadByteFromBus(IoPortBaseAddress + address);
69         }
70 
71         [Export]
ReadWordFromPort(uint address)72         private uint ReadWordFromPort(uint address)
73         {
74             return (uint)ReadWordFromBus(IoPortBaseAddress + address);
75         }
76 
77         [Export]
ReadDoubleWordFromPort(uint address)78         private uint ReadDoubleWordFromPort(uint address)
79         {
80             return (uint)ReadDoubleWordFromBus(IoPortBaseAddress + address);
81         }
82 
83         [Export]
WriteByteToPort(uint address, uint value)84         private void WriteByteToPort(uint address, uint value)
85         {
86             WriteByteToBus(IoPortBaseAddress + address, value);
87 
88         }
89 
90         [Export]
WriteWordToPort(uint address, uint value)91         private void WriteWordToPort(uint address, uint value)
92         {
93             WriteWordToBus(IoPortBaseAddress + address, value);
94         }
95 
96         [Export]
WriteDoubleWordToPort(uint address, uint value)97         private void WriteDoubleWordToPort(uint address, uint value)
98         {
99             WriteDoubleWordToBus(IoPortBaseAddress + address, value);
100         }
101 
102         [Export]
GetPendingInterrupt()103         private int GetPendingInterrupt()
104         {
105             return Lapic.GetPendingInterrupt();
106         }
107 
108         [Export]
GetInstructionCount()109         private ulong GetInstructionCount()
110         {
111             return this.ExecutedInstructions;
112         }
113 
114         // 649:  Field '...' is never assigned to, and will always have its default value null
115 #pragma warning disable 649
116 
117         [Import]
118         private Action<uint, uint, uint, uint> TlibSetCsDescriptor;
119 
120 #pragma warning restore 649
121 
122         private readonly Dictionary<ulong, string> ExceptionDescriptionsMap = new Dictionary<ulong, string>
123         {
124             {0, "Division by zero"},
125             {1, "Single-step interrupt"},
126             {2, "NMI"},
127             {3, "Breakpoint"},
128             {4, "Overflow"},
129             {5, "Bounds"},
130             {6, "Invalid Opcode"},
131             {7, "Coprocessor not available"},
132             {8, "Double Fault"},
133             {9, "Coprocessor Segment Overrun"},
134             {10, "Invalid Task State Segment"},
135             {11, "Segment not present"},
136             {12, "Stack Fault"},
137             {13, "General protection fault"},
138             {14, "Page Fault"},
139             {16, "Math Fault"},
140             {17, "Alignment Check"},
141             {18, "Machine Check"},
142             {256, "System call"}
143         };
144 
145         private const uint IoPortBaseAddress = 0xE0000000;
146 
147         public enum SegmentDescriptor
148         {
149             CS,
150             SS,
151             DS,
152             ES,
153             FS,
154             GS
155         }
156     }
157 }
158