ACPIStaticParser.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <Kernel/ACPI/ACPIStaticParser.h>
  27. #include <Kernel/PCI/Access.h>
  28. #include <Kernel/VM/MemoryManager.h>
  29. #include <LibBareMetal/IO.h>
  30. #include <LibBareMetal/StdLib.h>
  31. //#define ACPI_DEBUG
  32. namespace Kernel {
  33. namespace ACPI {
  34. void StaticParser::initialize(PhysicalAddress rsdp)
  35. {
  36. if (!Parser::is_initialized()) {
  37. new StaticParser(rsdp);
  38. }
  39. }
  40. void StaticParser::initialize_without_rsdp()
  41. {
  42. if (!Parser::is_initialized()) {
  43. new StaticParser();
  44. }
  45. }
  46. bool StaticParser::is_initialized()
  47. {
  48. return Parser::is_initialized();
  49. }
  50. void StaticParser::locate_static_data()
  51. {
  52. locate_main_system_description_table();
  53. initialize_main_system_description_table();
  54. init_fadt();
  55. init_facs();
  56. }
  57. PhysicalAddress StaticParser::find_table(const char* sig)
  58. {
  59. #ifdef ACPI_DEBUG
  60. dbg() << "ACPI: Calling Find Table method!";
  61. #endif
  62. for (auto p_sdt : m_sdt_pointers) {
  63. auto region = MM.allocate_kernel_region(p_sdt.page_base(), (PAGE_SIZE * 2), "ACPI Static Parser Tables Finding", Region::Access::Read);
  64. auto* sdt = (const Structures::SDTHeader*)region->vaddr().offset(p_sdt.offset_in_page()).as_ptr();
  65. #ifdef ACPI_DEBUG
  66. dbg() << "ACPI: Examining Table @ P " << physical_sdt_ptr;
  67. #endif
  68. if (!strncmp(sdt->sig, sig, 4)) {
  69. #ifdef ACPI_DEBUG
  70. dbg() << "ACPI: Found Table @ P " << physical_sdt_ptr;
  71. #endif
  72. return p_sdt;
  73. }
  74. }
  75. return {};
  76. }
  77. void StaticParser::init_facs()
  78. {
  79. m_facs = find_table("FACS");
  80. }
  81. void StaticParser::init_fadt()
  82. {
  83. klog() << "ACPI: Initializing Fixed ACPI data";
  84. klog() << "ACPI: Searching for the Fixed ACPI Data Table";
  85. m_fadt = find_table("FACP");
  86. ASSERT(!m_fadt.is_null());
  87. auto checkup_region = MM.allocate_kernel_region(m_fadt.page_base(), (PAGE_SIZE * 2), "ACPI Static Parser", Region::Access::Read);
  88. auto* sdt = (const Structures::SDTHeader*)checkup_region->vaddr().offset(m_fadt.offset_in_page()).as_ptr();
  89. #ifdef ACPI_DEBUG
  90. dbg() << "ACPI: FADT @ V " << sdt << ", P " << (void*)fadt.as_ptr();
  91. #endif
  92. klog() << "ACPI: Fixed ACPI data, Revision " << sdt->revision << ", Length " << sdt->length << " bytes";
  93. }
  94. bool StaticParser::can_reboot()
  95. {
  96. auto region = MM.allocate_kernel_region(m_fadt.page_base(), (PAGE_SIZE * 2), "ACPI Static Parser", Region::Access::Read);
  97. auto* fadt = (const Structures::FADT*)region->vaddr().offset(m_fadt.offset_in_page()).as_ptr();
  98. if (fadt->h.revision < 2)
  99. return false;
  100. return (fadt->flags & (u32)FADTFeatureFlags::RESET_REG_SUPPORTED) != 0;
  101. }
  102. void StaticParser::access_generic_address(const Structures::GenericAddressStructure& structure, u32 value)
  103. {
  104. switch (structure.address_space) {
  105. case (u8)GenericAddressStructure::AddressSpace::SystemIO: {
  106. dbg() << "ACPI: Sending value 0x" << String::format("%x", value) << " to " << IOAddress(structure.address);
  107. switch (structure.access_size) {
  108. case (u8)GenericAddressStructure::AccessSize::Byte: {
  109. IO::out8(structure.address, value);
  110. break;
  111. }
  112. case (u8)GenericAddressStructure::AccessSize::Word: {
  113. IO::out16(structure.address, value);
  114. break;
  115. }
  116. case (u8)GenericAddressStructure::AccessSize::DWord: {
  117. IO::out32(structure.address, value);
  118. break;
  119. }
  120. case (u8)GenericAddressStructure::AccessSize::QWord: {
  121. dbg() << "Trying to send QWord to IO port";
  122. ASSERT_NOT_REACHED();
  123. break;
  124. }
  125. default:
  126. // FIXME: Determine if for reset register we can actually determine the right IO operation.
  127. dbg() << "ACPI Warning: Unknown access size " << structure.access_size;
  128. IO::out8(structure.address, value);
  129. break;
  130. }
  131. return;
  132. }
  133. case (u8)GenericAddressStructure::AddressSpace::SystemMemory: {
  134. auto p_reg = PhysicalAddress(structure.address);
  135. auto p_region = MM.allocate_kernel_region(p_reg.page_base(), (PAGE_SIZE * 2), "ACPI Static Parser", Region::Access::Read);
  136. dbg() << "ACPI: Sending value 0x" << String::format("%x", value) << " to " << p_reg;
  137. switch (structure.access_size) {
  138. case (u8)GenericAddressStructure::AccessSize::Byte: {
  139. auto* reg = (volatile u8*)p_region->vaddr().offset(p_reg.offset_in_page()).as_ptr();
  140. (*reg) = value;
  141. break;
  142. }
  143. case (u8)GenericAddressStructure::AccessSize::Word: {
  144. auto* reg = (volatile u16*)p_region->vaddr().offset(p_reg.offset_in_page()).as_ptr();
  145. (*reg) = value;
  146. break;
  147. }
  148. case (u8)GenericAddressStructure::AccessSize::DWord: {
  149. auto* reg = (volatile u32*)p_region->vaddr().offset(p_reg.offset_in_page()).as_ptr();
  150. (*reg) = value;
  151. break;
  152. }
  153. case (u8)GenericAddressStructure::AccessSize::QWord: {
  154. auto* reg = (volatile u64*)p_region->vaddr().offset(p_reg.offset_in_page()).as_ptr();
  155. (*reg) = value;
  156. break;
  157. }
  158. default:
  159. ASSERT_NOT_REACHED();
  160. }
  161. return;
  162. }
  163. case (u8)GenericAddressStructure::AddressSpace::PCIConfigurationSpace: {
  164. // According to the ACPI specification 6.2, page 168, PCI addresses must be confined to devices on Segment group 0, bus 0.
  165. auto pci_address = PCI::Address(0, 0, ((structure.address >> 24) & 0xFF), ((structure.address >> 16) & 0xFF));
  166. dbg() << "ACPI: Sending value 0x" << String::format("%x", value) << " to " << pci_address;
  167. u32 offset_in_pci_address = structure.address & 0xFFFF;
  168. if (structure.access_size == (u8)GenericAddressStructure::AccessSize::QWord) {
  169. dbg() << "Trying to send QWord to PCI configuration space";
  170. ASSERT_NOT_REACHED();
  171. }
  172. ASSERT(structure.access_size != (u8)GenericAddressStructure::AccessSize::Undefined);
  173. PCI::raw_access(pci_address, offset_in_pci_address, (1 << (structure.access_size - 1)), value);
  174. return;
  175. }
  176. default:
  177. ASSERT_NOT_REACHED();
  178. }
  179. ASSERT_NOT_REACHED();
  180. }
  181. bool StaticParser::validate_reset_register()
  182. {
  183. // According to the ACPI spec 6.2, page 152, The reset register can only be located in I/O bus, PCI bus or memory-mapped.
  184. auto region = MM.allocate_kernel_region(m_fadt.page_base(), (PAGE_SIZE * 2), "ACPI Static Parser", Region::Access::Read);
  185. auto* fadt = (const Structures::FADT*)region->vaddr().offset(m_fadt.offset_in_page()).as_ptr();
  186. return (fadt->reset_reg.address_space == (u8)GenericAddressStructure::AddressSpace::PCIConfigurationSpace || fadt->reset_reg.address_space == (u8)GenericAddressStructure::AddressSpace::SystemMemory || fadt->reset_reg.address_space == (u8)GenericAddressStructure::AddressSpace::SystemIO);
  187. }
  188. void StaticParser::try_acpi_reboot()
  189. {
  190. InterruptDisabler disabler;
  191. if (!can_reboot()) {
  192. klog() << "ACPI: Reboot, Not supported!";
  193. return;
  194. }
  195. #ifdef ACPI_DEBUG
  196. dbg() << "ACPI: Rebooting, Probing FADT (" << m_fadt << ")";
  197. #endif
  198. auto region = MM.allocate_kernel_region(m_fadt.page_base(), (PAGE_SIZE * 2), "ACPI Static Parser", Region::Access::Read);
  199. auto* fadt = (const Structures::FADT*)region->vaddr().offset(m_fadt.offset_in_page()).as_ptr();
  200. ASSERT(validate_reset_register());
  201. access_generic_address(fadt->reset_reg, fadt->reset_value);
  202. for (;;)
  203. ;
  204. }
  205. void StaticParser::try_acpi_shutdown()
  206. {
  207. klog() << "ACPI: Shutdown is not supported with the current configuration, Abort!";
  208. }
  209. size_t StaticParser::get_table_size(PhysicalAddress table_header)
  210. {
  211. InterruptDisabler disabler;
  212. #ifdef ACPI_DEBUG
  213. dbg() << "ACPI: Checking SDT Length";
  214. #endif
  215. auto region = MM.allocate_kernel_region(table_header.page_base(), (PAGE_SIZE * 2), "ACPI get_table_size()", Region::Access::Read);
  216. auto* sdt = (volatile Structures::SDTHeader*)region->vaddr().offset(table_header.offset_in_page()).as_ptr();
  217. return sdt->length;
  218. }
  219. u8 StaticParser::get_table_revision(PhysicalAddress table_header)
  220. {
  221. InterruptDisabler disabler;
  222. #ifdef ACPI_DEBUG
  223. dbg() << "ACPI: Checking SDT Revision";
  224. #endif
  225. auto region = MM.allocate_kernel_region(table_header.page_base(), (PAGE_SIZE * 2), "ACPI get_table_revision()", Region::Access::Read);
  226. auto* sdt = (volatile Structures::SDTHeader*)region->vaddr().offset(table_header.offset_in_page()).as_ptr();
  227. return sdt->revision;
  228. }
  229. void StaticParser::initialize_main_system_description_table()
  230. {
  231. #ifdef ACPI_DEBUG
  232. dbg() << "ACPI: Checking Main SDT Length to choose the correct mapping size";
  233. #endif
  234. ASSERT(!m_main_system_description_table.is_null());
  235. auto length = get_table_size(m_main_system_description_table);
  236. auto revision = get_table_revision(m_main_system_description_table);
  237. auto main_sdt_region = MM.allocate_kernel_region(m_main_system_description_table.page_base(), PAGE_ROUND_UP(length) + PAGE_SIZE, "ACPI Static Parser Initialization", Region::Access::Read, false, true);
  238. auto* sdt = (volatile Structures::SDTHeader*)main_sdt_region->vaddr().offset(m_main_system_description_table.offset_in_page()).as_ptr();
  239. klog() << "ACPI: Main Description Table valid? " << StaticParsing::validate_table(const_cast<Structures::SDTHeader&>(*sdt), length);
  240. if (m_xsdt_supported) {
  241. volatile auto* xsdt = (volatile Structures::XSDT*)sdt;
  242. klog() << "ACPI: Using XSDT, Enumerating tables @ " << m_main_system_description_table;
  243. klog() << "ACPI: XSDT Revision " << revision << ", Total length - " << length;
  244. #ifdef ACPI_DEBUG
  245. dbg() << "ACPI: XSDT pointer @ V " << xsdt;
  246. #endif
  247. for (u32 i = 0; i < ((length - sizeof(Structures::SDTHeader)) / sizeof(u64)); i++) {
  248. #ifdef ACPI_DEBUG
  249. dbg() << "ACPI: Found new table [" << i << "], @ V 0x" << String::format("%x", &xsdt->table_ptrs[i]) << " - P 0x" << String::format("%x", xsdt->table_ptrs[i]);
  250. #endif
  251. m_sdt_pointers.append(PhysicalAddress(xsdt->table_ptrs[i]));
  252. }
  253. } else {
  254. volatile auto* rsdt = (volatile Structures::RSDT*)sdt;
  255. klog() << "ACPI: Using RSDT, Enumerating tables @ " << m_main_system_description_table;
  256. klog() << "ACPI: RSDT Revision " << revision << ", Total length - " << length;
  257. #ifdef ACPI_DEBUG
  258. dbg() << "ACPI: RSDT pointer @ V " << rsdt;
  259. #endif
  260. for (u32 i = 0; i < ((length - sizeof(Structures::SDTHeader)) / sizeof(u32)); i++) {
  261. #ifdef ACPI_DEBUG
  262. dbg() << "ACPI: Found new table [" << i << "], @ V 0x" << String::format("%x", &rsdt->table_ptrs[i]) << " - P 0x" << String::format("%x", rsdt->table_ptrs[i]);
  263. #endif
  264. m_sdt_pointers.append(PhysicalAddress(rsdt->table_ptrs[i]));
  265. }
  266. }
  267. }
  268. void StaticParser::locate_main_system_description_table()
  269. {
  270. auto rsdp_region = MM.allocate_kernel_region(m_rsdp.page_base(), (PAGE_SIZE * 2), "ACPI Static Parser Initialization", Region::Access::Read, false, true);
  271. volatile auto* rsdp = (Structures::RSDPDescriptor20*)rsdp_region->vaddr().offset(m_rsdp.offset_in_page()).as_ptr();
  272. if (rsdp->base.revision == 0) {
  273. m_xsdt_supported = false;
  274. } else if (rsdp->base.revision >= 2) {
  275. if (rsdp->xsdt_ptr != (u64) nullptr) {
  276. m_xsdt_supported = true;
  277. } else {
  278. m_xsdt_supported = false;
  279. }
  280. }
  281. if (!m_xsdt_supported) {
  282. m_main_system_description_table = PhysicalAddress(rsdp->base.rsdt_ptr);
  283. } else {
  284. m_main_system_description_table = PhysicalAddress(rsdp->xsdt_ptr);
  285. }
  286. }
  287. StaticParser::StaticParser()
  288. : Parser(true)
  289. , m_rsdp(StaticParsing::search_rsdp())
  290. {
  291. if (!m_rsdp.is_null()) {
  292. klog() << "ACPI: Using RSDP @ " << m_rsdp;
  293. m_operable = true;
  294. locate_static_data();
  295. } else {
  296. m_operable = false;
  297. klog() << "ACPI: Disabled, due to RSDP being absent";
  298. }
  299. }
  300. StaticParser::StaticParser(PhysicalAddress rsdp)
  301. : Parser(true)
  302. , m_rsdp(rsdp)
  303. {
  304. klog() << "ACPI: Using RSDP @ " << rsdp;
  305. m_operable = true;
  306. locate_static_data();
  307. }
  308. PhysicalAddress StaticParsing::search_rsdp_in_ebda(u16 ebda_segment)
  309. {
  310. auto rsdp_region = MM.allocate_kernel_region(PhysicalAddress(page_base_of((u32)(ebda_segment << 4))), PAGE_ROUND_UP(1024), "ACPI Static Parser RSDP Finding #1", Region::Access::Read, false, true);
  311. char* p_rsdp_str = (char*)(PhysicalAddress(ebda_segment << 4).as_ptr());
  312. for (char* rsdp_str = (char*)rsdp_region->vaddr().offset(offset_in_page((u32)(ebda_segment << 4))).as_ptr(); rsdp_str < (char*)(rsdp_region->vaddr().offset(offset_in_page((u32)(ebda_segment << 4))).get() + 1024); rsdp_str += 16) {
  313. #ifdef ACPI_DEBUG
  314. dbg() << "ACPI: Looking for RSDP in EBDA @ V " << (void*)rsdp_str << ", P " << (void*)p_rsdp_str;
  315. #endif
  316. if (!strncmp("RSD PTR ", rsdp_str, strlen("RSD PTR ")))
  317. return PhysicalAddress((FlatPtr)p_rsdp_str);
  318. p_rsdp_str += 16;
  319. }
  320. return {};
  321. }
  322. PhysicalAddress StaticParsing::search_rsdp_in_bios_area()
  323. {
  324. auto rsdp_region = MM.allocate_kernel_region(PhysicalAddress(0xE0000), PAGE_ROUND_UP(0xFFFFF - 0xE0000), "ACPI Static Parser RSDP Finding #2", Region::Access::Read, false, true);
  325. char* p_rsdp_str = (char*)(PhysicalAddress(0xE0000).as_ptr());
  326. for (char* rsdp_str = (char*)rsdp_region->vaddr().offset(offset_in_page((u32)(0xE0000))).as_ptr(); rsdp_str < (char*)(rsdp_region->vaddr().offset(offset_in_page((u32)(0xE0000))).get() + (0xFFFFF - 0xE0000)); rsdp_str += 16) {
  327. #ifdef ACPI_DEBUG
  328. dbg() << "ACPI: Looking for RSDP in BIOS ROM area @ V " << (void*)rsdp_str << ", P " << (void*)p_rsdp_str;
  329. #endif
  330. if (!strncmp("RSD PTR ", rsdp_str, strlen("RSD PTR ")))
  331. return PhysicalAddress((FlatPtr)p_rsdp_str);
  332. p_rsdp_str += 16;
  333. }
  334. return {};
  335. }
  336. inline bool StaticParsing::validate_table(Structures::SDTHeader& v_header, size_t length)
  337. {
  338. u8 checksum = 0;
  339. auto* sdt = (u8*)&v_header;
  340. for (size_t i = 0; i < length; i++)
  341. checksum += sdt[i];
  342. if (checksum == 0)
  343. return true;
  344. return false;
  345. }
  346. PhysicalAddress StaticParsing::search_rsdp()
  347. {
  348. PhysicalAddress rsdp;
  349. auto region = MM.allocate_kernel_region(PhysicalAddress(0), PAGE_SIZE, "ACPI RSDP Searching", Region::Access::Read);
  350. u16 ebda_seg = (u16) * ((uint16_t*)((region->vaddr().get() & PAGE_MASK) + 0x40e));
  351. klog() << "ACPI: Probing EBDA, Segment 0x" << String::format("%x", ebda_seg);
  352. rsdp = search_rsdp_in_ebda(ebda_seg);
  353. if (!rsdp.is_null())
  354. return rsdp;
  355. return search_rsdp_in_bios_area();
  356. }
  357. PhysicalAddress StaticParsing::search_table(PhysicalAddress rsdp, const char* signature)
  358. {
  359. // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables.
  360. // FIXME: Don't blindly use PAGE_SIZE here, but probe the actual length.
  361. ASSERT(strlen(signature) == 4);
  362. auto rsdp_region = MM.allocate_kernel_region(rsdp.page_base(), (PAGE_SIZE * 2), "ACPI Static Parsing search_table()", Region::Access::Read, false, true);
  363. volatile auto* rsdp_ptr = (Structures::RSDPDescriptor20*)rsdp_region->vaddr().offset(rsdp.offset_in_page()).as_ptr();
  364. if (rsdp_ptr->base.revision == 0) {
  365. return search_table_in_rsdt(PhysicalAddress(rsdp_ptr->base.rsdt_ptr), signature);
  366. }
  367. if (rsdp_ptr->base.revision >= 2) {
  368. if (rsdp_ptr->xsdt_ptr != (u64) nullptr)
  369. return search_table_in_xsdt(PhysicalAddress(rsdp_ptr->xsdt_ptr), signature);
  370. return search_table_in_rsdt(PhysicalAddress(rsdp_ptr->base.rsdt_ptr), signature);
  371. }
  372. ASSERT_NOT_REACHED();
  373. }
  374. PhysicalAddress StaticParsing::search_table_in_xsdt(PhysicalAddress xsdt, const char* signature)
  375. {
  376. // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables.
  377. // FIXME: Don't blindly use PAGE_SIZE here, but probe the actual length.
  378. ASSERT(strlen(signature) == 4);
  379. auto main_sdt_region = MM.allocate_kernel_region(xsdt.page_base(), PAGE_SIZE, "ACPI Static Parsing search_table_in_xsdt()", Region::Access::Read, false, true);
  380. auto* xsdt_ptr = (volatile Structures::XSDT*)main_sdt_region->vaddr().offset(xsdt.offset_in_page()).as_ptr();
  381. for (u32 i = 0; i < ((xsdt_ptr->h.length - sizeof(Structures::SDTHeader)) / sizeof(u64)); i++) {
  382. if (match_table_signature(PhysicalAddress((FlatPtr)xsdt_ptr->table_ptrs[i]), signature))
  383. return PhysicalAddress((FlatPtr)xsdt_ptr->table_ptrs[i]);
  384. }
  385. return {};
  386. }
  387. bool StaticParsing::match_table_signature(PhysicalAddress table_header, const char* signature)
  388. {
  389. // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables.
  390. // FIXME: Don't blindly use PAGE_SIZE here, but probe the actual length.
  391. ASSERT(strlen(signature) == 4);
  392. auto main_sdt_region = MM.allocate_kernel_region(table_header.page_base(), PAGE_SIZE, "ACPI Static Parsing match_table_signature()", Region::Access::Read, false, true);
  393. auto* table_ptr = (volatile Structures::RSDT*)main_sdt_region->vaddr().offset(table_header.offset_in_page()).as_ptr();
  394. return !strncmp(const_cast<const char*>(table_ptr->h.sig), signature, 4);
  395. }
  396. PhysicalAddress StaticParsing::search_table_in_rsdt(PhysicalAddress rsdt, const char* signature)
  397. {
  398. // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables.
  399. // FIXME: Don't blindly use PAGE_SIZE here, but probe the actual length.
  400. ASSERT(strlen(signature) == 4);
  401. auto main_sdt_region = MM.allocate_kernel_region(rsdt.page_base(), PAGE_SIZE, "ACPI Static Parsing search_table_in_rsdt()", Region::Access::Read, false, true);
  402. auto* rsdt_ptr = (volatile Structures::RSDT*)main_sdt_region->vaddr().offset(rsdt.offset_in_page()).as_ptr();
  403. for (u32 i = 0; i < ((rsdt_ptr->h.length - sizeof(Structures::SDTHeader)) / sizeof(u32)); i++) {
  404. if (match_table_signature(PhysicalAddress((FlatPtr)rsdt_ptr->table_ptrs[i]), signature))
  405. return PhysicalAddress((FlatPtr)rsdt_ptr->table_ptrs[i]);
  406. }
  407. return {};
  408. }
  409. }
  410. }