acpi: be robuster on IO_MEM session denied

Issue #5406
This commit is contained in:
Alexander Boettcher
2024-12-13 10:29:44 +01:00
committed by Christian Helmuth
parent ae90a8a10d
commit 1a0a1b3f27

View File

@ -617,7 +617,7 @@ class Table_wrapper
return sum; return sum;
} }
bool valid() { return !checksum((uint8_t *)_table, _table->size); } bool valid() { return _table && !checksum((uint8_t *)_table, _table->size); }
bool is_ivrs() const { return _cmp("IVRS");} bool is_ivrs() const { return _cmp("IVRS");}
@ -720,8 +720,13 @@ class Table_wrapper
Registry<Info> &registry, Allocator &heap) Registry<Info> &registry, Allocator &heap)
: _base(base), _table(0) : _base(base), _table(0)
{ {
/* make table header accessible */ try {
_table = reinterpret_cast<Generic *>(memory.map_region(base, 8)); /* make table header accessible */
_table = reinterpret_cast<Generic *>(memory.map_region(base, 8));
} catch (Service_denied &) {
error(__func__, " failed with exception");
return;
}
/* table size is known now - make it completely accessible (in place) */ /* table size is known now - make it completely accessible (in place) */
memory.map_region(base, _table->size); memory.map_region(base, _table->size);
@ -982,7 +987,7 @@ class Element : private List<Element>::Element
if (_name_len + parent_len > sizeof(_name)) { if (_name_len + parent_len > sizeof(_name)) {
Genode::error("name is not large enough"); Genode::error("name is not large enough");
throw -1; return;
} }
memcpy(_name, parent->_name, parent_len); memcpy(_name, parent->_name, parent_len);
@ -1440,7 +1445,7 @@ class Acpi_table
!Table_wrapper::checksum(area + addr, 20)) !Table_wrapper::checksum(area + addr, 20))
return area + addr; return area + addr;
throw -2; return 0;
} }
/** /**
@ -1454,8 +1459,7 @@ class Acpi_table
try { try {
_mmio.construct(_env, BIOS_BASE, BIOS_SIZE); _mmio.construct(_env, BIOS_BASE, BIOS_SIZE);
return _search_rsdp(_mmio->local_addr<uint8_t>(), BIOS_SIZE); return _search_rsdp(_mmio->local_addr<uint8_t>(), BIOS_SIZE);
} } catch (...) { }
catch (...) { }
/* search EBDA (BIOS addr + 0x40e) */ /* search EBDA (BIOS addr + 0x40e) */
try { try {
@ -1586,51 +1590,58 @@ class Acpi_table
if (!rsdt && !xsdt) { if (!rsdt && !xsdt) {
uint8_t * ptr_rsdp = _rsdp(); uint8_t * ptr_rsdp = _rsdp();
struct rsdp { if (ptr_rsdp) {
char signature[8]; struct rsdp {
uint8_t checksum; char signature[8];
char oemid[6]; uint8_t checksum;
uint8_t revision; char oemid[6];
/* table pointer at 16 byte offset in RSDP structure (5.2.5.3) */ uint8_t revision;
uint32_t rsdt; /* table pointer at 16 byte offset in RSDP structure (5.2.5.3) */
/* With ACPI 2.0 */ uint32_t rsdt;
uint32_t len; /* With ACPI 2.0 */
uint64_t xsdt; uint32_t len;
uint8_t checksum_extended; uint64_t xsdt;
uint8_t reserved[3]; uint8_t checksum_extended;
} __attribute__((packed)); uint8_t reserved[3];
struct rsdp * rsdp = reinterpret_cast<struct rsdp *>(ptr_rsdp); } __attribute__((packed));
struct rsdp * rsdp = reinterpret_cast<struct rsdp *>(ptr_rsdp);
if (!rsdp) { if (rsdp) {
Genode::error("No valid ACPI RSDP structure found"); rsdt = rsdp->rsdt;
return; xsdt = rsdp->xsdt;
acpi_revision = rsdp->revision;
} else {
Genode::error("No valid ACPI RSDP structure found");
}
} }
rsdt = rsdp->rsdt;
xsdt = rsdp->xsdt;
acpi_revision = rsdp->revision;
/* drop rsdp io_mem mapping since rsdt/xsdt may overlap */ /* drop rsdp io_mem mapping since rsdt/xsdt may overlap */
_mmio.destruct(); _mmio.destruct();
} }
if (acpi_revision != 0 && xsdt && sizeof(addr_t) != sizeof(uint32_t)) { if (rsdt || xsdt) {
/* running 64bit and xsdt is valid */ if (acpi_revision != 0 && xsdt && sizeof(addr_t) != sizeof(uint32_t)) {
Table_wrapper table(_memory, xsdt, _table_registry, _heap); /* running 64bit and xsdt is valid */
if (!table.valid()) throw -1; Table_wrapper table(_memory, xsdt, _table_registry, _heap);
if (table.valid()) {
uint64_t * entries = reinterpret_cast<uint64_t *>(table.table() + 1);
_parse_tables(entries, table.entry_count(entries));
uint64_t * entries = reinterpret_cast<uint64_t *>(table.table() + 1); log("XSDT ", *table.table());
_parse_tables(entries, table.entry_count(entries)); } else
error("XSDT parsing error");
Genode::log("XSDT ", *table.table()); } else {
} else { /* running (32bit) or (64bit and xsdt isn't valid) */
/* running (32bit) or (64bit and xsdt isn't valid) */ Table_wrapper table(_memory, rsdt, _table_registry, _heap);
Table_wrapper table(_memory, rsdt, _table_registry, _heap); if (table.valid()) {
if (!table.valid()) throw -1; uint32_t * entries = reinterpret_cast<uint32_t *>(table.table() + 1);
_parse_tables(entries, table.entry_count(entries));
uint32_t * entries = reinterpret_cast<uint32_t *>(table.table() + 1); log("RSDT ", *table.table());
_parse_tables(entries, table.entry_count(entries)); } else
error("RSDT parsing error");
Genode::log("RSDT ", *table.table()); }
} }
/* free up memory of elements not of any use */ /* free up memory of elements not of any use */
@ -1813,6 +1824,10 @@ void Acpi::generate_report(Genode::Env &env, Genode::Allocator &alloc,
* Intel opregion lookup & parsing must be finished before acpi * Intel opregion lookup & parsing must be finished before acpi
* report is sent, therefore the invocation is placed exactly here. * report is sent, therefore the invocation is placed exactly here.
*/ */
Pci_config_space::intel_opregion(env); try {
Pci_config_space::intel_opregion(env);
} catch (...) {
error("Intel opregion handling failed");
}
}); });
} }