diff --git a/repos/libports/src/lib/libdrm/ioctl_iris.cc b/repos/libports/src/lib/libdrm/ioctl_iris.cc index 256a9eb5c0..82e59b2042 100644 --- a/repos/libports/src/lib/libdrm/ioctl_iris.cc +++ b/repos/libports/src/lib/libdrm/ioctl_iris.cc @@ -253,12 +253,20 @@ class Drm_call Genode::Hex(buffer.gpu_vaddr.addr), " vs ", Genode::Hex(vaddr.addr)); -/* XXX out of cap XXX */ bool const ppgtt = Genode::retry( - [&]() { return _gpu_session.map_buffer_ppgtt(buffer.id(), - Utils::limit_to_48bit(vaddr.addr)); }, - [&]() { _gpu_session.upgrade_ram(4096); } - ); + [&]() { + return Genode::retry( + [&] () { + return _gpu_session.map_buffer_ppgtt(buffer.id(), + Utils::limit_to_48bit(vaddr.addr)); + }, + [&] () { + _gpu_session.upgrade_caps(2); + }); + }, + [&] () { + _gpu_session.upgrade_ram(4096); + }); if (!ppgtt) { Genode::error("could not insert buffer into PPGTT"); @@ -286,12 +294,17 @@ class Drm_call Buffer *buffer = nullptr; Genode::retry( [&] () { - buffer = - new (&_heap) Buffer(_gpu_session, size, _buffer_space); + Genode::retry( + [&] () { + buffer = + new (&_heap) Buffer(_gpu_session, size, _buffer_space); + }, + [&] () { + _gpu_session.upgrade_caps(2); + }); }, [&] () { _gpu_session.upgrade_ram(donate); - donate /= 4; }); if (buffer) @@ -339,13 +352,25 @@ class Drm_call } try { - _gpu_session.upgrade_ram(4096); - b.map_cap = _gpu_session.map_buffer(b.id(), true, - Gpu::Mapping_attributes::rw()); - b.map_offset = static_cast(_env.rm().attach(b.map_cap)); - offset = b.map_offset; + Genode::retry( + [&]() { + Genode::retry( + [&] () { + b.map_cap = _gpu_session.map_buffer(b.id(), true, + Gpu::Mapping_attributes::rw()); + b.map_offset = static_cast(_env.rm().attach(b.map_cap)); + offset = b.map_offset; + + _available_gtt_size -= b.size; + }, + [&] () { + _gpu_session.upgrade_caps(2); + }); + }, + [&] () { + _gpu_session.upgrade_ram(4096); + }); - _available_gtt_size -= b.size; } catch (...) { if (b.map_cap.valid()) _gpu_session.unmap_buffer(b.id()); diff --git a/repos/os/src/drivers/gpu/intel/main.cc b/repos/os/src/drivers/gpu/intel/main.cc index 616ba48506..e93e834022 100644 --- a/repos/os/src/drivers/gpu/intel/main.cc +++ b/repos/os/src/drivers/gpu/intel/main.cc @@ -74,6 +74,7 @@ struct Igd::Device_info struct Igd::Device { struct Unsupported_device : Genode::Exception { }; + struct Out_of_caps : Genode::Exception { }; struct Out_of_ram : Genode::Exception { }; struct Could_not_map_buffer : Genode::Exception { }; @@ -101,6 +102,43 @@ struct Igd::Device return _pci.alloc_dma_buffer(size, Genode::UNCACHED); }); } + Ram_dataspace_capability alloc(size_t size, + Cap_quota_guard &caps_guard, + Ram_quota_guard &ram_guard) override + { + /* + * For now we only reflect quota exceptions on explicit user + * allocations, e.g., buffers. + */ + try { + Genode::size_t donate = size; + return retry( + [&] () { + return retry( + [&] () { + return _pci.alloc_dma_buffer(size, Genode::UNCACHED); + }, + [&] () { + enum { UPGRADE_CAP_QUOTA = 2, }; + Cap_quota const caps { 2 }; + caps_guard.withdraw(caps); + _pci.upgrade_caps(caps.value); + } + ); + }, + [&] () { + Ram_quota const ram { donate }; + ram_guard.withdraw(ram); + _pci.upgrade_ram(ram.value); + } + ); + } catch (Ram_quota_guard::Limit_exceeded) { + throw Out_of_ram(); + } catch (Cap_quota_guard::Limit_exceeded) { + throw Out_of_caps(); + } + } + void free(Ram_dataspace_capability cap) override { if (!cap.valid()) { @@ -445,11 +483,13 @@ struct Igd::Device Engine(Igd::Device &device, uint32_t id, - Allocator &alloc) + Allocator &alloc, + Cap_quota_guard &caps_guard, + Ram_quota_guard &ram_guard) : ctx (device._env.rm(), alloc, device, CONTEXT::CONTEXT_PAGES, 1 /* omit GuC page */), ring(device._env.rm(), alloc, device, CONTEXT::RING_PAGES, 0), - ppgtt_allocator(device._env.rm(), device._pci_backend_alloc), + ppgtt_allocator(device._env.rm(), device._pci_backend_alloc, caps_guard, ram_guard), ppgtt_scratch(device._pci_backend_alloc) { /* PPGTT */ @@ -559,11 +599,13 @@ struct Igd::Device } Vgpu(Device &device, Allocator &alloc, - Ram_allocator &ram, Region_map &rm) + Ram_allocator &ram, Region_map &rm, + Cap_quota_guard &caps_guard, + Ram_quota_guard &ram_guard) : _device(device), _id(_id_alloc()), - rcs(_device, _id + Rcs_context::HW_ID, alloc), + rcs(_device, _id + Rcs_context::HW_ID, alloc, caps_guard, ram_guard), _info_dataspace(ram, rm, INFO_SIZE) { _device.vgpu_created(); @@ -843,16 +885,9 @@ struct Igd::Device Genode::Page_flags pf; pf.writeable = Genode::Writeable::RW; - try { - rcs.ppgtt->insert_translation(vo, pa, size, pf, - &rcs.ppgtt_allocator, - &rcs.ppgtt_scratch.pdp); - } catch (Igd::Ppgtt_allocator::Out_of_memory) { - throw Igd::Device::Out_of_ram(); - } catch (...) { - /* Double_insertion and the like */ - throw Igd::Device::Could_not_map_buffer(); - } + rcs.ppgtt->insert_translation(vo, pa, size, pf, + &rcs.ppgtt_allocator, + &rcs.ppgtt_scratch.pdp); } void rcs_unmap_ppgtt(addr_t vo, size_t size) @@ -1313,9 +1348,11 @@ struct Igd::Device * \throw Out_of_memory */ Genode::Dataspace_capability alloc_buffer(Allocator &, - size_t const size) + size_t const size, + Cap_quota_guard &cap_guard, + Ram_quota_guard &ram_guard) { - return _pci_backend_alloc.alloc(size); + return _pci_backend_alloc.alloc(size, cap_guard, ram_guard); } /** @@ -1347,13 +1384,9 @@ struct Igd::Device Genode::Dataspace_capability cap, bool aperture) { size_t const size = Genode::Dataspace_client(cap).size(); - try { - size_t const num = size / PAGE_SIZE; - Ggtt::Offset const offset = _ggtt->find_free(num, aperture); - return map_dataspace_ggtt(guard, cap, offset); - } catch (...) { - throw Could_not_map_buffer(); - } + size_t const num = size / PAGE_SIZE; + Ggtt::Offset const offset = _ggtt->find_free(num, aperture); + return map_dataspace_ggtt(guard, cap, offset); } /** @@ -1453,6 +1486,8 @@ struct Igd::Device void enable_master_irq() { _mmio.enable_master_irq(); } + Resources &resources() { return _resources; } + private: /* @@ -1541,6 +1576,19 @@ class Gpu::Session_component : public Genode::Session_object _buffer_registry.for_each(lookup_and_free); } + void _throw_if_avail_quota_insufficient(Cap_quota caps, Ram_quota ram) + { + Cap_quota const c = _cap_quota_guard().avail(); + if (c.value < caps.value) + throw Out_of_caps(); + + Ram_quota const r = _ram_quota_guard().avail(); + enum { MINIMAL_RAM_AMOUNT = 4096, }; + if (r.value < ram.value) + throw Out_of_ram(); + } + + public: /** @@ -1563,7 +1611,7 @@ class Gpu::Session_component : public Genode::Session_object _rm(rm), _ram(ram, _ram_quota_guard(), _cap_quota_guard()), _device(device), - _vgpu(_device, _heap, ram, rm) + _vgpu(_device, _heap, ram, rm, _cap_quota_guard(), _ram_quota_guard()) { } ~Session_component() @@ -1643,7 +1691,8 @@ class Gpu::Session_component : public Genode::Session_object size = ((size + 0xffful) & ~0xffful); try { - Genode::Dataspace_capability cap = _device.alloc_buffer(_heap, size); + Genode::Dataspace_capability cap = + _device.alloc_buffer(_heap, size, _cap_quota_guard(), _ram_quota_guard()); try { new (&_heap) Genode::Registered(_buffer_registry, id, cap); @@ -1653,6 +1702,8 @@ class Gpu::Session_component : public Genode::Session_object throw Gpu::Session_component::Out_of_ram(); } return cap; + } catch (Igd::Device::Out_of_caps) { + throw Gpu::Session_component::Out_of_caps(); } catch (Igd::Device::Out_of_ram) { throw Gpu::Session_component::Out_of_ram(); } @@ -1679,6 +1730,13 @@ class Gpu::Session_component : public Genode::Session_object bool aperture, Gpu::Mapping_attributes attrs) override { + enum { + CAP_AMOUNT = 2, + RAM_AMOUNT = 4096, + }; + _throw_if_avail_quota_insufficient(Cap_quota { CAP_AMOUNT }, + Ram_quota { RAM_AMOUNT }); + /* treat GGTT mapped buffers as rw */ if (!(attrs.readable && attrs.writeable)) return Genode::Dataspace_capability(); @@ -1698,8 +1756,7 @@ class Gpu::Session_component : public Genode::Session_object buffer.map.cap = map.cap; buffer.map.offset = map.offset; map_cap = buffer.map.cap; - } catch (Igd::Device::Could_not_map_buffer) { - Genode::error("could not map buffer object"); + } catch (Ram_quota_guard::Limit_exceeded) { throw Gpu::Session::Out_of_ram(); } }; @@ -1731,7 +1788,19 @@ class Gpu::Session_component : public Genode::Session_object bool map_buffer_ppgtt(Gpu::Buffer_id id, Gpu::addr_t va) override { - enum { ALLOC_FAILED, MAP_FAILED, OK } result = ALLOC_FAILED; + enum { + CAP_AMOUNT = 32, + RAM_AMOUNT = 8192, + }; + _throw_if_avail_quota_insufficient(Cap_quota { CAP_AMOUNT }, + Ram_quota { RAM_AMOUNT }); + + enum { + ALLOC_FAILED_RAM, + ALLOC_FAILED_CAPS, + MAP_FAILED, + OK + } result = ALLOC_FAILED_RAM; auto lookup_and_map = [&] (Buffer &buffer) { @@ -1749,21 +1818,25 @@ class Gpu::Session_component : public Genode::Session_object buffer.ppgtt_va = va; buffer.ppgtt_va_valid = true; result = OK; - } catch (Igd::Device::Could_not_map_buffer) { + } catch (Igd::Device::Out_of_caps) { + result = ALLOC_FAILED_CAPS; + return; + } catch (Igd::Device::Out_of_ram) { + result = ALLOC_FAILED_RAM; + return; + } catch (...) { + /* double inseration where the addresses do not match up */ Genode::error("could not map buffer object (", Genode::Hex(va), ") into PPGTT"); result = MAP_FAILED; return; } - catch (Igd::Device::Out_of_ram) { - result = ALLOC_FAILED; - return; - } }; _apply_buffer(id, lookup_and_map); switch (result) { - case ALLOC_FAILED: throw Gpu::Session::Out_of_ram(); - case MAP_FAILED: throw Gpu::Session::Mapping_buffer_failed(); + case ALLOC_FAILED_CAPS: throw Gpu::Session::Out_of_caps(); + case ALLOC_FAILED_RAM: throw Gpu::Session::Out_of_ram(); + case MAP_FAILED: throw Gpu::Session::Mapping_buffer_failed(); case OK: return true; default: return false; @@ -1864,12 +1937,22 @@ class Gpu::Root : public Gpu::Root_component throw Session::Out_of_ram(); } + Genode::Session::Resources resources = session_resources_from_args(args); + Cap_quota const minimal_caps { 220 }; + resources.cap_quota.value -= minimal_caps.value; + _device->resources().platform().upgrade_caps(minimal_caps.value); + + Ram_quota const minimal_ram { 128u << 10 }; + resources.ram_quota.value -= minimal_ram.value; + _device->resources().platform().upgrade_ram(minimal_ram.value); + try { + using namespace Genode; return new (md_alloc()) Session_component(_env.ep(), _env.ram(), _env.rm(), - session_resources_from_args(args), + resources, session_label_from_args(args), session_diag_from_args(args), *_device); @@ -1878,8 +1961,13 @@ class Gpu::Root : public Gpu::Root_component void _upgrade_session(Session_component *s, const char *args) override { - s->upgrade(ram_quota_from_args(args)); - s->upgrade(cap_quota_from_args(args)); + Genode::Ram_quota ram_quota = ram_quota_from_args(args); + ram_quota.value /= 2; + Genode::Cap_quota caps_quota = cap_quota_from_args(args); + caps_quota.value /= 2; + + s->upgrade(ram_quota); + s->upgrade(caps_quota); } void _destroy_session(Session_component *s) override diff --git a/repos/os/src/drivers/gpu/intel/ppgtt.h b/repos/os/src/drivers/gpu/intel/ppgtt.h index 44690868db..81fb88bafc 100644 --- a/repos/os/src/drivers/gpu/intel/ppgtt.h +++ b/repos/os/src/drivers/gpu/intel/ppgtt.h @@ -273,7 +273,9 @@ class Genode::Level_4_translation_table Descriptor::access_t table_entry = Descriptor::create(flags, pa); - if (!Descriptor::scratch(desc, scratch->addr)) { + /* only complain if we overmap */ + if ( !Descriptor::scratch(desc, scratch->addr) + && !Descriptor::scratch(desc, pa)) { throw Double_insertion(); } desc = table_entry; @@ -469,8 +471,7 @@ class Genode::Page_directory if (!alloc) { throw Allocator::Out_of_memory(); } /* create and link next level table */ - try { table = new (alloc) ENTRY(scratch->next); } - catch (...) { throw Allocator::Out_of_memory(); } + table = new (alloc) ENTRY(scratch->next); ENTRY * phys_addr = (ENTRY*) alloc->phys_addr(table); Gpu::addr_t const pa = (Gpu::addr_t)(phys_addr ? phys_addr : table); @@ -661,8 +662,7 @@ class Genode::Pml4_table if (!alloc) { throw Allocator::Out_of_memory(); } /* create and link next level table */ - try { table = new (alloc) ENTRY(scratch->next); } - catch (...) { throw Allocator::Out_of_memory(); } + table = new (alloc) ENTRY(scratch->next); ENTRY * phys_addr = (ENTRY*) alloc->phys_addr(table); Gpu::addr_t const pa = (Gpu::addr_t)(phys_addr ? phys_addr : table); diff --git a/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h b/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h index 0ef1b23cdf..d5dad045af 100644 --- a/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h +++ b/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h @@ -35,11 +35,21 @@ class Igd::Ppgtt_allocator : public Genode::Translation_table_allocator enum { ELEMENTS = 256, }; Utils::Address_map _map { }; + Genode::Cap_quota_guard &_caps_guard; + Genode::Ram_quota_guard &_ram_guard; + public: Ppgtt_allocator(Genode::Region_map &rm, - Utils::Backend_alloc &backend) - : _rm(rm), _backend(backend) { } + Utils::Backend_alloc &backend, + Genode::Cap_quota_guard &caps_guard, + Genode::Ram_quota_guard &ram_guard) + : + _rm { rm }, + _backend { backend }, + _caps_guard { caps_guard }, + _ram_guard { ram_guard } + { } /************************* ** Allocator interface ** @@ -47,8 +57,8 @@ class Igd::Ppgtt_allocator : public Genode::Translation_table_allocator bool alloc(size_t size, void **out_addr) override { - Genode::Ram_dataspace_capability ds = _backend.alloc(size); - if (!ds.valid()) { return false; } + Genode::Ram_dataspace_capability ds = + _backend.alloc(size, _caps_guard, _ram_guard); *out_addr = _rm.attach(ds); return _map.add(ds, *out_addr); diff --git a/repos/os/src/drivers/gpu/intel/utils.h b/repos/os/src/drivers/gpu/intel/utils.h index 4547be33b4..bf5d00d3de 100644 --- a/repos/os/src/drivers/gpu/intel/utils.h +++ b/repos/os/src/drivers/gpu/intel/utils.h @@ -30,6 +30,7 @@ namespace Utils { struct Backend_alloc : Genode::Interface { virtual Ram alloc(Genode::size_t) = 0; + virtual Ram alloc(Genode::size_t, Genode::Cap_quota_guard &, Genode::Ram_quota_guard&) = 0; virtual void free(Ram) = 0; };