diff --git a/repos/dde_bsd/src/lib/audio/bus.cc b/repos/dde_bsd/src/lib/audio/bus.cc index d73e3ed00..ab9352c49 100644 --- a/repos/dde_bsd/src/lib/audio/bus.cc +++ b/repos/dde_bsd/src/lib/audio/bus.cc @@ -19,6 +19,7 @@ #include #include #include +#include /* local includes */ #include "bsd.h" @@ -120,13 +121,17 @@ class Pci_driver : public Bsd::Bus_driver */ Genode::Ram_dataspace_capability _alloc_dma_memory(Genode::size_t size) { - try { - char buf[32]; - Genode::snprintf(buf, sizeof(buf), "ram_quota=%zu", size); - Genode::env()->parent()->upgrade(_pci.cap(), buf); + size_t donate = size; - return _pci.alloc_dma_buffer(size); - } catch (...) { return Genode::Ram_dataspace_capability(); } + return Genode::retry( + [&] () { return _pci.alloc_dma_buffer(size); }, + [&] () { + char quota[32]; + Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd", + donate); + Genode::env()->parent()->upgrade(_pci.cap(), quota); + donate = donate * 2 > size ? 4096 : donate * 2; + }); } public: @@ -374,7 +379,18 @@ extern "C" int pci_mapreg_map(struct pci_attach_args *pa, } cmd |= Pci_driver::CMD_MASTER; - device.config_write(Pci_driver::CMD, cmd, Platform::Device::ACCESS_16BIT); + + Genode::size_t donate = 4096; + Genode::retry( + [&] () { device.config_write(Pci_driver::CMD, cmd, + Platform::Device::ACCESS_16BIT); }, + [&] () { + char quota[32]; + Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd", + donate); + Genode::env()->parent()->upgrade(drv->pci().cap(), quota); + donate *= 2; + }); return 0; } diff --git a/repos/dde_ipxe/src/lib/dde_ipxe/dde_support.cc b/repos/dde_ipxe/src/lib/dde_ipxe/dde_support.cc index a5fd7f75e..2333f637d 100644 --- a/repos/dde_ipxe/src/lib/dde_ipxe/dde_support.cc +++ b/repos/dde_ipxe/src/lib/dde_ipxe/dde_support.cc @@ -35,6 +35,8 @@ #include #include #include +#include + /* local includes */ #include @@ -168,7 +170,17 @@ struct Pci_driver void config_write(unsigned int devfn, T val) { Platform::Device_client client(_cap); - client.config_write(devfn, val, _access_size(val)); + + Genode::size_t donate = 4096; + Genode::retry( + [&] () { client.config_write(devfn, val, _access_size(val)); } , + [&] () { + char quota[32]; + Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd", + donate); + Genode::env()->parent()->upgrade(_pci.cap(), quota); + donate *= 2; + }); } int first_device(int *bus, int *dev, int *fun) @@ -196,18 +208,26 @@ struct Pci_driver try { using namespace Genode; - /* transfer quota to pci driver, otherwise it will give us a exception */ - char buf[32]; - Genode::snprintf(buf, sizeof(buf), "ram_quota=%zd", size); - Genode::env()->parent()->upgrade(_pci.cap(), buf); + size_t donate = size; - Ram_dataspace_capability ram_cap = _pci.alloc_dma_buffer(size); + Ram_dataspace_capability ram_cap = Genode::retry( + [&] () { return _pci.alloc_dma_buffer(size); }, + [&] () { + char quota[32]; + Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd", + donate); + Genode::env()->parent()->upgrade(_pci.cap(), quota); + donate = donate * 2 > size ? 4096 : donate * 2; + }); _region.mapped_base = (Genode::addr_t)env()->rm_session()->attach(ram_cap); _region.base = Dataspace_client(ram_cap).phys_addr(); return _region.mapped_base; - } catch (...) { return 0; } + } catch (...) { + PERR("failed to allocate dma memory"); + return 0; + } } Genode::addr_t virt_to_phys(Genode::addr_t virt) { diff --git a/repos/dde_linux/src/lib/usb/pci_driver.cc b/repos/dde_linux/src/lib/usb/pci_driver.cc index ed1bc6274..a8862bda7 100644 --- a/repos/dde_linux/src/lib/usb/pci_driver.cc +++ b/repos/dde_linux/src/lib/usb/pci_driver.cc @@ -16,6 +16,7 @@ #include #include #include +#include /* Genode os includes */ #include @@ -421,7 +422,7 @@ int pci_register_driver(struct pci_driver *drv) try { cap = pci.next_device(cap, id->class_, id->class_mask); - } catch (Platform::Device::Quota_exceeded) { + } catch (Platform::Session::Out_of_metadata) { Genode::env()->parent()->upgrade(pci.cap(), "ram_quota=4096"); cap = pci.next_device(cap, id->class_, id->class_mask); } @@ -525,12 +526,16 @@ Backend_memory::alloc(Genode::addr_t size, Genode::Cache_attribute cached) cap = env()->ram_session()->alloc(size); o = new (env()->heap()) Ram_object(cap); } else { - /* transfer quota to pci driver, otherwise it will give us a exception */ - char buf[32]; - Genode::snprintf(buf, sizeof(buf), "ram_quota=%ld", size); - Genode::env()->parent()->upgrade(pci.cap(), buf); - - cap = pci.alloc_dma_buffer(size); + size_t donate = size; + cap = Genode::retry( + [&] () { return pci.alloc_dma_buffer(size); }, + [&] () { + char quota[32]; + Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd", + donate); + Genode::env()->parent()->upgrade(pci.cap(), quota); + donate = donate * 2 > size ? 4096 : donate * 2; + }); o = new (env()->heap()) Dma_object(cap); } diff --git a/repos/dde_linux/src/lib/wifi/pci_driver.cc b/repos/dde_linux/src/lib/wifi/pci_driver.cc index 9a17360cc..ccd1eedd5 100644 --- a/repos/dde_linux/src/lib/wifi/pci_driver.cc +++ b/repos/dde_linux/src/lib/wifi/pci_driver.cc @@ -454,12 +454,16 @@ Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached) cap = env()->ram_session()->alloc(size); o = new (env()->heap()) Ram_object(cap); } else { - /* transfer quota to pci driver, otherwise it will give us a exception */ - char buf[32]; - Genode::snprintf(buf, sizeof(buf), "ram_quota=%ld", size); - Genode::env()->parent()->upgrade(pci()->cap(), buf); - - cap = pci()->alloc_dma_buffer(size); + size_t donate = size; + cap = Genode::retry( + [&] () { return pci()->alloc_dma_buffer(size); }, + [&] () { + char quota[32]; + Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd", + donate); + Genode::env()->parent()->upgrade(pci()->cap(), quota); + donate = donate * 2 > size ? 4096 : donate * 2; + }); o = new (env()->heap()) Dma_object(cap); } diff --git a/repos/os/include/spec/x86/platform_device/platform_device.h b/repos/os/include/spec/x86/platform_device/platform_device.h index ca5f32739..d61598bf5 100644 --- a/repos/os/include/spec/x86/platform_device/platform_device.h +++ b/repos/os/include/spec/x86/platform_device/platform_device.h @@ -234,8 +234,9 @@ struct Platform::Device : Platform::Abstract_device GENODE_RPC(Rpc_resource, Resource, resource, int); GENODE_RPC(Rpc_config_read, unsigned, config_read, unsigned char, Access_size); - GENODE_RPC(Rpc_config_write, void, config_write, - unsigned char, unsigned, Access_size); + GENODE_RPC_THROW(Rpc_config_write, void, config_write, + GENODE_TYPE_LIST(Quota_exceeded), + unsigned char, unsigned, Access_size); GENODE_RPC(Rpc_irq, Genode::Irq_session_capability, irq, Genode::uint8_t); GENODE_RPC_THROW(Rpc_io_port, Genode::Io_port_session_capability, io_port, GENODE_TYPE_LIST(Quota_exceeded), diff --git a/repos/os/include/spec/x86/platform_session/client.h b/repos/os/include/spec/x86/platform_session/client.h index b92e362a6..c5bf3544a 100644 --- a/repos/os/include/spec/x86/platform_session/client.h +++ b/repos/os/include/spec/x86/platform_session/client.h @@ -38,9 +38,6 @@ struct Platform::Client : public Genode::Rpc_client void release_device(Device_capability device) override { call(device); } - Genode::Io_mem_dataspace_capability config_extended(Device_capability device_cap) override { - return call(device_cap); } - Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t size) override { return call(size); } diff --git a/repos/os/include/spec/x86/platform_session/platform_session.h b/repos/os/include/spec/x86/platform_session/platform_session.h index 6a9d9f6ae..77e8ea5f0 100644 --- a/repos/os/include/spec/x86/platform_session/platform_session.h +++ b/repos/os/include/spec/x86/platform_session/platform_session.h @@ -26,6 +26,14 @@ namespace Platform { struct Session; } struct Platform::Session : Genode::Session { + /********************* + ** Exception types ** + *********************/ + + class Alloc_failed : public Genode::Exception { }; + class Out_of_metadata : public Alloc_failed { }; + class Fatal : public Alloc_failed { }; + static const char *service_name() { return "Platform"; } virtual ~Session() { } @@ -53,12 +61,6 @@ struct Platform::Session : Genode::Session */ virtual void release_device(Device_capability device) = 0; - /** - * Provide mapping to device configuration space of 4k, known as - * "Enhanced Configuration Access Mechanism (ECAM) for PCI Express - */ - virtual Genode::Io_mem_dataspace_capability config_extended(Device_capability) = 0; - typedef Genode::Rpc_in_buffer<8> String; /** @@ -82,28 +84,23 @@ struct Platform::Session : Genode::Session *********************/ GENODE_RPC_THROW(Rpc_first_device, Device_capability, first_device, - GENODE_TYPE_LIST(Platform::Device::Quota_exceeded), + GENODE_TYPE_LIST(Out_of_metadata), unsigned, unsigned); GENODE_RPC_THROW(Rpc_next_device, Device_capability, next_device, - GENODE_TYPE_LIST(Platform::Device::Quota_exceeded), + GENODE_TYPE_LIST(Out_of_metadata), Device_capability, unsigned, unsigned); GENODE_RPC(Rpc_release_device, void, release_device, Device_capability); - GENODE_RPC_THROW(Rpc_config_extended, Genode::Io_mem_dataspace_capability, - config_extended, - GENODE_TYPE_LIST(Platform::Device::Quota_exceeded), - Device_capability); GENODE_RPC_THROW(Rpc_alloc_dma_buffer, Genode::Ram_dataspace_capability, alloc_dma_buffer, - GENODE_TYPE_LIST(Platform::Device::Quota_exceeded), + GENODE_TYPE_LIST(Out_of_metadata, Fatal), Genode::size_t); GENODE_RPC(Rpc_free_dma_buffer, void, free_dma_buffer, Genode::Ram_dataspace_capability); GENODE_RPC_THROW(Rpc_device, Device_capability, device, - GENODE_TYPE_LIST(Platform::Device::Quota_exceeded), + GENODE_TYPE_LIST(Out_of_metadata), String const &); GENODE_RPC_INTERFACE(Rpc_first_device, Rpc_next_device, - Rpc_release_device, Rpc_config_extended, - Rpc_alloc_dma_buffer, Rpc_free_dma_buffer, - Rpc_device); + Rpc_release_device, Rpc_alloc_dma_buffer, + Rpc_free_dma_buffer, Rpc_device); }; diff --git a/repos/os/src/drivers/ahci/spec/x86/platform.cc b/repos/os/src/drivers/ahci/spec/x86/platform.cc index 272e4f3a4..00c2d14d0 100644 --- a/repos/os/src/drivers/ahci/spec/x86/platform.cc +++ b/repos/os/src/drivers/ahci/spec/x86/platform.cc @@ -41,17 +41,15 @@ struct X86_hba : Platform::Hba X86_hba() { - for (unsigned i = 0; i < 2; i++) - try { - if (!(pci_device_cap = - pci.next_device(pci_device_cap, AHCI_DEVICE, CLASS_MASK)).valid()) { - PERR("No AHCI controller found"); - throw -1; - } - break; - } catch (Platform::Device::Quota_exceeded) { - Genode::env()->parent()->upgrade(pci.cap(), "ram_quota=4096"); - } + pci_device_cap = retry( + [&] () { return pci.next_device(pci_device_cap, AHCI_DEVICE, + CLASS_MASK); }, + [&] () { env()->parent()->upgrade(pci.cap(), "ram_quota=4096"); }); + + if (!pci_device_cap.valid()) { + PERR("No AHCI controller found"); + throw -1; + } /* construct pci client */ pci_device.construct(pci_device_cap); @@ -70,7 +68,7 @@ struct X86_hba : Platform::Hba /* enable bus master */ uint16_t cmd = pci_device->config_read(PCI_CMD, Platform::Device::ACCESS_16BIT); cmd |= 0x4; - pci_device->config_write(PCI_CMD, cmd, Platform::Device::ACCESS_16BIT); + _config_write(PCI_CMD, cmd, Platform::Device::ACCESS_16BIT); irq.construct(pci_device->irq(0)); } @@ -90,12 +88,28 @@ struct X86_hba : Platform::Hba uint16_t msi = pci_device->config_read(cap + 2, Platform::Device::ACCESS_16BIT); if (msi & MSI_ENABLED) { - pci_device->config_write(cap + 2, msi ^ MSI_CAP, Platform::Device::ACCESS_8BIT); + _config_write(cap + 2, msi ^ MSI_CAP, + Platform::Device::ACCESS_8BIT); PINF("Disabled MSIs %x", msi); } } } + void _config_write(uint8_t op, uint16_t cmd, + Platform::Device::Access_size width) + { + Genode::size_t donate = 4096; + Genode::retry( + [&] () { pci_device->config_write(op, cmd, width); }, + [&] () { + char quota[32]; + Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd", + donate); + Genode::env()->parent()->upgrade(pci.cap(), quota); + donate *= 2; + }); + } + /******************* ** Hba interface ** @@ -115,12 +129,16 @@ struct X86_hba : Platform::Hba Ram_dataspace_capability alloc_dma_buffer(Genode::size_t size) override { - /* transfer quota to pci driver, otherwise we get a exception */ - char quota[32]; - snprintf(quota, sizeof(quota), "ram_quota=%zd", size); - env()->parent()->upgrade(pci.cap(), quota); + size_t donate = size; - return pci.alloc_dma_buffer(size); + return retry( + [&] () { return pci.alloc_dma_buffer(size); }, + [&] () { + char quota[32]; + snprintf(quota, sizeof(quota), "ram_quota=%zd", donate); + env()->parent()->upgrade(pci.cap(), quota); + donate = donate * 2 > size ? 4096 : donate * 2; + }); } void free_dma_buffer(Genode::Ram_dataspace_capability ds) diff --git a/repos/os/src/drivers/platform/spec/x86/device_pd.h b/repos/os/src/drivers/platform/spec/x86/device_pd.h index 891997bda..88e1ebec0 100644 --- a/repos/os/src/drivers/platform/spec/x86/device_pd.h +++ b/repos/os/src/drivers/platform/spec/x86/device_pd.h @@ -15,10 +15,7 @@ #include -enum { - DEVICE_PD_RAM_QUOTA = 256 * 4096, - STACK_SIZE = 2 * sizeof(void *)*1024 -}; +enum { STACK_SIZE = 2 * sizeof(void *) * 1024 }; namespace Platform { class Device_pd_policy; } @@ -29,7 +26,8 @@ class Platform::Device_pd_policy : public Genode::Slave_policy Genode::Root_capability _cap; Genode::Lock _lock; - Genode::Slave _device_pd_slave; + Genode::Ram_session_capability _ram_ref_cap; + Genode::Slave _device_pd_slave; protected: @@ -41,11 +39,14 @@ class Platform::Device_pd_policy : public Genode::Slave_policy public: - Device_pd_policy(Genode::Rpc_entrypoint &slave_ep) + Device_pd_policy(Genode::Rpc_entrypoint &slave_ep, + Genode::Ram_session_capability ram_ref_cap, + Genode::addr_t device_pd_ram_quota) : Slave_policy("device_pd", slave_ep), _lock(Genode::Lock::LOCKED), - _device_pd_slave(slave_ep, *this, DEVICE_PD_RAM_QUOTA) + _ram_ref_cap(ram_ref_cap), + _device_pd_slave(slave_ep, *this, device_pd_ram_quota, ram_ref_cap) { } bool announce_service(const char *service_name, @@ -69,6 +70,15 @@ class Platform::Device_pd_policy : public Genode::Slave_policy _lock.lock(); return _cap; } + + Genode::Ram_connection &ram_slave() { return _device_pd_slave.ram(); } + + /** + * Override struct Genode::Child_policy::ref_ram_cap with our ram cap + */ + Genode::Ram_session_capability ref_ram_cap() const override { + return _ram_ref_cap; } + }; diff --git a/repos/os/src/drivers/platform/spec/x86/device_pd/main.cc b/repos/os/src/drivers/platform/spec/x86/device_pd/main.cc index 130351401..0c30e20ce 100644 --- a/repos/os/src/drivers/platform/spec/x86/device_pd/main.cc +++ b/repos/os/src/drivers/platform/spec/x86/device_pd/main.cc @@ -17,12 +17,58 @@ #include #include +#include #include #include +#include #include "../pci_device_pd_ipc.h" +/** + * + */ +struct Expanding_rm_session_client : Genode::Rm_session_client +{ + Genode::Rm_session_capability _cap; + + Expanding_rm_session_client(Genode::Rm_session_capability cap) + : Rm_session_client(cap), _cap(cap) { } + + Local_addr attach(Genode::Dataspace_capability ds, + Genode::size_t size, Genode::off_t offset, + bool use_local_addr, + Local_addr local_addr, + bool executable) override + { + return Genode::retry( + [&] () { + return Rm_session_client::attach(ds, size, offset, + use_local_addr, + local_addr, + executable); }, + [&] () { + enum { UPGRADE_QUOTA = 4096 }; + + if (Genode::env()->ram_session()->avail() < UPGRADE_QUOTA) + throw; + + char buf[32]; + Genode::snprintf(buf, sizeof(buf), "ram_quota=%u", + UPGRADE_QUOTA); + + Genode::env()->parent()->upgrade(_cap, buf); + }); + } +}; + +static Genode::Rm_session *rm_session() { + using namespace Genode; + static Expanding_rm_session_client rm (static_cap_cast(env()->parent()->session("Env::rm_session", ""))); + return &rm; +} + + static bool map_eager(Genode::addr_t const page, unsigned log2_order) { using Genode::addr_t; @@ -56,13 +102,15 @@ void Platform::Device_pd_component::attach_dma_mem(Genode::Dataspace_capability addr_t page = ~0UL; try { - page = env()->rm_session()->attach_at(ds_cap, phys); + page = rm_session()->attach_at(ds_cap, phys); + } catch (Rm_session::Out_of_metadata) { + throw; } catch (...) { } /* sanity check */ if ((page == ~0UL) || (page != phys)) { if (page != ~0UL) - env()->rm_session()->detach(page); + rm_session()->detach(page); PERR("attachment of DMA memory @ %lx+%zx failed", phys, size); return; @@ -85,7 +133,7 @@ void Platform::Device_pd_component::assign_pci(Genode::Io_mem_dataspace_capabili Dataspace_client ds_client(io_mem_cap); - addr_t page = env()->rm_session()->attach(io_mem_cap); + addr_t page = rm_session()->attach(io_mem_cap); /* sanity check */ if (!page) throw Rm_session::Region_conflict(); @@ -99,7 +147,7 @@ void Platform::Device_pd_component::assign_pci(Genode::Io_mem_dataspace_capabili PERR("assignment of PCI device failed"); /* we don't need the mapping anymore */ - env()->rm_session()->detach(page); + rm_session()->detach(page); } int main(int argc, char **argv) diff --git a/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc b/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc index 3fe875827..3f1580d24 100644 --- a/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc +++ b/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc @@ -125,7 +125,7 @@ Platform::Device_capability Platform::Session_component::device(String const &na _device_list.insert(dev); return _ep->manage(dev); } catch (Genode::Allocator::Out_of_memory) { - throw Platform::Device::Quota_exceeded(); + throw Out_of_metadata(); } catch (Genode::Parent::Service_denied) { return Device_capability(); } diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device.cc b/repos/os/src/drivers/platform/spec/x86/pci_device.cc index 07742ee8f..e57d8b4b6 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device.cc +++ b/repos/os/src/drivers/platform/spec/x86/pci_device.cc @@ -73,7 +73,7 @@ Genode::Io_mem_session_capability Platform::Device_component::io_mem(Genode::uin _io_mem[i].insert(io_mem); return io_mem->cap(); } catch (Genode::Allocator::Out_of_memory) { - throw Platform::Device::Quota_exceeded(); + throw Quota_exceeded(); } catch (...) { return Genode::Io_mem_session_capability(); } @@ -115,8 +115,15 @@ void Platform::Device_component::config_write(unsigned char address, } /* assign device to device_pd */ - if (address == PCI_CMD_REG && value & PCI_CMD_DMA && _session) - _session->assign_device(this); + if (address == PCI_CMD_REG && value & PCI_CMD_DMA && _session) { + try { + _session->assign_device(this); + } catch (Platform::Session::Out_of_metadata) { + throw Quota_exceeded(); + } catch (...) { + PERR("assignment to device failed"); + } + } _device_config.write(&_config_access, address, value, size, _device_config.DONT_TRACK_ACCESS); diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device_pd_ipc.h b/repos/os/src/drivers/platform/spec/x86/pci_device_pd_ipc.h index 8d8034749..6cf7bcde0 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device_pd_ipc.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_device_pd_ipc.h @@ -27,10 +27,13 @@ struct Platform::Device_pd : Genode::Session { static const char *service_name() { return "DEVICE_PD"; } - GENODE_RPC(Rpc_attach_dma_mem, void, attach_dma_mem, - Genode::Dataspace_capability); - GENODE_RPC(Rpc_assign_pci, void, assign_pci, - Genode::Io_mem_dataspace_capability); + GENODE_RPC_THROW(Rpc_attach_dma_mem, void, attach_dma_mem, + GENODE_TYPE_LIST(Genode::Rm_session::Out_of_metadata), + Genode::Dataspace_capability); + GENODE_RPC_THROW(Rpc_assign_pci, void, assign_pci, + GENODE_TYPE_LIST(Genode::Rm_session::Out_of_metadata, + Genode::Rm_session::Region_conflict), + Genode::Io_mem_dataspace_capability); GENODE_RPC_INTERFACE(Rpc_attach_dma_mem, Rpc_assign_pci); }; diff --git a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h index 06f49fdb4..6dbdbb64a 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h @@ -24,6 +24,7 @@ #include #include +#include /* os */ #include @@ -118,20 +119,49 @@ namespace Platform { Genode::Allocator_guard _md_alloc; Genode::Tslab _device_slab; Genode::List _device_list; + Genode::Rpc_entrypoint &_device_pd_ep; + + struct Resources { + Genode::Ram_connection _ram; + + Resources() : + /* restrict physical address to 3G on 32bit */ + _ram("dma", 0, (sizeof(void *) == 4) + ? 0xc0000000UL : 0x100000000ULL) + { + /* associate _ram session with platform_drv _ram session */ + _ram.ref_account(Genode::env()->ram_session_cap()); + } + + Genode::Ram_connection &ram() { return _ram; } + } _resources; struct Devicepd { - Platform::Device_pd_policy *policy; - Device_pd_client child; + Device_pd_policy *policy; + Device_pd_client child; + Genode::Allocator_guard &_md_alloc; + enum { DEVICE_PD_RAM_QUOTA = 160 * 4096 }; Devicepd (Genode::Rpc_entrypoint &ep, - Genode::Allocator_guard &md_alloc) + Genode::Allocator_guard &md_alloc, + Genode::Ram_session_capability ram_ref_cap) : policy(nullptr), - child(Genode::reinterpret_cap_cast(Genode::Native_capability())) + child(Genode::reinterpret_cap_cast(Genode::Native_capability())), + _md_alloc(md_alloc) { + if (!md_alloc.withdraw(DEVICE_PD_RAM_QUOTA)) + throw Out_of_metadata(); + + if (Genode::env()->ram_session()->transfer_quota(ram_ref_cap, DEVICE_PD_RAM_QUOTA)) { + PERR("Transferring quota for device pd failed"); + md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); + throw Platform::Session::Fatal(); + } + try { - policy = new (md_alloc) Device_pd_policy(ep); + policy = new (md_alloc) Device_pd_policy(ep, ram_ref_cap, DEVICE_PD_RAM_QUOTA); using Genode::Session_capability; using Genode::Affinity; @@ -141,13 +171,36 @@ namespace Platform { } catch (Genode::Rom_connection::Rom_connection_failed) { PWRN("PCI device protection domain for IOMMU support " "is not available"); + + if (policy) { + destroy(md_alloc, policy); + policy = nullptr; + } + + md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); + } catch (Genode::Allocator::Out_of_memory) { + md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); + throw Out_of_metadata(); + } catch(...) { + PERR("unknown exception"); + md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); + throw Platform::Session::Fatal(); } } - bool valid() { return policy && policy->root().valid(); } - } _device_pd; + ~Devicepd() { + if (!policy) + return; + + destroy(_md_alloc, policy); + _md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); + } + + bool valid() { return policy && policy->root().valid() && child.valid(); } + }; + + Genode::Lazy_volatile_object _device_pd; - Genode::Ram_connection _ram; Genode::Session_label _label; Genode::Session_policy _policy; @@ -413,16 +466,9 @@ namespace Platform { _ep(ep), _md_alloc(md_alloc, Genode::Arg_string::find_arg(args, "ram_quota").long_value(0)), _device_slab(&_md_alloc), - _device_pd(device_pd_ep, _md_alloc), - /* restrict physical address to 3G on 32bit with device_pd */ - _ram("dma", 0, (_device_pd.valid() && sizeof(void *) == 4) - ? 0xc0000000UL : 0x100000000ULL), + _device_pd_ep(device_pd_ep), _label(args), _policy(_label) { - /* associate _ram session with platform_drv _ram session */ - _ram.ref_account(Genode::env()->ram_session_cap()); - Genode::env()->ram_session()->transfer_quota(_ram.cap(), 0x1000); - /* non-pci devices */ _policy.for_each_sub_node("device", [&] (Genode::Xml_node device_node) { try { @@ -650,7 +696,7 @@ namespace Platform { _device_list.insert(dev); return _ep->manage(dev); } catch (Genode::Allocator::Out_of_memory) { - throw Device::Quota_exceeded(); + throw Out_of_metadata(); } }; return _ep->apply(prev_device, lambda); @@ -690,40 +736,33 @@ namespace Platform { destroy(_md_alloc, device); } - Genode::Io_mem_dataspace_capability assign_device(Device_component * device) + void assign_device(Device_component * device) { using namespace Genode; if (!device || !device->get_config_space().valid()) - return Io_mem_dataspace_capability(); + return; Io_mem_dataspace_capability io_mem = device->get_config_space(); - if (!_device_pd.child.valid()) - return Io_mem_dataspace_capability(); + if (!_device_pd.is_constructed()) + _device_pd.construct(_device_pd_ep, _md_alloc, + _resources.ram().cap()); - _device_pd.child.assign_pci(io_mem); + if (!_device_pd->valid()) + return; - for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) { - Io_mem_dataspace_capability rmrr_cap = r->match(device->config()); - if (rmrr_cap.valid()) - _device_pd.child.attach_dma_mem(rmrr_cap); + try { + _device_pd->child.assign_pci(io_mem); + + for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) { + Io_mem_dataspace_capability rmrr_cap = r->match(device->config()); + if (rmrr_cap.valid()) + _device_pd->child.attach_dma_mem(rmrr_cap); + } + } catch (...) { + PERR("assignment to device pd or of RMRR region failed"); } - - /* - * By now forbid usage of extended pci config space dataspace, - * - until required. - */ - // return io_mem; - return Io_mem_dataspace_capability(); - } - - Genode::Io_mem_dataspace_capability config_extended(Device_capability device_cap) - { - using namespace Genode; - - return _ep->apply(device_cap, [&] (Device_component *device) { - return assign_device(device);}); } /** @@ -731,34 +770,63 @@ namespace Platform { */ typedef Genode::Ram_dataspace_capability Ram_capability; - Ram_capability alloc_dma_buffer(Genode::size_t size) + Ram_capability alloc_dma_buffer(Genode::size_t const size) { + if (!_device_pd.is_constructed()) + _device_pd.construct(_device_pd_ep, _md_alloc, + _resources.ram().cap()); + if (!_md_alloc.withdraw(size)) - throw Device::Quota_exceeded(); + throw Out_of_metadata(); + /* transfer ram quota to session specific ram session */ Genode::Ram_session * const rs = Genode::env()->ram_session(); - if (rs->transfer_quota(_ram.cap(), size)) { + if (rs->transfer_quota(_resources.ram().cap(), size)) { _md_alloc.upgrade(size); - return Ram_capability(); + throw Fatal(); } - Ram_capability ram_cap; - try { - ram_cap = Genode::retry( - [&] () { return _ram.alloc(size, Genode::UNCACHED); }, - [&] () { Genode::env()->parent()->upgrade(_ram.cap(), "ram_quota=4K"); }); - } catch (Genode::Ram_session::Quota_exceeded) { } + enum { UPGRADE_QUOTA = 4096 }; - if (!ram_cap.valid()) { - _ram.transfer_quota(Genode::env()->ram_session_cap(), size); - _md_alloc.upgrade(size); - return ram_cap; - } + /* allocate dataspace from session specific ram session */ + Ram_capability ram_cap = Genode::retry( + [&] () { return _resources.ram().alloc(size, Genode::UNCACHED); }, + [&] () { + if (!_md_alloc.withdraw(UPGRADE_QUOTA)) { + /* role-back */ + if (_resources.ram().transfer_quota(Genode::env()->ram_session_cap(), size)) + throw Fatal(); + _md_alloc.upgrade(size); + throw Out_of_metadata(); + } + char buf[32]; + Genode::snprintf(buf, sizeof(buf), "ram_quota=%u", + UPGRADE_QUOTA); + Genode::env()->parent()->upgrade(_resources.ram().cap(), buf); + }); - if (!_device_pd.child.valid()) + if (!_device_pd->valid()) return ram_cap; - _device_pd.child.attach_dma_mem(ram_cap); + Genode::retry( + [&] () { _device_pd->child.attach_dma_mem(ram_cap); }, + [&] () { + if (!_md_alloc.withdraw(UPGRADE_QUOTA)) { + /* role-back */ + _resources.ram().free(ram_cap); + if (_resources.ram().transfer_quota(Genode::env()->ram_session_cap(), size)) + throw Fatal(); + _md_alloc.upgrade(size); + throw Out_of_metadata(); + } + + if (rs->transfer_quota(_resources.ram().cap(), UPGRADE_QUOTA)) + throw Fatal(); + + Genode::Ram_connection &slave = _device_pd->policy->ram_slave(); + if (_resources.ram().transfer_quota(slave.cap(), UPGRADE_QUOTA)) + throw Fatal(); + }); return ram_cap; } @@ -766,7 +834,7 @@ namespace Platform { void free_dma_buffer(Ram_capability ram) { if (ram.valid()) - _ram.free(ram); + _resources.ram().free(ram); } Device_capability device(String const &name) override; diff --git a/repos/ports/run/seoul.inc b/repos/ports/run/seoul.inc index 395dd701b..752e93967 100644 --- a/repos/ports/run/seoul.inc +++ b/repos/ports/run/seoul.inc @@ -214,7 +214,7 @@ append_platform_drv_config append_if $use_nic_session config { - + diff --git a/repos/ports/run/vbox_win.inc b/repos/ports/run/vbox_win.inc index 8327a43d5..25843adc6 100644 --- a/repos/ports/run/vbox_win.inc +++ b/repos/ports/run/vbox_win.inc @@ -75,7 +75,7 @@ append config_of_app { (Recording is configured to use the external mic.) --> - +