1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 using System.Text;
9 using System.Linq;
10 using Antmicro.Renode.Peripherals.Bus;
11 using Antmicro.Renode.Peripherals.CPU;
12 using Antmicro.Renode.Core.ACPI;
13 using Antmicro.Renode.Utilities.Packets;
14 
15 namespace Antmicro.Renode.Core.Extensions
16 {
17     public static class ACPIExtensions
18     {
GenerateACPITable(this IBusController bus, ulong address)19         public static void GenerateACPITable(this IBusController bus, ulong address)
20         {
21             var rootSystemDescriptionTableOffset =
22                 (uint)address + (uint)Packet.CalculateLength<RootSystemDescriptionPointer>();
23             var rootSystemDescriptionPointer = new RootSystemDescriptionPointer(rootSystemDescriptionTableOffset);
24             bus.WriteBytes(Packet.Encode(rootSystemDescriptionPointer), address);
25 
26             var fixedACPIDescriptionTableAddress =
27                 rootSystemDescriptionTableOffset + (uint)Packet.CalculateLength<RootSystemDescriptionTable>();
28             var multipleAPICDescriptionTableHeaderAddress =
29                 fixedACPIDescriptionTableAddress + (uint)Packet.CalculateLength<FixedACPIDescriptionTable>();
30 
31             var rootSystemDescriptionTable = new RootSystemDescriptionTable(fixedACPIDescriptionTableAddress, multipleAPICDescriptionTableHeaderAddress);
32             bus.WriteBytes(Packet.Encode(rootSystemDescriptionTable), rootSystemDescriptionTableOffset);
33 
34             var fixedACPIDescriptionTable = new FixedACPIDescriptionTable(multipleAPICDescriptionTableHeaderAddress - (uint)address, fixedACPIDescriptionTableAddress);
35             bus.WriteBytes(Packet.Encode(fixedACPIDescriptionTable), fixedACPIDescriptionTableAddress);
36 
37             var ids = bus.GetCPUs().OfType<BaseX86>().Select(x => (ulong)x.Lapic.ID).ToList();
38 
39             var multipleAPICDescriptionTableLength = Packet.CalculateLength<MultipleAPICDescriptionTable>();
40             var recordLength = (uint)Packet.CalculateLength<ProcessorLocalAPICRecord>();
41 
42             // Define table without records. They will be defined based on CPUs.
43             var multipleAPICDescriptionTable = new MultipleAPICDescriptionTable((uint)(multipleAPICDescriptionTableLength + ids.Count() * recordLength));
44             bus.WriteBytes(Packet.Encode(multipleAPICDescriptionTable), multipleAPICDescriptionTableHeaderAddress);
45 
46             var recordAddress =
47                 multipleAPICDescriptionTableHeaderAddress + (uint)Packet.CalculateLength<MultipleAPICDescriptionTable>();
48 
49             foreach(var id in ids)
50             {
51                 var processorLocalAPICRecord = new ProcessorLocalAPICRecord
52                 {
53                     EntryType = 0x0,    // 0x0 means local APIC entry type
54                     RecordLength = 0x8,
55                     APICID = (byte)id,
56                     Flags = 0x01        // bit 0 = Processor Enabled
57                 };
58                 var table = Packet.Encode(processorLocalAPICRecord).ToArray();
59                 bus.WriteBytes(table, recordAddress);
60 
61                 recordAddress += recordLength;
62             }
63         }
64     }
65 }
66