The Pedigree Project  0.1
Acpi.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #if defined(ACPI)
21 
22 #include "Acpi.h"
23 #include "../../core/processor/x86_common/PhysicalMemoryManager.h"
24 #include "pedigree/kernel/Log.h"
25 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
26 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
27 #include "pedigree/kernel/utilities/RangeList.h"
28 #include "pedigree/kernel/utilities/utility.h"
29 
30 Acpi Acpi::m_Instance;
31 
32 void Acpi::initialise()
33 {
34  // Search for the ACPI root system description pointer
35  if (find() == false)
36  {
37  WARNING("Acpi: not compliant to the ACPI Specification");
38  return;
39  }
40 
41  NOTICE("ACPI Specification");
42  NOTICE(
43  " RSDT pointer at " << Hex
44  << reinterpret_cast<uintptr_t>(m_pRsdtPointer));
45 
46  // XSDT present?
47  if (m_pRsdtPointer->revision >= 2)
48  {
49  if (m_pRsdtPointer->xsdtAddress != 0)
50  {
51  NOTICE(" XSDT at " << Hex << m_pRsdtPointer->xsdtAddress);
52  }
53  }
54 
55  NOTICE(" RSDT at " << Hex << m_pRsdtPointer->rsdtAddress);
56 
57  // Get the ACPI memory ranges
58  X86CommonPhysicalMemoryManager &physicalMemoryManager =
60  const RangeList<uint64_t> &AcpiRanges =
61  physicalMemoryManager.getAcpiRanges();
62  if (AcpiRanges.size() == 0)
63  {
64  ERROR("Acpi: No ACPI memory range");
65  return;
66  }
67  if (AcpiRanges.size() > 1)
68  {
69  ERROR("Acpi: More than one ACPI memory range");
70  return;
71  }
72 
73  // Allocate the ACPI memory as a MemoryRegion
74  RangeList<uint64_t>::Range AcpiRange = AcpiRanges.getRange(0);
75  physical_uintptr_t address =
76  AcpiRange.address & (~(PhysicalMemoryManager::getPageSize() - 1));
77  size_t sAddress = AcpiRange.length + (AcpiRange.address - address);
78  size_t nPages = (sAddress + (PhysicalMemoryManager::getPageSize() - 1)) /
80  if (physicalMemoryManager.allocateRegion(
81  m_AcpiMemoryRegion, nPages,
86  address) == false)
87  {
88  ERROR("Acpi: Could not allocate the MemoryRegion");
89  return;
90  }
91 
92  // Check the RSDT (Root System Description Table)
93  m_pRsdt =
94  m_AcpiMemoryRegion.convertPhysicalPointer<SystemDescriptionTableHeader>(
95  m_pRsdtPointer->rsdtAddress);
96  if (m_pRsdt->signature != 0x54445352 || checksum(m_pRsdt) != true)
97  {
98  ERROR("Acpi: RSDT invalid");
99  m_pRsdt = 0;
100  return;
101  }
102 
103  // Go through the table's entries
104  size_t sEntries =
105  (m_pRsdt->length - sizeof(SystemDescriptionTableHeader)) / 4;
106  for (size_t i = 0; i < sEntries; i++)
107  {
108  uint32_t *pTable = adjust_pointer(
109  reinterpret_cast<uint32_t *>(m_pRsdt),
110  sizeof(SystemDescriptionTableHeader) + 4 * i);
111 
112  SystemDescriptionTableHeader *pSystemDescTable =
113  m_AcpiMemoryRegion
114  .convertPhysicalPointer<SystemDescriptionTableHeader>(*pTable);
115 
116  char Signature[5];
117  StringCopyN(
118  Signature, reinterpret_cast<char *>(&pSystemDescTable->signature),
119  4);
120  Signature[4] = '\0';
121 
122  NOTICE(" " << Signature << " at " << Hex << *pTable);
123 
124  // Is the table valid?
125  if (checksum(pSystemDescTable) != true)
126  {
127  ERROR(" invalid");
128  continue;
129  }
130 
131  // Is Fixed ACPI Description Table?
132  if (pSystemDescTable->signature == 0x50434146)
133  m_pFacp =
134  reinterpret_cast<FixedACPIDescriptionTable *>(pSystemDescTable);
135 // Is Multiple APIC Description Table?
136 #if defined(APIC)
137  else if (pSystemDescTable->signature == 0x43495041)
138  m_pApic = pSystemDescTable;
139 #endif
140  else
141  {
142  NOTICE(" unknown table");
143  }
144  }
145 
146  // Do we have a Fixed ACPI Description Table?
147  if (m_pFacp == 0)
148  {
149  ERROR("Acpi: no Fixed ACPI Description Table (FACP)");
150  return;
151  }
152 
153  // Parse the FACP
154  parseFixedACPIDescriptionTable();
155 
156 #if defined(APIC)
157  // If we have an Multiple APIC Description Table parse it
158  if (m_pApic != 0)
159  parseMultipleApicDescriptionTable();
160 #endif
161 
162  m_bValid = true;
163 }
164 
165 Acpi::Acpi()
166  : m_bValid(0), m_pRsdtPointer(0), m_AcpiMemoryRegion("ACPI"), m_pRsdt(0),
167  m_pFacp(0)
168 #if defined(APIC)
169  ,
170  m_pApic(0), m_bValidApicInfo(false), m_bHasPICs(false),
171  m_LocalApicAddress(0), m_IoApics()
172 #if defined(MULTIPROCESSOR)
173  ,
174  m_bValidProcessorInfo(false), m_Processors()
175 #endif
176 #endif
177 {
178 }
179 
180 void Acpi::parseFixedACPIDescriptionTable()
181 {
182  NOTICE("ACPI: Fixed Description Table (FACP)");
183 
184  NOTICE(
185  " Firmware ACPI Control Structure at " << Hex
186  << m_pFacp->firmwareControl);
187  NOTICE(
188  " Differentiated System Description Table at " << Hex << m_pFacp->dsdt);
189  NOTICE(
190  " Interrupt Model: " << Dec
191  << ((m_pFacp->interruptModel == 0) ?
192  "dual 8259 PICs" :
193  "multiple local APICs"));
194  NOTICE(" SCI Interrupt #" << Dec << m_pFacp->sciInterrupt);
195  NOTICE(" SMI Command Port at " << Hex << m_pFacp->smiCommandPort);
196  NOTICE(" enable " << Hex << m_pFacp->acpiEnableCommand);
197  NOTICE(" disable " << Hex << m_pFacp->acpiDisableCommand);
198  if (m_pFacp->s4BiosCommand != 0)
199  {
200  NOTICE(" S4 BIOS " << Hex << m_pFacp->s4BiosCommand);
201  }
202  NOTICE(" Power-Management");
203  NOTICE(
204  " Event 1A at " << Hex << m_pFacp->pm1aEventBlock << " - "
205  << (m_pFacp->pm1aEventBlock +
206  m_pFacp->pm1EventLength));
207  if (m_pFacp->pm1bEventBlock != 0)
208  {
209  NOTICE(
210  " Event 1B at "
211  << Hex << m_pFacp->pm1bEventBlock << " - "
212  << (m_pFacp->pm1bEventBlock + m_pFacp->pm1EventLength));
213  }
214  NOTICE(
215  " Control 1A at " << Hex << m_pFacp->pm1aControlBlock << " - "
216  << (m_pFacp->pm1aControlBlock +
217  m_pFacp->pm1ControlLength));
218  if (m_pFacp->pm1bControlBlock != 0)
219  {
220  NOTICE(
221  " Control 1B at "
222  << Hex << m_pFacp->pm1bControlBlock << " - "
223  << (m_pFacp->pm1bControlBlock + m_pFacp->pm1ControlLength));
224  }
225  if (m_pFacp->pm2ControlBlock != 0)
226  {
227  NOTICE(
228  " Control 2 at "
229  << Hex << m_pFacp->pm2ControlBlock << " - "
230  << (m_pFacp->pm2ControlBlock + m_pFacp->pm2ControlLength));
231  }
232  NOTICE(
233  " Timer at " << Hex << m_pFacp->pmTimerBlock << " - "
234  << (m_pFacp->pmTimerBlock + m_pFacp->pmTimerLength));
235  if (m_pFacp->gpe0Block != 0)
236  {
237  NOTICE(
238  " General Purpose Event 0 at "
239  << Hex << m_pFacp->gpe0Block << " - "
240  << (m_pFacp->gpe0Block + m_pFacp->gpe0BlockLength));
241  }
242  if (m_pFacp->gpe1Block != 0)
243  {
244  NOTICE(
245  " General Purpose Event 1 at "
246  << Hex << m_pFacp->gpe1Block << " - "
247  << (m_pFacp->gpe1Block + m_pFacp->gpe1BlockLength));
248  }
249  if (m_pFacp->gpe1Base != 0)
250  {
251  NOTICE(" General Purpose Event Base: " << Hex << m_pFacp->gpe1Base);
252  }
253  // TODO: Unimportant imho
254  NOTICE(" Flags " << Hex << m_pFacp->flags);
255 }
256 
257 #if defined(APIC)
258 void Acpi::parseMultipleApicDescriptionTable()
259 {
260  NOTICE("ACPI: Multiple APIC Description Table (APIC)");
261 
262  // Parse the Multiple APIC Description Table
263  uint32_t *pLocalApicAddress = reinterpret_cast<uint32_t *>(
264  adjust_pointer(m_pApic, sizeof(SystemDescriptionTableHeader)));
265  uint32_t *pFlags = adjust_pointer(pLocalApicAddress, 4);
266 
267  m_LocalApicAddress = *pLocalApicAddress;
268  m_bHasPICs = (((*pFlags) & 0x01) == 0x01);
269 
270  uint8_t *pType = reinterpret_cast<uint8_t *>(adjust_pointer(pFlags, 4));
271  for (; pType < reinterpret_cast<uint8_t *>(
272  adjust_pointer(m_pApic, m_pApic->length));)
273  {
274  // Processor Local APIC
275  if (*pType == 0)
276  {
277  ProcessorLocalApic *pLocalApic =
278  reinterpret_cast<ProcessorLocalApic *>(
279  adjust_pointer(pType, 2));
280  bool bUsable = ((pLocalApic->flags & 0x01) == 0x01);
281  NOTICE(
282  " Processor #" << Dec << pLocalApic->processorId
283  << (bUsable ? " usable" : " unusable"));
284 
285 #if defined(MULTIPROCESSOR)
286  // Is the processor usable?
287  if (bUsable)
288  {
289  // Add the processor to the list
290  Multiprocessor::ProcessorInformation *pProcessorInfo =
292  pLocalApic->processorId, pLocalApic->apicId);
293  m_Processors.pushBack(pProcessorInfo);
294  }
295 #endif
296  }
297  // I/O APIC
298  else if (*pType == 1)
299  {
300  IoApic *pIoApic =
301  reinterpret_cast<IoApic *>(adjust_pointer(pType, 2));
302 
303  NOTICE(
304  " I/O APIC #" << Dec << pIoApic->apicId << " at " << Hex
305  << pIoApic->address
306  << ", global system interrupt base "
307  << pIoApic->globalSystemInterruptBase);
308 
309  // TODO: What should we do with the global system interrupt base?
310 
311  // Add to the I/O APIC list
312  Multiprocessor::IoApicInformation *pIoApicInfo =
314  pIoApic->apicId, pIoApic->address);
315  m_IoApics.pushBack(pIoApicInfo);
316  }
317  // Interrupt Source override
318  else if (*pType == 2)
319  {
320  InterruptSourceOverride *pInterruptSourceOverride =
321  reinterpret_cast<InterruptSourceOverride *>(
322  adjust_pointer(pType, 2));
323 
324  ERROR(
325  " Interrupt override: "
326  << ((pInterruptSourceOverride->bus == 0) ? "ISA" : "unknown")
327  << " bus, #" << Dec << pInterruptSourceOverride->source
328  << " -> #" << pInterruptSourceOverride->globalSystemInterrupt
329  << ", flags " << Hex << pInterruptSourceOverride->flags);
330 
331  // TODO
332  }
333  // Non-maskable Interrupt Source (NMI)
334  else if (*pType == 3)
335  {
336  ERROR(" NMI source");
337  }
338  // Local APIC NMI
339  else if (*pType == 4)
340  {
341  ERROR(" Local APIC NMI");
342  }
343  // Local APIC Address Override
344  else if (*pType == 5)
345  {
346  ERROR(" Local APIC address override");
347  }
348  // I/O SAPIC
349  else if (*pType == 6)
350  {
351  ERROR(" I/O SAPIC");
352  }
353  // Local SAPIC
354  else if (*pType == 7)
355  {
356  ERROR(" Local SAPIC");
357  }
358  // Platform Interrupt Source
359  else if (*pType == 8)
360  {
361  ERROR(" Platform Interrupt Source");
362  }
363  else
364  {
365  NOTICE(" unknown entry #" << Dec << *pType);
366  }
367 
368  // Go to the next entry;
369  uint8_t *sTable = adjust_pointer(pType, 1);
370  pType = adjust_pointer(pType, *sTable);
371  }
372 
373  m_bValidApicInfo = true;
374 #if defined(MULTIPROCESSOR)
375  m_bValidProcessorInfo = true;
376 #endif
377 }
378 #endif
379 
380 bool Acpi::find()
381 {
382  // Search in the first kilobyte of the EBDA
383  uint16_t *ebdaSegment = reinterpret_cast<uint16_t *>(0x40E);
384  m_pRsdtPointer = find(reinterpret_cast<void *>((*ebdaSegment) * 16), 0x400);
385 
386  if (m_pRsdtPointer == 0)
387  {
388  // Search in the BIOS ROM address space
389  m_pRsdtPointer = find(reinterpret_cast<void *>(0xE0000), 0x20000);
390  }
391 
392  return (m_pRsdtPointer != 0);
393 }
394 
395 Acpi::RsdtPointer *Acpi::find(void *pMemory, size_t sMemory)
396 {
397  RsdtPointer *pRdstPointer = reinterpret_cast<RsdtPointer *>(pMemory);
398  while (reinterpret_cast<uintptr_t>(pRdstPointer) <
399  (reinterpret_cast<uintptr_t>(pMemory) + sMemory))
400  {
401  if (pRdstPointer->signature == 0x2052545020445352ULL &&
402  checksum(pRdstPointer) == true)
403  return pRdstPointer;
404  pRdstPointer = adjust_pointer(pRdstPointer, 16);
405  }
406  return 0;
407 }
408 
409 bool Acpi::checksum(const RsdtPointer *pRdstPointer)
410 {
411  // ACPI 1.0 checksum
412  if (::checksum(reinterpret_cast<const uint8_t *>(pRdstPointer), 20) ==
413  false)
414  return false;
415 
416  if (pRdstPointer->revision >= 2)
417  {
418  // ACPI 2.0+ checksum
419  if (::checksum(
420  reinterpret_cast<const uint8_t *>(pRdstPointer),
421  pRdstPointer->length) == false)
422  return false;
423  }
424 
425  return true;
426 }
427 
428 bool Acpi::checksum(const SystemDescriptionTableHeader *pHeader)
429 {
430  return ::checksum(
431  reinterpret_cast<const uint8_t *>(pHeader), pHeader->length);
432 }
433 
434 #endif
size_t size() const
Definition: RangeList.h:101
Range getRange(size_t index) const
Definition: RangeList.h:348
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)
#define WARNING(text)
Definition: Log.h:78
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
#define ERROR(text)
Definition: Log.h:82
Definition: Log.h:138
Implementation of the PhysicalMemoryManager for common x86.