acpica: fix iomem handling code

Issue already encountered during #2242.

Fixes #2344
This commit is contained in:
Alexander Boettcher 2017-03-17 21:33:44 +01:00 committed by Christian Helmuth
parent 15a607f307
commit d8a151ef7d

View File

@ -38,18 +38,18 @@ class Acpica::Io_mem
{ {
private: private:
ACPI_PHYSICAL_ADDRESS _phys; ACPI_PHYSICAL_ADDRESS _phys = 0;
ACPI_SIZE _size; ACPI_SIZE _size = 0;
Genode::uint8_t *_virt = nullptr; Genode::uint8_t *_virt = nullptr;
Genode::Io_mem_connection *_io_mem = nullptr; Genode::Io_mem_connection *_io_mem = nullptr;
unsigned _ref; unsigned _ref = 0;
static Acpica::Io_mem _ios[32]; static Acpica::Io_mem _ios[32];
public: public:
bool valid() const { return _io_mem != nullptr; } bool unused() const { return _phys == 0 && _size == 0 && _io_mem == nullptr; }
bool refs() const { return _ref != ~0U; } bool stale() const { return !unused() && _io_mem == nullptr; }
bool contains_virt (const Genode::uint8_t * v, const ACPI_SIZE s) const bool contains_virt (const Genode::uint8_t * v, const ACPI_SIZE s) const
{ {
return _virt <= v && v + s <= _virt + _size; return _virt <= v && v + s <= _virt + _size;
@ -73,37 +73,42 @@ class Acpica::Io_mem
func(_ios[i]); func(_ios[i]);
} }
void invalidate(ACPI_SIZE s) void invalidate()
{ {
if (_io_mem && refs()) if (unused())
Genode::destroy(Acpica::heap(), _io_mem); FAIL();
ACPI_PHYSICAL_ADDRESS const p = _phys;
_phys = _size = 0;
_virt = nullptr;
_io_mem = nullptr;
if (refs())
return;
_ref = 0;
if (stale()) {
/** /**
* Continue in order to look for the larger entry that replaced * Look for the larger entry that replaced this one.
* this one. Required to decrement ref count. * Required to decrement ref count.
*/ */
apply_to_all([&] (Acpica::Io_mem &io_mem) { apply_to_all([&] (Acpica::Io_mem &io_mem) {
if (!io_mem.contains_phys(p, s) || !io_mem.refs()) if (&io_mem == this)
return;
if (!io_mem.contains_phys(_phys, _size))
return; return;
if (io_mem.ref_dec()) if (io_mem.ref_dec())
return; return;
io_mem.invalidate(s); io_mem._ref++;
io_mem.invalidate();
}); });
} }
if (ref_dec())
return;
if (!stale())
Genode::destroy(Acpica::heap(), _io_mem);
_phys = _size = 0;
_virt = nullptr;
_io_mem = nullptr;
}
template <typename FUNC> template <typename FUNC>
static Genode::addr_t apply_u(FUNC const &func = [] () { } ) static Genode::addr_t apply_u(FUNC const &func = [] () { } )
{ {
@ -130,7 +135,7 @@ class Acpica::Io_mem
unsigned r) unsigned r)
{ {
return Acpica::Io_mem::apply_p([&] (Acpica::Io_mem &io_mem) { return Acpica::Io_mem::apply_p([&] (Acpica::Io_mem &io_mem) {
if (io_mem.valid()) if (!io_mem.unused())
return reinterpret_cast<Acpica::Io_mem *>(0); return reinterpret_cast<Acpica::Io_mem *>(0);
io_mem._phys = p & ~0xFFFUL; io_mem._phys = p & ~0xFFFUL;
@ -163,8 +168,6 @@ class Acpica::Io_mem
if (_io_mem) if (_io_mem)
Genode::destroy(Acpica::heap(), _io_mem); Genode::destroy(Acpica::heap(), _io_mem);
_io_mem = nullptr;
Genode::addr_t xsize = _phys - p + _size; Genode::addr_t xsize = _phys - p + _size;
if (!allocate(p, xsize, _ref)) if (!allocate(p, xsize, _ref))
FAIL(0) FAIL(0)
@ -187,48 +190,34 @@ class Acpica::Io_mem
Genode::addr_t _expand(ACPI_PHYSICAL_ADDRESS const p, ACPI_SIZE const s) Genode::addr_t _expand(ACPI_PHYSICAL_ADDRESS const p, ACPI_SIZE const s)
{ {
/* mark this element as a stale reference */ /* mark this element as a stale reference */
_ref = ~0U; _io_mem = nullptr;
/* find new created entry */ /* find new created entry */
Genode::addr_t res = Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) { Genode::addr_t res = Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) {
if (!io_mem.valid() || !io_mem.refs() || if (io_mem.unused() || io_mem.stale() ||
!io_mem.contains_phys(p, s)) !io_mem.contains_phys(p, s))
return 0UL; return 0UL;
Genode::Io_mem_dataspace_capability const io_ds = io_mem._io_mem->dataspace(); Genode::Io_mem_dataspace_capability const io_ds = io_mem._io_mem->dataspace();
/* re-attach mem of stale entries partially using this iomem */ /* re-attach mem of stale entries partially using this iomem */
unsigned stale_count = 0;
Acpica::Io_mem::apply_to_all([&] (Acpica::Io_mem &io2) { Acpica::Io_mem::apply_to_all([&] (Acpica::Io_mem &io2) {
if (!io2.valid() || !io_mem.contains_phys(io2._phys, 0)) if (io2.unused() || !io2.stale() ||
return; !io_mem.contains_phys(io2._phys, 0))
if (io2.refs())
return; return;
Genode::addr_t off_phys = io2._phys - io_mem._phys; Genode::addr_t off_phys = io2._phys - io_mem._phys;
stale_count ++;
io2._io_mem = io_mem._io_mem;
Genode::addr_t virt = reinterpret_cast<Genode::addr_t>(io2._virt); Genode::addr_t virt = reinterpret_cast<Genode::addr_t>(io2._virt);
Acpica::env().rm().attach_at(io_ds, virt, io2._size, off_phys); Acpica::env().rm().attach_at(io_ds, virt, io2._size, off_phys);
}); });
/**
* In case the old *this* entry was solely a placeholder for
* other stale entries, the new one *io_mem* becomes just
* a placeholder too -> meaning ref must be increased by 1.
*/
if (io_mem._ref == stale_count)
io_mem._ref ++;
if (io_mem._virt) if (io_mem._virt)
FAIL(0UL); FAIL(0UL);
/* attach whole memory */ /* attach whole memory */
io_mem._virt = Acpica::env().rm().attach(io_ds); io_mem._virt = Acpica::env().rm().attach(io_ds);
return io_mem.to_virt(p); return io_mem.to_virt(p);
}); });
@ -246,7 +235,7 @@ Acpica::Io_mem Acpica::Io_mem::_ios[32];
void * AcpiOsMapMemory (ACPI_PHYSICAL_ADDRESS phys, ACPI_SIZE size) void * AcpiOsMapMemory (ACPI_PHYSICAL_ADDRESS phys, ACPI_SIZE size)
{ {
Genode::addr_t virt = Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) { Genode::addr_t virt = Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) {
if (!io_mem.valid() || !io_mem.refs()) if (io_mem.unused() || io_mem.stale())
return 0UL; return 0UL;
if (io_mem.contains_phys(phys, size)) if (io_mem.contains_phys(phys, size))
@ -279,13 +268,10 @@ void AcpiOsUnmapMemory (void * ptr, ACPI_SIZE size)
Genode::uint8_t const * virt = reinterpret_cast<Genode::uint8_t *>(ptr); Genode::uint8_t const * virt = reinterpret_cast<Genode::uint8_t *>(ptr);
if (Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) { if (Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) {
if (!io_mem.valid() || !io_mem.contains_virt(virt, size)) if (io_mem.unused() || !io_mem.contains_virt(virt, size))
return 0; return 0;
if (io_mem.refs() && io_mem.ref_dec()) io_mem.invalidate();
return 1;
io_mem.invalidate(size);
return 1; return 1;
})) }))
return; return;