diff --git a/doc/news.txt b/doc/news.txt index 69ca452c64..d6bbeabca3 100644 --- a/doc/news.txt +++ b/doc/news.txt @@ -4,6 +4,33 @@ =========== +Sculpt OS release 24.10 | 2024-10-30 +#################################### + +| Thanks to a largely revamped GUI stack, the Genode-based +| Sculpt OS 24.10 has gained profound support for multi-monitor setups. + +Among the many usability-related topics on our road map, multi-monitor +support is certainly the most anticipated feature. It motivated a holistic +modernization of Genode's GUI stack over several months, encompassing drivers, +the GUI multiplexer, inter-component interfaces, up to widget toolkits. Sculpt +OS 24.10 combines these new foundations with a convenient +[https:/documentation/articles/sculpt-24-10#Multi-monitor_support - user interface] +for controlling monitor modes, making brightness adjustments, and setting up +mirrored and panoramic monitor configurations. + +Besides this main theme, version 24.10 benefits from the advancements of the +Genode OS Framework over the past six months: compatibility with Qt6, +drivers ported from the Linux kernel version 6.6.47, and comprehensive +[https:/documentation/release-notes/24.08#Goa_SDK - debugging support] +for the Goa SDK. + +Sculpt OS 24.10 is available as ready-to-use system image for PC hardware, +the PinePhone, and the MNT Reform laptop at the +[https:/download/sculpt - Sculpt download page] accompanied +with updated [https:/documentation/articles/sculpt-24-10 - documentation]. + + Genode OS Framework release 24.08 | 2024-08-29 ############################################## diff --git a/repos/base-fiasco/recipes/src/base-fiasco/hash b/repos/base-fiasco/recipes/src/base-fiasco/hash index f8029e84b9..20e214286e 100644 --- a/repos/base-fiasco/recipes/src/base-fiasco/hash +++ b/repos/base-fiasco/recipes/src/base-fiasco/hash @@ -1 +1 @@ -2024-08-28 8f1db0e604a283f5d3aafea61d38d6852ee91911 +2024-10-07 19deb3e25765c65bef7ec4b7dd7c657b0c63a49d diff --git a/repos/base-foc/recipes/src/base-foc-imx6q_sabrelite/hash b/repos/base-foc/recipes/src/base-foc-imx6q_sabrelite/hash index 9c6fbc231c..d2f3570efa 100644 --- a/repos/base-foc/recipes/src/base-foc-imx6q_sabrelite/hash +++ b/repos/base-foc/recipes/src/base-foc-imx6q_sabrelite/hash @@ -1 +1 @@ -2024-08-28 deb70ebec813a19ba26a28cd94fa7d25bbe52e78 +2024-10-07 a906ce16359b301dda1031906fc6c9b3dd386d52 diff --git a/repos/base-foc/recipes/src/base-foc-imx7d_sabre/hash b/repos/base-foc/recipes/src/base-foc-imx7d_sabre/hash index 121f52746c..5065118d5a 100644 --- a/repos/base-foc/recipes/src/base-foc-imx7d_sabre/hash +++ b/repos/base-foc/recipes/src/base-foc-imx7d_sabre/hash @@ -1 +1 @@ -2024-08-28 a4ae12d703c38248ac22905163479000020e0bb0 +2024-10-07 8f88c87b67888d3aedccf628ceb214ec7305b2eb diff --git a/repos/base-foc/recipes/src/base-foc-pbxa9/hash b/repos/base-foc/recipes/src/base-foc-pbxa9/hash index cb9030ecd7..4704fee7dc 100644 --- a/repos/base-foc/recipes/src/base-foc-pbxa9/hash +++ b/repos/base-foc/recipes/src/base-foc-pbxa9/hash @@ -1 +1 @@ -2024-08-28 4c4d4d5d96bc345947e90c42559e45fec4dcc4c0 +2024-10-07 f2d0f8e9e79f3c4a11498d1df055488910d87279 diff --git a/repos/base-foc/recipes/src/base-foc-pc/hash b/repos/base-foc/recipes/src/base-foc-pc/hash index 837cb151a0..99bea661e6 100644 --- a/repos/base-foc/recipes/src/base-foc-pc/hash +++ b/repos/base-foc/recipes/src/base-foc-pc/hash @@ -1 +1 @@ -2024-08-28 b0160be55c422f860753dbd375f04ff8f7ffc7e9 +2024-10-07 af4a1a784fac28f321443a0659914f0aeb92e466 diff --git a/repos/base-foc/recipes/src/base-foc-rpi3/hash b/repos/base-foc/recipes/src/base-foc-rpi3/hash index 0843a59f28..ce2fb420cd 100644 --- a/repos/base-foc/recipes/src/base-foc-rpi3/hash +++ b/repos/base-foc/recipes/src/base-foc-rpi3/hash @@ -1 +1 @@ -2024-08-28 3e92e9cf1ec41d5de0bfa754ff48c63476e60d67 +2024-10-07 184b4030fb20c203ab996d46ddc029a1d6856f9c diff --git a/repos/base-foc/src/lib/base/x86/vm.cc b/repos/base-foc/src/lib/base/x86/vm.cc index 58f3d94c86..2c626f41ae 100644 --- a/repos/base-foc/src/lib/base/x86/vm.cc +++ b/repos/base-foc/src/lib/base/x86/vm.cc @@ -400,6 +400,7 @@ struct Foc_vcpu : Thread, Noncopyable if (state.fpu.charged()) { state.fpu.charge([&] (Vcpu_state::Fpu::State &fpu) { asm volatile ("fxrstor %0" : : "m" (fpu) : "memory"); + return 512; }); } else asm volatile ("fxrstor %0" : : "m" (_fpu_vcpu) : "memory"); @@ -412,6 +413,7 @@ struct Foc_vcpu : Thread, Noncopyable state.fpu.charge([&] (Vcpu_state::Fpu::State &fpu) { asm volatile ("fxsave %0" : "=m" (fpu) :: "memory"); asm volatile ("fxsave %0" : "=m" (_fpu_vcpu) :: "memory"); + return 512; }); asm volatile ("fxrstor %0" : : "m" (_fpu_ep) : "memory"); diff --git a/repos/base-hw/lib/mk/core-hw.inc b/repos/base-hw/lib/mk/core-hw.inc index 5ff6634311..8dacf55d10 100644 --- a/repos/base-hw/lib/mk/core-hw.inc +++ b/repos/base-hw/lib/mk/core-hw.inc @@ -62,6 +62,8 @@ SRC_CC += capability.cc SRC_CC += stack_area_addr.cc SRC_CC += heartbeat.cc +CC_OPT_platform += -DBOARD_NAME="\"$(BOARD)\"" + # provide Genode version information include $(BASE_DIR)/src/core/version.inc diff --git a/repos/base-hw/recipes/src/base-hw-pbxa9/hash b/repos/base-hw/recipes/src/base-hw-pbxa9/hash index b5ccec7f13..017ff3c100 100644 --- a/repos/base-hw/recipes/src/base-hw-pbxa9/hash +++ b/repos/base-hw/recipes/src/base-hw-pbxa9/hash @@ -1 +1 @@ -2024-08-28 de31628804f8541b6c0cf5a43ed621432befd5cb +2024-10-29 4bbe6a0fc64e242b3df0a4f888c69592a35c2c59 diff --git a/repos/base-hw/recipes/src/base-hw-pc/hash b/repos/base-hw/recipes/src/base-hw-pc/hash index 941ed16f56..c484ae4fe3 100644 --- a/repos/base-hw/recipes/src/base-hw-pc/hash +++ b/repos/base-hw/recipes/src/base-hw-pc/hash @@ -1 +1 @@ -2024-08-28 63ddb73a6a576208b86313411ea0e9ba78d2fe60 +2024-10-29 eb59e89aad9feb09d6a868c30f68e6295439f06a diff --git a/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash b/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash index bcd440379c..8c4c57d360 100644 --- a/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash +++ b/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v7a/hash @@ -1 +1 @@ -2024-08-28 73ea0cda27023fee8a56c5c104f85875e0ce2597 +2024-10-29 499d391798850ba3b784250d3b8a63bbb0ac27ab diff --git a/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash b/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash index 36f1d2dd44..cdd9b966b2 100644 --- a/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash +++ b/repos/base-hw/recipes/src/base-hw-virt_qemu_arm_v8a/hash @@ -1 +1 @@ -2024-08-28 268365a21014538c4524a43c86f1e4b1b9709a96 +2024-10-29 bc12b6bd4fc27e351d863c79752fcdc1173797ce diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h b/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h index 3fb5fdf4ad..0f1fc8bd60 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h +++ b/repos/base-hw/src/bootstrap/spec/x86_64/multiboot2.h @@ -73,7 +73,8 @@ class Genode::Multiboot2_info : Mmio<0x8> Multiboot2_info(addr_t mbi) : Mmio({(char *)mbi, Mmio::SIZE}) { } void for_each_tag(auto const &mem_fn, - auto const &acpi_fn, + auto const &acpi_rsdp_v1_fn, + auto const &acpi_rsdp_v2_fn, auto const &fb_fn, auto const &systab64_fn) { @@ -103,6 +104,7 @@ class Genode::Multiboot2_info : Mmio<0x8> if (tag.read() == Tag::Type::ACPI_RSDP_V1 || tag.read() == Tag::Type::ACPI_RSDP_V2) { + size_t const sizeof_tag = 1UL << Tag::LOG2_SIZE; addr_t const rsdp_addr = tag_addr + sizeof_tag; @@ -113,10 +115,12 @@ class Genode::Multiboot2_info : Mmio<0x8> Hw::Acpi_rsdp rsdp_v1; memset (&rsdp_v1, 0, sizeof(rsdp_v1)); memcpy (&rsdp_v1, rsdp, 20); - acpi_fn(rsdp_v1); + acpi_rsdp_v1_fn(rsdp_v1); + } else + if (sizeof(*rsdp) <= tag.read() - sizeof_tag) { + /* ACPI RSDP v2 */ + acpi_rsdp_v2_fn(*rsdp); } - if (sizeof(*rsdp) <= tag.read() - sizeof_tag) - acpi_fn(*rsdp); } if (tag.read() == Tag::Type::FRAMEBUFFER) { diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc index ed38b1d5e5..624579fce8 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc +++ b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc @@ -61,7 +61,7 @@ static Hw::Acpi_rsdp search_rsdp(addr_t area, addr_t area_size) } } - Hw::Acpi_rsdp invalid; + Hw::Acpi_rsdp invalid { }; return invalid; } @@ -143,10 +143,14 @@ Bootstrap::Platform::Board::Board() lambda(base, size); }, - [&] (Hw::Acpi_rsdp const &rsdp) { - /* prefer higher acpi revisions */ - if (!acpi_rsdp.valid() || acpi_rsdp.revision < rsdp.revision) - acpi_rsdp = rsdp; + [&] (Hw::Acpi_rsdp const &rsdp_v1) { + /* only use ACPI RSDP v1 if nothing available/valid by now */ + if (!acpi_rsdp.valid()) + acpi_rsdp = rsdp_v1; + }, + [&] (Hw::Acpi_rsdp const &rsdp_v2) { + /* prefer v2 ever, override stored previous rsdp v1 potentially */ + acpi_rsdp = rsdp_v2; }, [&] (Hw::Framebuffer const &fb) { info.framebuffer = fb; diff --git a/repos/base-hw/src/core/platform.cc b/repos/base-hw/src/core/platform.cc index 4df49e25f3..2090cf763d 100644 --- a/repos/base-hw/src/core/platform.cc +++ b/repos/base-hw/src/core/platform.cc @@ -161,6 +161,9 @@ void Platform::_init_platform_info() xml.attribute("acpi", true); xml.attribute("msi", true); }); + xml.node("board", [&] { + xml.attribute("name", BOARD_NAME); + }); _init_additional_platform_info(xml); xml.node("affinity-space", [&] { xml.attribute("width", affinity_space().width()); diff --git a/repos/base-hw/src/core/spec/x86_64/fpu.h b/repos/base-hw/src/core/spec/x86_64/fpu.h index 817a26b716..1a610e4c4f 100644 --- a/repos/base-hw/src/core/spec/x86_64/fpu.h +++ b/repos/base-hw/src/core/spec/x86_64/fpu.h @@ -60,6 +60,7 @@ class Genode::Fpu_context } addr_t fpu_context() const { return _fxsave_addr; } + addr_t fpu_size() const { return sizeof(_fxsave_area); } }; #endif /* _CORE__SPEC__X86_64__FPU_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc index 750d8f2d5f..f6de031093 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc @@ -222,7 +222,7 @@ void Board::Vcpu_context::read_vcpu_state(Vcpu_state &state) if (state.fpu.charged()) { state.fpu.with_state( [&](Vcpu_state::Fpu::State const &fpu) { - memcpy((void *) regs->fpu_context(), &fpu, sizeof(fpu)); + memcpy((void *) regs->fpu_context(), &fpu, regs->fpu_size()); }); } } @@ -233,7 +233,8 @@ void Board::Vcpu_context::write_vcpu_state(Vcpu_state &state) state.exit_reason = (unsigned) exit_reason; state.fpu.charge([&](Vcpu_state::Fpu::State &fpu) { - memcpy(&fpu, (void *) regs->fpu_context(), sizeof(fpu)); + memcpy(&fpu, (void *) regs->fpu_context(), regs->fpu_size()); + return regs->fpu_size(); }); /* SVM will overwrite rax but VMX doesn't. */ diff --git a/repos/base-linux/recipes/src/base-linux/hash b/repos/base-linux/recipes/src/base-linux/hash index 1e53e310e6..e89e5228a2 100644 --- a/repos/base-linux/recipes/src/base-linux/hash +++ b/repos/base-linux/recipes/src/base-linux/hash @@ -1 +1 @@ -2024-08-28 cbea0285f523b6943841f460fb1dab4471cb72f5 +2024-10-07 acb4a463ec1b2b6868f923900c2b04ee1a6487a8 diff --git a/repos/base-nova/include/nova/syscall-generic.h b/repos/base-nova/include/nova/syscall-generic.h index 7a481d3d58..db8fce16c7 100644 --- a/repos/base-nova/include/nova/syscall-generic.h +++ b/repos/base-nova/include/nova/syscall-generic.h @@ -697,7 +697,7 @@ namespace Nova { } gdtr, idtr; unsigned long long tsc_val, tsc_off, tsc_aux; unsigned long long exit_reason; - uint8_t fpu[512]; + uint8_t fpu[2560]; } __attribute__((packed)); mword_t mr[(4096 - 4 * sizeof(mword_t)) / sizeof(mword_t)]; }; diff --git a/repos/base-nova/ports/nova.hash b/repos/base-nova/ports/nova.hash index 321dbd6073..5fb40aa103 100644 --- a/repos/base-nova/ports/nova.hash +++ b/repos/base-nova/ports/nova.hash @@ -1 +1 @@ -e8997fb0870b6f8bdcb6da34a9b333ed4a304305 +dd4d2aba9dd83ec08e956cb31274c62cbcaf91f6 diff --git a/repos/base-nova/ports/nova.port b/repos/base-nova/ports/nova.port index 736a144c68..681aab6639 100644 --- a/repos/base-nova/ports/nova.port +++ b/repos/base-nova/ports/nova.port @@ -4,7 +4,7 @@ DOWNLOADS := nova.git # r10 branch URL(nova) := https://github.com/alex-ab/NOVA.git -REV(nova) := bca1aa3553d8c5df4f4b6ed5a2ee72f69bdf7a7f +REV(nova) := 60419b83599fbe506308b0375371c49136e00985 DIR(nova) := src/kernel/nova PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch)) diff --git a/repos/base-nova/recipes/api/base-nova/hash b/repos/base-nova/recipes/api/base-nova/hash index e82c972d7e..9c9994f2f2 100644 --- a/repos/base-nova/recipes/api/base-nova/hash +++ b/repos/base-nova/recipes/api/base-nova/hash @@ -1 +1 @@ -2024-08-28 80901e07dc386b2dcc259a85ea60fdd2bb4c1b6a +2024-10-07 d1a751a3b41d145c3a97b3431ae1f006050fee10 diff --git a/repos/base-nova/recipes/src/base-nova/hash b/repos/base-nova/recipes/src/base-nova/hash index 9957562e69..8c752c1637 100644 --- a/repos/base-nova/recipes/src/base-nova/hash +++ b/repos/base-nova/recipes/src/base-nova/hash @@ -1 +1 @@ -2024-08-28 2bdb13a64a152f7cb2601222245eb6f132d5325b +2024-10-07 3fdd714b4cf479987b027a09aa2b470dfc46a92a diff --git a/repos/base-nova/src/lib/base/vm.cc b/repos/base-nova/src/lib/base/vm.cc index bd2c407ded..43603e153b 100644 --- a/repos/base-nova/src/lib/base/vm.cc +++ b/repos/base-nova/src/lib/base/vm.cc @@ -177,7 +177,10 @@ void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb) if (utcb.mtd & Nova::Mtd::FPU) { _vcpu_state.fpu.charge([&] (Vcpu_state::Fpu::State &fpu) { - memcpy(&fpu, utcb.fpu, sizeof(fpu)); + auto const fpu_size = unsigned(min(_vcpu_state.fpu.size(), + sizeof(utcb.fpu))); + memcpy(&fpu, utcb.fpu, fpu_size); + return fpu_size; }); } diff --git a/repos/base-nova/src/test/nova/main.cc b/repos/base-nova/src/test/nova/main.cc index 2408639b82..060b5ce4c3 100644 --- a/repos/base-nova/src/test/nova/main.cc +++ b/repos/base-nova/src/test/nova/main.cc @@ -297,27 +297,27 @@ void test_pat(Genode::Env &env) Xml_node const hardware = platform_info.xml().sub_node("hardware"); uint64_t const tsc_freq = hardware.sub_node("tsc").attribute_value("freq_khz", 1ULL); - enum { DS_ORDER = 12, PAGE_4K = 12 }; + enum { DS_ORDER = 12, PAGE_4K = 12, DS_SIZE = 1ul << (DS_ORDER + PAGE_4K) }; - Attached_dataspace ds { env.rm(), env.ram().alloc (1 << (DS_ORDER + PAGE_4K), - WRITE_COMBINED) }; - addr_t const map_addr = addr_t(ds.local_addr()); + Genode::Rm_connection rm(env); + Genode::Region_map_client rm_unused(rm.create(DS_SIZE)); - enum { STACK_SIZE = 4096 }; + Attached_dataspace ds_wc { env.rm(), env.ram().alloc (DS_SIZE, WRITE_COMBINED) }; + Attached_dataspace ds { env.rm(), env.ram().alloc (DS_SIZE) }; + Attached_dataspace remap { env.rm(), rm_unused.dataspace() }; - static Rpc_entrypoint ep(&env.pd(), STACK_SIZE, "rpc_ep_pat", + auto const memory = addr_t(ds .local_addr()); + auto const memory_wc = addr_t(ds_wc.local_addr()); + auto const memory_remap = addr_t(remap.local_addr()); + + static Rpc_entrypoint ep(&env.pd(), 4096 /* STACK */, "rpc_ep_pat", Affinity::Location()); - Genode::Rm_connection rm(env); - Genode::Region_map_client rm_free_area(rm.create(1 << (DS_ORDER + PAGE_4K))); - - Attached_dataspace remap { env.rm(), rm_free_area.dataspace() }; - - addr_t const remap_addr = addr_t(remap.local_addr()); - /* trigger mapping of whole area */ - for (addr_t i = map_addr; i < map_addr + (1 << (DS_ORDER + PAGE_4K)); i += (1 << PAGE_4K)) - touch_read(reinterpret_cast(map_addr)); + for (auto offset = 0; offset < DS_SIZE; offset += (1u << PAGE_4K)) { + touch_read_write(reinterpret_cast(memory_wc + offset)); + touch_read_write(reinterpret_cast( memory + offset)); + } /* * Establish memory mapping with evilly wrong mapping attributes @@ -331,8 +331,8 @@ void test_pat(Genode::Env &env) native_pd.alloc_rpc_cap(thread_cap, (addr_t)portal_entry, 0 /* MTD */); Nova::Rights const all(true, true, true); - Nova::Mem_crd const rcv_crd(remap_addr >> PAGE_4K, DS_ORDER, all); - Nova::Mem_crd const snd_crd(map_addr >> PAGE_4K, DS_ORDER, all); + Nova::Mem_crd const rcv_crd(memory_remap >> PAGE_4K, DS_ORDER, all); + Nova::Mem_crd const snd_crd(memory_wc >> PAGE_4K, DS_ORDER, all); Nova::Crd const old_crd = utcb.crd_rcv; utcb.crd_rcv = rcv_crd; @@ -348,36 +348,45 @@ void test_pat(Genode::Env &env) } /* sanity check - touch re-mapped area */ - for (addr_t i = remap_addr; i < remap_addr + (1 << (DS_ORDER + PAGE_4K)); i += (1 << PAGE_4K)) - touch_read(reinterpret_cast(remap_addr)); + for (auto offset = 0; offset < DS_SIZE; offset += (1 << PAGE_4K)) + touch_read_write(reinterpret_cast(memory_remap + offset)); /* * measure time to write to the memory */ - memset(reinterpret_cast(map_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + memset(reinterpret_cast(memory), 0, DS_SIZE); + Trace::Timestamp normal_start = Trace::timestamp(); + memset(reinterpret_cast(memory), 0, DS_SIZE); + Trace::Timestamp normal_end = Trace::timestamp(); + + memset(reinterpret_cast(memory_wc), 0, DS_SIZE); Trace::Timestamp map_start = Trace::timestamp(); - memset(reinterpret_cast(map_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + memset(reinterpret_cast(memory_wc), 0, DS_SIZE); Trace::Timestamp map_end = Trace::timestamp(); - memset(reinterpret_cast(remap_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + memset(reinterpret_cast(memory_remap), 0, DS_SIZE); Trace::Timestamp remap_start = Trace::timestamp(); - memset(reinterpret_cast(remap_addr), 0, 1 << (DS_ORDER + PAGE_4K)); + memset(reinterpret_cast(memory_remap), 0, DS_SIZE); Trace::Timestamp remap_end = Trace::timestamp(); - Trace::Timestamp map_run = map_end - map_start; - Trace::Timestamp remap_run = remap_end - remap_start; + auto normal_run = normal_end - normal_start; + auto map_run = map_end - map_start; + auto remap_run = remap_end - remap_start; - Trace::Timestamp diff_run = map_run > remap_run ? map_run - remap_run : remap_run - map_run; + auto diff_run = map_run > remap_run ? map_run - remap_run : remap_run - map_run; - if (check_pat && diff_run * 100 / tsc_freq) { + log("memory non writecombined ", normal_run * 1000 / tsc_freq, " us"); + log("memory writecombined ", map_run * 1000 / tsc_freq, " us"); + log("memory writecombined remapped ", remap_run * 1000 / tsc_freq, " us"); + log("variance writecombined tests ", diff_run * 1000 / tsc_freq, " us"); + + if (check_pat && diff_run * 10 / tsc_freq) { failed ++; - error("map=", Hex(map_run), " remap=", Hex(remap_run), " --> " - "diff=", Hex(diff_run), " freq_tsc=", tsc_freq, " ", - diff_run * 1000 / tsc_freq, " us"); + error("PAT test considered failed - time difference above 100us"); } - Nova::revoke(Nova::Mem_crd(remap_addr >> PAGE_4K, DS_ORDER, all)); + Nova::revoke(Nova::Mem_crd(memory_remap >> PAGE_4K, DS_ORDER, all)); } void test_server_oom(Genode::Env &env) diff --git a/repos/base-okl4/recipes/src/base-okl4/hash b/repos/base-okl4/recipes/src/base-okl4/hash index 30faaab6bc..297d6e9cb6 100644 --- a/repos/base-okl4/recipes/src/base-okl4/hash +++ b/repos/base-okl4/recipes/src/base-okl4/hash @@ -1 +1 @@ -2024-08-28 4b22e47966d13c2de61a2d7349bd8fa83520fd1c +2024-10-07 0dfc585477f27e02dbe67acf3a23f48718c113f7 diff --git a/repos/base-pistachio/recipes/src/base-pistachio/hash b/repos/base-pistachio/recipes/src/base-pistachio/hash index 993b9b9441..49e578f619 100644 --- a/repos/base-pistachio/recipes/src/base-pistachio/hash +++ b/repos/base-pistachio/recipes/src/base-pistachio/hash @@ -1 +1 @@ -2024-08-28 ef60eabef7b6a62cb0ca9844e76dcaa0d5fd9032 +2024-10-07 4ec8eaa528d706f5b2a267f95443a48430a87a91 diff --git a/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash b/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash index 7fc8d755b8..1372db3453 100644 --- a/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash +++ b/repos/base-sel4/recipes/src/base-sel4-imx6q_sabrelite/hash @@ -1 +1 @@ -2024-08-28 6a6ef31c10a65d90eaba97c45324b4e6835f14db +2024-10-07 b23d40bed9c8b9ed8fc8d8d1e2c5cac4e719580a diff --git a/repos/base-sel4/recipes/src/base-sel4-x86/hash b/repos/base-sel4/recipes/src/base-sel4-x86/hash index 7f91bc2faf..10956db5c2 100644 --- a/repos/base-sel4/recipes/src/base-sel4-x86/hash +++ b/repos/base-sel4/recipes/src/base-sel4-x86/hash @@ -1 +1 @@ -2024-08-28 5656ef6d7282894b67b9aab50364f12f42aded49 +2024-10-07 9929145b5c04edaf41b0f726743eabb2de9cc832 diff --git a/repos/base/include/base/attached_dataspace.h b/repos/base/include/base/attached_dataspace.h index 8adaba4d48..98ef92b3dd 100644 --- a/repos/base/include/base/attached_dataspace.h +++ b/repos/base/include/base/attached_dataspace.h @@ -54,12 +54,6 @@ class Genode::Attached_dataspace : Noncopyable [&] (Region_map::Attach_error) { return nullptr; }); } - /* - * Noncopyable - */ - Attached_dataspace(Attached_dataspace const &); - Attached_dataspace &operator = (Attached_dataspace const &); - public: /** @@ -118,6 +112,11 @@ class Genode::Attached_dataspace : Noncopyable [&] (Region_map::Attach_error) { return 0UL; }); } + /** + * Return byte range of locally mapped dataspace + */ + Byte_range_ptr bytes() const { return { _ptr(), size() }; } + /** * Forget dataspace, thereby skipping the detachment on destruction * diff --git a/repos/base/include/base/attached_ram_dataspace.h b/repos/base/include/base/attached_ram_dataspace.h index f6b316ef94..b04c654c46 100644 --- a/repos/base/include/base/attached_ram_dataspace.h +++ b/repos/base/include/base/attached_ram_dataspace.h @@ -163,6 +163,11 @@ class Genode::Attached_ram_dataspace _alloc_and_attach(); } + + /** + * Return byte range of locally mapped dataspace + */ + Byte_range_ptr bytes() const { return { local_addr(), size() }; } }; #endif /* _INCLUDE__BASE__ATTACHED_RAM_DATASPACE_H_ */ diff --git a/repos/base/include/base/connection.h b/repos/base/include/base/connection.h index 1798d84906..9e6c915d5e 100644 --- a/repos/base/include/base/connection.h +++ b/repos/base/include/base/connection.h @@ -107,13 +107,14 @@ class Genode::Connection : public Connection_base Client_id const &id, Session_label const &label, Ram_quota const &ram_quota, + Cap_quota const &cap_quota, Affinity const &affinity, Args const &args) { /* supplement session quotas and label as session arguments */ Args const complete_args("label=\"", label, "\", " "ram_quota=", ram_quota, ", " - "cap_quota=", unsigned(SESSION_TYPE::CAP_QUOTA), ", ", + "cap_quota=", cap_quota, ", ", args); if (complete_args.length() == Args::capacity()) @@ -138,12 +139,26 @@ class Genode::Connection : public Connection_base Connection(Env &env, Session_label const &label, Ram_quota const &ram_quota, + Cap_quota const &cap_quota, Affinity const &affinity, Args const &args) : Connection_base(env), _cap(_request(env, _id_space_element.id(), - label, ram_quota, affinity, args)) + label, ram_quota, cap_quota, affinity, args)) + { } + + /** + * Constructor using the cap quota declared in as SESSION_TYPE::CAP_QUOTA + */ + Connection(Env &env, + Session_label const &label, + Ram_quota const &ram_quota, + Affinity const &affinity, + Args const &args) + : + Connection(env, label, ram_quota, Cap_quota { unsigned(SESSION_TYPE::CAP_QUOTA) }, + affinity, args) { } /** diff --git a/repos/base/include/spec/x86/cpu/vcpu_state.h b/repos/base/include/spec/x86/cpu/vcpu_state.h index 6141e566b1..f943a75283 100644 --- a/repos/base/include/spec/x86/cpu/vcpu_state.h +++ b/repos/base/include/spec/x86/cpu/vcpu_state.h @@ -206,15 +206,16 @@ class Genode::Vcpu_state struct State { - uint8_t _buffer[512] { }; - } __attribute__((aligned(16))); + uint8_t _buffer[2560] { }; + } __attribute__((aligned(64))); private: friend class Vcpu_state; - State _state { }; - bool _charged { false }; + State _state { }; + bool _charged { false }; + uint64_t _state_size { }; /* see comment for Register::operator=() */ Fpu & operator = (Fpu const &) @@ -232,12 +233,14 @@ class Genode::Vcpu_state void charge(auto const &fn) { - _charged = true; - fn(_state); + _charged = true; + _state_size = fn(_state); } + + auto size() const { return _state_size; } }; - Fpu fpu __attribute__((aligned(16))) { }; + Fpu fpu __attribute__((aligned(64))) { }; /* * Registers transfered by hypervisor from guest on VM exit are charged. diff --git a/repos/base/include/util/geometry.h b/repos/base/include/util/geometry.h index 0266ef6be9..4f362ef239 100644 --- a/repos/base/include/util/geometry.h +++ b/repos/base/include/util/geometry.h @@ -224,10 +224,26 @@ struct Genode::Rect */ Point center(Area const area) const { - return Point((CT(w()) - CT(area.w))/2, - (CT(h()) - CT(area.h))/2) + at; + return Point { .x = (CT(w()) - CT(area.w))/2, + .y = (CT(h()) - CT(area.h))/2 } + at; } + Point clamp(Point const p) const + { + return Point { .x = max(x1(), min(x2(), p.x)), + .y = max(y1(), min(y2(), p.y)) }; + } + + /** + * Operator for testing non-equality of two rectangled + */ + bool operator != (Rect const &r) const { return r.at != at || r.area != area; } + + /** + * Operator for testing equality of two rectangles + */ + bool operator == (Rect const &r) const { return r.at == at && r.area == area; } + /** * Print rectangle coordinates * diff --git a/repos/base/include/util/string.h b/repos/base/include/util/string.h index 0088a83e8f..af2a438d2b 100644 --- a/repos/base/include/util/string.h +++ b/repos/base/include/util/string.h @@ -84,6 +84,15 @@ struct Genode::Byte_range_ptr : Noncopyable Byte_range_ptr(char *start, size_t num_bytes) : start(start), num_bytes(num_bytes) { } + + void with_skipped_bytes(size_t const n, auto const &fn) + { + if (num_bytes <= n) + return; + + Byte_range_ptr const remainder { start + n, num_bytes - n }; + fn(remainder); + } }; diff --git a/repos/base/recipes/api/base/hash b/repos/base/recipes/api/base/hash index 38c2481b49..78c6f92472 100644 --- a/repos/base/recipes/api/base/hash +++ b/repos/base/recipes/api/base/hash @@ -1 +1 @@ -2024-08-28 952cb023f90e6d847b6bfc8da87d8f7ba24f842c +2024-10-07 513edfd85657a2cea7224093f02ad8f2525056f3 diff --git a/repos/base/recipes/pkg/test-alarm/hash b/repos/base/recipes/pkg/test-alarm/hash index e014853762..0521bb9a5c 100644 --- a/repos/base/recipes/pkg/test-alarm/hash +++ b/repos/base/recipes/pkg/test-alarm/hash @@ -1 +1 @@ -2024-08-28 38800f3da875e5de6f2d561358fa8f56c85a7b3c +2024-10-29 123419fe0f679a41e6e836a82f46be56644d36af diff --git a/repos/base/recipes/pkg/test-ds_ownership/hash b/repos/base/recipes/pkg/test-ds_ownership/hash index ccff0db4c7..ff2fbada53 100644 --- a/repos/base/recipes/pkg/test-ds_ownership/hash +++ b/repos/base/recipes/pkg/test-ds_ownership/hash @@ -1 +1 @@ -2024-08-28 1263204bd1a920d6ea1a414c0a7de506ab225d54 +2024-10-29 4121baf09683470114b15c6768cb939b7b78de65 diff --git a/repos/base/recipes/pkg/test-entrypoint/hash b/repos/base/recipes/pkg/test-entrypoint/hash index 5ef9617384..1413671a5b 100644 --- a/repos/base/recipes/pkg/test-entrypoint/hash +++ b/repos/base/recipes/pkg/test-entrypoint/hash @@ -1 +1 @@ -2024-08-28 916b2b926332cfcd7960395cbae045c2f79e22e1 +2024-10-29 964df1f1eebb297399d37ffc42cd5b717f81ac65 diff --git a/repos/base/recipes/pkg/test-log/hash b/repos/base/recipes/pkg/test-log/hash index 33bdefb237..e2ccca33d7 100644 --- a/repos/base/recipes/pkg/test-log/hash +++ b/repos/base/recipes/pkg/test-log/hash @@ -1 +1 @@ -2024-08-28 e9ad6072bfb3d9b3a33bc1bc0d8d569e572a23aa +2024-10-29 8acfdc522214ab48f3ba2662deca84562aedb62f diff --git a/repos/base/recipes/pkg/test-mmio/hash b/repos/base/recipes/pkg/test-mmio/hash index 63f14e6aca..19cdce938d 100644 --- a/repos/base/recipes/pkg/test-mmio/hash +++ b/repos/base/recipes/pkg/test-mmio/hash @@ -1 +1 @@ -2024-08-28 eb64887a9855af98fd59ca684d76a117ad6bc218 +2024-10-29 511875353e93f226ff52c3a79be5e6847fa95c19 diff --git a/repos/base/recipes/pkg/test-new_delete/hash b/repos/base/recipes/pkg/test-new_delete/hash index e90d442163..de8d71f161 100644 --- a/repos/base/recipes/pkg/test-new_delete/hash +++ b/repos/base/recipes/pkg/test-new_delete/hash @@ -1 +1 @@ -2024-08-28 2d87a4f1e768e5156bb2122e76aefe9b93250b98 +2024-10-29 4eb04b36a4589581afe4b8e5c09cd1a8202e389e diff --git a/repos/base/recipes/pkg/test-reconstructible/hash b/repos/base/recipes/pkg/test-reconstructible/hash index 46604b10f8..6c17d789ff 100644 --- a/repos/base/recipes/pkg/test-reconstructible/hash +++ b/repos/base/recipes/pkg/test-reconstructible/hash @@ -1 +1 @@ -2024-08-28 9999549086b013d745b7c29d0d73ce16a7b44460 +2024-10-29 ec0ee7597f35852ed2a1f0a3250ebc9de125141d diff --git a/repos/base/recipes/pkg/test-registry/hash b/repos/base/recipes/pkg/test-registry/hash index 9e20953106..3ea9b9de66 100644 --- a/repos/base/recipes/pkg/test-registry/hash +++ b/repos/base/recipes/pkg/test-registry/hash @@ -1 +1 @@ -2024-08-28 eb836fa23731d48906eb17a55f4493a1f1d5f31e +2024-10-29 2093c0cd6b5e73f07e682f8448abdf4bcc07ba90 diff --git a/repos/base/recipes/pkg/test-rm_fault/hash b/repos/base/recipes/pkg/test-rm_fault/hash index 1d80f7affc..1860ffcbe8 100644 --- a/repos/base/recipes/pkg/test-rm_fault/hash +++ b/repos/base/recipes/pkg/test-rm_fault/hash @@ -1 +1 @@ -2024-08-28 b338f91749569157a0ee70bdac8b63b4604a10f1 +2024-10-29 ea454149147f8535060bf076432dd67d473658dd diff --git a/repos/base/recipes/pkg/test-rm_fault_no_nox/hash b/repos/base/recipes/pkg/test-rm_fault_no_nox/hash index 77775062de..8ca5e15339 100644 --- a/repos/base/recipes/pkg/test-rm_fault_no_nox/hash +++ b/repos/base/recipes/pkg/test-rm_fault_no_nox/hash @@ -1 +1 @@ -2024-08-28 0c740d62b29e444a70f19786e73e919929b8a41b +2024-10-29 dde16843a89b11f0c76e73ab66906ccc68d65a0c diff --git a/repos/base/recipes/pkg/test-rm_nested/hash b/repos/base/recipes/pkg/test-rm_nested/hash index f936f1ffad..fac22d7a78 100644 --- a/repos/base/recipes/pkg/test-rm_nested/hash +++ b/repos/base/recipes/pkg/test-rm_nested/hash @@ -1 +1 @@ -2024-08-28 dcf9171eaf3917bc7dab03d2821105a25a8d9526 +2024-10-29 0816774e285a09f371e1c7b11c661aeb9925e4dc diff --git a/repos/base/recipes/pkg/test-rm_stress/hash b/repos/base/recipes/pkg/test-rm_stress/hash index 0d8cc58d39..c2bd76517c 100644 --- a/repos/base/recipes/pkg/test-rm_stress/hash +++ b/repos/base/recipes/pkg/test-rm_stress/hash @@ -1 +1 @@ -2024-08-28 20da1561fd882dbd113366082471d95b8533e310 +2024-10-29 1d173f7880db1f1252ab54cea4d8e6ba8e7ea77c diff --git a/repos/base/recipes/pkg/test-sanitizer/hash b/repos/base/recipes/pkg/test-sanitizer/hash index 2621e23b2e..bec03c90ef 100644 --- a/repos/base/recipes/pkg/test-sanitizer/hash +++ b/repos/base/recipes/pkg/test-sanitizer/hash @@ -1 +1 @@ -2024-08-28 2179cbeaf81dd04431742572f2f685473cd84594 +2024-10-29 50994e52f5f229a19d33169d3ae3aa1e1b06a83a diff --git a/repos/base/recipes/pkg/test-stack_smash/hash b/repos/base/recipes/pkg/test-stack_smash/hash index aff8a56547..084bd78e79 100644 --- a/repos/base/recipes/pkg/test-stack_smash/hash +++ b/repos/base/recipes/pkg/test-stack_smash/hash @@ -1 +1 @@ -2024-08-28 e9f6ccbe39344ae7f6a9e5787397d352383d50e9 +2024-10-29 54f3e743c82cc972eebb16023de863fa5e539812 diff --git a/repos/base/recipes/pkg/test-synced_interface/hash b/repos/base/recipes/pkg/test-synced_interface/hash index 8be6355d77..d84fc450c4 100644 --- a/repos/base/recipes/pkg/test-synced_interface/hash +++ b/repos/base/recipes/pkg/test-synced_interface/hash @@ -1 +1 @@ -2024-08-28 9a01b6b2d0d295435aa0a02ebc7348a285eeca8d +2024-10-29 5fde64bdb410c3b1d31e97f0d21cf3d064bbc2ce diff --git a/repos/base/recipes/pkg/test-timer/hash b/repos/base/recipes/pkg/test-timer/hash index 535345160b..41390bd20e 100644 --- a/repos/base/recipes/pkg/test-timer/hash +++ b/repos/base/recipes/pkg/test-timer/hash @@ -1 +1 @@ -2024-08-28 ae27770a9af453d0c385aa2eedf3aeea9d017223 +2024-10-29 f5a700f137cf815f7ce15b3fa9f5634b7828425e diff --git a/repos/base/recipes/pkg/test-tls/hash b/repos/base/recipes/pkg/test-tls/hash index ff94b68744..6ad96bf219 100644 --- a/repos/base/recipes/pkg/test-tls/hash +++ b/repos/base/recipes/pkg/test-tls/hash @@ -1 +1 @@ -2024-08-28 ebeb7886af2d31d276ab768af6bd8f3220de8953 +2024-10-29 d326468bba3e8af5f49179103fb74567410c016b diff --git a/repos/base/recipes/pkg/test-token/hash b/repos/base/recipes/pkg/test-token/hash index 71c6873ed2..5e36fce650 100644 --- a/repos/base/recipes/pkg/test-token/hash +++ b/repos/base/recipes/pkg/test-token/hash @@ -1 +1 @@ -2024-08-28 0f803f76ccc130569e39451c51626feec05a712b +2024-10-29 f5aa7c4c7928b4aa750133798ab5ced2862627ef diff --git a/repos/base/recipes/pkg/test-xml_generator/hash b/repos/base/recipes/pkg/test-xml_generator/hash index e9aee142a4..b56dd9133d 100644 --- a/repos/base/recipes/pkg/test-xml_generator/hash +++ b/repos/base/recipes/pkg/test-xml_generator/hash @@ -1 +1 @@ -2024-08-28 1fbbbbe8badb32ea8ec9b07cee8f8a5d95360acb +2024-10-29 0c302928b9f742d2dca1a7a7392217afc7d99518 diff --git a/repos/base/recipes/pkg/test-xml_node/hash b/repos/base/recipes/pkg/test-xml_node/hash index 36f87174ce..2e8ca57bb3 100644 --- a/repos/base/recipes/pkg/test-xml_node/hash +++ b/repos/base/recipes/pkg/test-xml_node/hash @@ -1 +1 @@ -2024-08-28 b48cf2518250d49a57109e7038d837ab02b94d56 +2024-10-29 778c0e244d381f663a04913e3fd490c9029454e7 diff --git a/repos/base/recipes/src/test-alarm/hash b/repos/base/recipes/src/test-alarm/hash index 6f3caf9123..ff4cf7877e 100644 --- a/repos/base/recipes/src/test-alarm/hash +++ b/repos/base/recipes/src/test-alarm/hash @@ -1 +1 @@ -2024-08-28 27a6c8bd9c14310c772eceaa6ce8545fad4161a0 +2024-10-07 a6a04c7c48e562c4450603757520e447af6ba3b7 diff --git a/repos/base/recipes/src/test-ds_ownership/hash b/repos/base/recipes/src/test-ds_ownership/hash index cc6790c865..966dc5efb3 100644 --- a/repos/base/recipes/src/test-ds_ownership/hash +++ b/repos/base/recipes/src/test-ds_ownership/hash @@ -1 +1 @@ -2024-08-28 81579f87117d620bded1b18b94d32f8dfcf798c0 +2024-10-07 c65f3e117d0576e35c93be32795ae44e40905806 diff --git a/repos/base/recipes/src/test-entrypoint/hash b/repos/base/recipes/src/test-entrypoint/hash index 09841a8644..158b59c957 100644 --- a/repos/base/recipes/src/test-entrypoint/hash +++ b/repos/base/recipes/src/test-entrypoint/hash @@ -1 +1 @@ -2024-08-28 353ca16a476ea875269280a482133917404af2b4 +2024-10-07 fd12392cdb6e8a73927eddb831b5a4a03f1dba99 diff --git a/repos/base/recipes/src/test-log/hash b/repos/base/recipes/src/test-log/hash index 58a5c77880..faf30cc537 100644 --- a/repos/base/recipes/src/test-log/hash +++ b/repos/base/recipes/src/test-log/hash @@ -1 +1 @@ -2024-08-28 5a105d705f54f092f8a5830a0ae6735ae9a4787a +2024-10-07 2d27a4ea191a544959688dddebc99c0158a2cc87 diff --git a/repos/base/recipes/src/test-mmio/hash b/repos/base/recipes/src/test-mmio/hash index 233f312dc0..510ba70361 100644 --- a/repos/base/recipes/src/test-mmio/hash +++ b/repos/base/recipes/src/test-mmio/hash @@ -1 +1 @@ -2024-08-28 1e93c3437d41e6177b8063f48aad15f5ca340956 +2024-10-07 a2f19169350426a2c92bfa82cd57ea1126ff40f9 diff --git a/repos/base/recipes/src/test-new_delete/hash b/repos/base/recipes/src/test-new_delete/hash index d18561c597..313d5ccfb6 100644 --- a/repos/base/recipes/src/test-new_delete/hash +++ b/repos/base/recipes/src/test-new_delete/hash @@ -1 +1 @@ -2024-08-28 215be20a911ed192b38c93319396f6a5b3f7cb6d +2024-10-07 fdd7695261277dcba03643f98bb2804c30c0cf04 diff --git a/repos/base/recipes/src/test-reconstructible/hash b/repos/base/recipes/src/test-reconstructible/hash index f8e73fdf76..0689384df9 100644 --- a/repos/base/recipes/src/test-reconstructible/hash +++ b/repos/base/recipes/src/test-reconstructible/hash @@ -1 +1 @@ -2024-08-28 a27dcf2ba32e600ce9b02a18222d8286d9220b6e +2024-10-07 45ffa221854a16794e7325d8ed6d6b5ce90635a5 diff --git a/repos/base/recipes/src/test-registry/hash b/repos/base/recipes/src/test-registry/hash index 8fa7788d32..ae13dd0c20 100644 --- a/repos/base/recipes/src/test-registry/hash +++ b/repos/base/recipes/src/test-registry/hash @@ -1 +1 @@ -2024-08-28 34c983d620520d362a146f6c9f062885b2d98c38 +2024-10-07 96b39a93b70d6732cd2f6a7e30ac3404f4f017d5 diff --git a/repos/base/recipes/src/test-rm_fault/hash b/repos/base/recipes/src/test-rm_fault/hash index 0a633b7d4c..c16620aff9 100644 --- a/repos/base/recipes/src/test-rm_fault/hash +++ b/repos/base/recipes/src/test-rm_fault/hash @@ -1 +1 @@ -2024-08-28 78709e0ea496651d938423d0bb18a0254a04acaf +2024-10-07 9843a171d4e781aec5597ce0b48ccc17431918d7 diff --git a/repos/base/recipes/src/test-rm_nested/hash b/repos/base/recipes/src/test-rm_nested/hash index cfb3987c66..b2e397aa10 100644 --- a/repos/base/recipes/src/test-rm_nested/hash +++ b/repos/base/recipes/src/test-rm_nested/hash @@ -1 +1 @@ -2024-08-28 59c0abed548b66f8d54c74e82f1ab0ab7f0d0ee6 +2024-10-07 b3d5f7577d058fd7d3a34846af555ba2ffec842b diff --git a/repos/base/recipes/src/test-rm_stress/hash b/repos/base/recipes/src/test-rm_stress/hash index 485f2fcc74..c0e516eebf 100644 --- a/repos/base/recipes/src/test-rm_stress/hash +++ b/repos/base/recipes/src/test-rm_stress/hash @@ -1 +1 @@ -2024-08-28 3ea09d83887d1fc0e07409e68d52c99f794846f9 +2024-10-07 40512d1349569b95538ce6c61613c295cf7f9487 diff --git a/repos/base/recipes/src/test-sanitizer/hash b/repos/base/recipes/src/test-sanitizer/hash index 52c4b35c74..daca3375f5 100644 --- a/repos/base/recipes/src/test-sanitizer/hash +++ b/repos/base/recipes/src/test-sanitizer/hash @@ -1 +1 @@ -2024-08-28 e4c5cc271035fd20416eca2b23005800bdbe22d5 +2024-10-07 4725441ba5bbe72651a38e5e13ac2ed3bda4af37 diff --git a/repos/base/recipes/src/test-segfault/hash b/repos/base/recipes/src/test-segfault/hash index 3b07ec270f..cc4b1ac80e 100644 --- a/repos/base/recipes/src/test-segfault/hash +++ b/repos/base/recipes/src/test-segfault/hash @@ -1 +1 @@ -2024-08-28 d30834f3bb7de0b8450835323179e126c057206d +2024-10-07 5c9f35640dd353fe429cac6d93c022a99a609fb5 diff --git a/repos/base/recipes/src/test-stack_smash/hash b/repos/base/recipes/src/test-stack_smash/hash index 7d41efcd8e..ab49b6822a 100644 --- a/repos/base/recipes/src/test-stack_smash/hash +++ b/repos/base/recipes/src/test-stack_smash/hash @@ -1 +1 @@ -2024-08-28 6106585c8708899bc2b5580583ae3d80a873a4bb +2024-10-07 635ede2b3116c2dd4817b120ba9c346f72032fae diff --git a/repos/base/recipes/src/test-synced_interface/hash b/repos/base/recipes/src/test-synced_interface/hash index 7c3b2287eb..2417a331ad 100644 --- a/repos/base/recipes/src/test-synced_interface/hash +++ b/repos/base/recipes/src/test-synced_interface/hash @@ -1 +1 @@ -2024-08-28 548d48fdd30db99f612a172dbb6733b9705de758 +2024-10-07 a1eb033228bdbe39301dd2fae6502870c3162b26 diff --git a/repos/base/recipes/src/test-timer/hash b/repos/base/recipes/src/test-timer/hash index 6b33630d2b..c5e3dbabb8 100644 --- a/repos/base/recipes/src/test-timer/hash +++ b/repos/base/recipes/src/test-timer/hash @@ -1 +1 @@ -2024-08-28 e9bcac3043d0ec5b0f99cf70c79c6a4602d7b381 +2024-10-07 f4fc22ec46e47ed91c121beb24657d911f6b7411 diff --git a/repos/base/recipes/src/test-tls/hash b/repos/base/recipes/src/test-tls/hash index 141411fdf8..6f69226d42 100644 --- a/repos/base/recipes/src/test-tls/hash +++ b/repos/base/recipes/src/test-tls/hash @@ -1 +1 @@ -2024-08-28 54a1cf1254fb7f5a3e21f19a4e93aaf48244e727 +2024-10-07 83118776eba8117187854ababa680cb1fe4b2b77 diff --git a/repos/base/recipes/src/test-token/hash b/repos/base/recipes/src/test-token/hash index 30f6b65c29..66c1514965 100644 --- a/repos/base/recipes/src/test-token/hash +++ b/repos/base/recipes/src/test-token/hash @@ -1 +1 @@ -2024-08-28 a39e757b6833857b4ec32f2060305079d6cc068f +2024-10-07 b1c7aacfa16f9ecbd103e3df98a0a2bb36bae272 diff --git a/repos/base/recipes/src/test-xml_generator/hash b/repos/base/recipes/src/test-xml_generator/hash index 1f107545ee..17838a62ca 100644 --- a/repos/base/recipes/src/test-xml_generator/hash +++ b/repos/base/recipes/src/test-xml_generator/hash @@ -1 +1 @@ -2024-08-28 8fded3cec4f36bfe77abbed9060c577906c8f643 +2024-10-07 472cfb4a2918d0ecb9251eba8cd3b624275a94ab diff --git a/repos/base/recipes/src/test-xml_node/hash b/repos/base/recipes/src/test-xml_node/hash index 2b7cd83038..d588964483 100644 --- a/repos/base/recipes/src/test-xml_node/hash +++ b/repos/base/recipes/src/test-xml_node/hash @@ -1 +1 @@ -2024-08-28 636f2fe518818087444a67b7fea94c7daf5dd5af +2024-10-07 17a0ac2f692ff963d89fab0ae111606a837bcaaf diff --git a/repos/dde_bsd/ports/dde_bsd.hash b/repos/dde_bsd/ports/dde_bsd.hash index 460d603aaa..0fc8469337 100644 --- a/repos/dde_bsd/ports/dde_bsd.hash +++ b/repos/dde_bsd/ports/dde_bsd.hash @@ -1 +1 @@ -b6086e021be26a2f2a07463c0318b79fd8d0513e +931ffc4e67642ff7c5e639d8ca7b6f5bc345c803 diff --git a/repos/dde_bsd/ports/dde_bsd.port b/repos/dde_bsd/ports/dde_bsd.port index 4e45a44e98..423c46521e 100644 --- a/repos/dde_bsd/ports/dde_bsd.port +++ b/repos/dde_bsd/ports/dde_bsd.port @@ -3,13 +3,12 @@ VERSION := individual (see sources) DOWNLOADS := audio.archive # -# Audio drivers from OpenBSD 7.3 +# Audio drivers from OpenBSD # SRC_DIR_AUDIO := src/lib/audio -VERSION(audio) := 7.3 -BASE_URL := https://cdn.openbsd.org/pub/OpenBSD -URL(audio) := $(BASE_URL)/${VERSION(audio)}/sys.tar.gz -SHA(audio) := bb0dfa11584d68464b3f788e43655f6454bb3ecba8ad5500377630bcf23570ec +VERSION(audio) := 8571a5a +URL(audio) := https://distfiles.sysret.de/Genode/dde_bsd-8571a5a.tar.xz +SHA(audio) := 4a0de8a026d3a844022135c25bab5aabfd5f77146aaedaa6d7253b2cc110efca DIR(audio) := $(SRC_DIR_AUDIO) TAR_OPT(audio) := --strip-components=1 --files-from $(REP_DIR)/audio.list HASH_INPUT += $(REP_DIR)/audio.list diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio/hash b/repos/dde_bsd/recipes/pkg/bsd_audio/hash index b8ccf5f15a..e36f279361 100644 --- a/repos/dde_bsd/recipes/pkg/bsd_audio/hash +++ b/repos/dde_bsd/recipes/pkg/bsd_audio/hash @@ -1 +1 @@ -2024-08-28 d9b3b6700616965b61c9cf673d1d2924d795437b +2024-10-07 49864c449ff2a8f7de7d54b6231c62ff4ad75dcd diff --git a/repos/dde_bsd/recipes/pkg/bsd_audio/runtime b/repos/dde_bsd/recipes/pkg/bsd_audio/runtime index 99cfae20b7..2ee62bf288 100644 --- a/repos/dde_bsd/recipes/pkg/bsd_audio/runtime +++ b/repos/dde_bsd/recipes/pkg/bsd_audio/runtime @@ -1,6 +1,6 @@ - + diff --git a/repos/dde_bsd/recipes/src/bsd_audio/hash b/repos/dde_bsd/recipes/src/bsd_audio/hash index c6969cf50a..6282042f1a 100644 --- a/repos/dde_bsd/recipes/src/bsd_audio/hash +++ b/repos/dde_bsd/recipes/src/bsd_audio/hash @@ -1 +1 @@ -2024-08-28 efd2b77afecdc8673da69eaa69f4e8baf3d03950 +2024-10-07 9c7c095fe94c898d473c97596e50a29d1cfaa088 diff --git a/repos/dde_bsd/run/audio_out.run b/repos/dde_bsd/run/audio_out.run index 50bbb6539d..00e5ccc84d 100644 --- a/repos/dde_bsd/run/audio_out.run +++ b/repos/dde_bsd/run/audio_out.run @@ -14,14 +14,18 @@ if {[have_spec linux]} { proc use_record_play_sessions { } { return 1 } create_boot_directory +import_from_depot [depot_user]/src/[base_src] \ + [depot_user]/src/acpi \ + [depot_user]/src/bsd_audio \ + [depot_user]/src/init \ + [depot_user]/src/pci_decode \ + [depot_user]/src/platform \ + [depot_user]/src/report_rom + proc build_targets { } { - set targets { - core init timer - driver/acpi driver/platform app/pci_decode server/report_rom - driver/audio - } + set targets { driver/audio/pci } if {[use_record_play_sessions]} { lappend targets server/record_play_mixer app/waveform_player \ @@ -48,7 +52,7 @@ proc record_play_start_nodes { } { return "" } return { - + @@ -58,12 +62,12 @@ proc record_play_start_nodes { } { - - + + - + @@ -94,7 +98,7 @@ proc audio_in_out_start_nodes { } { } install_config { - + @@ -108,7 +112,7 @@ install_config { - + @@ -122,15 +126,15 @@ install_config { - - + + - + @@ -139,7 +143,7 @@ install_config { - + @@ -154,7 +158,7 @@ install_config { - + diff --git a/repos/dde_ipxe/recipes/pkg/ipxe_nic/hash b/repos/dde_ipxe/recipes/pkg/ipxe_nic/hash index acb9781c1c..71102cc094 100644 --- a/repos/dde_ipxe/recipes/pkg/ipxe_nic/hash +++ b/repos/dde_ipxe/recipes/pkg/ipxe_nic/hash @@ -1 +1 @@ -2024-08-28 7f3df4651694eb8b127d3dc0aabf16341b4cbf75 +2024-10-07 ebc62d24f7c3bae4d285d96732c5c76a9d06da73 diff --git a/repos/dde_ipxe/recipes/src/ipxe_nic/hash b/repos/dde_ipxe/recipes/src/ipxe_nic/hash index a9768ba451..6f646b5082 100644 --- a/repos/dde_ipxe/recipes/src/ipxe_nic/hash +++ b/repos/dde_ipxe/recipes/src/ipxe_nic/hash @@ -1 +1 @@ -2024-08-28 d0fdf4e7f4928d752541494d82dc0eb14adabed1 +2024-10-07 11b76ee4b6ed52235d29283e1d8f377c65e71630 diff --git a/repos/dde_linux/include/wifi/ctrl.h b/repos/dde_linux/include/wifi/ctrl.h index 5cc748aa47..df95f66cb5 100644 --- a/repos/dde_linux/include/wifi/ctrl.h +++ b/repos/dde_linux/include/wifi/ctrl.h @@ -14,33 +14,90 @@ #ifndef _WIFI__CTRL_H_ #define _WIFI__CTRL_H_ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +#include -#define WPA_CTRL_FD 51 +namespace Wifi { -struct Msg_buffer + /* + * FD used to poll CTRL state from the supplicant. + */ + enum { CTRL_FD = 51, }; + + struct Msg_buffer; + + struct Notify_interface : Genode::Interface + { + virtual void submit_response() = 0; + virtual void submit_event() = 0; + virtual void block_for_processing() = 0; + }; + + void ctrl_init(Msg_buffer &); + +} /* namespace Wifi */ + + +struct Wifi::Msg_buffer { - unsigned char recv[4096*8]; - unsigned char send[4096]; - unsigned recv_id; + char send[4096]; unsigned send_id; - unsigned char event[1024]; + + char recv[4096*8]; + unsigned recv_id; + unsigned last_recv_id; + + char event[1024]; unsigned event_id; -} __attribute__((packed)); + unsigned last_event_id; + + Notify_interface &_notify; + + Msg_buffer(Notify_interface ¬ify) + : _notify { notify } { } + + /* + * Member functions below are called by the + * CTRL interface. + */ + + void notify_response() const { + _notify.submit_response(); } + + void notify_event() const { + _notify.submit_event(); } + + void block_for_processing() { + _notify.block_for_processing(); } + + /* + * Member functions below are called by the + * Manager. + */ + + void with_new_reply(auto const &fn) + { + char const *msg = reinterpret_cast(recv); + /* return early */ + if (last_recv_id == recv_id) + return; + + last_recv_id = recv_id; + fn(msg); + } + + void with_new_event(auto const &fn) + { + char const *msg = reinterpret_cast(event); + + if (last_event_id == event_id) + return; + + last_event_id = event_id; + fn(msg); + } +}; void wpa_ctrl_set_fd(void); -void *wifi_get_buffer(void); -void wifi_notify_cmd_result(void); -void wifi_block_for_processing(void); -void wifi_notify_event(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - #endif /* _WIFI__CTRL_H_ */ diff --git a/repos/dde_linux/include/wifi/rfkill.h b/repos/dde_linux/include/wifi/rfkill.h index 641b19d8be..ceb1824046 100644 --- a/repos/dde_linux/include/wifi/rfkill.h +++ b/repos/dde_linux/include/wifi/rfkill.h @@ -36,12 +36,20 @@ namespace Wifi { bool rfkill_blocked(); /** - * Set RFKILL state from the frontend + * Set RFKILL state from the manager * * May be only called from an EP context. */ void set_rfkill(bool); + /** + * Trigger RFKILL notification signal + * + * Used by the supplicants RFKILL driver to notify + * the management-layer. + */ + void rfkill_notify(); + } /* namespace Wifi */ #endif /* _WIFI__RFKILL_H_ */ diff --git a/repos/dde_linux/lib/mk/wpa_supplicant.mk b/repos/dde_linux/lib/mk/wpa_supplicant.mk index 3fe6593f26..8d7f0eb40e 100644 --- a/repos/dde_linux/lib/mk/wpa_supplicant.mk +++ b/repos/dde_linux/lib/mk/wpa_supplicant.mk @@ -10,7 +10,8 @@ CC_OPT += -Wno-unused-function CC_CXX_OPT += -fpermissive -SRC_C += main.c ctrl_iface_genode.c +SRC_C += main.c +SRC_CC += ctrl_iface_genode.cc INC_DIR += $(REP_DIR)/include @@ -31,6 +32,7 @@ SRC_C_wpa_supplicant = bssid_ignore.c \ scan.c \ sme.c \ wmm_ac.c \ + wnm_sta.c \ wpa_supplicant.c \ wpas_glue.c # @@ -45,7 +47,7 @@ CC_OPT += -DCONFIG_BACKEND_FILE -DCONFIG_NO_CONFIG_WRITE \ -DCONFIG_SME -DCONFIG_CTRL_IFACE \ -DCONFIG_BGSCAN -DCONFIG_BGSCAN_SIMPLE \ -DCONFIG_OPENSSL_CMAC -DCONFIG_SHA256 \ - -DCONFIG_SAE -DCONFIG_ECC + -DCONFIG_SAE -DCONFIG_ECC -DCONFIG_WNM CC_OPT += -DTLS_DEFAULT_CIPHERS=\"DEFAULT:!EXP:!LOW\" @@ -53,7 +55,7 @@ INC_DIR += $(WS_CONTRIB_DIR)/src/ # common SRC_C_common = ieee802_11_common.c wpa_common.c hw_features_common.c \ - ctrl_iface_common.c sae.c dragonfly.c + ctrl_iface_common.c sae.c dragonfly.c ptksa_cache.c SRC_C += $(addprefix src/common/, $(SRC_C_common)) INC_DIR += $(WS_CONTRIB_DIR)/src/common diff --git a/repos/dde_linux/lib/symbols/wifi b/repos/dde_linux/lib/symbols/wifi index 9f72cd9260..acde1609b6 100644 --- a/repos/dde_linux/lib/symbols/wifi +++ b/repos/dde_linux/lib/symbols/wifi @@ -22,5 +22,7 @@ wifi_ifname T _ZN4Wifi20firmware_get_requestEv T _ZN4Wifi26firmware_establish_handlerERNS_24Firmware_request_handlerE T _ZN4Wifi10set_rfkillEb T +_ZN4Wifi13rfkill_notifyEv T _ZN4Wifi14rfkill_blockedEv T _ZN4Wifi24rfkill_establish_handlerERNS_27Rfkill_notification_handlerE T +convert_errno_from_linux T diff --git a/repos/dde_linux/patches/r8169_disable_irq_coalescing.patch b/repos/dde_linux/patches/r8169_disable_irq_coalescing.patch new file mode 100644 index 0000000000..87e69a57f2 --- /dev/null +++ b/repos/dde_linux/patches/r8169_disable_irq_coalescing.patch @@ -0,0 +1,15 @@ +Disable IRQ coalescing as it seems to not work properly in our +port because at some point triggering interrupts stops altogether. +In this case the netperf tests produce around 0.1(!) MBit/s of +throughput. +--- src/linux/drivers/net/ethernet/realtek/r8169_main.c ++++ src/linux/drivers/net/ethernet/realtek/r8169_main.c +@@ -5374,7 +5374,7 @@ + dev->hw_features |= NETIF_F_RXALL; + dev->hw_features |= NETIF_F_RXFCS; + +- netdev_sw_irq_coalesce_default_on(dev); ++ // netdev_sw_irq_coalesce_default_on(dev); + + /* configure chip for default features */ + rtl8169_set_features(dev, dev->features); diff --git a/repos/dde_linux/patches/wpa_supplicant.patch b/repos/dde_linux/patches/wpa_supplicant.patch index 1c1cc99cab..06c0651934 100644 --- a/repos/dde_linux/patches/wpa_supplicant.patch +++ b/repos/dde_linux/patches/wpa_supplicant.patch @@ -1,8 +1,38 @@ -diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c -index aec179a..6c07c73 100644 +The nl80211 driver patch contains the following changes: + +- Convert inline error values from Linux to libc (FreeBSD) as otherwise + wpa_supplicant might come to the wrong conclusions. + +- Show RFKILL operations at INFO level (so that the always appear in the + log) and generate a interface dis-/enable event that will be handled + by the management layer. + +- Remove netlink messages that rely on newer libnl versions, e.g. signed + value where introduced in 3.2.27. + +- Hardcode the I/O control socket rather than calling socket because it + is not used anyway (see wpa_driver_nl80211/ioctl.cc). --- a/src/drivers/driver_nl80211.c -+++ b/src/drivers/driver_nl80211.c -@@ -1985,13 +1985,13 @@ static void wpa_driver_nl80211_rfkill_blocked(void *ctx) ++++ a/src/drivers/driver_nl80211.c +@@ -487,6 +487,8 @@ + } + + ++extern int convert_errno_from_linux(int linux_errno); ++ + int send_and_recv(struct nl80211_global *global, + struct nl_sock *nl_handle, struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), +@@ -579,7 +581,7 @@ + /* Always clear the message as it can potentially contain keys */ + nl80211_nlmsg_clear(msg); + nlmsg_free(msg); +- return err.err; ++ return convert_errno_from_linux(err.err); + } + + +@@ -2088,13 +2090,13 @@ { struct wpa_driver_nl80211_data *drv = ctx; @@ -18,7 +48,7 @@ index aec179a..6c07c73 100644 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); } -@@ -1999,7 +1999,7 @@ static void wpa_driver_nl80211_rfkill_blocked(void *ctx) +@@ -2102,7 +2104,7 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) { struct wpa_driver_nl80211_data *drv = ctx; @@ -27,7 +57,7 @@ index aec179a..6c07c73 100644 if (i802_set_iface_flags(drv->first_bss, 1)) { wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP " "after rfkill unblock"); -@@ -2013,7 +2013,7 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) +@@ -2116,7 +2118,7 @@ * rtnetlink ifup handler will report interfaces other than the P2P * Device interface as enabled. */ @@ -36,12 +66,34 @@ index aec179a..6c07c73 100644 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); } -@@ -8709,7 +8709,7 @@ static void * nl80211_global_init(void *ctx) +@@ -7826,7 +7828,7 @@ + [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8}, + [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 }, + [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 }, +- [NL80211_STA_INFO_ACK_SIGNAL_AVG] = { .type = NLA_S8 }, ++ [NL80211_STA_INFO_ACK_SIGNAL_AVG] = { .type = NLA_U8 }, + [NL80211_STA_INFO_RX_MPDUS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_FCS_ERROR_COUNT] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 }, +@@ -7930,9 +7932,9 @@ + nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]); + data->flags |= STA_DRV_DATA_LAST_ACK_RSSI; + } +- if (stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]) +- data->avg_ack_signal = +- nla_get_s8(stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]); ++ // if (stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]) ++ // data->avg_ack_signal = ++ // nla_get_s8(stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]); + if (stats[NL80211_STA_INFO_RX_MPDUS]) + data->rx_mpdus = nla_get_u32(stats[NL80211_STA_INFO_RX_MPDUS]); + if (stats[NL80211_STA_INFO_FCS_ERROR_COUNT]) +@@ -9939,7 +9941,7 @@ if (wpa_driver_nl80211_init_nl_global(global) < 0) goto err; - global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ global->ioctl_sock = 42; ++ global->ioctl_sock = 12345; /* arbitrarily chosen number b/c it won't be used anyway */ if (global->ioctl_sock < 0) { wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s", strerror(errno)); diff --git a/repos/dde_linux/ports/linux-firmware.hash b/repos/dde_linux/ports/linux-firmware.hash index d3384f7ac3..6769e95ac8 100644 --- a/repos/dde_linux/ports/linux-firmware.hash +++ b/repos/dde_linux/ports/linux-firmware.hash @@ -1 +1 @@ -5fff60c84cc929423efe4d572ab9624da974ea25 +5727b3009cb951578cd5478b6c3d2bf14c7236ea diff --git a/repos/dde_linux/ports/linux-firmware.port b/repos/dde_linux/ports/linux-firmware.port index 3431395dc8..5cdaf44483 100644 --- a/repos/dde_linux/ports/linux-firmware.port +++ b/repos/dde_linux/ports/linux-firmware.port @@ -1,8 +1,8 @@ LICENSE := mixed (binary) -VERSION := 896ed3fb7ebd785adc2c232ce1e7008e38f795dc +VERSION := 6726071dc75e85fcf70558073a23faec3e976a08 DOWNLOADS := fw.archive FW_REV := $(VERSION) URL(fw) := https://github.com/cnuke/dde_linux_firmware/archive/$(FW_REV).tar.gz -SHA(fw) := 0120f27ebf7950671bc27dc0a2142da41784a9a5522eeed8ee54508c3f4e1994 +SHA(fw) := ed58a34df08fe962f97e827b3b89861963589b6d8c077d96da2209f1fb1981c6 DIR(fw) := firmware diff --git a/repos/dde_linux/ports/linux.hash b/repos/dde_linux/ports/linux.hash index 63ad33ef51..e5e5f25405 100644 --- a/repos/dde_linux/ports/linux.hash +++ b/repos/dde_linux/ports/linux.hash @@ -1 +1 @@ -403e8fecb5e0303605e2c7b913089710e66ad3d6 +501de7d0dc5363c9f271c2cd853b963b2a881438 diff --git a/repos/dde_linux/ports/linux.port b/repos/dde_linux/ports/linux.port index 1f645de54b..ba49c27c46 100644 --- a/repos/dde_linux/ports/linux.port +++ b/repos/dde_linux/ports/linux.port @@ -18,6 +18,7 @@ PATCH_FILES := i915_irq.patch \ usb_net_cdc_ncm.patch \ usb_net_pinephone.patch \ usb_net_smsc95xx.patch \ - workqueue_deadlock.patch + workqueue_deadlock.patch \ + r8169_disable_irq_coalescing.patch PATCHES += $(addprefix patches/,$(PATCH_FILES)) diff --git a/repos/dde_linux/ports/wpa_supplicant.hash b/repos/dde_linux/ports/wpa_supplicant.hash index 8eb5196c87..bd65b206b1 100644 --- a/repos/dde_linux/ports/wpa_supplicant.hash +++ b/repos/dde_linux/ports/wpa_supplicant.hash @@ -1 +1 @@ -6242912dd6f6c22550a7fe0b443bfd80c5cfedae +15974e67af9112d919f1625a5c2ed2d996cdbdfb diff --git a/repos/dde_linux/ports/wpa_supplicant.port b/repos/dde_linux/ports/wpa_supplicant.port index 6fb96266d0..eb4da6d1af 100644 --- a/repos/dde_linux/ports/wpa_supplicant.port +++ b/repos/dde_linux/ports/wpa_supplicant.port @@ -1,12 +1,12 @@ LICENSE := BSD-3-Clause -VERSION := 2.10 +VERSION := 2.11 DOWNLOADS := wpa_supplicant.archive # # wpa_supplicant sources # -URL(wpa_supplicant) := https://w1.fi/releases/wpa_supplicant-2.10.tar.gz -SHA(wpa_supplicant) := 20df7ae5154b3830355f8ab4269123a87affdea59fe74fe9292a91d0d7e17b2f +URL(wpa_supplicant) := https://w1.fi/releases/wpa_supplicant-2.11.tar.gz +SHA(wpa_supplicant) := 912ea06f74e30a8e36fbb68064d6cdff218d8d591db0fc5d75dee6c81ac7fc0a DIR(wpa_supplicant) := src/app/wpa_supplicant # diff --git a/repos/dde_linux/recipes/api/virt_linux/hash b/repos/dde_linux/recipes/api/virt_linux/hash index d7763a6de7..644e1639a4 100644 --- a/repos/dde_linux/recipes/api/virt_linux/hash +++ b/repos/dde_linux/recipes/api/virt_linux/hash @@ -1 +1 @@ -2024-08-28 203107a559eaf5f4d23126894356dab42c76384a +2024-10-29 a0f80d05ac5f5d87e619cd2041ef4fab8f2c906f diff --git a/repos/dde_linux/recipes/pkg/wireguard/hash b/repos/dde_linux/recipes/pkg/wireguard/hash index b4de56c928..157157097e 100644 --- a/repos/dde_linux/recipes/pkg/wireguard/hash +++ b/repos/dde_linux/recipes/pkg/wireguard/hash @@ -1 +1 @@ -2024-08-28 461a4a470e6385e77585a1ed7b2d1c0f6a280275 +2024-10-29 29712abb79c1d33c6cfff831b0a41de51c1f0479 diff --git a/repos/dde_linux/recipes/src/usb_hid/hash b/repos/dde_linux/recipes/src/usb_hid/hash index 13ff8ca28f..6338f3928c 100644 --- a/repos/dde_linux/recipes/src/usb_hid/hash +++ b/repos/dde_linux/recipes/src/usb_hid/hash @@ -1 +1 @@ -2024-08-28 1eca1b3baa82ba8cc89c6f0e34de3e0659ce2c13 +2024-10-29 a0864eb06b2b8f868a024feda080ec1be04ad1b8 diff --git a/repos/dde_linux/recipes/src/usb_net/hash b/repos/dde_linux/recipes/src/usb_net/hash index c8354a652a..dbc712324f 100644 --- a/repos/dde_linux/recipes/src/usb_net/hash +++ b/repos/dde_linux/recipes/src/usb_net/hash @@ -1 +1 @@ -2024-08-28 f8ca538f97a744ec3f1c83c9dfce43c529ee377d +2024-10-29 693dab02a78f3582895f1a44d60b2ac0f6712cc5 diff --git a/repos/dde_linux/recipes/src/vfs_lxip/hash b/repos/dde_linux/recipes/src/vfs_lxip/hash index 8847faca88..fb31526d6e 100644 --- a/repos/dde_linux/recipes/src/vfs_lxip/hash +++ b/repos/dde_linux/recipes/src/vfs_lxip/hash @@ -1 +1 @@ -2024-08-28 e7253c5f91faf73ea45e0e1dac8f3b0ce3d05096 +2024-10-29 64e12d496d0d0e9949f01df8bd22be1c15c2f6bf diff --git a/repos/dde_linux/recipes/src/wireguard/hash b/repos/dde_linux/recipes/src/wireguard/hash index 72876e348e..c1aaa8c37b 100644 --- a/repos/dde_linux/recipes/src/wireguard/hash +++ b/repos/dde_linux/recipes/src/wireguard/hash @@ -1 +1 @@ -2024-08-28 17ae0534a3585c0bf11f818ec5163472b7a0d628 +2024-10-29 eb4747d4055fa678c1fc6f4c517906eb91c0f98b diff --git a/repos/dde_linux/run/nic_router_uplinks.run b/repos/dde_linux/run/nic_router_uplinks.run index 77fe902d95..a17f051731 100644 --- a/repos/dde_linux/run/nic_router_uplinks.run +++ b/repos/dde_linux/run/nic_router_uplinks.run @@ -133,8 +133,8 @@ install_config { - - + + diff --git a/repos/dde_linux/run/wifi_config.inc b/repos/dde_linux/run/wifi_config.inc new file mode 100644 index 0000000000..b3a4dcf643 --- /dev/null +++ b/repos/dde_linux/run/wifi_config.inc @@ -0,0 +1,71 @@ +# +# This file includes snippets to generate the 'wifi_config' for the +# various wireless LAN driver for each test run-script. +# + +proc wifi_ssid { } { + return $::env(GENODE_WIFI_SSID) +} + +proc wifi_psk { } { + return $::env(GENODE_WIFI_PSK) +} + +proc wifi_wpa { } { + if {![info exists ::env(GENODE_WIFI_WPA)]} { + return WPA2 + } + return $::env(GENODE_WIFI_WPA) +} + +proc wifi_verbose { } { + if {![info exists ::env(GENODE_WIFI_VERBOSE)]} { + return false + } + return true +} + +# +# wifi-driver config generator (supporting a network list) +# +# You may script your tests with this function in the dynamic_rom config below. +# The syntax for the networks parameter is +# +# { ssid protection passphrase explicit_scan } +# +# Example dynamic_rom config: +# +# { +# } [wifi_config 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk no"]] { +# +# +# } [wifi_config 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk yes"]] { +# } +# + +set wifi_verbose false + +proc wifi_config { scan_interval update_quality_interval rfkill networks } { + global wifi_verbose + + set config "\n" + foreach n $networks { + if {[lindex $n 4] == "yes"} { + append config " \n" + } + append config " \n" + } + append config "\n" + + return $config +} + diff --git a/repos/dde_linux/src/driver/usb_net/lx_user.c b/repos/dde_linux/src/driver/usb_net/lx_user.c index d038379a95..e5d7a3698f 100644 --- a/repos/dde_linux/src/driver/usb_net/lx_user.c +++ b/repos/dde_linux/src/driver/usb_net/lx_user.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -30,230 +31,17 @@ struct task_struct *lx_user_new_usb_task(int (*func)(void*), void *args, } -static struct genode_uplink *dev_genode_uplink(struct net_device *dev) -{ - return (struct genode_uplink *)dev->ifalias; -} - - -struct genode_uplink_rx_context -{ - struct net_device *dev; -}; - - -struct genode_uplink_tx_packet_context -{ - struct sk_buff *skb; -}; - - -static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx, - char *dst, unsigned long dst_len) -{ - struct sk_buff * const skb = ctx->skb; - - skb_push(skb, ETH_HLEN); - - if (dst_len < skb->len) { - printk("uplink_tx_packet_content: packet exceeds uplink packet size\n"); - memset(dst, 0, dst_len); - return 0; - } - - skb_copy_from_linear_data(skb, dst, skb->len); - - /* clear unused part of the destination buffer */ - memset(dst + skb->len, 0, dst_len - skb->len); - - return skb->len; -} - - -static rx_handler_result_t handle_rx(struct sk_buff **pskb) -{ - struct sk_buff *skb = *pskb; - struct net_device *dev = skb->dev; - struct genode_uplink_tx_packet_context ctx = { .skb = skb }; - - /* if uplink still exists */ - if (dev->ifalias) { - bool progress = genode_uplink_tx_packet(dev_genode_uplink(dev), - uplink_tx_packet_content, - &ctx); - if (!progress) - printk("handle_rx: uplink saturated, dropping packet\n"); - } - - kfree_skb(skb); - return RX_HANDLER_CONSUMED; -} - - -/** - * Create Genode uplink for given net device - * - * The uplink is registered at the dev->ifalias pointer. - */ -static void handle_create_uplink(struct net_device *dev) -{ - struct genode_uplink_args args; - - if (dev_genode_uplink(dev)) - return; - - if (!netif_carrier_ok(dev)) - return; - - printk("create uplink for net device %s\n", &dev->name[0]); - - memset(&args, 0, sizeof(args)); - - if (dev->addr_len != sizeof(args.mac_address)) { - printk("error: net device has unexpected addr_len %u\n", dev->addr_len); - return; - } - - { - unsigned i; - for (i = 0; i < dev->addr_len; i++) - args.mac_address[i] = dev->dev_addr[i]; - } - - args.label = &dev->name[0]; - - dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args); -} - - -static void handle_destroy_uplink(struct net_device *dev) -{ - struct genode_uplink *uplink = dev_genode_uplink(dev); - - if (!uplink) - return; - - if (netif_carrier_ok(dev)) - return; - - printk("destroy uplink for net device %s\n", &dev->name[0]); - genode_uplink_destroy(uplink); - - dev->ifalias = NULL; -} - - -static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx, - char const *ptr, unsigned long len) -{ - struct sk_buff *skb = alloc_skb(len, GFP_KERNEL); - - if (!skb) { - printk("alloc_skb failed\n"); - return GENODE_UPLINK_RX_RETRY; - } - - skb_copy_to_linear_data(skb, ptr, len); - skb_put(skb, len); - skb->dev = ctx->dev; - - if (dev_queue_xmit(skb) < 0) { - printk("lx_user: failed to xmit packet\n"); - return GENODE_UPLINK_RX_REJECTED; - } - - return GENODE_UPLINK_RX_ACCEPTED; -} - - -/* - * custom MAC address - */ -bool use_mac_address; -unsigned char mac_address[6]; -static bool mac_address_configured = false; - -static void handle_mac_address(struct net_device *dev) -{ - int err; - struct sockaddr addr; - struct genode_mac_address dev_addr; - - if (mac_address_configured || !netif_device_present(dev)) return; - - if (use_mac_address) { - memcpy(&addr.sa_data, mac_address, ETH_ALEN); - addr.sa_family = dev->type; - err = dev_set_mac_address(dev, &addr, NULL); - if (err < 0) - printk("Warning: Could not set configured MAC address: %pM (err=%d)\n", - mac_address, err); - } - - memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr)); - genode_mac_address_register(dev->name, dev_addr); - - mac_address_configured =true; -} - - -static int network_loop(void *arg) -{ - for (;;) { - - struct net_device *dev; - - for_each_netdev(&init_net, dev) { - - handle_mac_address(dev); - - /* enable link sensing, repeated calls are handled by testing IFF_UP */ - dev_open(dev, 0); - - /* install rx handler once */ - if (!netdev_is_rx_handler_busy(dev)) - netdev_rx_handler_register(dev, handle_rx, NULL); - - /* respond to cable plug/unplug */ - handle_create_uplink(dev); - handle_destroy_uplink(dev); - - /* transmit packets received from the uplink session */ - if (netif_carrier_ok(dev)) { - - struct genode_uplink_rx_context ctx = { .dev = dev }; - - while (genode_uplink_rx(dev_genode_uplink(dev), - uplink_rx_one_packet, - &ctx)); - } - }; - - /* block until lx_emul_task_unblock */ - lx_emul_task_schedule(true); - } - return 0; -} - - -static struct task_struct *net_task; - void lx_user_init(void) { - pid_t pid; - lx_emul_usb_client_init(); - - pid = kernel_thread(network_loop, NULL, "network_loop", - CLONE_FS | CLONE_FILES); - net_task = find_task_by_pid_ns(pid, NULL); + lx_emul_nic_init(); } void lx_user_handle_io(void) { lx_emul_usb_client_ticker(); - if (net_task) lx_emul_task_unblock(net_task); + lx_emul_nic_handle_io(); } @@ -269,11 +57,10 @@ void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags, u32 portid, const struct nlmsghdr *nlh) { - /* trigger handle_create_uplink / handle_destroy_uplink */ - if (net_task) lx_emul_task_unblock(net_task); + lx_emul_nic_handle_io(); if (force_uplink_destroy) { - struct genode_uplink *uplink = dev_genode_uplink(dev); + struct genode_uplink *uplink = (struct genode_uplink *)dev->ifalias; printk("force destroy uplink for net device %s\n", &dev->name[0]); genode_uplink_destroy(uplink); force_uplink_destroy = false; @@ -284,7 +71,9 @@ void rtmsg_ifinfo(int type, struct net_device * dev, void lx_emul_usb_client_device_unregister_callback(struct usb_device *) { force_uplink_destroy = true; - mac_address_configured = false; + + /* set mac as unconfigured by setting nothing */ + lx_emul_nic_set_mac_address(NULL, 0); } diff --git a/repos/dde_linux/src/driver/usb_net/main.cc b/repos/dde_linux/src/driver/usb_net/main.cc index 8ae8a8d458..497afb9980 100644 --- a/repos/dde_linux/src/driver/usb_net/main.cc +++ b/repos/dde_linux/src/driver/usb_net/main.cc @@ -23,15 +23,13 @@ #include #include #include +#include /* C-interface */ #include using namespace Genode; -extern bool use_mac_address; -extern unsigned char mac_address[6]; - struct Main { Env &env; @@ -90,12 +88,10 @@ struct Main usb_config = config_rom.xml().attribute_value("configuration", 0ul); /* retrieve possible MAC */ - use_mac_address = config_rom.xml().has_attribute("mac"); - if (use_mac_address) { + if (config_rom.xml().has_attribute("mac")) { auto const mac = config_rom.xml().attribute_value("mac", Nic::Mac_address{}); - mac.copy(mac_address); - use_mac_address = true; log("Trying to use configured mac: ", mac); + lx_emul_nic_set_mac_address(mac.addr, sizeof(mac.addr)); } } }; diff --git a/repos/dde_linux/src/driver/usb_net/target.inc b/repos/dde_linux/src/driver/usb_net/target.inc index 7fbee1840b..08d2559ef0 100644 --- a/repos/dde_linux/src/driver/usb_net/target.inc +++ b/repos/dde_linux/src/driver/usb_net/target.inc @@ -8,6 +8,7 @@ SRC_C += dummies.c \ lx_emul.c \ lx_user.c +SRC_C += lx_emul/nic.c SRC_C += lx_emul/virt/shadow/drivers/usb/core/buffer.c SRC_C += lx_emul/virt/shadow/drivers/usb/core/hcd.c SRC_C += lx_emul/virt/usb_client.c diff --git a/repos/dde_linux/src/driver/wifi/README b/repos/dde_linux/src/driver/wifi/README index d964b409b9..2350231d90 100644 --- a/repos/dde_linux/src/driver/wifi/README +++ b/repos/dde_linux/src/driver/wifi/README @@ -1,5 +1,5 @@ -The wifi component is a port of the Linux mac802.11 stack as well as -libnl and wpa_supplicant to Genode. Depending on the used platform it +The wifi component consists of a port of the Linux mac802.11 stack as well +as libnl and wpa_supplicant to Genode. Depending on the used platform it features a selection of drivers for wireless devices. For example on the PC platform it contains the ath9k, iwlwifi and rtlwifi drivers for PCI(e) devices. @@ -10,14 +10,18 @@ The 'wifi' binary is the generic management part that includes the Wifi configuration interface and the 'wpa_supplicant'. A suitable driver library is loaded at run-time (see section [Debugging]). -To start the component on the PC platform the following configuration snippet -can be used: + +Configuration +~~~~~~~~~~~~~ + +This configuration snippet shows how to start the component on the PC +platform. ! ! ! ! -! +! ! ! ! @@ -38,14 +42,14 @@ can be used: ! ! -On other platforms the wifi library will be different. The following -snippet illustrates the use of the driver on the PinePhone: +On other platforms the wifi library will be different. So, the +following snippet illustrates the use of the driver on the PinePhone. ! ! ! ! -! +! ! ! ! @@ -79,55 +83,93 @@ directory in the driver's local VFS. It is up to the configuration how those files are made available. In these examples they are contained in an '.tar' archive that is request as a ROM module. -The driver will request access to the ROM module 'wifi_config' to -connect to a network: +The driver will request access to the 'wifi_config' ROM module that +contains its actual configuration in the '' node. This +node features the following attributes. -! -! +* :scan_interval: sets the time interval in seconds in which scan + operations are requested and is used when not already connected + to a network. The default is 5 seconds. + +* :update_quality_interval: sets the time interval in which the current + signal quality of the connected access point is updated (RSSI polling). + The default value is 30 seconds. + +* :rfkill: allows to temporarily prevent any radio activity. The + default is 'false'. + +* :bgscan: is an expert option that configures the way the + supplicant performs background scanning to steer or rather optimize + roaming decisions within the same network (SSID). The syntax of the + option string corresponds to the original WPA-supplicant 'bgscan' option. + The default value is set to 'simple:30:-70:600'. This functionality can + be disabled by specifying an empty value, e.g. 'bgscan=""'. If bgscan is + disabled the 'accesspoints' report will not be updated while the + supplicant is connected to a network. + +* :log_level: allows for steering the verbosity of the supplicant + and may assist while diagnosing problems with the driver. + Valid values correspond to levels used by the supplicant + and are as follows 'excessive', 'msgdump', 'debug', 'info', + 'warning' and 'error'. The default value is 'error' and configures + the least amount of verbosity. + +* :verbose: allows for logging of diagnostic messages generated + by the managing portion of the driver. The default is 'false'. + +Besides those attributes the '' node can host '' +nodes. Such a node describes the parameters of a network and its +existence implies the intent to join the network. It has the following +attributes. + +* :ssid: sets the name of the network. + + Note: the SSID is copied verbatim and at the moment, there is no way + to express or escape non alphanumeric characters. + +* :bssid: can be used to select a specific access point within a + network. + +* :protection: specifies the used protection mechanism of the + network. Valid values are 'WPA', 'WPA2', 'WPA3' and 'NONE'. + The last one is used in case the network uses other means of + protection and access is open. + + Note: currently only personal WPA protection using a pre-shared-key + (PSK) is supported. + +* :passphrase: sets the PSK that is required should the + network be protected. + +Of all attributes solely the 'ssid' attribute is mandatory and all +others are optional. They should be used when needed only. + +Note: If configured networks overlap in locality, the driver might + switch dynamically between these networks. + +To scan for a hidden network a '' node must by added. +It contains the following mandatory attribute. + +* :ssid: set the name of the hidden network to scan for + + Note: the SSID is copied verbatim and at the moment, there is no way + to express or escape non alphanumeric characters. + +The following exemplary snippet showcases a config for two networks where +the first one should be automatically considered for joining and uses 'WPA2' +while the second one is hidden but should show up in the scan results. + +! +! ! -To temporarily prevent any radio activity, the 'rfkill' attribute -can be set to 'true'. +To join the hidden network a corresponding '' is needed. -If the network is protected by, e.g., WPA/WPA2/WPA3, the protection type, -either 'WPA', 'WPA2' or 'WPA3' as well as the the passphrase have to be -specified. -The 'bssid' attribute can be used to select a specifc accesspoint within a -network. Of all attributes only the 'ssid' attribute is mandatory, all others -are optional and should only be used when needed. - -The configuration may contain more than one network. In This case the driver -will try to select the best one it gets a response from. To prevent it -from automatically joining the network the 'auto_connect' attribute must be -set to 'false'; the default value is 'true'. If the 'explicit_scan' attribute -is set, the driver will pro-actively scan for a hidden network with the given -SSID: - -! -! -! -! - -By default, the driver scans for available networks only when not -connected. This can be changed with the 'connected_scan_interval' -attribute, which specifies the interval for connected scans in -seconds and directly influences any roaming decision, i.e., select -a better fit accesspoint for the configured network. - -In addition, by specifing 'update_quality_interval', the driver will -every so often update the current signal quality of the established -connection to the accesspoint. Note that this option is only useable when -the 'connected_scan_interval' is set to '0' as both options are mutually -exclusive. - -Also, the driver can be switched to verbose logging during runtime -by setting the 'verbose' or 'verbose_state' attribute to 'true'. - -The wifi driver creates two distinct reports to communicate its state and -information about the wireless infrastructure to other components. The -first one is a list of all available accesspoints. The following examplary -report shows its general structure: +The wifi driver uses two distinct reports, 'state' and 'accesspoints', +to communicate its state of connectivity and information about the wireless +access points in the vicinity to other components. +This exemplary 'accesspoints' report shows its general structure. ! ! @@ -135,32 +177,50 @@ report shows its general structure: ! ! -Each accesspoint node has attributes that contain the SSID and the BSSID -of the accesspoint as well as the link quality (signal strength). These -attributes are mandatory. If the network is protected, the node will also -have an attribute describing the type of protection in addition. +The '' node can contain a fluctuating number of '' +nodes that describe an access point with the following attributes. -The second report provides information about the state of the connection -to the currently connected accesspoint: +* :ssid: specifies the name of the network the access point advertises. + Empty SSIDs are not reported. + +* :bssid: specifies the physical address of the access point. + +* :freq: specifies the frequency used by the access point. + +* :quality: specifies the approximated link quality (calculated from the + RSSI value). + +* :protection: specifies which kind of protection is employed by the access + point. + + Note: when a mixed protection is used by the network, like WPA2-PSK and + WPA3-PSK mixed-mode, only the strongest protection (WPA3-PSK) is + advertised. + +The 'state' report provides information about the state of the connectivity +and looks as follows. ! ! ! -Valid state values are 'connected', 'disconnected', 'connecting'. Depending -on the state, there are additional attributes that can be checked. In case -of an authentication error, e.g. the passphrase is wrong, the 'auth_failure' -attribute will be set to 'true'. The 'rfkilled' attribute is set to 'true' -if a disconnect was triggered by disabling the radio activity via setting -the 'rfkill' attribute. It can also contain the optional 'quality' attribute -to denote the current signal quality (see 'update_quality_interval'). +The '' node encompasses one '' node that has the +following additional attributes beside the ones already discussed. -By subscribing to both reports and providing the required 'wifi_config' ROM -module, a component is able control the wireless driver. +* :state: specifies the actual state of connectivity. Valid values + are 'connected', 'connecting' and 'disconnected'. -Currently only WPA/WPA2/WPA3 protection using a passphrase is supported and -the SSID is copied verbatim. At the moment, there is no way to express or -escape non alphanumeric characters. +* :auth_failure: is an optional attribute and set to 'true' in case + the PSK was wrong + +* :rfkilled: is an optional attribute and set to 'true' whenever + radio activity was temporarily disabled. + +* :not_found: is an optional attribute and is only set when a single + auto-connect network was configured but could not be found. + +By subscribing to both reports and providing the required 'wifi_config' +ROM module, a component is able control the wireless driver. The driver optionally reports the following information under the label "devices" if requested in the config as depicted. @@ -177,7 +237,7 @@ As mentioned in the introduction the 'wifi' component is special in the regard that the actual driver is provided as a shared-object to better isolate it from the the driver binary that is a Libc::Component managing the 'wpa_supplicant'. Since this code and in return the binary is the same for each -platform it is linked against an artifical 'wifi' library that only exists as +platform it is linked against an artificial 'wifi' library that only exists as an ABI stub created via 'lib/symbols/wifi'. In case the driver is integrated via depot archives this is, besides setting the proper ROM routes, of no concern. However, when the driver is built without the depot, the boot image @@ -198,7 +258,7 @@ rather then stub ABI library. This is achieved by adapting the driver's ![…] 'LIBS' must be changed as follows in case the PC wifi driver library is -used: +used. !LIBS := base pc_wifi diff --git a/repos/dde_linux/src/driver/wifi/frontend.h b/repos/dde_linux/src/driver/wifi/frontend.h deleted file mode 100644 index f003987132..0000000000 --- a/repos/dde_linux/src/driver/wifi/frontend.h +++ /dev/null @@ -1,1829 +0,0 @@ - /* - * \author Josef Soentgen - * \date 2018-07-31 - * - * This wifi driver front end uses the CTRL interface of the wpa_supplicant via - * a Genode specific backend, which merely wraps a shared memory buffer, to - * manage the supplicant. - * - * Depending on the 'wifi_config' ROM content it will instruct the supplicant - * to enable, disable and connect to wireless networks. Commands and their - * corresponding execute result are handled by the '_cmd_handler' dispatcher. - * This handler drives the front end's state-machine. Any different type of - * action can only be initiated from the 'IDLE' state. Unsolicited events, e.g. - * a scan-results-available event, may influence the current state. Config - * updates are deferred in case the current state is not 'IDLE'. - * - * brain-dump - * ========== - * - * config update overview: - * [[block any new update]] > [mark stale] > [rm stale] > [add new] > [update new] > [[unblock update]] - * - * add new network: - * [[new ap]] > [ssid] > bssid? + [bssid] > [psk] > auto? + [enable] > new ap? + [[new ap]] - * - * update network: - * [[update ap] > bssid? + [bssid] > psk? + [psk] > auto? + [enable] > update ap? + [[update ap]] - * - * remove network: - * [[mark stale]] > [remove network] > stale? + [remove network] - */ - -/* - * Copyright (C) 2018-2022 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#ifndef _WIFI_FRONTEND_H_ -#define _WIFI_FRONTEND_H_ - -/* Genode includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* rep includes */ -#include -#include - -/* local includes */ -#include - -/* declare manually as it is a internal hack^Winterface */ -extern void wifi_kick_socketcall(); - - -namespace Wifi { - struct Frontend; -} - - -/* keep ordered! */ -static struct Recv_msg_table { - char const *string; - size_t len; -} recv_table[] = { - { "OK", 2 }, - { "FAIL", 4 }, - { "CTRL-EVENT-SCAN-RESULTS", 23 }, - { "CTRL-EVENT-CONNECTED", 20 }, - { "CTRL-EVENT-DISCONNECTED", 23 }, - { "SME: Trying to authenticate", 27 }, - { "CTRL-EVENT-NETWORK-NOT-FOUND", 28 }, -}; - -enum Rmi { - OK = 0, - FAIL, - SCAN_RESULTS, - CONNECTED, - DISCONNECTED, - SME_AUTH, - NOT_FOUND, -}; - - -static inline bool check_recv_msg(char const *msg, - Recv_msg_table const &entry) { - return Genode::strcmp(entry.string, msg, entry.len) == 0; } - - -static bool cmd_successful(char const *msg) { - return check_recv_msg(msg, recv_table[OK]); } - - -static bool cmd_fail(char const *msg) { - return check_recv_msg(msg, recv_table[FAIL]); } - - -static bool results_available(char const *msg) { - return check_recv_msg(msg, recv_table[SCAN_RESULTS]); } - - -static bool connecting_to_network(char const *msg) { - return check_recv_msg(msg, recv_table[SME_AUTH]); } - - -static bool network_not_found(char const *msg) { - return check_recv_msg(msg, recv_table[NOT_FOUND]); } - - -static bool scan_results(char const *msg) { - return Genode::strcmp("bssid", msg, 5) == 0; } - - -static bool list_network_results(char const *msg) { - return Genode::strcmp("network", msg, 7) == 0; } - - -/* - * Central network data structure - */ -struct Accesspoint : Genode::Interface -{ - using Bssid = Genode::String<17+1>; - using Freq = Genode::String< 4+1>; - using Prot = Genode::String< 7+1>; - using Ssid = Genode::String<32+1>; - using Pass = Genode::String<63+1>; - - /* - * Accesspoint information fields used by the front end - */ - Bssid bssid { }; - Freq freq { }; - Prot prot { }; - Ssid ssid { }; - Pass pass { }; - unsigned signal { 0 }; - - /* - * CTRL interface fields - * - * The 'enabled' field is set to true if ENABLE_NETWORK - * was successfully executed. The network itself might - * get disabled by wpa_supplicant itself in case it cannot - * connect to the network, which will _not_ be reflected - * here. - */ - int id { -1 }; - bool enabled { false }; - - /* - * Internal configuration fields - */ - bool auto_connect { false }; - bool update { false }; - bool stale { false }; - bool explicit_scan { false }; - - /** - * Default constructor - */ - Accesspoint() { } - - /** - * Constructor that initializes information fields - */ - Accesspoint(char const *bssid, char const *freq, - char const *prot, char const *ssid, unsigned signal) - : bssid(bssid), freq(freq), prot(prot), ssid(ssid), signal(signal) - { } - - void invalidate() { ssid = Ssid(); bssid = Bssid(); } - - bool valid() const { return ssid.length() > 1; } - bool bssid_valid() const { return bssid.length() > 1; } - bool wpa() const { return prot != "NONE"; } - bool wpa3() const { return prot == "WPA3"; } - bool stored() const { return id != -1; } -}; - - -template -static void for_each_line(char const *msg, FUNC const &func) -{ - char line_buffer[1024]; - size_t cur = 0; - - while (msg[cur] != 0) { - size_t until = Util::next_char(msg, cur, '\n'); - Genode::memcpy(line_buffer, &msg[cur], until); - line_buffer[until] = 0; - cur += until + 1; - - func(line_buffer); - } -} - - -template -static void for_each_result_line(char const *msg, FUNC const &func) -{ - char line_buffer[1024]; - size_t cur = 0; - - /* skip headline */ - size_t until = Util::next_char(msg, cur, '\n'); - cur += until + 1; - - while (msg[cur] != 0) { - until = Util::next_char(msg, cur, '\n'); - Genode::memcpy(line_buffer, &msg[cur], until); - line_buffer[until] = 0; - cur += until + 1; - - char const *s[5] = { }; - - for (size_t c = 0, i = 0; i < 5; i++) { - size_t pos = Util::next_char(line_buffer, c, '\t'); - line_buffer[c+pos] = 0; - s[i] = (char const*)&line_buffer[c]; - c += pos + 1; - } - - bool const is_wpa1 = Util::string_contains((char const*)s[3], "WPA"); - bool const is_wpa2 = Util::string_contains((char const*)s[3], "WPA2"); - bool const is_wpa3 = Util::string_contains((char const*)s[3], "SAE"); - - unsigned signal = Util::approximate_quality(s[2]); - - char const *prot = is_wpa1 ? "WPA" : "NONE"; - prot = is_wpa2 ? "WPA2" : prot; - prot = is_wpa3 ? "WPA3" : prot; - - Accesspoint ap(s[0], s[1], prot, s[4], signal); - - func(ap); - } -} - - -/* - * Wifi driver front end - */ -struct Wifi::Frontend : Wifi::Rfkill_notification_handler -{ - Frontend(const Frontend&) = delete; - Frontend& operator=(const Frontend&) = delete; - - /* accesspoint */ - - Genode::Heap _ap_allocator; - - using Accesspoint_r = Genode::Registered; - - Genode::Registry _aps { }; - - Accesspoint *_lookup_ap_by_ssid(Accesspoint::Ssid const &ssid) - { - Accesspoint *p = nullptr; - _aps.for_each([&] (Accesspoint &ap) { - if (ap.valid() && ap.ssid == ssid) { p = ≈ } - }); - return p; - } - - Accesspoint *_lookup_ap_by_bssid(Accesspoint::Bssid const &bssid) - { - Accesspoint *p = nullptr; - _aps.for_each([&] (Accesspoint &ap) { - if (ap.valid() && ap.bssid == bssid) { p = ≈ } - }); - return p; - } - - Accesspoint *_alloc_ap() - { - return new (&_ap_allocator) Accesspoint_r(_aps); - } - - void _free_ap(Accesspoint &ap) - { - Genode::destroy(&_ap_allocator, &ap); - } - - template - void _for_each_ap(FUNC const &func) - { - _aps.for_each([&] (Accesspoint &ap) { - func(ap); - }); - } - - unsigned _count_to_be_enabled() - { - unsigned count = 0; - auto enable = [&](Accesspoint const &ap) { - count += ap.auto_connect; - }; - _for_each_ap(enable); - return count; - } - - unsigned _count_enabled() - { - unsigned count = 0; - auto enabled = [&](Accesspoint const &ap) { - count += ap.enabled; - }; - _for_each_ap(enabled); - return count; - } - - unsigned _count_stored() - { - unsigned count = 0; - auto enabled = [&](Accesspoint const &ap) { - count += ap.stored(); - }; - _for_each_ap(enabled); - return count; - } - - /* remaining stuff */ - - Msg_buffer &_msg; - - Genode::Blockade _notify_blockade { }; - - void _notify_lock_lock() { _notify_blockade.block(); } - void _notify_lock_unlock() { _notify_blockade.wakeup(); } - - bool _rfkilled { false }; - - Genode::Signal_handler _rfkill_handler; - - void _handle_rfkill() - { - _rfkilled = Wifi::rfkill_blocked(); - - /* re-enable scan timer */ - if (!_rfkilled) { - _timer.sigh(_timer_sigh); - _try_arming_any_timer(); - } else { - _timer.sigh(Genode::Signal_context_capability()); - } - - if (_rfkilled && _state != State::IDLE) { - Genode::warning("rfkilled in state ", state_strings(_state)); - } - } - - /* config */ - - Genode::Attached_rom_dataspace _config_rom; - Genode::Signal_handler _config_sigh; - - bool _verbose { false }; - bool _verbose_state { false }; - - bool _deferred_config_update { false }; - bool _single_autoconnect { false }; - - Genode::uint64_t _connected_scan_interval { 30 }; - Genode::uint64_t _scan_interval { 5 }; - Genode::uint64_t _update_quality_interval { 0 }; - - void _config_update(bool signal) - { - _config_rom.update(); - - if (!_config_rom.valid()) { return; } - - Genode::Xml_node config = _config_rom.xml(); - - _verbose = config.attribute_value("verbose", _verbose); - _verbose_state = config.attribute_value("verbose_state", _verbose_state); - - Genode::uint64_t const connected_scan_interval = - Util::check_time(config.attribute_value("connected_scan_interval", - _connected_scan_interval), - 0, 15*60); - - Genode::uint64_t const scan_interval = - Util::check_time(config.attribute_value("scan_interval", - _scan_interval), - 5, 15*60); - - Genode::uint64_t const update_quality_interval = - Util::check_time(config.attribute_value("update_quality_interval", - _update_quality_interval), - 0, 15*60); - - bool const new_connected_scan_interval = - connected_scan_interval != _connected_scan_interval; - - bool const new_scan_interval = - connected_scan_interval != _scan_interval; - - bool const new_update_quality_interval = - update_quality_interval != _update_quality_interval; - - _connected_scan_interval = connected_scan_interval; - _scan_interval = scan_interval; - _update_quality_interval = update_quality_interval; - - /* - * Arm again if intervals changed, implicitly discards - * an already scheduled timer. - * - * First try to arm scanning and if that fails try arming - * signal-strength polling. - */ - if ( new_connected_scan_interval - || new_scan_interval - || new_update_quality_interval) - _try_arming_any_timer(); - - /* - * Always handle rfkill, regardless in which state we are currently in. - * When we come back from rfkill, will most certainly will be IDLE anyway. - */ - if (config.has_attribute("rfkill")) { - bool const blocked = config.attribute_value("rfkill", false); - Wifi::set_rfkill(blocked); - - /* - * In case we get blocked set rfkilled immediately to prevent - * any further scanning operation. The actual value will be set - * by the singal handler but is not expected to be any different - * as the rfkill call is not supposed to fail. - */ - if (blocked && !_rfkilled) { - _rfkilled = true; - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "disconnected"); - xml.attribute("rfkilled", _rfkilled); - }); - }); - - _connected_ap.invalidate(); - } - } - - /* - * Block any further config updates until we have finished applying - * the current one. - */ - if (_state != State::IDLE) { - Genode::warning("deferring config update (", state_strings(_state), ")"); - _deferred_config_update = true; - return; - } - - bool single_autoconnect = false; - - /* update AP list */ - auto parse = [&] ( Genode::Xml_node node) { - - Accesspoint ap; - ap.ssid = node.attribute_value("ssid", Accesspoint::Ssid()); - ap.bssid = node.attribute_value("bssid", Accesspoint::Bssid()); - - size_t const ssid_len = ap.ssid.length() - 1; - if (ssid_len == 0 || ssid_len > 32) { - Genode::warning("ignoring accesspoint with invalid ssid"); - return; - } - - Accesspoint *p = _lookup_ap_by_ssid(ap.ssid); - if (p) { - if (_verbose) { Genode::log("Update: '", p->ssid, "'"); } - /* mark for updating */ - p->update = true; - } else { - p = _alloc_ap(); - if (!p) { - Genode::warning("could not add accesspoint, no slots left"); - return; - } - } - - ap.pass = node.attribute_value("passphrase", Accesspoint::Pass("")); - ap.prot = node.attribute_value("protection", Accesspoint::Prot("NONE")); - ap.auto_connect = node.attribute_value("auto_connect", true); - ap.explicit_scan = node.attribute_value("explicit_scan", false); - - if (ap.wpa()) { - size_t const psk_len = ap.pass.length() - 1; - if (psk_len < 8 || psk_len > 63) { - Genode::warning("ignoring accesspoint '", ap.ssid, - "' with invalid pass"); - return; - } - } - - - /* check if updating is really necessary */ - if (p->update) { - p->update = ((ap.bssid.length() > 1 && ap.bssid != p->bssid) - || ap.pass != p->pass - || ap.prot != p->prot - || ap.auto_connect != p->auto_connect); - } - - /* TODO add better way to check validity */ - if (ap.bssid.length() == 17 + 1) { p->bssid = ap.bssid; } - - p->ssid = ap.ssid; - p->prot = ap.prot; - p->pass = ap.pass; - p->auto_connect = ap.auto_connect; - p->explicit_scan = ap.explicit_scan; - - single_autoconnect |= (p->update || p->auto_connect) && !_connected_ap.valid(); - }; - config.for_each_sub_node("network", parse); - - /* - * To accomodate a management component that only deals - * with on network, e.g. the sculpt_manager, generate a - * fake connecting event. Either a connected or disconnected - * event will bring us to square one. - */ - if (signal && _count_to_be_enabled() == 1 && single_autoconnect && !_rfkilled) { - - auto lookup = [&] (Accesspoint const &ap) { - if (!ap.auto_connect) { return; } - - if (_verbose) { Genode::log("Single autoconnect event for '", ap.ssid, "'"); } - - try { - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("ssid", ap.ssid); - xml.attribute("state", "connecting"); - }); - }); - - _single_autoconnect = true; - - } catch (...) { } - }; - _for_each_ap(lookup); - } - - /* - * Marking removes stale APs first and triggers adding of - * new ones afterwards. - */ - _mark_stale_aps(config); - } - - void _handle_config_update() { _config_update(true); } - - /* state */ - - Accesspoint *_processed_ap { nullptr }; - Accesspoint _connected_ap { }; - - enum State { - IDLE = 0x00, - SCAN = 0x01, - NETWORK = 0x02, - CONNECT = 0x03, - STATUS = 0x04, - INFO = 0x05, - SIGNAL = 0x06, - - INITIATE_SCAN = 0x00|SCAN, - PENDING_RESULTS = 0x10|SCAN, - - ADD_NETWORK = 0x00|NETWORK, - FILL_NETWORK_SSID = 0x10|NETWORK, - FILL_NETWORK_BSSID = 0x20|NETWORK, - FILL_NETWORK_KEY_MGMT = 0x30|NETWORK, - FILL_NETWORK_PSK = 0x40|NETWORK, - REMOVE_NETWORK = 0x50|NETWORK, - ENABLE_NETWORK = 0x60|NETWORK, - DISABLE_NETWORK = 0x70|NETWORK, - LIST_NETWORKS = 0x90|NETWORK, - SET_NETWORK_PMF = 0xA0|NETWORK, - - CONNECTING = 0x00|CONNECT, - CONNECTED = 0x10|CONNECT, - DISCONNECTED = 0x20|CONNECT, - }; - - State _state { State::IDLE }; - - char const *state_strings(State state) - { - switch (state) { - case IDLE: return "idle"; - case INITIATE_SCAN: return "initiate scan"; - case PENDING_RESULTS: return "pending results"; - case ADD_NETWORK: return "add network"; - case FILL_NETWORK_SSID: return "fill network ssid"; - case FILL_NETWORK_BSSID: return "fill network bssid"; - case FILL_NETWORK_KEY_MGMT: return "fill network key_mgmt"; - case FILL_NETWORK_PSK: return "fill network pass"; - case REMOVE_NETWORK: return "remove network"; - case ENABLE_NETWORK: return "enable network"; - case DISABLE_NETWORK: return "disable network"; - case CONNECTING: return "connecting"; - case CONNECTED: return "connected"; - case DISCONNECTED: return "disconnected"; - case STATUS: return "status"; - case LIST_NETWORKS: return "list networks"; - case INFO: return "info"; - case SET_NETWORK_PMF: return "set network pmf"; - case SIGNAL: return "signal poll"; - default: return "unknown"; - }; - } - - void _state_transition(State ¤t, State next) - { - if (_verbose_state) { - using namespace Genode; - log("Transition: ", state_strings(current), " -> ", - state_strings(next)); - } - - current = next; - } - - using Cmd_str = Genode::String; - - void _submit_cmd(Cmd_str const &str) - { - Genode::memset(_msg.send, 0, sizeof(_msg.send)); - Genode::memcpy(_msg.send, str.string(), str.length()); - ++_msg.send_id; - - wpa_ctrl_set_fd(); - - /* - * We might have to pull the socketcall task out of poll_all() - * because otherwise we might be late and wpa_supplicant has - * already removed all scan results due to BSS age settings. - */ - wifi_kick_socketcall(); - } - - /* scan */ - - enum class Timer_type : uint8_t { CONNECTED_SCAN, SCAN, SIGNAL_POLL }; - - Genode::uint64_t _seconds_from_type(Timer_type const type) - { - switch (type) { - case Timer_type::CONNECTED_SCAN: return _connected_scan_interval; - case Timer_type::SCAN: return _scan_interval; - case Timer_type::SIGNAL_POLL: return _update_quality_interval; - } - /* never reached */ - return 0; - } - - static char const *_name_from_type(Timer_type const type) - { - switch (type) { - case Timer_type::CONNECTED_SCAN: return "connected-scan"; - case Timer_type::SCAN: return "scan"; - case Timer_type::SIGNAL_POLL: return "signal-poll"; - } - /* never reached */ - return nullptr; - } - - Timer::Connection _timer; - Genode::Signal_handler _timer_sigh; - - bool _arm_timer(Timer_type const type) - { - Genode::uint64_t const sec = _seconds_from_type(type); - if (!sec) { return false; } - - if (_verbose) - Genode::log("Arm timer for ", _name_from_type(type)); - - _timer.trigger_once(sec * (1000 * 1000)); - return true; - } - - void _request_scan() - { - /* skip as we will be scheduled some time soon(tm) anyway */ - if (_state != State::IDLE) { - if (_verbose) { - Genode::log("Not idle, ignore scan request, state: ", - Genode::Hex((unsigned)_state)); - } - return; - } - - /* left one attempt out */ - if (_scan_busy) { - if (_verbose) { Genode::log("Scan already pending, ignore scan request"); } - _scan_busy = false; - return; - } - - enum { SSID_ARG_LEN = 6 + 64, /* " ssid " + "a5a5a5a5..." */ }; - /* send buffer - 'SCAN ' + stuff */ - char ssid_buffer[sizeof(Msg_buffer::send)-16] = { }; - size_t buffer_pos = 0; - - auto valid_ssid = [&] (Accesspoint const &ap) { - - if (buffer_pos + SSID_ARG_LEN >= sizeof(ssid_buffer)) { - return; - } - - if (!ap.explicit_scan) { return; } - - char ssid_hex[64+1] = { }; - char const *ssid = ap.ssid.string(); - - for (size_t i = 0; i < ap.ssid.length() - 1; i++) { - Util::byte2hex((ssid_hex + i * 2), ssid[i]); - } - - Genode::String tmp(" ssid ", (char const*)ssid_hex); - size_t const tmp_len = tmp.length() - 1; - - Genode::memcpy((ssid_buffer + buffer_pos), tmp.string(), tmp_len); - buffer_pos += tmp_len; - }; - _for_each_ap(valid_ssid); - - _state_transition(_state, State::INITIATE_SCAN); - _submit_cmd(Cmd_str("SCAN", (char const*)ssid_buffer)); - } - - void _poll_signal_strength() - { - if (_state != State::IDLE) { - if (_verbose) - Genode::log("Not idle, ignore signal-poll request, state: ", - Genode::Hex((unsigned)_state)); - return; - } - - _state_transition(_state, State::SIGNAL); - _submit_cmd(Cmd_str("SIGNAL_POLL")); - } - - void _handle_timer() - { - /* - * If we are blocked or currently trying to join a network - * suspend scanning. - */ - if (_rfkilled || _connecting.length() > 1) { - if (_verbose) - Genode::log("Timer: suspend due to RFKILL or connection" - " attempt"); - return; - } - - /* - * First check if (connected-)scanning is enabled, re-arm - * the timer again and try to submit the request. In case we - * are not able to submit it the timer will trigger another - * attempt later on. - */ - if (_arm_scan_timer()) { - _request_scan(); - return; - } else - if (_verbose) - Genode::log("Timer: scanning disabled"); - - /* - * We arm the poll timer only when we are not scanning. - * So connected-scan MUST be disabled for the signal-strength - * polling to be active. - */ - if (_arm_poll_timer()) { - _poll_signal_strength(); - return; - } else - if (_verbose) - Genode::log("Timer: signal-strength polling disabled"); - } - - bool _arm_scan_timer() - { - Timer_type const type = _connected_ap.bssid_valid() - ? Timer_type::CONNECTED_SCAN - : Timer_type::SCAN; - return _arm_timer(type); - } - - bool _arm_poll_timer() - { - if (!_connected_ap.bssid_valid()) - return false; - - return _arm_timer(Timer_type::SIGNAL_POLL); - } - - void _try_arming_any_timer() - { - if (!_arm_scan_timer()) - (void)_arm_poll_timer(); - } - - Genode::Constructible _ap_reporter { }; - - void _generate_scan_results_report(char const *msg) - { - unsigned count_lines = 0; - for_each_line(msg, [&] (char const*) { count_lines++; }); - - if (!count_lines) { - if (_verbose) { Genode::log("Scan results empty"); } - return; - } - - bool connecting_attempt = false; - try { - - _ap_reporter->generate([&] (Genode::Xml_generator &xml) { - - for_each_result_line(msg, [&] (Accesspoint const &ap) { - - /* ignore potentially empty ssids */ - if (ap.ssid == "") { return; } - - xml.node("accesspoint", [&]() { - xml.attribute("ssid", ap.ssid); - xml.attribute("bssid", ap.bssid); - xml.attribute("freq", ap.freq); - xml.attribute("quality", ap.signal); - if (ap.wpa()) { xml.attribute("protection", ap.prot); } - }); - - auto check_existence = [&] (Accesspoint &lap) { - connecting_attempt |= (lap.ssid == ap.ssid) && ap.auto_connect; - }; - _for_each_ap(check_existence); - }); - }); - - } catch (...) { /* silently omit report */ } - - try { - if (!_connected_ap.bssid_valid() && connecting_attempt) { - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "connecting"); - }); - }); - } - } catch (...) { /* silently omit state */ } - } - - /* network commands */ - - void _mark_stale_aps(Genode::Xml_node const &config) - { - auto mark_stale = [&] (Accesspoint &ap) { - ap.stale = true; - - config.for_each_sub_node("network", [&] ( Genode::Xml_node node) { - Accesspoint::Ssid ssid = node.attribute_value("ssid", Accesspoint::Ssid("")); - - if (ap.ssid == ssid) { ap.stale = false; } - }); - }; - _for_each_ap(mark_stale); - - _remove_stale_aps(); - } - - void _remove_stale_aps() - { - if (_state != State::IDLE) { - Genode::warning("cannot remove stale APs in non-idle state " - "(", state_strings(_state), ")"); - return; - } - - if (_processed_ap) { return; } - - _aps.for_each([&] (Accesspoint &ap) { - if (!_processed_ap && ap.valid() && ap.stale) { - _processed_ap = ≈ - } - }); - - if (!_processed_ap) { - /* TODO move State transition somewhere more sane */ - _state_transition(_state, State::IDLE); - _add_new_aps(); - return; - } - - if (_verbose) { - Genode::log("Remove network: '", _processed_ap->ssid, "'"); - } - - _state_transition(_state, State::REMOVE_NETWORK); - _submit_cmd(Cmd_str("REMOVE_NETWORK ", _processed_ap->id)); - } - - void _update_aps() - { - if (_state != State::IDLE) { - Genode::warning("cannot enable network in non-idle state"); - return; - } - - if (_processed_ap) { return; } - - _aps.for_each([&] (Accesspoint &ap) { - if (!_processed_ap && ap.stored() && ap.update) { - _processed_ap = ≈ - } - }); - - if (!_processed_ap) { return; } - - if (_verbose) { - Genode::log("Update network: '", _processed_ap->ssid, "'"); - } - - /* re-use state to change PSK */ - _state_transition(_state, State::FILL_NETWORK_PSK); - _network_set_psk(); - } - - - void _add_new_aps() - { - if (_state != State::IDLE) { - Genode::warning("cannot enable network in non-idle state"); - return; - } - - if (_processed_ap) { return; } - - _aps.for_each([&] (Accesspoint &ap) { - if (!_processed_ap && ap.valid() && !ap.stored()) { - _processed_ap = ≈ - } - }); - - if (!_processed_ap) { - /* XXX move State transition somewhere more sane */ - _state_transition(_state, State::IDLE); - _update_aps(); - return; - } - - if (_verbose) { - Genode::log("Add network: '", _processed_ap->ssid, "'"); - } - - _state_transition(_state, State::ADD_NETWORK); - _submit_cmd(Cmd_str("ADD_NETWORK")); - } - - void _network_enable(Accesspoint &ap) - { - if (_state != State::IDLE) { - Genode::warning("cannot enable network in non-idle state"); - return; - } - - if (ap.enabled) { return; } - - if (_verbose) { - Genode::log("Enable network: ", ap.id, " '", ap.ssid, "'"); - } - - ap.enabled = true; - - _state_transition(_state, State::ENABLE_NETWORK); - _submit_cmd(Cmd_str("ENABLE_NETWORK ", ap.id)); - } - - void _network_disable(Accesspoint &ap) - { - if (_state != State::IDLE) { - Genode::warning("cannot enable network in non-idle state"); - return; - } - - if (!ap.enabled) { return; } - - if (_verbose) { - Genode::log("Disable network: ", ap.id, " '", ap.ssid, "'"); - } - - ap.enabled = false; - - _state_transition(_state, State::DISABLE_NETWORK); - _submit_cmd(Cmd_str("DISABLE_NETWORK ", ap.id)); - } - - void _network_set_ssid(char const *msg) - { - long id = -1; - Genode::ascii_to(msg, id); - - _processed_ap->id = static_cast(id); - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " ssid \"", _processed_ap->ssid, "\"")); - } - - void _network_set_bssid() - { - bool const valid = _processed_ap->bssid.length() == 17 + 1; - char const *bssid = valid ? _processed_ap->bssid.string() : ""; - - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " bssid ", bssid)); - } - - void _network_set_key_mgmt_sae() - { - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " key_mgmt SAE")); - } - - void _network_set_pmf() - { - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " ieee80211w 2")); - } - - void _network_set_psk() - { - if (_processed_ap->wpa()) { - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " psk \"", _processed_ap->pass, "\"")); - } else { - _submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id, - " key_mgmt NONE")); - } - } - - /* result handling */ - - bool _scan_busy { false }; - - void _handle_scan_results(State state, char const *msg) - { - switch (state) { - case State::INITIATE_SCAN: - if (!cmd_successful(msg)) { - _scan_busy = Genode::strcmp(msg, "FAIL-BUSY"); - if (!_scan_busy) { - Genode::warning("could not initiate scan: ", msg); - } - } - _state_transition(_state, State::IDLE); - break; - case State::PENDING_RESULTS: - if (scan_results(msg)) { - _state_transition(_state, State::IDLE); - _generate_scan_results_report(msg); - } - break; - default: - Genode::warning("unknown SCAN state: ", msg); - break; - } - } - - void _handle_network_results(State state, char const *msg) - { - bool successfully = false; - - switch (state) { - case State::ADD_NETWORK: - if (cmd_fail(msg)) { - Genode::error("could not add network: ", msg); - _state_transition(_state, State::IDLE); - } else { - _state_transition(_state, State::FILL_NETWORK_SSID); - _network_set_ssid(msg); - - successfully = true; - } - break; - case State::REMOVE_NETWORK: - { - _state_transition(_state, State::IDLE); - - Accesspoint &ap = *_processed_ap; - /* reset processed AP as this is an end state */ - _processed_ap = nullptr; - - if (cmd_fail(msg)) { - Genode::error("could not remove network: ", msg); - } else { - _free_ap(ap); - - /* trigger the next round */ - _remove_stale_aps(); - - successfully = true; - } - break; - } - case State::FILL_NETWORK_SSID: - _state_transition(_state, State::IDLE); - - if (!cmd_successful(msg)) { - Genode::error("could not set ssid for network: ", msg); - _state_transition(_state, State::IDLE); - } else { - _state_transition(_state, State::FILL_NETWORK_BSSID); - _network_set_bssid(); - - successfully = true; - } - break; - case State::FILL_NETWORK_BSSID: - _state_transition(_state, State::IDLE); - - if (!cmd_successful(msg)) { - Genode::error("could not set bssid for network: ", msg); - _state_transition(_state, State::IDLE); - } else { - - /* - * For the moment branch here to handle WPA3-personal-only - * explicitly. - */ - if (_processed_ap->wpa3()) { - _state_transition(_state, State::FILL_NETWORK_KEY_MGMT); - _network_set_key_mgmt_sae(); - } else { - _state_transition(_state, State::FILL_NETWORK_PSK); - _network_set_psk(); - } - - successfully = true; - } - break; - case State::FILL_NETWORK_KEY_MGMT: - _state_transition(_state, State::IDLE); - - if (!cmd_successful(msg)) { - Genode::error("could not set key_mgmt for network: ", msg); - _state_transition(_state, State::IDLE); - } else { - _state_transition(_state, State::SET_NETWORK_PMF); - _network_set_pmf(); - - successfully = true; - } - break; - case State::SET_NETWORK_PMF: - _state_transition(_state, State::IDLE); - - if (!cmd_successful(msg)) { - Genode::error("could not set PMF for network: ", msg); - _state_transition(_state, State::IDLE); - } else { - _state_transition(_state, State::FILL_NETWORK_PSK); - _network_set_psk(); - - successfully = true; - } - break; - case State::FILL_NETWORK_PSK: - { - _state_transition(_state, State::IDLE); - - Accesspoint &ap = *_processed_ap; - - if (!cmd_successful(msg)) { - Genode::error("could not set passphrase for network: ", msg); - } else { - - /* - * Disable network to trick wpa_supplicant into reloading - * the settings. - */ - if (ap.update) { - ap.enabled = true; - _network_disable(ap); - } else - - if (ap.auto_connect) { - _network_enable(ap); - } else { - /* trigger the next round */ - _add_new_aps(); - } - - successfully = true; - } - break; - } - case State::ENABLE_NETWORK: - { - _state_transition(_state, State::IDLE); - - /* reset processed AP as this is an end state */ - _processed_ap = nullptr; - - if (!cmd_successful(msg)) { - Genode::error("could not enable network: ", msg); - } else { - /* trigger the next round */ - _add_new_aps(); - - successfully = true; - } - break; - } - case State::DISABLE_NETWORK: - { - _state_transition(_state, State::IDLE); - - Accesspoint &ap = *_processed_ap; - /* reset processed AP as this is an end state */ - _processed_ap = nullptr; - - if (!cmd_successful(msg)) { - Genode::error("could not disable network: ", msg); - } else { - - /* - * Updated settings are applied, enable the network - * anew an try again. - */ - if (ap.update) { - ap.update = false; - - if (ap.auto_connect) { - _network_enable(ap); - } - } - - successfully = true; - } - break; - } - case State::LIST_NETWORKS: - _state_transition(_state, State::IDLE); - - if (list_network_results(msg)) { - Genode::error("List networks:\n", msg); - } - break; - default: - Genode::warning("unknown network state: ", msg); - break; - } - - /* - * If some step failed we have to generate a fake - * disconnect event. - */ - if (_single_autoconnect && !successfully) { - try { - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "disconnected"); - xml.attribute("rfkilled", _rfkilled); - xml.attribute("config_error", true); - }); - }); - - _single_autoconnect = false; - } catch (...) { } - } - } - - void _handle_status_result(State &state, char const *msg) - { - _state_transition(state, State::IDLE); - - /* - * Querying the status might have failed but we already sent - * out a rudimentary report, just stop here. - */ - if (0 == msg[0]) { return; } - - Accesspoint ap { }; - - auto fill_ap = [&] (char const *line) { - if (Genode::strcmp(line, "ssid=", 5) == 0) { - ap.ssid = Accesspoint::Ssid(line+5); - } else - - if (Genode::strcmp(line, "bssid=", 6) == 0) { - ap.bssid = Accesspoint::Bssid(line+6); - } else - - if (Genode::strcmp(line, "freq=", 5) == 0) { - ap.freq = Accesspoint::Freq(line+5); - } - }; - for_each_line(msg, fill_ap); - - if (!ap.ssid.valid()) { - Genode::error("Cannot query SSID :-("); - return; - } - - Accesspoint *p = _lookup_ap_by_ssid(ap.ssid); - if (p) { - p->bssid = ap.bssid; - p->freq = ap.freq; - } - - _connected_ap.ssid = ap.ssid; - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("ssid", ap.ssid); - xml.attribute("bssid", ap.bssid); - xml.attribute("freq", ap.freq); - xml.attribute("state", "connected"); - - /* - * Only add the attribute when we have something - * to report so that a consumer of the state report - * may take appropriate actions. - */ - if (_connected_ap.signal) - xml.attribute("quality", _connected_ap.signal); - }); - }); - } - - void _handle_info_result(State &state, char const *msg) - { - _state_transition(state, State::IDLE); - - if (!_connected_event && !_disconnected_event) { return; } - - /* - * It might happen that the supplicant already flushed - * its internal BSS information and cannot help us out. - * Since we already sent out a rudimentary report, just - * stop here. - */ - if (0 == msg[0]) { return; } - - Accesspoint ap { }; - - auto fill_ap = [&] (char const *line) { - if (Genode::strcmp(line, "ssid=", 5) == 0) { - ap.ssid = Accesspoint::Ssid(line+5); - } else - - if (Genode::strcmp(line, "bssid=", 6) == 0) { - ap.bssid = Accesspoint::Bssid(line+6); - } else - - if (Genode::strcmp(line, "freq=", 5) == 0) { - ap.freq = Accesspoint::Freq(line+5); - } - }; - for_each_line(msg, fill_ap); - - /* - * When the config is changed while we are still connecting and - * for some reasons the accesspoint does not get disabled - * a connected event could arrive and we will get a nullptr... - */ - Accesspoint *p = _lookup_ap_by_ssid(ap.ssid); - - /* - * ... but we still generate a report and let the management - * component deal with it. - */ - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("ssid", ap.ssid); - xml.attribute("bssid", ap.bssid); - xml.attribute("freq", ap.freq); - xml.attribute("state", _connected_event ? "connected" - : "disconnected"); - if (!_connected_event) { - xml.attribute("rfkilled", _rfkilled); - xml.attribute("auth_failure", _disconnected_fail); - } - }); - }); - - if (_disconnected_fail) { - /* - * Being able to remove a failed network from the internal - * state of the supplicant relies on a sucessful BSS request. - * In case that failes the supplicant will try to join the - * network again and again... - */ - if (!p || _processed_ap) { - Genode::error("cannot disabled failed network"); - } else { - _processed_ap = p; - _network_disable(*_processed_ap); - } - } else - - if (_connected_event) { - /* - * In case the BSS cmd did not return a valid SSID, which - * was observed only with hidden networks so far, check the - * current status. - */ - if (!p) { - _state_transition(state, State::STATUS); - _submit_cmd(Cmd_str("STATUS")); - - } else { - p->bssid = ap.bssid; - p->freq = ap.freq; - } - - _connected_ap = ap; - } - } - - void _handle_signal_poll_result(State &state, char const *msg) - { - _state_transition(state, State::IDLE); - - using Rssi = Genode::String<5>; - Rssi rssi { }; - auto get_rssi = [&] (char const *line) { - if (Genode::strcmp(line, "RSSI=", 5) != 0) - return; - - rssi = Rssi(line + 5); - }; - for_each_line(msg, get_rssi); - - /* - * Use the same simplified approximation for denoting - * the quality to be in line with the scan results. - */ - _connected_ap.signal = - Util::approximate_quality(rssi.valid() ? rssi.string() - : "-100"); - - /* - * Query the status to incorporate the newly acquired - * quality into a new state report. - */ - _state_transition(state, State::STATUS); - _submit_cmd(Cmd_str("STATUS")); - } - - /* connection state */ - - Genode::Constructible _state_reporter { }; - - Accesspoint::Bssid _connecting { }; - - Accesspoint::Bssid const _extract_bssid(char const *msg, State state) - { - char bssid[32] = { }; - /* by the power of wc -c, I have the start pos... */ - enum { BSSID_CONNECT = 37, BSSID_DISCONNECT = 30, BSSID_CONNECTING = 33, }; - - bool const connected = state == State::CONNECTED; - bool const connecting = state == State::CONNECTING; - - size_t const len = 17; - size_t const start = connected ? BSSID_CONNECT - : connecting ? BSSID_CONNECTING - : BSSID_DISCONNECT; - Genode::memcpy(bssid, msg + start, len); - return Accesspoint::Bssid((char const*)bssid); - } - - bool _auth_failure(char const *msg) - { - enum { REASON_OFFSET = 55, }; - unsigned reason = 0; - Genode::ascii_to((msg + REASON_OFFSET), reason); - switch (reason) { - case 2: /* prev auth no longer valid */ - case 15: /* 4-way handshake timeout/failed */ - return true; - default: - return false; - } - } - - /* events */ - - bool _connected_event { false }; - bool _disconnected_event { false }; - bool _disconnected_fail { false }; - bool _was_connected { false }; - - enum { MAX_REAUTH_ATTEMPTS = 1 }; - unsigned _reauth_attempts { 0 }; - - enum { MAX_ATTEMPTS = 3, }; - unsigned _scan_attempts { 0 }; - - Accesspoint::Bssid _pending_bssid { }; - - void _handle_connection_events(char const *msg) - { - _connected_event = false; - _disconnected_event = false; - _disconnected_fail = false; - - bool const connected = check_recv_msg(msg, recv_table[Rmi::CONNECTED]); - bool const disconnected = check_recv_msg(msg, recv_table[Rmi::DISCONNECTED]); - bool const auth_failed = disconnected && _auth_failure(msg); - - State state = connected ? State::CONNECTED : State::DISCONNECTED; - Accesspoint::Bssid const &bssid = _extract_bssid(msg, state); - - /* simplistic heuristic to ignore re-authentication requests */ - if (_connected_ap.bssid.valid() && auth_failed) { - if (_reauth_attempts < MAX_ATTEMPTS) { - Genode::log("ignore deauth from: ", _connected_ap.bssid); - _reauth_attempts++; - return; - } - } - _reauth_attempts = 0; - - /* - * Always reset the "global" connection state first - */ - _connected_ap.invalidate(); - if (connected) { _connected_ap.bssid = bssid; } - if (connected || disconnected) { _connecting = Accesspoint::Bssid(); } - - /* - * Save local connection state here for later re-use when - * the BSS information are handled. - */ - _connected_event = connected; - _disconnected_event = disconnected; - _disconnected_fail = auth_failed; - - if (!_rfkilled) { - - /* - * As we only received the BSSID, try to gather more information - * so we may generate a more thorough follow-up state report. - */ - if (_state != State::IDLE) { - _pending_bssid = bssid; - } else { - _state_transition(_state, State::INFO); - _submit_cmd(Cmd_str("BSS ", bssid)); - } - - _try_arming_any_timer(); - } - - /* - * Generate the first rudimentary report whose missing information - * are (potentially) filled in later (see above). - */ - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("bssid", bssid); - xml.attribute("state", connected ? "connected" - : "disconnected"); - if (disconnected) { - xml.attribute("rfkilled", _rfkilled); - if (auth_failed) { - xml.attribute("auth_failure", auth_failed); - } - } - }); - }); - - /* reset */ - _single_autoconnect = false; - } - - Genode::Signal_handler _events_handler; - - unsigned _last_event_id { 0 }; - - void _handle_events() - { - char const *msg = reinterpret_cast(_msg.event); - unsigned const event_id = _msg.event_id; - - /* return early */ - if (_last_event_id == event_id) { - _notify_lock_unlock(); - return; - } - - if (results_available(msg)) { - - /* - * We might have to pull the socketcall task out of poll_all() - * because otherwise we might be late and wpa_supplicant has - * already removed all scan results due to BSS age settings. - */ - wifi_kick_socketcall(); - - if (_state == State::IDLE) { - _state_transition(_state, State::PENDING_RESULTS); - _submit_cmd(Cmd_str("SCAN_RESULTS")); - } - } else - - if (connecting_to_network(msg)) { - if (!_single_autoconnect) { - Accesspoint::Bssid const &bssid = _extract_bssid(msg, State::CONNECTING); - _connecting = bssid; - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("bssid", bssid); - xml.attribute("state", "connecting"); - }); - }); - } - } else - - if (network_not_found(msg)) { - - /* always try to update the accesspoint list */ - if (_state == State::IDLE) { - _state_transition(_state, State::PENDING_RESULTS); - _submit_cmd(Cmd_str("SCAN_RESULTS")); - } - - if (_single_autoconnect && ++_scan_attempts >= MAX_ATTEMPTS) { - _scan_attempts = 0; - _single_autoconnect = false; - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "disconnected"); - xml.attribute("rfkilled", _rfkilled); - xml.attribute("not_found", true); - }); - }); - } - - } else - - { - _handle_connection_events(msg); - } - - _notify_lock_unlock(); - } - - Genode::Signal_handler _cmd_handler; - - unsigned _last_recv_id { 0 }; - - void _handle_cmds() - { - char const *msg = reinterpret_cast(_msg.recv); - unsigned const recv_id = _msg.recv_id; - - - /* return early */ - if (_last_recv_id == recv_id) { - _notify_lock_unlock(); - return; - } - - _last_recv_id = recv_id; - - switch (_state & 0xf) { - case State::SCAN: - _handle_scan_results(_state, msg); - break; - case State::NETWORK: - _handle_network_results(_state, msg); - break; - case State::STATUS: - _handle_status_result(_state, msg); - break; - case State::INFO: - _handle_info_result(_state, msg); - break; - case State::SIGNAL: - _handle_signal_poll_result(_state, msg); - break; - case State::IDLE: - default: - break; - } - _notify_lock_unlock(); - - if (_verbose_state) { - Genode::log("State:", - " connected: ", _connected_ap.bssid_valid(), - " connecting: ", _connecting.length() > 1, - " enabled: ", _count_enabled(), - " stored: ", _count_stored(), - ""); - } - - if (_state == State::IDLE && _deferred_config_update) { - _deferred_config_update = false; - _handle_config_update(); - } - - if (_state == State::IDLE && _pending_bssid.length() > 1) { - _state_transition(_state, State::INFO); - _submit_cmd(Cmd_str("BSS ", _pending_bssid)); - - _pending_bssid = Accesspoint::Bssid(); - } - } - - /** - * Constructor - */ - Frontend(Genode::Env &env, Msg_buffer &msg_buffer) - : - _ap_allocator(env.ram(), env.rm()), - _msg(msg_buffer), - _rfkill_handler(env.ep(), *this, &Wifi::Frontend::_handle_rfkill), - _config_rom(env, "wifi_config"), - _config_sigh(env.ep(), *this, &Wifi::Frontend::_handle_config_update), - _timer(env), - _timer_sigh(env.ep(), *this, &Wifi::Frontend::_handle_timer), - _events_handler(env.ep(), *this, &Wifi::Frontend::_handle_events), - _cmd_handler(env.ep(), *this, &Wifi::Frontend::_handle_cmds) - { - _config_rom.sigh(_config_sigh); - _timer.sigh(_timer_sigh); - - /* set/initialize as unblocked */ - _notify_blockade.wakeup(); - - try { - _ap_reporter.construct(env, "accesspoints", "accesspoints"); - _ap_reporter->generate([&] (Genode::Xml_generator &) { }); - } catch (...) { - Genode::warning("no Report session available, scan results will " - "not be reported"); - } - - try { - _state_reporter.construct(env, "state"); - _state_reporter->enabled(true); - - Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { - xml.node("accesspoint", [&] () { - xml.attribute("state", "disconnected"); - xml.attribute("rfkilled", _rfkilled); - }); - }); - } catch (...) { - Genode::warning("no Report session available, connectivity will " - "not be reported"); - } - - /* read in list of APs */ - _config_update(false); - - /* get initial RFKILL state */ - _handle_rfkill(); - - /* kick-off initial scanning */ - _handle_timer(); - } - - /** - * Trigger RFKILL notification - * - * Used by the wifi driver to notify front end. - */ - void rfkill_notify() override - { - _rfkill_handler.local_submit(); - } - - /** - * Get result signal capability - * - * Used by the wpa_supplicant to notify front end after processing - * a command. - */ - Genode::Signal_context_capability result_sigh() - { - return _cmd_handler; - } - - /** - * Get event signal capability - * - * Used by the wpa_supplicant to notify front whenever a event - * was triggered. - */ - Genode::Signal_context_capability event_sigh() - { - return _events_handler; - } - - /** - * Block until events were handled by the front end - * - * Used by the wpa_supplicant to wait for the front end. - */ - void block_for_processing() { _notify_lock_lock(); } -}; - -#endif /* _WIFI_FRONTEND_H_ */ diff --git a/repos/dde_linux/src/driver/wifi/main.cc b/repos/dde_linux/src/driver/wifi/main.cc index ef5842875e..18c1386bbd 100644 --- a/repos/dde_linux/src/driver/wifi/main.cc +++ b/repos/dde_linux/src/driver/wifi/main.cc @@ -28,68 +28,12 @@ /* local includes */ #include "util.h" #include "wpa.h" -#include "frontend.h" +#include "manager.h" #include "access_firmware.h" using namespace Genode; -static Msg_buffer _wifi_msg_buffer; -static Wifi::Frontend *_wifi_frontend = nullptr; - - -/** - * Notify front end about command processing - * - * Called by the CTRL interface after wpa_supplicant has processed - * the command. - */ -void wifi_block_for_processing(void) -{ - if (!_wifi_frontend) { - warning("frontend not available, dropping notification"); - return; - } - - /* - * Next time we block as long as the front end has not finished - * handling our previous request - */ - _wifi_frontend->block_for_processing(); - - /* XXX hack to trick poll() into returning faster */ - wpa_ctrl_set_fd(); -} - - -void wifi_notify_cmd_result(void) -{ - if (!_wifi_frontend) { - warning("frontend not available, dropping notification"); - return; - } - - Signal_transmitter(_wifi_frontend->result_sigh()).submit(); -} - - -/** - * Notify front end about triggered event - * - * Called by the CTRL interface whenever wpa_supplicant has triggered - * a event. - */ -void wifi_notify_event(void) -{ - if (!_wifi_frontend) { - Genode::warning("frontend not available, dropping notification"); - return; - } - - Signal_transmitter(_wifi_frontend->event_sigh()).submit(); -} - - /* exported by wifi.lib.so */ extern void wifi_init(Genode::Env&, Genode::Blockade&); extern void wifi_set_rfkill_sigh(Genode::Signal_context_capability); @@ -101,8 +45,8 @@ struct Main { Env &env; - Constructible _wpa; - Constructible _frontend; + Constructible _wpa; + Constructible _manager; struct Request_handler : Wifi::Firmware_request_handler { @@ -173,28 +117,17 @@ struct Main /* prepare Lx_kit::Env */ wifi_init(env, _wpa_startup_blockade); - _frontend.construct(env, _wifi_msg_buffer); - _wifi_frontend = &*_frontend; + _manager.construct(env); - Wifi::rfkill_establish_handler(*_wifi_frontend); + Wifi::rfkill_establish_handler(*_manager); Wifi::firmware_establish_handler(_request_handler); + Wifi::ctrl_init(_manager->msg_buffer()); _wpa.construct(env, _wpa_startup_blockade); } }; -/** - * Return shared-memory message buffer - * - * It is used by the wpa_supplicant CTRL interface. - */ -void *wifi_get_buffer(void) -{ - return &_wifi_msg_buffer; -} - - void Libc::Component::construct(Libc::Env &env) { static Main server(env); diff --git a/repos/dde_linux/src/driver/wifi/manager.h b/repos/dde_linux/src/driver/wifi/manager.h new file mode 100644 index 0000000000..8ee850eb5e --- /dev/null +++ b/repos/dde_linux/src/driver/wifi/manager.h @@ -0,0 +1,2199 @@ + /* + * \author Josef Soentgen + * \date 2018-07-31 + * + * Wifi manager uses the CTRL interface of the wpa_supplicant via a Genode + * specific ctrl_iface implementation that comprises two distinct memory + * buffers for communication - one for the command results and one for events. + */ + +/* + * Copyright (C) 2018-2024 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _WIFI_MANAGER_H_ +#define _WIFI_MANAGER_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* rep includes */ +#include +#include +using Ctrl_msg_buffer = Wifi::Msg_buffer; + +/* local includes */ +#include + +using namespace Genode; + +/* internal interface of lib/wifi/socket_call.cc */ +extern void wifi_kick_socketcall(); + + +namespace Wifi { + struct Manager; +} + + +enum Recv_msg_index : unsigned char { + OK = 0, + FAIL, + SCAN_RESULTS, + CONNECTED, + DISCONNECTED, + SME_AUTH, + NOT_FOUND, + MAX_INDEX, /* keep as last entry */ +}; + + +static struct { + char const *string; + size_t len; +} recv_table[Recv_msg_index::MAX_INDEX] = { + { "OK", 2 }, + { "FAIL", 4 }, + { "CTRL-EVENT-SCAN-RESULTS", 23 }, + { "CTRL-EVENT-CONNECTED", 20 }, + { "CTRL-EVENT-DISCONNECTED", 23 }, + { "SME: Trying to authenticate", 27 }, + { "CTRL-EVENT-NETWORK-NOT-FOUND", 28 }, +}; + + +static inline bool check_recv_msg(char const *msg, + auto const &entry) { + return Genode::strcmp(entry.string, msg, entry.len) == 0; } + + +static bool cmd_successful(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::OK]); } + + +static bool cmd_fail(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::FAIL]); } + + +static bool results_available(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::SCAN_RESULTS]); } + + +static bool connecting_to_network(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::SME_AUTH]); } + + +static bool network_not_found(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::NOT_FOUND]); } + + +static bool disconnected_from_network(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::DISCONNECTED]); } + + +static bool connected_to_network(char const *msg) { + return check_recv_msg(msg, recv_table[Recv_msg_index::CONNECTED]); } + + +static bool scan_results(char const *msg) { + return Genode::strcmp("bssid", msg, 5) == 0; } + + +using Cmd = String; +static void ctrl_cmd(Ctrl_msg_buffer &msg, Cmd const &cmd) +{ + memcpy(msg.send, cmd.string(), cmd.length()); + ++msg.send_id; + + wpa_ctrl_set_fd(); + + /* + * We might have to pull the socketcall task out of poll_all() + * because otherwise we might be late and wpa_supplicant has + * already removed all scan results due to BSS age settings. + */ + wifi_kick_socketcall(); +} + + +/* + * The Accesspoint object contains all information to join + * a wireless network. + */ +struct Accesspoint : Interface +{ + using Bssid = String<17+1>; + using Freq = String< 4+1>; + using Prot = String< 7+1>; + using Ssid = String<32+1>; + using Pass = String<63+1>; + + static bool valid(Ssid const &ssid) { + return ssid.length() > 1 && ssid.length() <= 32 + 1; } + + static bool valid(Pass const &pass) { + return pass.length() > 8 && pass.length() <= 63 + 1; } + + static bool valid(Bssid const &bssid) { + return bssid.length() == 17 + 1; } + + /* + * Accesspoint information fields used by manager + */ + Bssid bssid { }; + Freq freq { }; + Prot prot { }; + Ssid ssid { }; + Pass pass { }; + unsigned quality { 0 }; + + static Accesspoint from_xml(Xml_node const &node) + { + Accesspoint ap { }; + + ap.ssid = node.attribute_value("ssid", Accesspoint::Ssid()); + ap.bssid = node.attribute_value("bssid", Accesspoint::Bssid()); + + ap.pass = node.attribute_value("passphrase", Accesspoint::Pass("")); + ap.prot = node.attribute_value("protection", Accesspoint::Prot("NONE")); + + return ap; + } + + /* + * CTRL interface fields + */ + int id { -1 }; + + /** + * Default constructor + */ + Accesspoint() { } + + /** + * Constructor that initializes SSID fields + * + * It is used by the join-state handling to construct + * the connect/connecting AP. + */ + Accesspoint(Bssid const &bssid, Ssid const &ssid) + : bssid { bssid }, ssid { ssid } { } + + /** + * Constructor that initializes information fields + * + * It is used when parsing the scan results into an + * AP. + */ + Accesspoint(char const *bssid, char const *freq, + char const *prot, char const *ssid, unsigned quality) + : bssid(bssid), freq(freq), prot(prot), ssid(ssid), quality(quality) + { } + + void print(Output &out) const + { + Genode::print(out, "SSID: '", ssid, "'", " " + "BSSID: '", bssid, "'", " " + "protection: ", prot, " " + "id: ", id, " " + "quality: ", quality); + } + + bool wpa() const { return prot != "NONE"; } + bool wpa3() const { return prot == "WPA3"; } + bool stored() const { return id != -1; } + + bool updated_from(Accesspoint const &other) + { + bool const update = ((Accesspoint::valid(other.bssid) && other.bssid != bssid) + || pass != other.pass + || prot != other.prot); + if (!update) + return false; + + if (Accesspoint::valid(other.bssid)) + bssid = other.bssid; + + pass = other.pass; + prot = other.prot; + return true; + } +}; + + +struct Network : List_model::Element +{ + + Accesspoint _accesspoint { }; + + Network(Accesspoint const &ap) : _accesspoint { ap } { } + + virtual ~Network() { } + + void with_accesspoint(auto const &fn) { + fn(_accesspoint); } + + void with_accesspoint(auto const &fn) const { + fn(_accesspoint); } + + /************************** + ** List_model interface ** + **************************/ + + static bool type_matches(Xml_node const &node) { + return node.has_type("network"); } + + bool matches(Xml_node const &node) { + return _accesspoint.ssid == node.attribute_value("ssid", Accesspoint::Ssid()); } +}; + + +struct Explicit_scan : List_model::Element +{ + + Accesspoint::Ssid _ssid { }; + + Explicit_scan(Accesspoint::Ssid const &ssid) : _ssid { ssid } { } + + virtual ~Explicit_scan() { } + + void with_ssid(auto const &fn) { + if (Accesspoint::valid(_ssid)) + fn(_ssid); + } + + void with_ssid(auto const &fn) const { + if (Accesspoint::valid(_ssid)) + fn(_ssid); + } + + /************************** + ** List_model interface ** + **************************/ + + static bool type_matches(Xml_node const &node) { + return node.has_type("explicit_scan"); } + + bool matches(Xml_node const &node) { + return _ssid == node.attribute_value("ssid", Accesspoint::Ssid()); } +}; + + +static void for_each_line(char const *msg, auto const &fn) +{ + char line_buffer[1024]; + size_t cur = 0; + + while (msg[cur] != 0) { + size_t until = Util::next_char(msg, cur, '\n'); + if (until >= sizeof(line_buffer)) { + Genode::error(__func__, ": line too large, abort processing"); + return; + } + memcpy(line_buffer, &msg[cur], until); + line_buffer[until] = 0; + cur += until + 1; + + fn(line_buffer); + } +} + + +static void for_each_result_line(char const *msg, auto const &fn) +{ + char line_buffer[1024]; + size_t cur = 0; + + /* skip headline */ + size_t until = Util::next_char(msg, cur, '\n'); + cur += until + 1; + + while (msg[cur] != 0) { + until = Util::next_char(msg, cur, '\n'); + if (until >= sizeof(line_buffer)) { + Genode::error(__func__, ": line too large, abort processing"); + return; + } + memcpy(line_buffer, &msg[cur], until); + line_buffer[until] = 0; + cur += until + 1; + + char const *s[5] = { }; + + for (size_t c = 0, i = 0; i < 5; i++) { + size_t pos = Util::next_char(line_buffer, c, '\t'); + line_buffer[c+pos] = 0; + s[i] = (char const*)&line_buffer[c]; + c += pos + 1; + } + + bool const is_wpa1 = Util::string_contains((char const*)s[3], "WPA"); + bool const is_wpa2 = Util::string_contains((char const*)s[3], "WPA2"); + bool const is_wpa3 = Util::string_contains((char const*)s[3], "SAE"); + + unsigned const quality = Util::approximate_quality(s[2]); + + char const *prot = is_wpa1 ? "WPA" : "NONE"; + prot = is_wpa2 ? "WPA2" : prot; + prot = is_wpa3 ? "WPA3" : prot; + + fn(Accesspoint(s[0], s[1], prot, s[4], quality)); + } +} + + +struct Action : Fifo::Element +{ + enum class Type : unsigned { COMMAND, QUERY }; + enum class Command : unsigned { + INVALID, ADD, DISABLE, ENABLE, EXPLICIT_SCAN, + LOG_LEVEL, REMOVE, SCAN, SCAN_RESULTS, SET, UPDATE, }; + enum class Query : unsigned { + INVALID, BSS, RSSI, STATUS, }; + + Type const type; + Command const command; + Query const query; + + bool successful; + + Action(Command cmd) + : + type { Type::COMMAND }, + command { cmd }, + query { Query::INVALID }, + successful { true } + { } + + Action(Query query) + : + type { Type::QUERY }, + command { Command::INVALID }, + query { query }, + successful { true } + { } + + virtual void execute() { } + + virtual void check(char const *) { } + + virtual void response(char const *, Accesspoint &) { } + + virtual bool complete() const = 0; + + virtual void print(Genode::Output &) const = 0; +}; + + +/* + * Action for adding a new network + * + * In case the 'auto_connect' option is set for the network it + * will also be enabled to active auto-joining. + */ +struct Add_network_cmd : Action +{ + enum class State : unsigned { + INIT, ADD_NETWORK, FILL_NETWORK_SSID, FILL_NETWORK_BSSID, + FILL_NETWORK_KEY_MGMT, SET_NETWORK_PMF, FILL_NETWORK_PSK, + ENABLE_NETWORK, COMPLETE + }; + + Ctrl_msg_buffer &_msg; + Accesspoint _accesspoint; + State _state; + + Add_network_cmd(Ctrl_msg_buffer &msg, Accesspoint const &ap) + : + Action { Command::ADD }, + _msg { msg }, + _accesspoint { ap }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Add_network_cmd[", (unsigned)_state, + "] '", _accesspoint.ssid, "'"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("ADD_NETWORK")); + _state = State::ADD_NETWORK; + break; + case State::ADD_NETWORK: + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " ssid \"", _accesspoint.ssid, "\"")); + _state = State::FILL_NETWORK_SSID; + break; + case State::FILL_NETWORK_SSID: + { + bool const valid = Accesspoint::valid(_accesspoint.bssid); + char const *bssid = valid ? _accesspoint.bssid.string() : ""; + + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " bssid ", bssid)); + _state = State::FILL_NETWORK_BSSID; + break; + } + case State::FILL_NETWORK_BSSID: + if (_accesspoint.wpa3()) { + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " key_mgmt SAE")); + _state = State::FILL_NETWORK_KEY_MGMT; + } else { + if (_accesspoint.wpa()) + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " psk \"", _accesspoint.pass, "\"")); + else + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " key_mgmt NONE")); + _state = State::FILL_NETWORK_PSK; + } + break; + case State::FILL_NETWORK_KEY_MGMT: + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " ieee80211w 2")); + _state = State::SET_NETWORK_PMF; + break; + case State::SET_NETWORK_PMF: + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " psk \"", _accesspoint.pass, "\"")); + _state = State::FILL_NETWORK_PSK; + break; + case State::FILL_NETWORK_PSK: + ctrl_cmd(_msg, Cmd("ENABLE_NETWORK ", _accesspoint.id)); + _state = State::ENABLE_NETWORK; + break; + case State::ENABLE_NETWORK: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + /* + * Handle response by expected failure handling + * and use fallthrough switch cases to reduce code. + */ + switch (_state) { + case State::INIT: break; + + case State::ADD_NETWORK: + if (cmd_fail(msg)) { + error("ADD_NETWORK(", (unsigned)_state, ") failed: ", msg); + Action::successful = false; + complete = true; + } + break; + + case State::FILL_NETWORK_SSID: [[fallthrough]]; + case State::FILL_NETWORK_BSSID: [[fallthrough]]; + case State::FILL_NETWORK_KEY_MGMT: [[fallthrough]]; + case State::SET_NETWORK_PMF: [[fallthrough]]; + case State::FILL_NETWORK_PSK: [[fallthrough]]; + case State::ENABLE_NETWORK: + if (!cmd_successful(msg)) { + error("ADD_NETWORK(", (unsigned)_state, ") failed: ", msg); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) { + _state = State::COMPLETE; + return; + } + + switch (_state) { + case State::INIT: break; + case State::ADD_NETWORK: + { + long id = -1; + ascii_to(msg, id); + _accesspoint.id = static_cast(id); + break; + } + case State::FILL_NETWORK_SSID: break; + case State::FILL_NETWORK_BSSID: break; + case State::FILL_NETWORK_KEY_MGMT: break; + case State::SET_NETWORK_PMF: break; + case State::FILL_NETWORK_PSK: break; + case State::ENABLE_NETWORK: break; + case State::COMPLETE: break; + } + } + + Accesspoint const &accesspoint() const + { + return _accesspoint; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for removing a network + */ +struct Remove_network_cmd : Action +{ + enum class State : unsigned { + INIT, REMOVE_NETWORK, COMPLETE + }; + + Ctrl_msg_buffer &_msg; + int _id; + State _state; + + Remove_network_cmd(Ctrl_msg_buffer &msg, int id) + : + Action { Command::REMOVE }, + _msg { msg }, + _id { id }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Remove_network_cmd[", (unsigned)_state, "] id: ", _id); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("REMOVE_NETWORK ", _id)); + _state = State::REMOVE_NETWORK; + break; + case State::REMOVE_NETWORK: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::REMOVE_NETWORK: + if (cmd_fail(msg)) { + error("could not remove network: ", msg); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for updating a network + * + * For now only the PSK is updated. + */ +struct Update_network_cmd : Action +{ + enum class Op : unsigned { + UPDATE_ALL, DISABLE_ONLY }; + enum class State : unsigned { + INIT, UPDATE_NETWORK_PSK, + DISABLE_NETWORK, ENABLE_NETWORK, COMPLETE + }; + Ctrl_msg_buffer &_msg; + Accesspoint _accesspoint; + State _state; + Op _op; + + Update_network_cmd(Ctrl_msg_buffer &msg, + Accesspoint const &ap, + Op op = Op::UPDATE_ALL) + : + Action { Command::UPDATE }, + _msg { msg }, + _accesspoint { ap }, + _state { State::INIT }, + _op { op } + { } + + void print(Output &out) const override + { + Genode::print(out, "Update_network_cmd[", (unsigned)_state, + "] id: ", _accesspoint.id); + } + + void execute() override + { + // XXX change to disable -> psk ?-> enable + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SET_NETWORK ", _accesspoint.id, + " psk \"", _accesspoint.pass, "\"")); + _state = State::UPDATE_NETWORK_PSK; + break; + case State::UPDATE_NETWORK_PSK: + ctrl_cmd(_msg, Cmd("DISABLE_NETWORK ", _accesspoint.id)); + _state = State::DISABLE_NETWORK; + break; + case State::DISABLE_NETWORK: + if (_op != Op::DISABLE_ONLY) { + ctrl_cmd(_msg, Cmd("ENABLE_NETWORK ", _accesspoint.id)); + _state = State::ENABLE_NETWORK; + } else + _state = State::COMPLETE; + break; + case State::ENABLE_NETWORK: + _state = State::COMPLETE; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::UPDATE_NETWORK_PSK: [[fallthrough]]; + case State::ENABLE_NETWORK: [[fallthrough]]; + case State::DISABLE_NETWORK: + if (!cmd_successful(msg)) { + error("UPDATE_NETWORK(", (unsigned)_state, ") failed: ", msg); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for initiating a scan request + */ +struct Scan_cmd : Action +{ + enum class State : unsigned { + INIT, SCAN, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + /* enough to store 64 hidden networks */ + char ssid_buffer[4060] { }; + size_t buffer_pos { 0 }; + + Scan_cmd(Ctrl_msg_buffer &msg) + : + Action { Command::SCAN }, + _msg { msg }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Scan_cmd[", (unsigned)_state, "]"); + } + + void append_ssid(Accesspoint::Ssid const &ssid) + { + enum { SSID_ARG_LEN = 6 + 64, /* " ssid " + "a5a5a5a5..." */ }; + /* silently ignore SSID */ + if (buffer_pos + SSID_ARG_LEN >= sizeof(ssid_buffer)) + return; + + char ssid_hex[64+1] { }; + char const *ssid_ptr = ssid.string(); + + for (size_t i = 0; i < ssid.length() - 1; i++) { + Util::byte2hex((ssid_hex + i * 2), ssid_ptr[i]); + } + + Genode::String tmp(" ssid ", (char const*)ssid_hex); + size_t const tmp_len = tmp.length() - 1; + + Genode::memcpy((ssid_buffer + buffer_pos), tmp.string(), tmp_len); + buffer_pos += tmp_len; + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SCAN ", (char const*)ssid_buffer)); + _state = State::SCAN; + break; + case State::SCAN: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::SCAN: + if (!cmd_successful(msg)) { + /* ignore busy fails silently */ + bool const scan_busy = strcmp(msg, "FAIL-BUSY"); + if (!scan_busy) { + error("could not initiate scan: ", msg); + Action::successful = false; + complete = true; + } + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for initiating a scan results request + */ +struct Scan_results_cmd : Action +{ + enum class State : unsigned { + INIT, SCAN_RESULTS, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Expanding_reporter &_reporter; + + void _generate_report(char const *msg) + { + unsigned count_lines = 0; + for_each_line(msg, [&] (char const*) { count_lines++; }); + + if (!count_lines) + return; + + try { + _reporter.generate([&] (Xml_generator &xml) { + + for_each_result_line(msg, [&] (Accesspoint const &ap) { + + /* ignore potentially empty ssids */ + if (ap.ssid == "") + return; + + xml.node("accesspoint", [&]() { + xml.attribute("ssid", ap.ssid); + xml.attribute("bssid", ap.bssid); + xml.attribute("freq", ap.freq); + xml.attribute("quality", ap.quality); + if (ap.wpa()) { xml.attribute("protection", ap.prot); } + }); + }); + }); + + } catch (...) { /* silently omit report */ } + } + + Scan_results_cmd(Ctrl_msg_buffer &msg, + Genode::Expanding_reporter &reporter) + : + Action { Command::SCAN_RESULTS }, + _msg { msg }, + _state { State::INIT }, + _reporter { reporter } + { } + + void print(Output &out) const override + { + Genode::print(out, "Scan_results_cmd[", (unsigned)_state, "]"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SCAN_RESULTS")); + _state = State::SCAN_RESULTS; + break; + case State::SCAN_RESULTS: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::SCAN_RESULTS: + if (scan_results(msg)) + _generate_report(msg); + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for setting a configuration variable + */ +struct Set_cmd : Action +{ + using Key = String<64>; + using Value = String<128>; + + enum class State : unsigned { + INIT, SET, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Key _key; + Value _value; + + Set_cmd(Ctrl_msg_buffer &msg, Key key, Value value) + : + Action { Command::SET }, + _msg { msg }, + _state { State::INIT }, + _key { key }, + _value { value } + { } + + void print(Output &out) const override + { + Genode::print(out, "Set_cmd[", (unsigned)_state, "] key: '", + _key, "' value: '", _value, "'"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SET ", _key, " \"", _value, "\"")); + _state = State::SET; + break; + case State::SET: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::SET: + if (!cmd_successful(msg)) { + error("could not set '", _key, "' to '", + _value, "': '", msg, "'"); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for setting a configuration variable + */ +struct Log_level_cmd : Action +{ + using Level = Genode::String<16>; + + enum class State : unsigned { + INIT, LOG_LEVEL, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Level _level; + + Log_level_cmd(Ctrl_msg_buffer &msg, Level const &level) + : + Action { Command::LOG_LEVEL }, + _msg { msg }, + _state { State::INIT }, + _level { level } + { } + + void print(Output &out) const override + { + Genode::print(out, "Log_level_cmd[", (unsigned)_state, "] '", _level, "'"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("LOG_LEVEL ", _level)); + _state = State::LOG_LEVEL; + break; + case State::LOG_LEVEL: + _state = State::COMPLETE; + break; + case State::COMPLETE: + break; + } + } + + void check(char const *msg) override + { + using namespace Genode; + + bool complete = false; + + switch (_state) { + case State::INIT: break; + case State::LOG_LEVEL: + if (!cmd_successful(msg)) { + error("could not set LOG_LEVEL to ", _level); + Action::successful = false; + complete = true; + } + break; + case State::COMPLETE: break; + } + + if (complete) + _state = State::COMPLETE; + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for querying BSS information + */ +struct Bss_query : Action +{ + enum class State : unsigned { + INIT, BSS, COMPLETE + }; + Ctrl_msg_buffer &_msg; + Accesspoint::Bssid _bssid; + State _state; + + Bss_query(Ctrl_msg_buffer &msg, Accesspoint::Bssid bssid) + : + Action { Query::BSS }, + _msg { msg }, + _bssid { bssid }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Bss_query[", (unsigned)_state, "] ", _bssid); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("BSS ", _bssid)); + _state = State::BSS; + break; + case State::BSS: break; + case State::COMPLETE: break; + } + } + + void response(char const *msg, Accesspoint &ap) override + { + if (_state != State::BSS) + return; + + _state = State::COMPLETE; + + /* + * It might happen that the supplicant already flushed + * its internal BSS information and cannot help us out. + * Since we already sent out a rudimentary report, just + * stop here. + */ + if (0 == msg[0]) + return; + + auto fill_ap = [&] (char const *line) { + if (Genode::strcmp(line, "ssid=", 5) == 0) { + ap.ssid = Accesspoint::Ssid(line+5); + } else + + if (Genode::strcmp(line, "bssid=", 6) == 0) { + ap.bssid = Accesspoint::Bssid(line+6); + } else + + if (Genode::strcmp(line, "freq=", 5) == 0) { + ap.freq = Accesspoint::Freq(line+5); + } + }; + for_each_line(msg, fill_ap); + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for querying RSSI information + */ +struct Rssi_query : Action +{ + enum class State : unsigned { + INIT, RSSI, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Rssi_query(Ctrl_msg_buffer &msg) + : + Action { Query::RSSI }, + _msg { msg }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Rssi_query[", (unsigned)_state, "]"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("SIGNAL_POLL")); + _state = State::RSSI; + break; + case State::RSSI: break; + case State::COMPLETE: break; + } + } + + void response(char const *msg, Accesspoint &ap) override + { + if (_state != State::RSSI) + return; + + _state = State::COMPLETE; + + using Rssi = Genode::String<5>; + Rssi rssi { }; + auto get_rssi = [&] (char const *line) { + if (strcmp(line, "RSSI=", 5) != 0) + return; + + rssi = Rssi(line + 5); + }; + for_each_line(msg, get_rssi); + + /* + * Use the same simplified approximation for denoting + * the quality to be in line with the scan results. + */ + ap.quality = Util::approximate_quality(rssi.valid() ? rssi.string() + : "-100"); + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Action for querying the current connection status + */ +struct Status_query : Action +{ + enum class State : unsigned { + INIT, STATUS, COMPLETE + }; + Ctrl_msg_buffer &_msg; + State _state; + + Status_query(Ctrl_msg_buffer &msg) + : + Action { Query::STATUS }, + _msg { msg }, + _state { State::INIT } + { } + + void print(Output &out) const override + { + Genode::print(out, "Status_query[", (unsigned)_state, "]"); + } + + void execute() override + { + switch (_state) { + case State::INIT: + ctrl_cmd(_msg, Cmd("STATUS")); + _state = State::STATUS; + break; + case State::STATUS: break; + case State::COMPLETE: break; + } + } + + void response(char const *msg, Accesspoint &ap) override + { + if (_state != State::STATUS) + return; + + _state = State::COMPLETE; + + /* + * It might happen that the supplicant already flushed + * its internal BSS information and cannot help us out. + * Since we already sent out a rudimentary report, just + * stop here. + */ + if (0 == msg[0]) + return; + + auto fill_ap = [&] (char const *line) { + if (strcmp(line, "ssid=", 5) == 0) { + ap.ssid = Accesspoint::Ssid(line+5); + } else + + if (strcmp(line, "bssid=", 6) == 0) { + ap.bssid = Accesspoint::Bssid(line+6); + } else + + if (strcmp(line, "freq=", 5) == 0) { + ap.freq = Accesspoint::Freq(line+5); + } + }; + for_each_line(msg, fill_ap); + } + + bool complete() const override { + return _state == State::COMPLETE; } +}; + + +/* + * Wifi driver manager + */ +struct Wifi::Manager : Wifi::Rfkill_notification_handler +{ + Manager(const Manager&) = delete; + Manager& operator=(const Manager&) = delete; + + /* Network handling */ + + Heap _network_allocator; + List_model _network_list { }; + + /* Explicit_scan handling */ + + Heap _explicit_scan_allocator; + List_model _explicit_scan_list { }; + + /* + * Action queue handling + */ + + Heap _actions_alloc; + Fifo _actions { }; + + Action *_pending_action { nullptr }; + + void _queue_action(Action &action, bool verbose) + { + _actions.enqueue(action); + if (verbose) + Genode::log("Queue ", action); + } + + enum class Pending_action_result : unsigned { + INCOMPLETE, COMPLETE }; + + void _with_pending_action(auto const &fn) + { + if (!_pending_action) + _actions.dequeue([&] (Action &action) { + _pending_action = &action; }); + + Pending_action_result const result = + _pending_action ? fn(*_pending_action) + : Pending_action_result::INCOMPLETE; + if (result == Pending_action_result::COMPLETE) { + destroy(_actions_alloc, _pending_action); + _pending_action = nullptr; + } + } + + void _dispatch_action_if_needed() + { + if (_pending_action) + return; + + /* + * Grab the next action and call execute() + * to poke the CTRL interface. + */ + + _actions.dequeue([&] (Action &action) { + _pending_action = &action; + _pending_action->execute(); + }); + } + + Signal_handler _cmd_handler; + Signal_handler _events_handler; + + Blockade _notify_blockade { }; + + struct Notify : Notify_interface + { + Signal_handler &_response; + Signal_handler &_event; + Blockade &_blockade; + + Notify(Signal_handler &response, + Signal_handler &event, + Blockade &blockade) + : + _response { response }, + _event { event }, + _blockade { blockade } + { } + + /********************** + ** Notify_interface ** + **********************/ + + void submit_response() override { + _response.local_submit(); } + + void submit_event() override { + _event.local_submit(); } + + void block_for_processing() override { + _blockade.block(); } + } _notify { _cmd_handler, _events_handler, _notify_blockade }; + + Msg_buffer _msg { _notify }; + + void _handle_rfkill() + { + _join.rfkilled = Wifi::rfkill_blocked(); + + /* re-enable scan timer */ + if (!_join.rfkilled) + _try_arming_any_timer(); + } + + Signal_handler _rfkill_handler; + + /* + * Configuration handling + */ + + Attached_rom_dataspace _config_rom; + Signal_handler _config_sigh; + + struct Config + { + enum { + DEFAULT_CONNECTED_SCAN_INTERVAL = 30, + DEFAULT_SCAN_INTERVAL = 5, + DEFAULT_UPDATE_QUAILITY_INTERVAL = 30, + + DEFAULT_VERBOSE = false, + DEFAULT_RFKILL = false, + }; + + unsigned scan_interval { DEFAULT_SCAN_INTERVAL }; + unsigned update_quality_interval { DEFAULT_UPDATE_QUAILITY_INTERVAL }; + + bool intervals_changed(Config const &cfg) const + { + return scan_interval != cfg.scan_interval + || update_quality_interval != cfg.update_quality_interval; + } + + bool verbose { DEFAULT_VERBOSE }; + bool rfkill { DEFAULT_RFKILL }; + + bool rfkill_changed(Config const &cfg) const { + return rfkill != cfg.rfkill; } + + /* see wpa_debug.h - EXCESSIVE, MSGDUMP, DEBUG, INFO, WARNING, ERROR */ + using Log_level = Log_level_cmd::Level; + Log_level log_level { "" }; + + bool log_level_changed(Config const &cfg) const { + return log_level != cfg.log_level; } + + bool log_level_set() const { + return log_level.length() > 1; } + + using Bgscan = Genode::String<16>; + Bgscan bgscan { "" }; + + bool bgscan_changed(Config const &cfg) const { + return bgscan != cfg.bgscan; } + + bool bgscan_set() const { + return bgscan.length() >= 1; } + + static Config from_xml(Xml_node const &node) + { + bool const verbose = node.attribute_value("verbose", + (bool)DEFAULT_VERBOSE); + bool const rfkill = node.attribute_value("rfkill", + (bool)DEFAULT_RFKILL); + Log_level log_level = + node.attribute_value("log_level", Log_level("error")); + /* always enforce at leaast error level of verbosity */ + if (log_level.length() <= 1) + log_level = Log_level("error"); + + Bgscan const bgscan = + node.attribute_value("bgscan", Bgscan("simple:30:-70:600")); + + unsigned const scan_interval = + Util::check_time(node.attribute_value("scan_interval", + (unsigned)DEFAULT_SCAN_INTERVAL), + 5, 15*60); + + unsigned const update_quality_interval = + Util::check_time(node.attribute_value("update_quality_interval", + (unsigned)DEFAULT_UPDATE_QUAILITY_INTERVAL), + 10, 15*60); + + Config new_config { + .scan_interval = scan_interval, + .update_quality_interval = update_quality_interval, + .verbose = verbose, + .rfkill = rfkill, + .log_level = log_level, + .bgscan = bgscan + }; + return new_config; + } + }; + + Config _config { }; + + void _config_update(bool initial_config) + { + _config_rom.update(); + + if (!_config_rom.valid()) + return; + + Xml_node const config_node = _config_rom.xml(); + + Config const old_config = _config; + + _config = Config::from_xml(config_node); + + if (_config.intervals_changed(old_config) || initial_config) + _try_arming_any_timer(); + + if (_config.rfkill_changed(old_config) || initial_config) { + Wifi::set_rfkill(_config.rfkill); + + /* + * In case we get blocked set rfkilled immediately to prevent + * any further scanning operation. The actual value will be set + * by the singal handler but is not expected to be any different + * as the rfkill call is not supposed to fail. + */ + if (_config.rfkill && !_join.rfkilled) + _join.rfkilled = true; + } + + if (_config.log_level_changed(old_config) || initial_config) + if (_config.log_level_set()) + _queue_action(*new (_actions_alloc) + Log_level_cmd(_msg, _config.log_level), _config.verbose); + + if (_config.bgscan_changed(old_config) || initial_config) + if (_config.bgscan_set()) + _queue_action(*new (_actions_alloc) + Set_cmd(_msg, Set_cmd::Key("bgscan"), + Set_cmd::Value(_config.bgscan)), + _config.verbose); + + _network_list.update_from_xml(config_node, + + [&] (Genode::Xml_node const &node) -> Network & { + + Accesspoint const ap = Accesspoint::from_xml(node); + + /* + * Only make the supplicant acquainted with the network + * when it is usable, it always needs a valid SSID and + * in case it is protected also a valid PSK, but create + * the Network object nonetheless to satisfy the List_model + * requirements. + */ + + bool const ssid_valid = Accesspoint::valid(ap.ssid); + if (!ssid_valid) + warning("accesspoint has invalid ssid: '", ap.ssid, "'"); + + bool const pass_valid = ap.wpa() ? Accesspoint::valid(ap.pass) + : true; + if (!pass_valid) + warning("accesspoint '", ap.ssid, "' has invalid psk"); + + if (ssid_valid && pass_valid) + _queue_action(*new (_actions_alloc) + Add_network_cmd(_msg, ap), _config.verbose); + + return *new (_network_allocator) Network(ap); + }, + [&] (Network &network) { + + network.with_accesspoint([&] (Accesspoint &ap) { + + if (!Accesspoint::valid(ap.ssid) || !ap.stored()) + return; + + _queue_action(*new (_actions_alloc) + Remove_network_cmd(_msg, ap.id), _config.verbose); + }); + + Genode::destroy(_network_allocator, &network); + }, + [&] (Network &network, Genode::Xml_node const &node) { + Accesspoint const updated_ap = Accesspoint::from_xml(node); + + network.with_accesspoint([&] (Accesspoint &ap) { + + if (!ap.updated_from(updated_ap)) + return; + + if (!ap.stored()) + return; + + _queue_action(*new (_actions_alloc) + Update_network_cmd(_msg, ap), _config.verbose); + }); + }); + + _explicit_scan_list.update_from_xml(config_node, + + [&] (Genode::Xml_node const &node) -> Explicit_scan & { + Accesspoint::Ssid const ssid = + node.attribute_value("ssid", Accesspoint::Ssid()); + + /* + * Always created the Explicit_scan object but ignore + * invalid ones during SCAN operation to satisfy the + * List_model requirements. + */ + return *new (_explicit_scan_allocator) Explicit_scan(ssid); + }, + [&] (Explicit_scan &explicit_scan) { + Genode::destroy(_explicit_scan_allocator, + &explicit_scan); + }, + [&] (Explicit_scan &explicit_scan, Genode::Xml_node const &node) { + /* + * Intentionally left empty as we never have to update the + * object as it only contains the SSID that also serves as + * identifier. + */ + }); + + _dispatch_action_if_needed(); + } + + void _handle_config_update() { _config_update(false); } + + /* + * Timeout handling + */ + + Timer::Connection _timer; + + Timer::One_shot_timeout _scan_timeout { + _timer, *this, &Wifi::Manager::_handle_scan_timeout }; + + Timer::One_shot_timeout _quality_timeout { + _timer, *this, &Wifi::Manager::_handle_quality_timeout }; + + enum class Timer_type : uint8_t { SCAN, SIGNAL_POLL }; + + bool _arm_timer(Timer_type const type) + { + auto seconds_from_type = [&] (Timer_type const type) { + switch (type) { + case Timer_type::SCAN: return _config.scan_interval; + case Timer_type::SIGNAL_POLL: return _config.update_quality_interval; + } + return 0u; + }; + + Microseconds const us { seconds_from_type(type) * 1000'000u }; + if (!us.value) + return false; + + if (_config.verbose) { + auto name_from_type = [&] (Timer_type const type) { + switch (type) { + case Timer_type::SCAN: return "scan"; + case Timer_type::SIGNAL_POLL: return "signal-poll"; + } + return ""; + }; + + log("Arm timer for ", name_from_type(type), ": ", us); + } + + switch (type) { + case Timer_type::SCAN: _scan_timeout.schedule(us); break; + case Timer_type::SIGNAL_POLL: _quality_timeout.schedule(us); break; + } + return true; + } + + bool _arm_scan_timer() + { + if (_join.state == Join_state::State::CONNECTED) + return false; + + return _arm_timer(Timer_type::SCAN); + } + + bool _arm_poll_timer() + { + if (_join.state != Join_state::State::CONNECTED) + return false; + + return _arm_timer(Timer_type::SIGNAL_POLL); + } + + void _try_arming_any_timer() + { + _arm_scan_timer(); + _arm_poll_timer(); + } + + void _handle_scan_timeout(Genode::Duration) + { + if (_join.rfkilled) { + if (_config.verbose) + log("Scanning: suspend due to RFKILL"); + return; + } + + if (!_arm_scan_timer()) { + if (_config.verbose) + log("Timer: scanning disabled"); + return; + } + + Scan_cmd &scan_cmd = *new (_actions_alloc) Scan_cmd(_msg); + _explicit_scan_list.for_each([&] (Explicit_scan const &explicit_scan) { + explicit_scan.with_ssid([&] (Accesspoint::Ssid const &ssid) { + scan_cmd.append_ssid(ssid); + }); + }); + _queue_action(scan_cmd, _config.verbose); + + _dispatch_action_if_needed(); + } + + void _handle_quality_timeout(Genode::Duration) + { + if (_join.rfkilled) { + if (_config.verbose) + log("Quality polling: suspend due to RFKIL"); + return; + } + + if (!_arm_poll_timer()) { + if (_config.verbose) + log("Timer: signal-strength polling disabled"); + return; + } + + _queue_action(*new (_actions_alloc) Rssi_query(_msg), _config.verbose); + + _dispatch_action_if_needed(); + } + + /* + * CTRL interface event handling + */ + + Constructible _state_reporter { }; + Constructible _ap_reporter { }; + + enum class Bssid_offset : unsigned { + /* by the power of wc -c, I have the start pos... */ + CONNECT = 37, CONNECTING = 33, DISCONNECT = 30, }; + + Accesspoint::Bssid const _extract_bssid(char const *msg, Bssid_offset offset) + { + char bssid[32] = { }; + + size_t const len = 17; + size_t const start = (size_t)offset; + + memcpy(bssid, msg + start, len); + return Accesspoint::Bssid((char const*)bssid); + } + + Accesspoint::Ssid const _extract_ssid(char const *msg) + { + char ssid[64] = { }; + size_t const start = 58; + + /* XXX assume "SME:.*SSID='xx xx' ...)", so look for the + * closing ' but we _really_ should use something like + * printf_encode/printf_deccode functions + * (see wpa_supplicant/src/utils/common.c) and + * remove our patch… + */ + size_t const len = Util::next_char(msg, start, 0x27); + if (!len || len >= 33) + return Accesspoint::Ssid(); + + memcpy(ssid, msg + start, len); + + return Accesspoint::Ssid((char const *)ssid); + } + + enum class Auth_result : unsigned { + OK, FAILED, INVALIDED }; + + Auth_result _auth_result(char const *msg) + { + enum { REASON_OFFSET = 55, }; + unsigned reason = 0; + ascii_to((msg + REASON_OFFSET), reason); + switch (reason) { + case 2: /* prev auth no longer valid */ + return Auth_result::INVALIDED; + case 15: /* 4-way handshake timeout/failed */ + return Auth_result::FAILED; + default: + return Auth_result::OK; + } + } + + struct Join_state + { + enum class State : unsigned { + DISCONNECTED, CONNECTING, CONNECTED }; + + Accesspoint ap { }; + + State state { DISCONNECTED }; + + bool auth_failure { false }; + bool not_found { false }; + bool rfkilled { false }; + + enum { MAX_REAUTH_ATTEMPTS = 3 }; + unsigned reauth_attempts { 0 }; + + enum { MAX_NOT_FOUND_IGNORE_ATTEMPTS = 3 }; + unsigned ignore_not_found { 0 }; + + void print(Output &out) const + { + auto state_string = [&] (State const state) { + switch (state) { + case State::DISCONNECTED: return "disconnected"; + case State::CONNECTED: return "connected"; + case State::CONNECTING: return "connecting"; + } + return ""; + }; + Genode::print(out, state_string(state), " " + "ssid: '", ap.ssid, "' " + "bssid: ", ap.bssid, " " + "freq: ", ap.freq, " " + "quality: ", ap.quality, " " + "auth_failure: ", auth_failure, " " + "reauth_attempts: ", reauth_attempts, " " + "not_found: ", not_found, " " + "ignore_not_found: ", ignore_not_found, " " + "rfkilled: ", rfkilled); + } + + void generate_state_report_if_needed(Expanding_reporter &reporter, + Join_state const &old) + { + /* + * Explicitly check for the all changes provoked by + * actions or events. + */ + if (state == old.state + && ap.quality == old.ap.quality + && ap.ssid == old.ap.ssid + && ap.bssid == old.ap.bssid + && ap.freq == old.ap.freq) + return; + + reporter.generate([&] (Xml_generator &xml) { + xml.node("accesspoint", [&] () { + xml.attribute("ssid", ap.ssid); + xml.attribute("bssid", ap.bssid); + xml.attribute("freq", ap.freq); + + if (state == Join_state::State::CONNECTED) + xml.attribute("state", "connected"); + else + + if (state == Join_state::State::DISCONNECTED) { + xml.attribute("state", "disconnected"); + xml.attribute("rfkilled", rfkilled); + xml.attribute("auth_failure", auth_failure); + xml.attribute("not_found", not_found); + } else + + if (state == Join_state::State::CONNECTING) + xml.attribute("state", "connecting"); + + /* + * Only add the attribute when we have something + * to report so that a consumer of the state report + * may take appropriate actions. + */ + if (ap.quality) + xml.attribute("quality", ap.quality); + }); + }); + } + }; + + Join_state _join { }; + + bool _single_network() const + { + unsigned count = 0; + _network_list.for_each([&] (Network const &network) { + network.with_accesspoint([&] (Accesspoint const &ap) { + ++count; }); }); + return count == 1; + } + + void _handle_events() + { + Join_state const old_join = _join; + + _msg.with_new_event([&] (char const *msg) { + + /* + * CTRL-EVENT-SCAN-RESULTS + */ + if (results_available(msg)) { + + /* + * We might have to pull the socketcall task out of poll_all() + * because otherwise we might be late and wpa_supplicant has + * already removed all scan results due to BSS age settings. + */ + wifi_kick_socketcall(); + + _queue_action(*new (_actions_alloc) + Scan_results_cmd(_msg, *_ap_reporter), _config.verbose); + } else + + /* + * SME: Trying to authenticate with ... + */ + if (connecting_to_network(msg)) { + + _join.state = Join_state::State::CONNECTING; + _join.ap = Accesspoint(_extract_bssid(msg, Bssid_offset::CONNECTING), + _extract_ssid(msg)); + _join.auth_failure = false; + _join.not_found = false; + } else + + /* + * CTRL-EVENT-NETWORK-NOT-FOUND + */ + if (network_not_found(msg)) { + + /* + * In case there is only one auto-connect network configured + * generate a disconnect event so that a management component + * can deal with that situation. However, we do not disable the + * network to allow for automatically rejoining a reapparing + * network that was previously not found. + * + * This may happen when an accesspoint is power-cycled or when + * there is a key management mismatch due to operator error. + * Unfortunately we cannot easily distinguish a wrongly prepared + * where the 'protection' attribute does not match + * as we do not have the available accesspoints at hand to compare + * that. + */ + if ((_join.state == Join_state::State::CONNECTING) && _single_network()) { + + /* + * Ignore the event for a while as it may happen that hidden + * networks may take some time. + */ + if (++_join.ignore_not_found >= Join_state::MAX_NOT_FOUND_IGNORE_ATTEMPTS) { + _join.ignore_not_found = 0; + + _network_list.for_each([&] (Network &network) { + network.with_accesspoint([&] (Accesspoint &ap) { + + if (ap.ssid != _join.ap.ssid) + return; + + _join.state = Join_state::State::DISCONNECTED; + _join.ap = Accesspoint(); + _join.not_found = true; + }); + }); + } + } + } else + + /* + * CTRL-EVENT-DISCONNECTED ... reason=... + */ + if (disconnected_from_network(msg)) { + + Join_state::State const old_state = _join.state; + + Auth_result const auth_result = _auth_result(msg); + + _join.auth_failure = auth_result != Auth_result::OK; + _join.state = Join_state::State::DISCONNECTED; + _join.not_found = false; + + Accesspoint::Bssid const bssid = + _extract_bssid(msg, Bssid_offset::DISCONNECT); + + if (bssid != _join.ap.bssid) + warning(bssid, " does not match stored ", _join.ap.bssid); + + /* + * Use a simplistic heuristic to ignore re-authentication requests + * and hope for the supplicant to do its magic. + */ + if ((old_state == Join_state::State::CONNECTED) && _join.auth_failure) + if (++_join.reauth_attempts <= Join_state::MAX_REAUTH_ATTEMPTS) { + log("ignore deauth from: ", bssid); + return; + } + _join.reauth_attempts = 0; + + _network_list.for_each([&] (Network &network) { + network.with_accesspoint([&] (Accesspoint &ap) { + + if (ap.ssid != _join.ap.ssid) + return; + + if (!_join.auth_failure) + return; + + /* + * Prevent the supplicant from trying to join the network + * again. At this point intervention by the management + * component is needed. + */ + + _queue_action(*new (_actions_alloc) + Update_network_cmd(_msg, ap, + Update_network_cmd::Op::DISABLE_ONLY), + _config.verbose); + }); + }); + } else + + /* + * CTRL-EVENT-CONNECTED - Connection to ... + */ + if (connected_to_network(msg)) { + + _join.state = Join_state::State::CONNECTED; + _join.ap.bssid = _extract_bssid(msg, Bssid_offset::CONNECT); + _join.auth_failure = false; + _join.not_found = false; + _join.reauth_attempts = 0; + + /* collect further information like frequency and so on */ + _queue_action(*new (_actions_alloc) Status_query(_msg), + _config.verbose); + + _arm_poll_timer(); + } + }); + + _notify_blockade.wakeup(); + + _join.generate_state_report_if_needed(*_state_reporter, old_join); + + _dispatch_action_if_needed(); + } + + /* + * CTRL interface command handling + */ + + void _handle_cmds() + { + Join_state const old_join = _join; + + _msg.with_new_reply([&] (char const *msg) { + + _with_pending_action([&] (Action &action) { + + /* + * Check response first as we ended up here due + * to an already submitted cmd. + */ + switch (action.type) { + + case Action::Type::COMMAND: + action.check(msg); + break; + + case Action::Type::QUERY: + action.response(msg, _join.ap); + break; + } + + /* + * We always switch to the next state after checking and + * handling the response from the CTRL interface. + */ + action.execute(); + + if (!action.complete()) + return Pending_action_result::INCOMPLETE; + + switch (action.command) { + case Action::Command::ADD: + { + Add_network_cmd const &add_cmd = + *dynamic_cast(&action); + + bool handled = false; + Accesspoint const &added_ap = add_cmd.accesspoint(); + _network_list.for_each([&] (Network &network) { + network.with_accesspoint([&] (Accesspoint &ap) { + if (ap.ssid != added_ap.ssid) + return; + + if (ap.stored()) { + error("accesspoint for SSID '", ap.ssid, "' " + "already stored ", ap.id); + return; + } + + ap.id = added_ap.id; + handled = true; + }); + }); + + /* + * We have to guard against having the accesspoint removed via a config + * update while we are still adding it to the supplicant by removing the + * + * network directly afterwards. + */ + if (!handled) { + _queue_action(*new (_actions_alloc) + Remove_network_cmd(_msg, added_ap.id), _config.verbose); + } else + + if (handled && _single_network()) + /* + * To accomodate a management component that only deals + * with one network, e.g. the sculpt_manager, generate a + * fake connecting event. Either a connected or disconnected + * event will bring us to square one. + */ + if ((_join.state != Join_state::State::CONNECTED) && !_join.rfkilled) { + _network_list.for_each([&] (Network const &network) { + network.with_accesspoint([&] (Accesspoint const &ap) { + + _join.ap = ap; + _join.state = Join_state::State::CONNECTING; + }); + }); + } + + break; + } + default: /* ignore the rest */ + break; + } + + return Pending_action_result::COMPLETE; + }); + }); + + _notify_blockade.wakeup(); + + _join.generate_state_report_if_needed(*_state_reporter, old_join); + + _dispatch_action_if_needed(); + } + + /** + * Constructor + */ + Manager(Env &env) + : + _network_allocator(env.ram(), env.rm()), + _explicit_scan_allocator(env.ram(), env.rm()), + _actions_alloc(env.ram(), env.rm()), + _cmd_handler(env.ep(), *this, &Wifi::Manager::_handle_cmds), + _events_handler(env.ep(), *this, &Wifi::Manager::_handle_events), + _rfkill_handler(env.ep(), *this, &Wifi::Manager::_handle_rfkill), + _config_rom(env, "wifi_config"), + _config_sigh(env.ep(), *this, &Wifi::Manager::_handle_config_update), + _timer(env) + { + _config_rom.sigh(_config_sigh); + + /* set/initialize as unblocked */ + _notify_blockade.wakeup(); + + /* + * Both Report sessions are mandatory, let the driver fail in + * case they cannot be created. + */ + { + _ap_reporter.construct(env, "accesspoints", "accesspoints"); + _ap_reporter->generate([&] (Genode::Xml_generator &) { }); + } + + { + _state_reporter.construct(env, "state", "state"); + _state_reporter->generate([&] (Genode::Xml_generator &xml) { + xml.node("accesspoint", [&] () { + xml.attribute("state", "disconnected"); + }); + }); + } + + /* read in list of APs */ + _config_update(true); + + /* get initial RFKILL state */ + _handle_rfkill(); + + /* kick-off initial scanning */ + _handle_scan_timeout(Duration(Microseconds(0))); + } + + /** + * Trigger RFKILL notification + * + * Used by the wifi driver to notify the manager. + */ + void rfkill_notify() override { + _rfkill_handler.local_submit(); } + + /** + * Return message buffer + * + * Used for communication with the CTRL interface + */ + Msg_buffer &msg_buffer() { return _msg; } +}; + +#endif /* _WIFI_MANAGER_H_ */ diff --git a/repos/dde_linux/src/driver/wifi/util.h b/repos/dde_linux/src/driver/wifi/util.h index 0db3931afc..2285fd12fa 100644 --- a/repos/dde_linux/src/driver/wifi/util.h +++ b/repos/dde_linux/src/driver/wifi/util.h @@ -1,5 +1,5 @@ /* - * \brief Wifi front end utilities + * \brief Wifi manager utilities * \author Josef Soentgen * \date 2018-07-23 */ @@ -59,9 +59,9 @@ namespace Util { } } - /********************************** - ** Front end specific utilities ** - **********************************/ + /******************************** + ** Manager-specific utilities ** + ********************************/ inline unsigned approximate_quality(char const *str) { diff --git a/repos/dde_linux/src/include/lx_emul/nic.h b/repos/dde_linux/src/include/lx_emul/nic.h new file mode 100644 index 0000000000..307b2835ee --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/nic.h @@ -0,0 +1,31 @@ +/* + * \brief Lx_emul support for NICs + * \author Stefan Kalkowski + * \date 2024-10-15 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__NIC_H_ +#define _LX_EMUL__NIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void lx_emul_nic_init(void); +extern void lx_emul_nic_handle_io(void); +extern void lx_emul_nic_set_mac_address(const unsigned char *mac, + unsigned long size); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__USB_H_ */ + diff --git a/repos/dde_linux/src/include/lx_emul/shmem_file.h b/repos/dde_linux/src/include/lx_emul/shmem_file.h index fcced61a15..ec81ecb0e0 100644 --- a/repos/dde_linux/src/include/lx_emul/shmem_file.h +++ b/repos/dde_linux/src/include/lx_emul/shmem_file.h @@ -91,8 +91,15 @@ err_inode: } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0) +#define folio_cast struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp) +#else +#define folio_cast (struct folio *) +struct folio *shmem_read_folio_gfp(struct address_space *mapping, + pgoff_t index, gfp_t gfp) +#endif { struct page *p; struct shmem_file_buffer *private_data; @@ -103,17 +110,27 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, private_data = mapping->private_data; p = private_data->pages; - return (p + index); + return folio_cast(p + index); } #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0) void __pagevec_release(struct pagevec * pvec) { /* XXX check if we have to call release_pages */ pagevec_reinit(pvec); } +#else +void __folio_batch_release(struct folio_batch *fbatch) +{ + lx_emul_trace(__func__); + + /* XXX check if we have to call release_pages */ + folio_batch_reinit(fbatch); +} +#endif #include diff --git a/repos/dde_linux/src/include/lx_kit/device.h b/repos/dde_linux/src/include/lx_kit/device.h index d54dcea977..affb640dd4 100644 --- a/repos/dde_linux/src/include/lx_kit/device.h +++ b/repos/dde_linux/src/include/lx_kit/device.h @@ -142,6 +142,16 @@ class Lx_kit::Device : List::Element void _for_each_clock(FN const & fn) { for (Clock * c = _clocks.first(); c; c = c->next()) fn(*c); } + protected: + + Device(Platform::Connection &plat, + Name name) + : + _platform(plat), _name(name), _type("") + { } + + virtual ~Device() { } + public: const char * compatible(); @@ -171,7 +181,8 @@ class Lx_kit::Device : List::Element bool irq_unmask(unsigned irq); void irq_mask(unsigned irq); void irq_ack(unsigned irq); - int pending_irq(); + + virtual int pending_irq(); bool read_config(unsigned reg, unsigned len, unsigned *val); bool write_config(unsigned reg, unsigned len, unsigned val); @@ -210,6 +221,8 @@ class Lx_kit::Device_list : List Device_list(Entrypoint & ep, Heap & heap, Platform::Connection & platform); + + void insert(Device const *device) { List::insert(device); } }; #endif /* _LX_KIT__DEVICE_H_ */ diff --git a/repos/dde_linux/src/lib/lx_emul/nic.c b/repos/dde_linux/src/lib/lx_emul/nic.c new file mode 100644 index 0000000000..2f5d702c32 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/nic.c @@ -0,0 +1,258 @@ +/* + * \brief PC Ethernet driver + * \author Norman Feske + * \author Christian Helmuth + * \author Stefan Kalkowski + * \date 2024-10-15 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include +#include + + +static struct genode_uplink *dev_genode_uplink(struct net_device *dev) +{ + return (struct genode_uplink *)dev->ifalias; +} + + +struct genode_uplink_rx_context +{ + struct net_device *dev; +}; + + +struct genode_uplink_tx_packet_context +{ + struct sk_buff *skb; +}; + + +static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx, + char *dst, unsigned long dst_len) +{ + struct sk_buff * const skb = ctx->skb; + + skb_push(skb, ETH_HLEN); + + if (dst_len < skb->len) { + printk("uplink_tx_packet_content: packet exceeds uplink packet size\n"); + memset(dst, 0, dst_len); + return 0; + } + + skb_copy_from_linear_data(skb, dst, skb->len); + + /* clear unused part of the destination buffer */ + memset(dst + skb->len, 0, dst_len - skb->len); + + return skb->len; +} + + +static rx_handler_result_t handle_rx(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct net_device *dev = skb->dev; + struct genode_uplink_tx_packet_context ctx = { .skb = skb }; + struct genode_uplink *uplink = dev_genode_uplink(dev); + + if (!uplink) + return RX_HANDLER_PASS; + + { + bool progress = genode_uplink_tx_packet(uplink, + uplink_tx_packet_content, + &ctx); + if (!progress) + printk("handle_rx: uplink saturated, dropping packet\n"); + } + + kfree_skb(skb); + return RX_HANDLER_CONSUMED; +} + + +/** + * Create Genode uplink for given net device + * + * The uplink is registered at the dev->ifalias pointer. + */ +static void handle_create_uplink(struct net_device *dev) +{ + struct genode_uplink_args args; + + if (dev_genode_uplink(dev)) + return; + + if (!netif_carrier_ok(dev)) + return; + + printk("create uplink for net device %s\n", &dev->name[0]); + + memset(&args, 0, sizeof(args)); + + if (dev->addr_len != sizeof(args.mac_address)) { + printk("error: net device has unexpected addr_len %u\n", dev->addr_len); + return; + } + + { + unsigned i; + for (i = 0; i < dev->addr_len; i++) + args.mac_address[i] = dev->dev_addr[i]; + } + + args.label = &dev->name[0]; + + dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args); +} + + +static void handle_destroy_uplink(struct net_device *dev) +{ + struct genode_uplink *uplink = dev_genode_uplink(dev); + + if (!uplink) + return; + + if (netif_carrier_ok(dev)) + return; + + genode_uplink_destroy(uplink); + + dev->ifalias = NULL; +} + + +static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx, + char const *ptr, unsigned long len) +{ + struct sk_buff *skb = alloc_skb(len, GFP_KERNEL); + + if (!skb) { + printk("alloc_skb failed\n"); + return GENODE_UPLINK_RX_RETRY; + } + + skb_copy_to_linear_data(skb, ptr, len); + skb_put(skb, len); + skb->dev = ctx->dev; + + if (dev_queue_xmit(skb) < 0) { + printk("lx_user: failed to xmit packet\n"); + return GENODE_UPLINK_RX_REJECTED; + } + + return GENODE_UPLINK_RX_ACCEPTED; +} + + +/* + * custom MAC address + */ +static unsigned char mac_address[6]; +static bool mac_address_configured = false; + +static void handle_mac_address(struct net_device *dev) +{ + int err; + struct sockaddr addr; + struct genode_mac_address dev_addr; + + if (mac_address_configured || !netif_device_present(dev)) return; + + if (mac_address[0] || mac_address[1] || mac_address[2] || + mac_address[3] || mac_address[4] || mac_address[5]) { + memcpy(&addr.sa_data, mac_address, ETH_ALEN); + addr.sa_family = dev->type; + err = dev_set_mac_address(dev, &addr, NULL); + if (err < 0) + printk("Warning: Could not set configured MAC address: %pM (err=%d)\n", + mac_address, err); + } + + memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr)); + genode_mac_address_register(dev->name, dev_addr); + + mac_address_configured =true; +} + + +static int nic_task_function(void *arg) +{ + for (;;) { + + struct net_device *dev; + + for_each_netdev(&init_net, dev) { + + handle_mac_address(dev); + + /* enable link sensing, repeated calls are handled by testing IFF_UP */ + dev_open(dev, 0); + + /* install rx handler once */ + if (!netdev_is_rx_handler_busy(dev)) + netdev_rx_handler_register(dev, handle_rx, NULL); + + /* respond to cable plug/unplug */ + handle_create_uplink(dev); + handle_destroy_uplink(dev); + + /* transmit packets received from the uplink session */ + if (netif_carrier_ok(dev)) { + + struct genode_uplink_rx_context ctx = { .dev = dev }; + + while (genode_uplink_rx(dev_genode_uplink(dev), + uplink_rx_one_packet, + &ctx)); + } + }; + + /* block until lx_emul_task_unblock */ + lx_emul_task_schedule(true); + } + return 0; +} + + +static struct task_struct *nic_task_struct_ptr; + + +void lx_emul_nic_init(void) +{ + pid_t pid; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,3,0) + pid = kernel_thread(nic_task_function, NULL, "user_task", CLONE_FS | CLONE_FILES); +#else + pid = kernel_thread(nic_task_function, NULL, CLONE_FS | CLONE_FILES); +#endif + + nic_task_struct_ptr = find_task_by_pid_ns(pid, NULL); +} + + +void lx_emul_nic_handle_io(void) +{ + if (nic_task_struct_ptr) lx_emul_task_unblock(nic_task_struct_ptr); +} + + +void lx_emul_nic_set_mac_address(const unsigned char *mac, unsigned long size) +{ + memcpy(mac_address, mac, min(sizeof(mac_address), size)); + mac_address_configured = false; +} diff --git a/repos/dde_linux/src/lib/lx_emul/pin.cc b/repos/dde_linux/src/lib/lx_emul/pin.cc index 2b477d3b4a..0cb9796a2c 100644 --- a/repos/dde_linux/src/lib/lx_emul/pin.cc +++ b/repos/dde_linux/src/lib/lx_emul/pin.cc @@ -24,19 +24,25 @@ namespace { using namespace Genode; - class Global_irq_controller : Noncopyable + class Global_irq_controller : Lx_kit::Device, Noncopyable { private: Lx_kit::Env &_env; - unsigned _pending_irq = 0; + int _pending_irq { -1 }; public: struct Number { unsigned value; }; - Global_irq_controller(Lx_kit::Env &env) : _env(env) { } + Global_irq_controller(Lx_kit::Env &env) + : + Lx_kit::Device(env.platform, "pin_irq"), + _env(env) + { + _env.devices.insert(this); + } void trigger_irq(Number number) { @@ -45,6 +51,14 @@ namespace { _env.scheduler.unblock_irq_handler(); _env.scheduler.schedule(); } + + int pending_irq() override + { + int irq = _pending_irq; + _pending_irq = -1; + + return irq; + } }; using Pin_name = Session_label; diff --git a/repos/dde_linux/src/lib/lx_emul/start.c b/repos/dde_linux/src/lib/lx_emul/start.c index e64b6732f0..aad3ba6a19 100644 --- a/repos/dde_linux/src/lib/lx_emul/start.c +++ b/repos/dde_linux/src/lib/lx_emul/start.c @@ -132,8 +132,6 @@ int lx_emul_init_task_function(void * dtb) * Here we do the minimum normally done start_kernel() of init/main.c */ - lx_emul_setup_arch(dtb); - jump_label_init(); kmem_cache_init(); wait_bit_init(); @@ -143,6 +141,12 @@ int lx_emul_init_task_function(void * dtb) maple_tree_init(); #endif + /* + * unflatten_device tree requires memblock, so kmem_cache_init has to be + * called before lx_emul_setup_arch on ARM platforms + */ + lx_emul_setup_arch(dtb); + workqueue_init_early(); skb_init(); diff --git a/repos/dde_linux/src/lib/wifi/lx_emul.c b/repos/dde_linux/src/lib/wifi/lx_emul.c index a8c0712862..05e3d1f58b 100644 --- a/repos/dde_linux/src/lib/wifi/lx_emul.c +++ b/repos/dde_linux/src/lib/wifi/lx_emul.c @@ -179,7 +179,7 @@ int request_firmware_common(const struct firmware **firmware_p, { struct firmware *fw; - if (!*firmware_p) + if (!firmware_p) return -1; fw = kzalloc(sizeof(struct firmware), GFP_KERNEL); @@ -460,10 +460,10 @@ static int rfkill_task_function(void *arg) bool rfkilled = !!rfkill_get_global_sw_state(RFKILL_TYPE_WLAN); - if (rfkilled != _rfkill_state.blocked) + if (rfkilled != _rfkill_state.blocked) { rfkill_switch_all(RFKILL_TYPE_WLAN, !!_rfkill_state.blocked); - - _rfkill_state.rfkilled = rfkilled; + _rfkill_state.rfkilled = !!_rfkill_state.blocked; + } lx_emul_task_schedule(true); } diff --git a/repos/dde_linux/src/lib/wifi/socket_call.cc b/repos/dde_linux/src/lib/wifi/socket_call.cc index a21ca8582d..a646e724f9 100644 --- a/repos/dde_linux/src/lib/wifi/socket_call.cc +++ b/repos/dde_linux/src/lib/wifi/socket_call.cc @@ -54,7 +54,7 @@ enum : int { }; -static int convert_errno_from_linux(int linux_errno) +extern "C" int convert_errno_from_linux(int linux_errno) { if (linux_errno >= 0) return linux_errno; @@ -100,9 +100,7 @@ static int convert_errno_from_linux(int linux_errno) case ENODEV: return -(int)Libc::Errno::BSD_ENODEV; case ENOENT: return -(int)Libc::Errno::BSD_ENOENT; case ENOEXEC: return -(int)Libc::Errno::BSD_ENOEXEC; - case ENOLINK: - error("ENOLINK (", (int) ENOLINK, ") -> ", (int)Libc::Errno::BSD_ENOLINK); - return -(int)Libc::Errno::BSD_ENOLINK; + case ENOLINK: return -(int)Libc::Errno::BSD_ENOLINK; case ENOMEM: return -(int)Libc::Errno::BSD_ENOMEM; case ENOMSG: return -(int)Libc::Errno::BSD_ENOMSG; case ENOPROTOOPT: return -(int)Libc::Errno::BSD_ENOPROTOOPT; diff --git a/repos/dde_linux/src/lib/wifi/symbol.map b/repos/dde_linux/src/lib/wifi/symbol.map index b2f8892648..9d6e7cb346 100644 --- a/repos/dde_linux/src/lib/wifi/symbol.map +++ b/repos/dde_linux/src/lib/wifi/symbol.map @@ -18,6 +18,7 @@ /* interface for libnl/wpa_driver_nl82011 */ wifi_if*; + convert_errno_from_linux; local: diff --git a/repos/dde_linux/src/lib/wifi/wlan.cc b/repos/dde_linux/src/lib/wifi/wlan.cc index 518c3648ba..c7d44eb7eb 100644 --- a/repos/dde_linux/src/lib/wifi/wlan.cc +++ b/repos/dde_linux/src/lib/wifi/wlan.cc @@ -342,7 +342,11 @@ void Wifi::set_rfkill(bool blocked) */ lx_emul_task_unblock(uplink_task_struct_ptr); Lx_kit::env().scheduler.execute(); +} + +void Wifi::rfkill_notify() +{ if (_wlan_ptr->rfkill_helper.constructed()) _wlan_ptr->rfkill_helper->submit_notification(); } diff --git a/repos/dde_linux/src/lib/wpa_driver_nl80211/rfkill_genode.cc b/repos/dde_linux/src/lib/wpa_driver_nl80211/rfkill_genode.cc index c7749c9df4..b85106b9b4 100644 --- a/repos/dde_linux/src/lib/wpa_driver_nl80211/rfkill_genode.cc +++ b/repos/dde_linux/src/lib/wpa_driver_nl80211/rfkill_genode.cc @@ -54,6 +54,8 @@ static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) } else { rfkill->cfg->unblocked_cb(rfkill->cfg->ctx); } + + Wifi::rfkill_notify(); } } diff --git a/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.c b/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.c deleted file mode 100644 index fc5d359665..0000000000 --- a/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * \brief WPA Supplicant frontend - * \author Josef Soentgen - * \date 2018-07-18 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -/* - * based on: - * - * WPA Supplicant / UNIX domain socket -based control interface - * Copyright (c) 2004-2014, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -/* wpa_supplicant includes */ -#include "includes.h" -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/list.h" -#include "common/ctrl_iface_common.h" -#include "eapol_supp/eapol_supp_sm.h" -#include "config.h" -#include "wpa_supplicant_i.h" -#include "ctrl_iface.h" - -/* rep includes */ -#include - -typedef unsigned unaligned_unsigned __attribute__ ((aligned (1))); - -struct ctrl_iface_priv { - struct wpa_supplicant *wpa_s; - int fd; - int level; - - /* TODO replace w/ Msg_buffer */ - char *send_buffer; - size_t send_buffer_size; - unaligned_unsigned *send_id; - - char *recv_buffer; - size_t recv_buffer_size; - unaligned_unsigned *recv_id; - - unsigned last_recv_id; - - char *event_buffer; - size_t event_buffer_size; - unaligned_unsigned *event_id; -}; - - -struct ctrl_iface_global_priv { - struct wpa_global *global; -}; - - -extern void nl_set_wpa_ctrl_fd(void); - - -void wpa_ctrl_set_fd() -{ - nl_set_wpa_ctrl_fd(); -} - - -static void send_reply(struct ctrl_iface_priv *priv, char const *txt, size_t len) -{ - char *msg = priv->send_buffer; - size_t mlen = priv->send_buffer_size; - - if (len >= mlen) { - len = mlen - 1; - } - - memcpy(msg, txt, len); - msg[len] = 0; - (*priv->send_id)++; -} - - -/* - * This function is called by wpa_supplicant whenever it receives a - * command via the CTRL interface, i.e. the front end has sent a new - * message. - */ -static void wpa_supplicant_ctrl_iface_receive(int fd, void *eloop_ctx, - void *sock_ctx) -{ - struct wpa_supplicant *wpa_s = eloop_ctx; - struct ctrl_iface_priv *priv = sock_ctx; - - char *msg = priv->recv_buffer; - - unsigned const recv_id = *priv->recv_id; - - char *reply = NULL; - size_t reply_len = 0; - - if (msg[0] == 0 || recv_id == priv->last_recv_id) { return; } - - priv->last_recv_id = recv_id; - - reply = wpa_supplicant_ctrl_iface_process(wpa_s, msg, - &reply_len); - - if (reply) { - wifi_block_for_processing(); - send_reply(priv, reply, reply_len); - wifi_notify_cmd_result(); - os_free(reply); - } else - - if (reply_len == 1) { - wifi_block_for_processing(); - send_reply(priv, "FAIL", 4); - wifi_notify_cmd_result(); - } else - - if (reply_len == 2) { - wifi_block_for_processing(); - send_reply(priv, "OK", 2); - wifi_notify_cmd_result(); - } -} - - -static void send_event(struct ctrl_iface_priv *priv, char const *txt, size_t len) -{ - char *msg = priv->event_buffer; - size_t mlen = priv->event_buffer_size; - - if (len >= mlen) { - len = mlen - 1; - } - - memcpy(msg, txt, len); - msg[len] = 0; - (*priv->event_id)++; -} - - -/* - * This function is called by wpa_supplicant whenever it wants to - * forward some message. We filter these messages and forward only - * those, which are of interest to the front end. - */ -static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, - enum wpa_msg_type type, - const char *txt, size_t len) -{ - /* there is not global support */ - if (type == WPA_MSG_ONLY_GLOBAL) { return; } - - struct wpa_supplicant *wpa_s = ctx; - if (wpa_s == NULL) { return; } - - struct ctrl_iface_priv *priv = wpa_s->ctrl_iface; - if (!priv || level < priv->level) { return; } - - /* - * Filter messages and only forward events the front end cares - * about or rather knows how to handle. - */ - int const forward = - strncmp(txt, "CTRL-EVENT-SCAN-RESULTS", 23) == 0 - || strncmp(txt, "CTRL-EVENT-CONNECTED", 20) == 0 - || strncmp(txt, "CTRL-EVENT-DISCONNECTED", 23) == 0 - || strncmp(txt, "CTRL-EVENT-NETWORK-NOT-FOUND", 28) == 0 - /* needed to detect connecting state */ - || strncmp(txt, "SME: Trying to authenticate", 27) == 0 - ; - if (!forward) { return; } - - wifi_notify_event(); - send_event(priv, txt, len); -} - - -struct ctrl_iface_priv * -wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) -{ - struct ctrl_iface_priv *priv; - - priv = os_zalloc(sizeof(*priv)); - if (priv == NULL) { return NULL; } - - if (wpa_s->conf->ctrl_interface == NULL) { - return priv; - } - - struct Msg_buffer *msg_buffer = (struct Msg_buffer*)wifi_get_buffer(); - priv->recv_buffer = (char *)msg_buffer->send; - priv->recv_buffer_size = sizeof(msg_buffer->send); - priv->send_buffer = (char *)msg_buffer->recv; - priv->send_buffer_size = sizeof(msg_buffer->recv); - priv->send_id = &msg_buffer->recv_id; - priv->recv_id = &msg_buffer->send_id; - - priv->event_buffer = (char *)msg_buffer->event; - priv->event_buffer_size = sizeof(msg_buffer->event); - priv->event_id = &msg_buffer->event_id; - - priv->level = MSG_INFO; - priv->fd = WPA_CTRL_FD; - - eloop_register_read_sock(priv->fd, - wpa_supplicant_ctrl_iface_receive, - wpa_s, priv); - - wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); - return priv; -} - - -void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, - struct ctrl_iface_priv *priv) -{ - (void)wpa_s; - - os_free(priv); -} - - -void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { } - - -struct ctrl_iface_global_priv * -wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) -{ - struct ctrl_iface_global_priv *priv; - - priv = os_zalloc(sizeof(*priv)); - return priv; -} - - -void wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *p) -{ - os_free(p); -} diff --git a/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.cc b/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.cc new file mode 100644 index 0000000000..9dfac61e1d --- /dev/null +++ b/repos/dde_linux/src/lib/wpa_supplicant/ctrl_iface_genode.cc @@ -0,0 +1,240 @@ +/* + * \brief Genode-specific WPA supplicant ctrl_iface + * \author Josef Soentgen + * \date 2018-07-18 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +/* + * based on: + * + * WPA Supplicant / UNIX domain socket -based control interface + * Copyright (c) 2004-2014, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +/* wpa_supplicant includes */ +extern "C" { +#include "includes.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/list.h" +#include "common/ctrl_iface_common.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +} + +/* rep includes */ +#include + + +static Wifi::Msg_buffer *_msg_buffer; + + +void Wifi::ctrl_init(Msg_buffer &buffer) +{ + _msg_buffer = &buffer; +} + + +struct ctrl_iface_priv { + struct wpa_supplicant *wpa_s; + int fd; + int level; + + Wifi::Msg_buffer *buffer; + unsigned last_send_id; +}; + + +struct ctrl_iface_global_priv { + struct wpa_global *global; +}; + + +extern "C" +void nl_set_wpa_ctrl_fd(void); + + +void wpa_ctrl_set_fd() +{ + nl_set_wpa_ctrl_fd(); +} + + +static void send_reply(Wifi::Msg_buffer &buffer, char const *txt, size_t len) +{ + buffer.block_for_processing(); + + /* XXX hack to trick poll() into returning faster */ + wpa_ctrl_set_fd(); + + if (len >= sizeof(buffer.recv)) + len = sizeof(buffer.recv) - 1; + + memcpy(buffer.recv, txt, len); + buffer.recv[len] = 0; + buffer.recv_id++; + + buffer.notify_response(); +} + + +/* + * This function is called by wpa_supplicant whenever it receives a + * command via the CTRL interface, i.e. the manager has sent a new + * message. + */ +static void wpa_supplicant_ctrl_iface_receive(int fd, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = static_cast(eloop_ctx); + struct ctrl_iface_priv *priv = static_cast(sock_ctx); + + Wifi::Msg_buffer &buffer = *priv->buffer; + + char *reply = NULL; + size_t reply_len = 0; + + if (buffer.send[0] == 0 || buffer.send_id == priv->last_send_id) + return; + + priv->last_send_id = buffer.send_id; + + reply = wpa_supplicant_ctrl_iface_process(wpa_s, + buffer.send, + &reply_len); + + if (reply) { + send_reply(buffer, reply, reply_len); + os_free(reply); + } else + + if (reply_len == 1) { + send_reply(buffer, "FAIL", 4); + } else + + if (reply_len == 2) { + send_reply(buffer, "OK", 2); + } +} + + +static void send_event(Wifi::Msg_buffer &buffer, char const *txt, size_t len) +{ + buffer.block_for_processing(); + + /* XXX hack to trick poll() into returning faster */ + wpa_ctrl_set_fd(); + + if (len >= sizeof(buffer.event)) + len = sizeof(buffer.event) - 1; + + memcpy(buffer.event, txt, len); + buffer.event[len] = 0; + buffer.event_id++; + + buffer.notify_event(); +} + + +/* + * This function is called by wpa_supplicant whenever it wants to + * forward some message. We filter these messages and forward only + * those, which are of interest to the Wifi manager. + */ +static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, + enum wpa_msg_type type, + const char *txt, size_t len) +{ + /* there is not global support */ + if (type == WPA_MSG_ONLY_GLOBAL) + return; + + struct wpa_supplicant *wpa_s = static_cast(ctx); + if (wpa_s == NULL) + return; + + struct ctrl_iface_priv *priv = wpa_s->ctrl_iface; + if (!priv || level < priv->level) + return; + + /* + * Filter messages and only forward events the manager cares + * about or rather knows how to handle. + */ + bool const forward = + strncmp(txt, "CTRL-EVENT-SCAN-RESULTS", 23) == 0 + || strncmp(txt, "CTRL-EVENT-CONNECTED", 20) == 0 + || strncmp(txt, "CTRL-EVENT-DISCONNECTED", 23) == 0 + || strncmp(txt, "CTRL-EVENT-NETWORK-NOT-FOUND", 28) == 0 + /* needed to detect connecting state */ + || strncmp(txt, "SME: Trying to authenticate", 27) == 0; + if (!forward) + return; + + Wifi::Msg_buffer &buffer = *priv->buffer; + send_event(buffer, txt, len); +} + + +extern "C" struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv = (ctrl_iface_priv*)os_zalloc(sizeof(*priv)); + if (priv == NULL) { return NULL; } + + if (wpa_s->conf->ctrl_interface == NULL) { + return priv; + } + + priv->buffer = _msg_buffer; + priv->level = MSG_INFO; + priv->fd = Wifi::CTRL_FD; + + eloop_register_read_sock(priv->fd, + wpa_supplicant_ctrl_iface_receive, + wpa_s, priv); + + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); + return priv; +} + +extern "C" +void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, + struct ctrl_iface_priv *priv) +{ + (void)wpa_s; + + os_free(priv); +} + + +extern "C" +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { } + + +extern "C" struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *priv = + (ctrl_iface_global_priv*)os_zalloc(sizeof(*priv)); + return priv; +} + + +extern "C" +void wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *p) +{ + os_free(p); +} diff --git a/repos/dde_linux/src/lib/wpa_supplicant/main.c b/repos/dde_linux/src/lib/wpa_supplicant/main.c index 0a18ba610f..7bc61b7108 100644 --- a/repos/dde_linux/src/lib/wpa_supplicant/main.c +++ b/repos/dde_linux/src/lib/wpa_supplicant/main.c @@ -1,5 +1,5 @@ /* - * \brief WPA Supplicant frontend + * \brief Custom WPA Supplicant main routine * \author Josef Soentgen * \date 2014-12-08 */ @@ -45,8 +45,7 @@ int wpa_main(void) memset(¶ms, 0, sizeof(params)); - // TODO use CTRL interface for setting debug level - params.wpa_debug_level = 1 ? MSG_DEBUG : MSG_INFO; + params.wpa_debug_level = MSG_ERROR; params.ctrl_interface = "GENODE"; global = wpa_supplicant_init(¶ms); diff --git a/repos/dde_linux/src/lib/wpa_supplicant/symbol.map b/repos/dde_linux/src/lib/wpa_supplicant/symbol.map index 9110d727b2..6db93374fe 100644 --- a/repos/dde_linux/src/lib/wpa_supplicant/symbol.map +++ b/repos/dde_linux/src/lib/wpa_supplicant/symbol.map @@ -7,21 +7,27 @@ /* needed by wifi driver */ wpa_main; wpa_reporter_init; - wpa_ctrl_set_fd; + *wpa_ctrl_set_fd*; + *ctrl_init*; /* needed by wpa_driver_nl80211 */ __hide_aliasing_typecast; + channel_width_to_int; eloop_*; + fc2str*; get_hdr_bssid; + get_ie*; + get_ml_ie; ieee80211_freq_to_chan; ieee80211_radiotap_*; + ieee802_11_defrag; + ieee802_11_parse_elems; + is_6ghz_freq; + is_same_band; os_*; + sha1_vector*; wpa_*; wpabuf_*; - sha1_vector*; - get_ie*; - fc2str*; - is_6ghz_freq; local: diff --git a/repos/dde_rump/recipes/pkg/ext2_fs/hash b/repos/dde_rump/recipes/pkg/ext2_fs/hash index 8698e52120..5a126489a6 100644 --- a/repos/dde_rump/recipes/pkg/ext2_fs/hash +++ b/repos/dde_rump/recipes/pkg/ext2_fs/hash @@ -1 +1 @@ -2024-08-28 cd657483ba93236252970c2b67cac318ecda0f76 +2024-10-07 3b78de56d7957b75c20d407055bd72ff08c5e231 diff --git a/repos/dde_rump/recipes/src/vfs_rump/hash b/repos/dde_rump/recipes/src/vfs_rump/hash index 733ddcad1d..7b78474c92 100644 --- a/repos/dde_rump/recipes/src/vfs_rump/hash +++ b/repos/dde_rump/recipes/src/vfs_rump/hash @@ -1 +1 @@ -2024-08-28 c1c8f14f76d62c6edeaffa136657552a557465ad +2024-10-07 ff61b93700f9eb0d7d2441c4bc17aba1785090d9 diff --git a/repos/demo/include/scout/graphics_backend_impl.h b/repos/demo/include/scout/graphics_backend_impl.h index 9f02aacb7b..c8d49b561b 100644 --- a/repos/demo/include/scout/graphics_backend_impl.h +++ b/repos/demo/include/scout/graphics_backend_impl.h @@ -45,9 +45,7 @@ class Scout::Graphics_backend_impl : public Graphics_backend Genode::Dataspace_capability _init_fb_ds(Area max_size) { - Framebuffer::Mode const mode { .area = { max_size.w, max_size.h*2 }}; - - _gui.buffer(mode, false); + _gui.buffer({ .area = { max_size.w, max_size.h*2 }, .alpha = false }); return _gui.framebuffer.dataspace(); } @@ -58,37 +56,22 @@ class Scout::Graphics_backend_impl : public Graphics_backend Point _position; Area _view_size; - Canvas_base *_canvas[2]; bool _flip_state = { false }; Gui::Top_level_view _view { _gui, { _position, _view_size } }; - void _update_viewport() - { - using Command = Gui::Session::Command; - - Gui::Rect rect(_position, _view_size); - _gui.enqueue(_view.id(), rect); - - Gui::Point offset(0, _flip_state ? -_max_size.h : 0); - _gui.enqueue(_view.id(), offset); - - _gui.execute(); - } - - void _refresh_view(Rect rect) - { - int const y_offset = _flip_state ? _max_size.h : 0; - _gui.framebuffer.refresh(rect.x1(), rect.y1() + y_offset, - rect.w(), rect.h()); - } - template PT *_base(unsigned idx) { return (PT *)_fb_ds.local_addr() + idx*_max_size.count(); } + using PT = Genode::Pixel_rgb888; + + Canvas _canvas_0, _canvas_1; + + Canvas_base *_canvas[2] { &_canvas_0, &_canvas_1 }; + unsigned _front_idx() const { return _flip_state ? 1 : 0; } unsigned _back_idx() const { return _flip_state ? 0 : 1; } @@ -108,15 +91,10 @@ class Scout::Graphics_backend_impl : public Graphics_backend _gui(gui), _max_size(max_size), _position(position), - _view_size(view_size) - { - using PT = Genode::Pixel_rgb888; - static Canvas canvas_0(_base(0), max_size, alloc); - static Canvas canvas_1(_base(1), max_size, alloc); - - _canvas[0] = &canvas_0; - _canvas[1] = &canvas_1; - } + _view_size(view_size), + _canvas_0(_base(0), max_size, alloc), + _canvas_1(_base(1), max_size, alloc) + { } /******************************** @@ -128,34 +106,22 @@ class Scout::Graphics_backend_impl : public Graphics_backend void copy_back_to_front(Rect rect) override { + Point const from = rect.p1() + Point { 0, int( _back_idx()*_max_size.h) }; + Point const to = rect.p1() + Point { 0, int(_front_idx()*_max_size.h) }; - using PT = Genode::Pixel_rgb888; - - PT const *src = _base( _back_idx()); - PT *dst = _base(_front_idx()); - - unsigned long const offset = rect.y1()*_max_size.w + rect.x1(); - - src += offset; - dst += offset; - - blit(src, (unsigned)sizeof(PT)*_max_size.w, dst, - (int)sizeof(PT)*_max_size.w, - (int)sizeof(PT)*rect.w(), rect.h()); - - _refresh_view(rect); + _gui.framebuffer.blit({ from, rect.area }, to); } void swap_back_and_front() override { _flip_state = !_flip_state; - _update_viewport(); + _gui.framebuffer.panning({ 0, int(_front_idx()*_max_size.h) }); } void position(Point p) override { _position = p; - _update_viewport(); + _view.at(p); } void bring_to_front() override @@ -166,6 +132,7 @@ class Scout::Graphics_backend_impl : public Graphics_backend void view_area(Area area) override { _view_size = area; + _view.area(area); } }; diff --git a/repos/demo/recipes/src/demo/hash b/repos/demo/recipes/src/demo/hash index 33a7f5b195..ed812ba23d 100644 --- a/repos/demo/recipes/src/demo/hash +++ b/repos/demo/recipes/src/demo/hash @@ -1 +1 @@ -2024-08-28 14eede134747889773a1c019754dcd2b3dfcb370 +2024-10-29 32f67fc7f2de8d00e39e3c71d5401792f60cfcd8 diff --git a/repos/demo/src/server/liquid_framebuffer/main.cc b/repos/demo/src/server/liquid_framebuffer/main.cc index f3ef47dd00..01955f9c89 100644 --- a/repos/demo/src/server/liquid_framebuffer/main.cc +++ b/repos/demo/src/server/liquid_framebuffer/main.cc @@ -125,7 +125,8 @@ namespace Liquid_fb { } -class Liquid_fb::Main : public Scout::Event_handler +class Liquid_fb::Main : public Scout::Event_handler, + private Input::Session_component::Action { private: @@ -162,7 +163,16 @@ class Liquid_fb::Main : public Scout::Event_handler _graphics_backend { _env.rm(), _gui, _heap, _max_size, _initial_position, _initial_size }; - Input::Session_component _input_session_component { _env, _env.ram() }; + Input::Session_component _input_session_component { + _env.ep(), _env.ram(), _env.rm(), *this }; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool enabled) override + { + _gui.input.exclusive(enabled); + } bool const _window_content_initialized = (init_window_content(_env.ram(), _env.rm(), _heap, _input_session_component, diff --git a/repos/demo/src/server/liquid_framebuffer/services.cc b/repos/demo/src/server/liquid_framebuffer/services.cc index 208ee1ff86..bec5a210c2 100644 --- a/repos/demo/src/server/liquid_framebuffer/services.cc +++ b/repos/demo/src/server/liquid_framebuffer/services.cc @@ -239,10 +239,10 @@ class Framebuffer::Session_component : public Genode::Rpc_object public: - Session_component(Genode::Env &env, Window_content &window_content) + Session_component(Env &env, Window_content &window_content) : _timer(env), _window_content(window_content) { } - Genode::Dataspace_capability dataspace() override + Dataspace_capability dataspace() override { _window_content.realloc_framebuffer(); return _window_content.fb_ds_cap(); @@ -250,21 +250,36 @@ class Framebuffer::Session_component : public Genode::Rpc_object Mode mode() const override { - return Mode { .area = _window_content.mode_size() }; + return { .area = _window_content.mode_size(), .alpha = false }; } - void mode_sigh(Genode::Signal_context_capability sigh) override { - _window_content.mode_sigh(sigh); } + void mode_sigh(Signal_context_capability sigh) override + { + _window_content.mode_sigh(sigh); + } - void sync_sigh(Genode::Signal_context_capability sigh) override + void sync_sigh(Signal_context_capability sigh) override { _timer.sigh(sigh); _timer.trigger_periodic(10*1000); } - void refresh(int x, int y, int w, int h) override + void sync_source(Session_label const &) override { } + + void refresh(Rect rect) override { - _window_content.redraw_area(x, y, w, h); + _window_content.redraw_area(rect.x1(), rect.y1(), rect.w(), rect.h()); + } + + Blit_result blit(Blit_batch const &) override + { + warning("Framebuffer::Session::blit not supported"); + return Blit_result::OK; + } + + void panning(Point) override + { + warning("Framebuffer::Session::panning not supported"); } }; @@ -285,7 +300,27 @@ void init_services(Genode::Env &env, Input::Session_component &input_component) using namespace Genode; static Framebuffer::Session_component fb_session(env, *_window_content); - static Static_root fb_root(env.ep().manage(fb_session)); + + env.ep().manage(fb_session); + + struct Fb_root : Static_root + { + Framebuffer::Session_component &_fb_session; + + Fb_root(Framebuffer::Session_component &fb_session) + : + Static_root(fb_session.cap()), + _fb_session(fb_session) + { } + + void close(Genode::Capability) override + { + _fb_session.sync_sigh(Genode::Signal_context_capability()); + _fb_session.mode_sigh(Genode::Signal_context_capability()); + } + }; + + static Fb_root fb_root { fb_session }; static Input::Root_component input_root(env.ep().rpc_ep(), input_component); diff --git a/repos/demo/src/server/nitlog/main.cc b/repos/demo/src/server/nitlog/main.cc index 8b4ef8d1ff..b2efdf9ad2 100644 --- a/repos/demo/src/server/nitlog/main.cc +++ b/repos/demo/src/server/nitlog/main.cc @@ -366,7 +366,7 @@ struct Nitlog::Main void _init_gui_buffer() { - _gui.buffer(Framebuffer::Mode { .area = { _win_w, _win_h } }, false); + _gui.buffer({ .area = { _win_w, _win_h }, .alpha = false }); } bool const _gui_buffer_initialized = (_init_gui_buffer(), true); @@ -444,7 +444,7 @@ struct Nitlog::Main void _handle_timer() { if (_log_window.draw()) - _gui.framebuffer.refresh(0, 0, _win_w, _win_h); + _gui.framebuffer.refresh({ { 0, 0 }, { _win_w, _win_h } }); } Main(Env &env) : _env(env) diff --git a/repos/gems/include/dialog/sandboxed_runtime.h b/repos/gems/include/dialog/sandboxed_runtime.h index 33f10fd029..8385edc86d 100644 --- a/repos/gems/include/dialog/sandboxed_runtime.h +++ b/repos/gems/include/dialog/sandboxed_runtime.h @@ -102,7 +102,7 @@ class Dialog::Sandboxed_runtime : Noncopyable { Start_name const name; Ram_quota const initial_ram { 4*1024*1024 }; - Cap_quota const initial_caps { 100 }; + Cap_quota const initial_caps { 130 }; Ram_quota ram = initial_ram; Cap_quota caps = initial_caps; diff --git a/repos/gems/include/gems/gui_buffer.h b/repos/gems/include/gems/gui_buffer.h index cfc87a17a9..5fc015dc5b 100644 --- a/repos/gems/include/gems/gui_buffer.h +++ b/repos/gems/include/gems/gui_buffer.h @@ -15,14 +15,8 @@ #define _INCLUDE__GEMS__GUI_BUFFER_H_ /* Genode includes */ -#include #include -#include #include -#include -#include -#include -#include struct Gui_buffer : Genode::Noncopyable @@ -36,50 +30,38 @@ struct Gui_buffer : Genode::Noncopyable using Point = Genode::Surface_base::Point; using Ram_ds = Genode::Attached_ram_dataspace; using size_t = Genode::size_t; + using uint8_t = Genode::uint8_t; - Genode::Ram_allocator &ram; - Genode::Region_map &rm; + Genode::Ram_allocator &_ram; + Genode::Region_map &_rm; - Gui::Connection &gui; + Gui::Connection &_gui; Framebuffer::Mode const mode; - bool const use_alpha; + /* + * Make the GUI mode twice as high as the requested mode. The upper part + * of the GUI framebuffer contains the front buffer, the lower part + * contains the back buffer. + */ + Framebuffer::Mode const _gui_mode { .area = { mode.area.w, mode.area.h*2 }, + .alpha = mode.alpha }; + + Genode::Surface_window const _backbuffer { .y = mode.area.h, .h = mode.area.h }; Pixel_rgb888 const reset_color; - /** - * Return dataspace capability for virtual framebuffer - */ - Genode::Dataspace_capability _ds_cap(Gui::Connection &gui) - { - /* setup virtual framebuffer mode */ - gui.buffer(mode, use_alpha); - - return gui.framebuffer.dataspace(); - } - - Genode::Attached_dataspace fb_ds { rm, _ds_cap(gui) }; - - size_t pixel_surface_num_bytes() const - { - return size().count()*sizeof(Pixel_rgb888); - } - - size_t alpha_surface_num_bytes() const - { - return use_alpha ? size().count() : 0; - } - - Ram_ds pixel_surface_ds { ram, rm, pixel_surface_num_bytes() }; - Ram_ds alpha_surface_ds { ram, rm, alpha_surface_num_bytes() }; + Genode::Attached_dataspace _fb_ds { + _rm, ( _gui.buffer(_gui_mode), _gui.framebuffer.dataspace() ) }; enum class Alpha { OPAQUE, ALPHA }; - static Genode::Color default_reset_color() - { - return Genode::Color(127, 127, 127, 255); - } + /* + * Do not use black by default to limit the bleeding of black into + * antialiased drawing operations applied onto an initially transparent + * background. + */ + static constexpr Genode::Color default_reset_color = { 127, 127, 127, 255 }; /** * Constructor @@ -87,39 +69,42 @@ struct Gui_buffer : Genode::Noncopyable Gui_buffer(Gui::Connection &gui, Area size, Genode::Ram_allocator &ram, Genode::Region_map &rm, Alpha alpha = Alpha::ALPHA, - Genode::Color reset_color = default_reset_color()) + Genode::Color reset_color = default_reset_color) : - ram(ram), rm(rm), gui(gui), + _ram(ram), _rm(rm), _gui(gui), mode({ .area = { Genode::max(1U, size.w), - Genode::max(1U, size.h) } }), - use_alpha(alpha == Alpha::ALPHA), + Genode::max(1U, size.h) }, + .alpha = (alpha == Alpha::ALPHA) }), reset_color(reset_color.r, reset_color.g, reset_color.b, reset_color.a) { reset_surface(); } /** - * Return size of virtual framebuffer + * Return size of the drawing surface */ Area size() const { return mode.area; } - template - void with_alpha_surface(FN const &fn) + void with_alpha_surface(auto const &fn) { - Area const alpha_size = use_alpha ? size() : Area(0, 0); - Alpha_surface alpha(alpha_surface_ds.local_addr(), alpha_size); - fn(alpha); + if (!_gui_mode.alpha) { + Alpha_surface dummy { nullptr, Gui::Area { } }; + fn(dummy); + return; + } + _gui_mode.with_alpha_surface(_fb_ds, [&] (Alpha_surface &surface) { + surface.with_window(_backbuffer, [&] (Alpha_surface &surface) { + fn(surface); }); }); } - template - void with_pixel_surface(FN const &fn) + void with_pixel_surface(auto const &fn) { - Pixel_surface pixel(pixel_surface_ds.local_addr(), size()); - fn(pixel); + _gui_mode.with_pixel_surface(_fb_ds, [&] (Pixel_surface &surface) { + surface.with_window(_backbuffer, [&] (Pixel_surface &surface) { + fn(surface); }); }); } - template - void apply_to_surface(FN const &fn) + void apply_to_surface(auto const &fn) { with_alpha_surface([&] (Alpha_surface &alpha) { with_pixel_surface([&] (Pixel_surface &pixel) { @@ -128,18 +113,11 @@ struct Gui_buffer : Genode::Noncopyable void reset_surface() { - if (use_alpha) - with_alpha_surface([&] (Alpha_surface &alpha) { - Genode::memset(alpha.addr(), 0, alpha_surface_num_bytes()); }); + with_alpha_surface([&] (Alpha_surface &alpha) { + Genode::memset(alpha.addr(), 0, alpha.size().count()); }); with_pixel_surface([&] (Pixel_surface &pixel) { - /* - * Initialize color buffer with 50% gray - * - * We do not use black to limit the bleeding of black into antialiased - * drawing operations applied onto an initially transparent background. - */ Pixel_rgb888 *dst = pixel.addr(); Pixel_rgb888 const color = reset_color; @@ -148,71 +126,40 @@ struct Gui_buffer : Genode::Noncopyable }); } - template - void _convert_back_to_front(DST_PT *front_base, - Genode::Texture const &texture, - Rect const clip_rect) - { - Genode::Surface surface(front_base, size()); - - surface.clip(clip_rect); - - Blit_painter::paint(surface, texture, Point()); - } - void _update_input_mask() { - if (!use_alpha) - return; + with_alpha_surface([&] (Alpha_surface &alpha) { - size_t const num_pixels = size().count(); + using Input_surface = Genode::Surface; - unsigned char * const alpha_base = fb_ds.local_addr() - + mode.bytes_per_pixel()*num_pixels; + _gui_mode.with_input_surface(_fb_ds, [&] (Input_surface &input) { + input.with_window(_backbuffer, [&] (Input_surface &input) { - unsigned char * const input_base = alpha_base + num_pixels; + uint8_t const * src = (uint8_t *)alpha.addr(); + uint8_t * dst = (uint8_t *)input.addr(); - unsigned char const *src = alpha_base; - unsigned char *dst = input_base; + /* + * Set input mask for all pixels where the alpha value is + * above a given threshold. The threshold is defined such + * that typical drop shadows are below the value. + */ + uint8_t const threshold = 100; + size_t const num_pixels = Genode::min(alpha.size().count(), + input.size().count()); - /* - * Set input mask for all pixels where the alpha value is above a - * given threshold. The threshold is defined such that typical - * drop shadows are below the value. - */ - unsigned char const threshold = 100; - - for (unsigned i = 0; i < num_pixels; i++) - *dst++ = (*src++) > threshold; + for (unsigned i = 0; i < num_pixels; i++) + *dst++ = (*src++) > threshold; + }); + }); + }); } void flush_surface() { - // XXX track dirty rectangles - Rect const clip_rect(Genode::Surface_base::Point(0, 0), size()); + _update_input_mask(); - { - /* represent back buffer as texture */ - Genode::Texture - pixel_texture(pixel_surface_ds.local_addr(), - nullptr, size()); - Pixel_rgb888 *pixel_base = fb_ds.local_addr(); - - _convert_back_to_front(pixel_base, pixel_texture, clip_rect); - } - - if (use_alpha) { - Genode::Texture - alpha_texture(alpha_surface_ds.local_addr(), - nullptr, size()); - - Pixel_alpha8 *alpha_base = fb_ds.local_addr() - + mode.bytes_per_pixel()*size().count(); - - _convert_back_to_front(alpha_base, alpha_texture, clip_rect); - - _update_input_mask(); - } + /* copy lower part of virtual framebuffer to upper part */ + _gui.framebuffer.blit({ { 0, int(size().h) }, size() }, { 0, 0 }); } }; diff --git a/repos/gems/include/gems/vfs_font.h b/repos/gems/include/gems/vfs_font.h index 52be3c4e65..8a8067530c 100644 --- a/repos/gems/include/gems/vfs_font.h +++ b/repos/gems/include/gems/vfs_font.h @@ -60,11 +60,22 @@ class Genode::Vfs_font : public Text_painter::Font Glyph_header() { } - Glyph glyph() const { return Glyph { .width = _width, - .height = _height, - .vpos = _vpos, - .advance = _advance(), - .values = _values }; } + Advance_info advance_info() const + { + return { .width = _width, .advance = _advance() }; + } + + void with_glyph(Text_painter::Area const bb, auto const &fn) const + { + /* consider glyph bounds exceeding the font's bounding box */ + uint8_t const clipped_h = uint8_t(_width ? (bb.count() / _width) : 0u); + + fn(Glyph { .width = _width, + .height = min(_height, clipped_h), + .vpos = _vpos, + .advance = _advance(), + .values = _values }); + } } __attribute__((packed)); @@ -149,7 +160,8 @@ class Genode::Vfs_font : public Text_painter::Font { _glyphs_file.read(_file_pos(c), _buffer); - fn.apply(_buffer.header.glyph()); + _buffer.header.with_glyph(_bounding_box, [&] (Glyph const &glyph) { + fn.apply(glyph); }); } Advance_info advance_info(Codepoint c) const override @@ -158,9 +170,7 @@ class Genode::Vfs_font : public Text_painter::Font _glyphs_file.read(_file_pos(c), header_buffer); - Glyph const glyph = _buffer.header.glyph(); - - return Advance_info { .width = glyph.width, .advance = glyph.advance }; + return _buffer.header.advance_info(); } unsigned baseline() const override { return _baseline; } diff --git a/repos/gems/include/nano3d/scene.h b/repos/gems/include/nano3d/scene.h index 7728a8c20f..196f8788c5 100644 --- a/repos/gems/include/nano3d/scene.h +++ b/repos/gems/include/nano3d/scene.h @@ -86,10 +86,9 @@ class Nano3d::Scene * visible view because it contains the visible buffer, the * front buffer, and the back buffer. */ - bool const use_alpha = true; - unsigned const height = size.h*NUM_BUFFERS; - gui.buffer(Framebuffer::Mode { .area = { size.w, height } }, - use_alpha); + gui.buffer({ .area = { .w = size.w, + .h = size.h*NUM_BUFFERS }, + .alpha = true }); return gui.framebuffer; } diff --git a/repos/gems/recipes/api/gems/hash b/repos/gems/recipes/api/gems/hash index 55edc00338..0609e828a0 100644 --- a/repos/gems/recipes/api/gems/hash +++ b/repos/gems/recipes/api/gems/hash @@ -1 +1 @@ -2024-08-28 9f92618dfcef016aaca5b1963ae33f40626d54de +2024-11-04 e8575582c9a41c25b2ac78247fcc22b7dd68d90d diff --git a/repos/gems/recipes/api/nano3d/hash b/repos/gems/recipes/api/nano3d/hash index 5042f6258b..8c1a3acb49 100644 --- a/repos/gems/recipes/api/nano3d/hash +++ b/repos/gems/recipes/api/nano3d/hash @@ -1 +1 @@ -2024-08-28 2e647171d0de1b6dddb31cc95899999dff02b086 +2024-10-07 e10d9f51cbda23d1e49cd3877eac383f5ec21f6d diff --git a/repos/gems/recipes/pkg/backdrop/hash b/repos/gems/recipes/pkg/backdrop/hash index 45a7258365..e160576591 100644 --- a/repos/gems/recipes/pkg/backdrop/hash +++ b/repos/gems/recipes/pkg/backdrop/hash @@ -1 +1 @@ -2024-08-28 ef02c87b0fda9b5c79c169914cfced6ad709c928 +2024-11-04 b7d904eae19a37ba521331f044c657b5d0bf2c51 diff --git a/repos/gems/recipes/pkg/cpu_load_display/hash b/repos/gems/recipes/pkg/cpu_load_display/hash index 06ac3c3d13..ccc4259fb3 100644 --- a/repos/gems/recipes/pkg/cpu_load_display/hash +++ b/repos/gems/recipes/pkg/cpu_load_display/hash @@ -1 +1 @@ -2024-08-28 5194783789dffe2786da57a9f04403b1540b39b3 +2024-11-04 ab0ee9eddcc48d9dbb672980ae1d8c33641c240a diff --git a/repos/gems/recipes/pkg/dbg_download/hash b/repos/gems/recipes/pkg/dbg_download/hash index 5a6967bc23..3ff8858309 100644 --- a/repos/gems/recipes/pkg/dbg_download/hash +++ b/repos/gems/recipes/pkg/dbg_download/hash @@ -1 +1 @@ -2024-08-28 66beef21dd430e1acd854d550f60f7cdd6673d5f +2024-10-29 bca2b717abc3762e5f804d1a2a1ad37ee7427f69 diff --git a/repos/gems/recipes/pkg/depot_download/hash b/repos/gems/recipes/pkg/depot_download/hash index ae5121d65f..e85ffc0a87 100644 --- a/repos/gems/recipes/pkg/depot_download/hash +++ b/repos/gems/recipes/pkg/depot_download/hash @@ -1 +1 @@ -2024-08-28 e99d0ffe15f9b990a2700776dc7acc9571c163db +2024-10-29 6ac7587114c7c5c0e0c39cec79d558e43be4b2a8 diff --git a/repos/gems/recipes/pkg/drivers_nic-pc/hash b/repos/gems/recipes/pkg/drivers_nic-pc/hash index b3bd511dc6..5c7aae4974 100644 --- a/repos/gems/recipes/pkg/drivers_nic-pc/hash +++ b/repos/gems/recipes/pkg/drivers_nic-pc/hash @@ -1 +1 @@ -2024-08-28 8e059884f22dc1114a03a878e516c21404f1314d +2024-10-29 ea2dd52023f432f627d9e73f126d32e33e7573b7 diff --git a/repos/gems/recipes/pkg/file_vault/hash b/repos/gems/recipes/pkg/file_vault/hash index 7500555f86..d8dd4d2e13 100644 --- a/repos/gems/recipes/pkg/file_vault/hash +++ b/repos/gems/recipes/pkg/file_vault/hash @@ -1 +1 @@ -2024-08-28 c7cf8c9ad08fbaf1195454e8a12f0610177bc448 +2024-11-04 6b945368ee8885f1b91fee5e076d4d94902fca87 diff --git a/repos/gems/recipes/pkg/fonts_fs/hash b/repos/gems/recipes/pkg/fonts_fs/hash index 8088fa762e..f48d15133f 100644 --- a/repos/gems/recipes/pkg/fonts_fs/hash +++ b/repos/gems/recipes/pkg/fonts_fs/hash @@ -1 +1 @@ -2024-08-28 00bbb74b8b3db75992e0b3ceb500cd1ce80f74ac +2024-11-04 5ddd8bd91018464d17194240747714267351aa4c diff --git a/repos/gems/recipes/pkg/goa-linux/hash b/repos/gems/recipes/pkg/goa-linux/hash index 7c35a7c82a..a3e0913fee 100644 --- a/repos/gems/recipes/pkg/goa-linux/hash +++ b/repos/gems/recipes/pkg/goa-linux/hash @@ -1 +1 @@ -2024-08-28 66cf8dd5c0739e6818f0cd51c2b53fff848573f8 +2024-10-07 01f0f61a2be72c244afeb3f3d4db8a1f3dcd9ca7 diff --git a/repos/gems/recipes/pkg/goa/archives b/repos/gems/recipes/pkg/goa/archives index a48986b2d9..9c43233eab 100644 --- a/repos/gems/recipes/pkg/goa/archives +++ b/repos/gems/recipes/pkg/goa/archives @@ -7,6 +7,7 @@ _/src/compat-libc _/src/coreutils _/src/event_filter _/src/file_terminal +_/src/fs_query _/src/fs_report _/src/fs_rom _/src/gui_fb @@ -28,12 +29,16 @@ _/src/sed _/src/stdcxx _/src/stdin2out _/src/terminal +_/src/terminal_crosslink _/src/terminal_log _/src/vfs +_/src/vfs_audit +_/src/vfs_block _/src/vfs_import _/src/vfs_jitterentropy _/src/vfs_lwip _/src/vfs_pipe +_/src/vfs_rump _/src/vfs_ttf _/src/vim _/src/zlib diff --git a/repos/gems/recipes/pkg/goa/hash b/repos/gems/recipes/pkg/goa/hash index 4fb6106cec..f883d955fd 100644 --- a/repos/gems/recipes/pkg/goa/hash +++ b/repos/gems/recipes/pkg/goa/hash @@ -1 +1 @@ -2024-08-28 b6eb36b8998fda9e3f8f295538baf76b0b7c31b3 +2024-11-04 ec3a99b55f1535f8a511e744745eedd567819f6e diff --git a/repos/gems/recipes/pkg/motif_decorator/hash b/repos/gems/recipes/pkg/motif_decorator/hash index 3b417deef2..d506b56d99 100644 --- a/repos/gems/recipes/pkg/motif_decorator/hash +++ b/repos/gems/recipes/pkg/motif_decorator/hash @@ -1 +1 @@ -2024-08-28 5ac652162ed3f6c852aa07c196b11ec148b8baee +2024-11-04 77428f56c3e30b211537eb22ee53f7de1dbf72bb diff --git a/repos/gems/recipes/pkg/motif_decorator/runtime b/repos/gems/recipes/pkg/motif_decorator/runtime index 485bd0b5fc..8a93670391 100644 --- a/repos/gems/recipes/pkg/motif_decorator/runtime +++ b/repos/gems/recipes/pkg/motif_decorator/runtime @@ -1,4 +1,4 @@ - + diff --git a/repos/gems/recipes/pkg/motif_wm/hash b/repos/gems/recipes/pkg/motif_wm/hash index 28fe31667f..0093c330c5 100644 --- a/repos/gems/recipes/pkg/motif_wm/hash +++ b/repos/gems/recipes/pkg/motif_wm/hash @@ -1 +1 @@ -2024-08-28 0d1a81603266603d1d2bc80089fbdd183fc6d89b +2024-11-04 ff4665592a5f2ea8cff0116029e3943cfcdf9308 diff --git a/repos/gems/recipes/pkg/nano3d/hash b/repos/gems/recipes/pkg/nano3d/hash index f413a06853..00d77d01e5 100644 --- a/repos/gems/recipes/pkg/nano3d/hash +++ b/repos/gems/recipes/pkg/nano3d/hash @@ -1 +1 @@ -2024-08-28 4760b4a0b9e51ce6437bfa0b4ca2ccfc5490bdff +2024-10-29 d7776f7094077fa04ee0772be0c9e10396764faf diff --git a/repos/gems/recipes/pkg/osci/hash b/repos/gems/recipes/pkg/osci/hash index 0af17af12c..80fd4a4c94 100644 --- a/repos/gems/recipes/pkg/osci/hash +++ b/repos/gems/recipes/pkg/osci/hash @@ -1 +1 @@ -2024-08-28 ab13c3aab45db919cccf37dfeddc1d84942862a1 +2024-11-04 6b7b0b62150266b843955330f37422b37ee4e559 diff --git a/repos/gems/recipes/pkg/rom_osci/hash b/repos/gems/recipes/pkg/rom_osci/hash index 9801adb246..e05c0ecb6b 100644 --- a/repos/gems/recipes/pkg/rom_osci/hash +++ b/repos/gems/recipes/pkg/rom_osci/hash @@ -1 +1 @@ -2024-08-28 d458670e38599a23e2edf21f8d5c8e686a25f13c +2024-11-04 b97a63dfaa4d0fd364c9ad19db991cfa985f25dd diff --git a/repos/gems/recipes/pkg/screenshot_trigger/hash b/repos/gems/recipes/pkg/screenshot_trigger/hash index a4b363c272..0d21544357 100644 --- a/repos/gems/recipes/pkg/screenshot_trigger/hash +++ b/repos/gems/recipes/pkg/screenshot_trigger/hash @@ -1 +1 @@ -2024-08-28 e4e8816f6e757b7dcc294956335e3d92f4aeb6d3 +2024-11-04 cb0d924392ee07e3b3cb687fb26df8d668a5d4c9 diff --git a/repos/gems/recipes/pkg/sculpt/README b/repos/gems/recipes/pkg/sculpt/README index 555d27342b..b9335b4a6f 100644 --- a/repos/gems/recipes/pkg/sculpt/README +++ b/repos/gems/recipes/pkg/sculpt/README @@ -1,7 +1,7 @@ ============================= - Sculpt Operating System 24.04 + Sculpt Operating System 24.10 ============================= @@ -61,7 +61,7 @@ Your feedback is appreciated! [https://www.genode-labs.com] A printable PDF version of this document is available at the -[https://genode.org/documentation/sculpt-24.04.pdf - Genode website]. +[https://genode.org/documentation/sculpt-24.10.pdf - Genode website]. Hardware requirements and preparations @@ -557,7 +557,7 @@ connectivity. Most importantly, however, it allows the user to access the _config_ and _report_ file systems. Both file systems are readily accessible under the "Files" tab of the panel. The file browser allows you to traverse directory hierarchies, inspect individual files, and edit files. -Alternatively to the "Files" tab, Sculpt 24.04 features a command-line +Alternatively to the "Files" tab, Sculpt 24.10 features a command-line interface. To spawn this command-line interface, click on the "ram fs" component in the graph and select "Inspect". In the panel, a third tab named "Inspect" appears, which hosts the command-line interface. @@ -680,24 +680,6 @@ emulating a scroll wheel by moving the pointer while pressing the middle mouse button (''). -Display settings ----------------- - -If you are running the Intel graphics driver, you can inspect the connected -displays and their supported resolutions by taking a look at the report at -_/report/runtime/intel_fb/connectors_. This report is updated -whenever a display is connected or disconnected. You can use this -information to enable or disable a display in the driver's configuration, -which you can find at _/config/fb_. - -For a quick test, change the attributes 'height="768"' to 'force_height="768"' -and 'width="1024"' to 'force_width="1024"'. When saving the file, the screen -real-estate will forcibly be limited to the specified size. This is helpful -during presentations where the projector has a lower resolution than the -laptop's internal display. By specifying the beamer's resolution, both the -laptop and the beamer show the same content. - - Exploring the drivers and Leitzentrale subsystems ------------------------------------------------- @@ -1477,7 +1459,7 @@ _/config/presets/_. To keep your custom preset available after reboot, follow the pattern described in Section [Making customizations permanent] by copying the file to -_/config/24.04/presets/_ at your Sculpt partition. +_/config/24.10/presets/_ at your Sculpt partition. Installation on disk @@ -1555,6 +1537,102 @@ One way to do that is by changing the system state in _/config/system_ to "reset". +Window management +================= + +The best starting point for realizing a Sculpt-OS-based desktop scenario +is the window-manager preset. Applications connected to the window manager +(wm) appear with window decorations that can be used to arrange, maximize, +or close the window. The window size of a resizeable application can be +changed by dragging the window border. + +Some applications like games may grab the pointer when clicking into their +window. One can regain the control over the pointer at any time by pressing +the 'Super' key. Other useful key combinations are 'Super-Tab' to switch the +keyboard focus between windows, and 'Super-Return' to toggle the maximized +state of the currently focused window. + +One can switch between virtual desktops using the key combinations 'Super+1', +'Super+2', 'Super+3', etc. New windows always appear at the first virtual +desktop. To move a window to a different one, use the system shell to edit +_/rw/recall/window_layouter/recall/rules_. Look out for the '' rule +for the window, and change the target attribute to another screen, e.g., +"screen_2". By editing the rules file, one can do further window manipulations: + +* Changing the order to rules to change the window-stacking order. +* Move or resize a window by changing the corresponding xpos, ypos, width, and + height attributes. +* Maximize/un-maximize a window by setting the maximized attribute + to "yes" or "no". + +As the rules file is a regular file, one can create a backup of the current +window layout by copying the file, and switch between different layouts by +overwriting the rules file by a different version. The window layout is +preserved across reboots because the rules file is a regular file stored on +the used file system, except when using the RAM file system. + + +Multi-monitor support +===================== + +Sculpt OS supports the use of multiple monitors on PCs with Intel graphics. +By default, all connected monitors display the same mirrored image. +This default can be tweaked using the configuration dialog hosted in the +_intel fb_ node of the component graph. + +[image sculpt_24_10_intel_fb] + +The dialog displays a list of present monitors labeled after their respective +connectors. A mode can be selected for each connector when clicking on the +connector entry. In-between the entries there are two buttons. The link +button (showing two vertical lines) is a toggle that defines whether the two +adjacent entries are mirrored or operated as discrete monitors. It is enabled +by default so that all monitors participate in the mirroring. By deselecting +the last enabled link button, the entry below the button becomes a discrete +(non-mirrored) monitor. + +The swap button allows for changing the order of the monitors, which has two +effects. First, the resolution of the very first monitor defines the size for +mirrored image. Hence, by changing the order of mirrored monitors, one can +pick the preferred image size. Second, the order of discrete monitors +defines the layout of a panorama, which spans the mirrored image on the left +followed by each discrete monitor towards the right. + +When using discrete monitors, Sculpt OS places the Leitzentrale GUI on the monitor +that currently hosts the mouse pointer. When moving the pointer from one +monitor to another, the GUI moves with it. Should the monitors have different +resolutions, Sculpt OS automatically adjusts the system-global font configuration +according to the monitor used. Should this effect on all users of the +system-global font configuration (like terminal windows hosted on yet another +monitor) be undesired, one can define a static font configuration by placing +a snapshot of _/config/managed/fonts_ to _/config/fonts_. + +If a monitor supports brightness control, the brightness can by adjusted in +the mode selection of the monitor. The mode selection also offers the option +to switch off the monitor, except for the monitor currently hosting the +Leitzentrale GUI. As a note of caution, there is currently no safety mechanism +against locking oneself out of the user interface by selecting a mode not +properly handled by a single connected monitor. + +The framebuffer-driver configuration as driven by the interactive dialog +can be found at _/config/managed/fb_. It is meant to be taken as starting +point for a manually managed configuration at _/config/fb_. Therefore, several +multi-monitor profiles (like office, home, train) can be realized by merely +replacing this file. +The panorama is defined at the _/config/managed/nitpicker_ configuration, +specifically the '' node. The '' node assigns the +viewports on the panorama as captured by the framebuffer driver. Sculpt OS +manages the panorama only if the '' node of _/config/nitpicker_ +is empty. By filling the '' node with custom policies, arbitrary +panorama layouts can be realized using the attributes 'xpos', 'ypos', 'width', +and 'height'. + +For diagnostic purposes, the _/report/runtime/intel_fb/connectors_ report +contains the connector state as currently observed by the framebuffer driver. +Furthermore, _/report/nitpicker/panorama_ contains the information about +the panorama and the components participating in capturing the panorama. + + Audio ===== @@ -1689,11 +1767,11 @@ download at [https://genode.org]. ! git clone https://github.com/genodelabs/genode.git ! cd genode - ! git checkout -b sculpt-24.04 sculpt-24.04 + ! git checkout -b sculpt-24.10 sculpt-24.10 # Download the support for the NOVA microkernel - ! ./tool/depot/download genodelabs/bin/x86_64/base-nova/2024-04-26 + ! ./tool/depot/download genodelabs/bin/x86_64/base-nova/2024-10-30 The content is downloaded to the _public/_ directory and extracted to the _depot/_ directory. @@ -1701,8 +1779,8 @@ download at [https://genode.org]. # Download all ingredients for the Sculpt boot image ! ./tool/depot/download \ - ! genodelabs/pkg/x86_64/sculpt/2024-04-26 \ - ! genodelabs/pkg/x86_64/sculpt_drivers-pc/2024-04-26 + ! genodelabs/pkg/x86_64/sculpt/2024-10-30 \ + ! genodelabs/pkg/x86_64/sculpt_drivers-pc/2024-10-30 # Create a build directory diff --git a/repos/gems/recipes/pkg/sculpt/hash b/repos/gems/recipes/pkg/sculpt/hash index 4ab713f00a..566149f89a 100644 --- a/repos/gems/recipes/pkg/sculpt/hash +++ b/repos/gems/recipes/pkg/sculpt/hash @@ -1 +1 @@ -2024-08-28 efe6cd4c63380ded30b7944afc007bb850de9c16 +2024-11-05 96f60eda3ad22e3bfb01db3bae1614cc056e3f72 diff --git a/repos/gems/recipes/pkg/sculpt_distribution-pc/hash b/repos/gems/recipes/pkg/sculpt_distribution-pc/hash index 9d562679b7..71a2881a30 100644 --- a/repos/gems/recipes/pkg/sculpt_distribution-pc/hash +++ b/repos/gems/recipes/pkg/sculpt_distribution-pc/hash @@ -1 +1 @@ -2024-08-28 d35f206e7d6fcdd019dda4f2f471e2fb529035cb +2024-11-05 dc53fdab465d5cb7d4f1d1d1ee8993988f075d26 diff --git a/repos/gems/recipes/pkg/sculpt_distribution/hash b/repos/gems/recipes/pkg/sculpt_distribution/hash index c28ca3e7bc..136a979308 100644 --- a/repos/gems/recipes/pkg/sculpt_distribution/hash +++ b/repos/gems/recipes/pkg/sculpt_distribution/hash @@ -1 +1 @@ -2024-08-28 062100bdb91d2a89fe549d0ca653311e88fbaa48 +2024-11-04 72748639fae7b9e4bc6c73f57a294fc806ba16c8 diff --git a/repos/gems/recipes/pkg/sculpt_drivers-pc/hash b/repos/gems/recipes/pkg/sculpt_drivers-pc/hash index 1df55d6cd4..e352ca1027 100644 --- a/repos/gems/recipes/pkg/sculpt_drivers-pc/hash +++ b/repos/gems/recipes/pkg/sculpt_drivers-pc/hash @@ -1 +1 @@ -2024-08-28 70fb780a3b943bc41bab9ebf1e139985536cbda8 +2024-10-30 88fea61b723ca4c2e4fb808c8f25490c22176c9f diff --git a/repos/gems/recipes/pkg/sticks_blue_backdrop/hash b/repos/gems/recipes/pkg/sticks_blue_backdrop/hash index 1238363862..abf576dd73 100644 --- a/repos/gems/recipes/pkg/sticks_blue_backdrop/hash +++ b/repos/gems/recipes/pkg/sticks_blue_backdrop/hash @@ -1 +1 @@ -2024-08-28 f594df98660636ff12bd6039051837baf52d3da0 +2024-11-04 7af2fe6b6fb23b13402eecae0b2098b18cf637c3 diff --git a/repos/gems/recipes/pkg/sticks_blue_backdrop/runtime b/repos/gems/recipes/pkg/sticks_blue_backdrop/runtime index dd3b7074ee..f49b8b961f 100644 --- a/repos/gems/recipes/pkg/sticks_blue_backdrop/runtime +++ b/repos/gems/recipes/pkg/sticks_blue_backdrop/runtime @@ -1,4 +1,4 @@ - + diff --git a/repos/gems/recipes/pkg/terminal/hash b/repos/gems/recipes/pkg/terminal/hash index d5b9203a3c..a3b1c931b2 100644 --- a/repos/gems/recipes/pkg/terminal/hash +++ b/repos/gems/recipes/pkg/terminal/hash @@ -1 +1 @@ -2024-08-28 c8a23f229431fcf97358edaab5b1cc8b757be61e +2024-11-04 b58721f29f35c343c766718bc766716386202ba4 diff --git a/repos/gems/recipes/pkg/terminal/runtime b/repos/gems/recipes/pkg/terminal/runtime index fa2d11abf1..3d634faf0a 100644 --- a/repos/gems/recipes/pkg/terminal/runtime +++ b/repos/gems/recipes/pkg/terminal/runtime @@ -1,4 +1,4 @@ - + diff --git a/repos/gems/recipes/pkg/test-depot_query_index/hash b/repos/gems/recipes/pkg/test-depot_query_index/hash index 2c170302b4..1973ff45ec 100644 --- a/repos/gems/recipes/pkg/test-depot_query_index/hash +++ b/repos/gems/recipes/pkg/test-depot_query_index/hash @@ -1 +1 @@ -2024-08-28 1945fdeeb41ab8aa2e85f326b605a83004c5b789 +2024-10-29 72a3f0fb92adc0a882a5ede26e3f31d599ce0381 diff --git a/repos/gems/recipes/pkg/test-file_vault/hash b/repos/gems/recipes/pkg/test-file_vault/hash index a007820498..303a5578dd 100644 --- a/repos/gems/recipes/pkg/test-file_vault/hash +++ b/repos/gems/recipes/pkg/test-file_vault/hash @@ -1 +1 @@ -2024-08-28 4b09ba801fb71acac101ffcef51e464b5ae0817c +2024-11-04 24f21b93bf4e67d227e45e933bc2fb38f9321258 diff --git a/repos/gems/recipes/pkg/test-file_vault_no_entropy/hash b/repos/gems/recipes/pkg/test-file_vault_no_entropy/hash index 6941adb290..5f0f1adfe3 100644 --- a/repos/gems/recipes/pkg/test-file_vault_no_entropy/hash +++ b/repos/gems/recipes/pkg/test-file_vault_no_entropy/hash @@ -1 +1 @@ -2024-08-28 dbcd5df91cd813738081d8b5a52fe76ec3169b63 +2024-11-04 a0eded3d31598f6c4c6f5f41d9624c392e488424 diff --git a/repos/gems/recipes/pkg/test-fs_tool/hash b/repos/gems/recipes/pkg/test-fs_tool/hash index d8c4c55176..80a3de1bc5 100644 --- a/repos/gems/recipes/pkg/test-fs_tool/hash +++ b/repos/gems/recipes/pkg/test-fs_tool/hash @@ -1 +1 @@ -2024-08-28 05730ef204996d86a51e42305fb7a0840d3139cb +2024-11-04 038eeef0ad6223c508521b8abfa75cc3e39b2370 diff --git a/repos/gems/recipes/pkg/test-libc_vfs_audit/hash b/repos/gems/recipes/pkg/test-libc_vfs_audit/hash index d068d84527..a4db8f0c42 100644 --- a/repos/gems/recipes/pkg/test-libc_vfs_audit/hash +++ b/repos/gems/recipes/pkg/test-libc_vfs_audit/hash @@ -1 +1 @@ -2024-08-28 90c78c2cc96ef24c2387b5986f2a61b46132ff36 +2024-11-04 18bf3c0e89229b6ce5b65f1e739aea0dc78aba55 diff --git a/repos/gems/recipes/pkg/themed_decorator/hash b/repos/gems/recipes/pkg/themed_decorator/hash index 3aabd0d6b7..a1b4b0573f 100644 --- a/repos/gems/recipes/pkg/themed_decorator/hash +++ b/repos/gems/recipes/pkg/themed_decorator/hash @@ -1 +1 @@ -2024-08-28 bd55579c99712a624c5ce9a4e44aed5d9fae1052 +2024-11-04 26a4b14a416866e638c4dac9a2f9e9e171dfd98c diff --git a/repos/gems/recipes/pkg/themed_wm/hash b/repos/gems/recipes/pkg/themed_wm/hash index a33c1edd51..d811cad539 100644 --- a/repos/gems/recipes/pkg/themed_wm/hash +++ b/repos/gems/recipes/pkg/themed_wm/hash @@ -1 +1 @@ -2024-08-28 64afc4082fce3637ccb43b5ff296d36729ca7327 +2024-11-04 7b5e9aecc8cad7964deebf322c09f79557bb77f1 diff --git a/repos/gems/recipes/pkg/touch_keyboard/hash b/repos/gems/recipes/pkg/touch_keyboard/hash index 6cddbd5733..54b9d7ba3f 100644 --- a/repos/gems/recipes/pkg/touch_keyboard/hash +++ b/repos/gems/recipes/pkg/touch_keyboard/hash @@ -1 +1 @@ -2024-08-28 ac307c27d772bcaebb1669f7e052c1c2db233713 +2024-11-04 23f8a049283137020972f4f72d112931bb4a3743 diff --git a/repos/gems/recipes/pkg/trace_fs/hash b/repos/gems/recipes/pkg/trace_fs/hash index cbc41bf0f6..5a48936967 100644 --- a/repos/gems/recipes/pkg/trace_fs/hash +++ b/repos/gems/recipes/pkg/trace_fs/hash @@ -1 +1 @@ -2024-08-28 a1037d9fa41db2dfd182169d158b0885e1248aaf +2024-11-04 2e60e4321df7fe203fcbfed2447293109c104d66 diff --git a/repos/gems/recipes/pkg/trace_recorder/hash b/repos/gems/recipes/pkg/trace_recorder/hash index 3e1a6b37d0..ddaa73201d 100644 --- a/repos/gems/recipes/pkg/trace_recorder/hash +++ b/repos/gems/recipes/pkg/trace_recorder/hash @@ -1 +1 @@ -2024-08-28 a6857dd53f38f1d8197e21a77466162e07554e71 +2024-10-07 78a8e28f934914e60e9f9bf78932ea62dc26339a diff --git a/repos/gems/recipes/pkg/unconfigured_nano3d/hash b/repos/gems/recipes/pkg/unconfigured_nano3d/hash index 80d6b6058a..a8882f2941 100644 --- a/repos/gems/recipes/pkg/unconfigured_nano3d/hash +++ b/repos/gems/recipes/pkg/unconfigured_nano3d/hash @@ -1 +1 @@ -2024-08-28 323a0e88d9b19c25ce710e034f4fae9091b75a51 +2024-10-29 17aff7dfc9c2bc05e6ec9638c6f13ddc6654c6a9 diff --git a/repos/gems/recipes/pkg/window_layouter/hash b/repos/gems/recipes/pkg/window_layouter/hash index 29decd9d8b..eb82cd62b2 100644 --- a/repos/gems/recipes/pkg/window_layouter/hash +++ b/repos/gems/recipes/pkg/window_layouter/hash @@ -1 +1 @@ -2024-08-28 0d98cc1f2f68904f796e5d15e8213a1fd843bc03 +2024-10-29 dcf3cb77e26c74535de7e8fdfef56f9bbf765eec diff --git a/repos/gems/recipes/pkg/window_layouter/runtime b/repos/gems/recipes/pkg/window_layouter/runtime index c4034a9062..15ffb76358 100644 --- a/repos/gems/recipes/pkg/window_layouter/runtime +++ b/repos/gems/recipes/pkg/window_layouter/runtime @@ -1,4 +1,4 @@ - + @@ -49,7 +49,7 @@ - + diff --git a/repos/gems/recipes/pkg/wm/hash b/repos/gems/recipes/pkg/wm/hash index 8547860908..5e3020d67f 100644 --- a/repos/gems/recipes/pkg/wm/hash +++ b/repos/gems/recipes/pkg/wm/hash @@ -1 +1 @@ -2024-08-28 563b0ffcd7c4100dba6e7dae1e24fd179f7e1f88 +2024-11-04 5a423707da25061829d09aad9b1151524c85e689 diff --git a/repos/gems/recipes/pkg/wm/runtime b/repos/gems/recipes/pkg/wm/runtime index d37fdf039f..4545d796c0 100644 --- a/repos/gems/recipes/pkg/wm/runtime +++ b/repos/gems/recipes/pkg/wm/runtime @@ -1,4 +1,4 @@ - + diff --git a/repos/gems/recipes/raw/motif_wm/decorator_init.config b/repos/gems/recipes/raw/motif_wm/decorator_init.config index 10ac1836c0..8d0e912d0d 100644 --- a/repos/gems/recipes/raw/motif_wm/decorator_init.config +++ b/repos/gems/recipes/raw/motif_wm/decorator_init.config @@ -9,7 +9,7 @@ - + </controls> <default-policy/> diff --git a/repos/gems/recipes/raw/motif_wm/hash b/repos/gems/recipes/raw/motif_wm/hash index 84df4f4607..5ed1e0d9bb 100644 --- a/repos/gems/recipes/raw/motif_wm/hash +++ b/repos/gems/recipes/raw/motif_wm/hash @@ -1 +1 @@ -2022-04-27 945e936c1b8c4328ee1745b2218699e29c55a276 +2024-10-07 68458ebc4b4f508958f2d55058c76e6de2d2ad73 diff --git a/repos/gems/recipes/raw/motif_wm/layouter.config b/repos/gems/recipes/raw/motif_wm/layouter.config index 4611a48a59..1560e09e17 100644 --- a/repos/gems/recipes/raw/motif_wm/layouter.config +++ b/repos/gems/recipes/raw/motif_wm/layouter.config @@ -15,7 +15,7 @@ <assign label_prefix="" target="screen_1" xpos="any" ypos="any"/> </rules> - <press key="KEY_SCREEN"> + <press key="KEY_SCREEN" action="release_grab"> <press key="KEY_TAB" action="next_window"> <release key="KEY_TAB"> <release key="KEY_SCREEN" action="raise_window"/> diff --git a/repos/gems/recipes/raw/motif_wm/wm.config b/repos/gems/recipes/raw/motif_wm/wm.config index 7a31d0009c..29aaabbc08 100644 --- a/repos/gems/recipes/raw/motif_wm/wm.config +++ b/repos/gems/recipes/raw/motif_wm/wm.config @@ -46,8 +46,8 @@ </config> </start> - <start name="wm" caps="250"> - <resource name="RAM" quantum="6M"/> + <start name="wm" caps="100"> + <resource name="RAM" quantum="2M"/> <provides> <service name="Gui"/> <service name="Report"/> <service name="ROM"/> </provides> @@ -70,7 +70,7 @@ </route> </start> - <start name="layouter"> + <start name="layouter" caps="120"> <binary name="window_layouter"/> <resource name="RAM" quantum="4M"/> <route> @@ -89,7 +89,7 @@ <start name="decorator" caps="450"> <binary name="init"/> - <resource name="RAM" quantum="12M"/> + <resource name="RAM" quantum="20M"/> <route> <service name="ROM" label="config"> <parent label="decorator_init.config"/> </service> diff --git a/repos/gems/recipes/raw/themed_wm/decorator_init.config b/repos/gems/recipes/raw/themed_wm/decorator_init.config index efe0bec858..9e8bf6b7ca 100644 --- a/repos/gems/recipes/raw/themed_wm/decorator_init.config +++ b/repos/gems/recipes/raw/themed_wm/decorator_init.config @@ -8,9 +8,9 @@ <service name="Timer"/> <service name="Report"/> </parent-provides> - <start name="decorator" caps="400"> + <start name="decorator" caps="320"> <binary name="themed_decorator"/> - <resource name="RAM" quantum="12M"/> + <resource name="RAM" quantum="11M"/> <config> <libc/> <vfs> <tar name="plain_decorator_theme.tar"/> </vfs> diff --git a/repos/gems/recipes/raw/themed_wm/hash b/repos/gems/recipes/raw/themed_wm/hash index cabcec9ab0..a414d17016 100644 --- a/repos/gems/recipes/raw/themed_wm/hash +++ b/repos/gems/recipes/raw/themed_wm/hash @@ -1 +1 @@ -2022-04-27 8ed349741e0beafb6f0473cb9f19ebd21dcef2f7 +2024-10-07 d5b44206be832ec30f7ec3028b70c3434c0971b3 diff --git a/repos/gems/recipes/raw/window_layouter/hash b/repos/gems/recipes/raw/window_layouter/hash index a379fc03fc..7112a3e90b 100644 --- a/repos/gems/recipes/raw/window_layouter/hash +++ b/repos/gems/recipes/raw/window_layouter/hash @@ -1 +1 @@ -2020-02-19 f8e677270d4386d000c8758cc401e7a9df82001d +2024-10-29 57d38bd73ebb281b2dfa779f03d47af88ba4515c diff --git a/repos/gems/recipes/raw/window_layouter/window_layouter.config b/repos/gems/recipes/raw/window_layouter/window_layouter.config index 4611a48a59..1560e09e17 100644 --- a/repos/gems/recipes/raw/window_layouter/window_layouter.config +++ b/repos/gems/recipes/raw/window_layouter/window_layouter.config @@ -15,7 +15,7 @@ <assign label_prefix="" target="screen_1" xpos="any" ypos="any"/> </rules> - <press key="KEY_SCREEN"> + <press key="KEY_SCREEN" action="release_grab"> <press key="KEY_TAB" action="next_window"> <release key="KEY_TAB"> <release key="KEY_SCREEN" action="raise_window"/> diff --git a/repos/gems/recipes/raw/wm/hash b/repos/gems/recipes/raw/wm/hash index 05b725f987..fba8f33a5e 100644 --- a/repos/gems/recipes/raw/wm/hash +++ b/repos/gems/recipes/raw/wm/hash @@ -1 +1 @@ -2020-06-21 beadfa2f974b9944ab9807c27c119c718abbd01f +2024-10-07 f9bdc38c7b4158ee82feab00283fbd133caa5eb5 diff --git a/repos/gems/recipes/raw/wm/wm.config b/repos/gems/recipes/raw/wm/wm.config index a967d99475..56235b11c2 100644 --- a/repos/gems/recipes/raw/wm/wm.config +++ b/repos/gems/recipes/raw/wm/wm.config @@ -74,8 +74,8 @@ </config> </start> - <start name="wm" caps="250"> - <resource name="RAM" quantum="8M"/> + <start name="wm" caps="150"> + <resource name="RAM" quantum="2M"/> <provides> <service name="Gui"/> <service name="Report"/> <service name="ROM"/> </provides> diff --git a/repos/gems/recipes/src/backdrop/hash b/repos/gems/recipes/src/backdrop/hash index 9be6f75810..30cfcc65fd 100644 --- a/repos/gems/recipes/src/backdrop/hash +++ b/repos/gems/recipes/src/backdrop/hash @@ -1 +1 @@ -2024-08-28 c06b592ecd63ca0fcd084c7f52db87907824f9a6 +2024-11-04 cd4ebf9848f7f8e0833709331f02a8e5d49ef2d1 diff --git a/repos/gems/recipes/src/cpu_load_display/hash b/repos/gems/recipes/src/cpu_load_display/hash index 9a2b82ec06..0a4d8b4c96 100644 --- a/repos/gems/recipes/src/cpu_load_display/hash +++ b/repos/gems/recipes/src/cpu_load_display/hash @@ -1 +1 @@ -2024-08-28 852adfdf56d6b9c867391372af9418bcca9e9782 +2024-11-04 984d85c1768302dc435a6b51810cd2a09727ff14 diff --git a/repos/gems/recipes/src/dbg_download/hash b/repos/gems/recipes/src/dbg_download/hash index 2dcddeed57..712036a186 100644 --- a/repos/gems/recipes/src/dbg_download/hash +++ b/repos/gems/recipes/src/dbg_download/hash @@ -1 +1 @@ -2024-08-28 f20ef23315abc0c081b8866b96bbafe2703a3ddb +2024-10-07 9f120fbc7ad3f0217d48a3a861c27d626d8eac6f diff --git a/repos/gems/recipes/src/decorator/hash b/repos/gems/recipes/src/decorator/hash index 96b6b1ee6d..cf91d2f565 100644 --- a/repos/gems/recipes/src/decorator/hash +++ b/repos/gems/recipes/src/decorator/hash @@ -1 +1 @@ -2024-08-28 284d5916381cd8e3c9138dd6a8b70a03a01e9987 +2024-11-04 1877a655ee50a7a34212f6aeea2030731cab471c diff --git a/repos/gems/recipes/src/depot_deploy/hash b/repos/gems/recipes/src/depot_deploy/hash index a92fae9be7..c6900682b4 100644 --- a/repos/gems/recipes/src/depot_deploy/hash +++ b/repos/gems/recipes/src/depot_deploy/hash @@ -1 +1 @@ -2024-08-28 ff82926d17f2a113ebf64b118d3f9dae69ca039a +2024-10-07 4ba817f5300e8d42b1eacdfc919094df88e0d6f4 diff --git a/repos/gems/recipes/src/depot_download_manager/hash b/repos/gems/recipes/src/depot_download_manager/hash index 7aa2597b27..b5bfc8f4b9 100644 --- a/repos/gems/recipes/src/depot_download_manager/hash +++ b/repos/gems/recipes/src/depot_download_manager/hash @@ -1 +1 @@ -2024-08-28 0a7a376cb38f151dd6f90b33cf13f996d00650cc +2024-10-07 2b764ef33952424093d3e6a384cd8e0ea7aee2a4 diff --git a/repos/gems/recipes/src/depot_query/hash b/repos/gems/recipes/src/depot_query/hash index 3c9c6a417e..80b4f53287 100644 --- a/repos/gems/recipes/src/depot_query/hash +++ b/repos/gems/recipes/src/depot_query/hash @@ -1 +1 @@ -2024-08-28 e34136da1d1c2333537f83c8142a30248f614137 +2024-10-07 002a0b61bd9ba520bdbce30e195b1801e3fa563a diff --git a/repos/gems/recipes/src/depot_remove/hash b/repos/gems/recipes/src/depot_remove/hash index a18377990f..7f79ec9b84 100644 --- a/repos/gems/recipes/src/depot_remove/hash +++ b/repos/gems/recipes/src/depot_remove/hash @@ -1 +1 @@ -2024-08-28 10bcd3381e68f6464b49121f49b7c77adc056a90 +2024-10-07 e8cd8c20c24113a11f752d4a5beb8e7da2d5d687 diff --git a/repos/gems/recipes/src/file_terminal/hash b/repos/gems/recipes/src/file_terminal/hash index 09288f02aa..34e4bec47d 100644 --- a/repos/gems/recipes/src/file_terminal/hash +++ b/repos/gems/recipes/src/file_terminal/hash @@ -1 +1 @@ -2024-08-28 ab6934f75137b81262596d539f5adaf199a3e175 +2024-10-07 2bfba46c0b152486c07eb74709876b9e970940d6 diff --git a/repos/gems/recipes/src/file_vault/hash b/repos/gems/recipes/src/file_vault/hash index c2264d1d75..b544034512 100644 --- a/repos/gems/recipes/src/file_vault/hash +++ b/repos/gems/recipes/src/file_vault/hash @@ -1 +1 @@ -2024-08-28 fb0b48bcf12b88a78a2f6227cfa9348119d12470 +2024-10-29 844ae174b2bf8a4c975d888110cf8f6f7eada868 diff --git a/repos/gems/recipes/src/file_vault_gui/hash b/repos/gems/recipes/src/file_vault_gui/hash index 48a497722b..99b0367070 100644 --- a/repos/gems/recipes/src/file_vault_gui/hash +++ b/repos/gems/recipes/src/file_vault_gui/hash @@ -1 +1 @@ -2024-08-28 9c2500ebce81ac440a0489a9544f5f97e8c39858 +2024-11-04 0e693d03c461bc078cfa2a35daf304863cd4937a diff --git a/repos/gems/recipes/src/fs_query/hash b/repos/gems/recipes/src/fs_query/hash index 55d4a82a6a..34ef4f2ff1 100644 --- a/repos/gems/recipes/src/fs_query/hash +++ b/repos/gems/recipes/src/fs_query/hash @@ -1 +1 @@ -2024-08-28 24276c7b5b4e6a97db749cb13e6d88a26bc9f49e +2024-10-07 13adfc76913632fdc7a187b7464cd0e415499b95 diff --git a/repos/gems/recipes/src/fs_tool/hash b/repos/gems/recipes/src/fs_tool/hash index 2589084966..3adf42beaf 100644 --- a/repos/gems/recipes/src/fs_tool/hash +++ b/repos/gems/recipes/src/fs_tool/hash @@ -1 +1 @@ -2024-08-28 e45f6a0c4449de35d602a3f67d79becdc4d15e12 +2024-10-07 e7ab62b24bca24b83a885bf58f63c81634d11cd3 diff --git a/repos/gems/recipes/src/gpt_write/hash b/repos/gems/recipes/src/gpt_write/hash index 2203f2c3a5..62afb3475b 100644 --- a/repos/gems/recipes/src/gpt_write/hash +++ b/repos/gems/recipes/src/gpt_write/hash @@ -1 +1 @@ -2024-08-28 2021d89c85c3463b1d2661c32aacc407a366b735 +2024-10-07 a230c20ee8fe8dc014c3458a5fd0ac4f6dae7e4e diff --git a/repos/gems/recipes/src/gui_fader/hash b/repos/gems/recipes/src/gui_fader/hash index b690aa506a..107d74d4f9 100644 --- a/repos/gems/recipes/src/gui_fader/hash +++ b/repos/gems/recipes/src/gui_fader/hash @@ -1 +1 @@ -2024-08-28 74213c19b72937426ed9ffe9c40a7990dce7bee1 +2024-10-29 517197ef1ccd99b7b509e74d659e0d96d8f6007c diff --git a/repos/gems/recipes/src/menu_view/hash b/repos/gems/recipes/src/menu_view/hash index 4d8b90dd6d..f8f134d6ea 100644 --- a/repos/gems/recipes/src/menu_view/hash +++ b/repos/gems/recipes/src/menu_view/hash @@ -1 +1 @@ -2024-08-28 105bc681ae0ca76606695ec9b6235cbe2ea53796 +2024-11-04 136af1755f9ca89f179ef144638794f966f339b2 diff --git a/repos/gems/recipes/src/mixer_gui_qt/hash b/repos/gems/recipes/src/mixer_gui_qt/hash index b4297d5336..a8b760d9b7 100644 --- a/repos/gems/recipes/src/mixer_gui_qt/hash +++ b/repos/gems/recipes/src/mixer_gui_qt/hash @@ -1 +1 @@ -2024-08-28 55ccba2abbcda46250b243075b5727fae4389675 +2024-10-29 2806cdc96c4a22e4f1d12e9940f92afc1a0c2351 diff --git a/repos/gems/recipes/src/mixer_gui_qt6/hash b/repos/gems/recipes/src/mixer_gui_qt6/hash index 890e2682a8..85c7de8cfc 100644 --- a/repos/gems/recipes/src/mixer_gui_qt6/hash +++ b/repos/gems/recipes/src/mixer_gui_qt6/hash @@ -1 +1 @@ -2024-08-28 1df576794d8dd2da27d253ab417e35bcd3b9dae3 +2024-10-29 6fc354be1ef107b978dbc5fcbfd1bdba9d183b98 diff --git a/repos/gems/recipes/src/nano3d/hash b/repos/gems/recipes/src/nano3d/hash index 9f4c09cae9..9b4dcf930a 100644 --- a/repos/gems/recipes/src/nano3d/hash +++ b/repos/gems/recipes/src/nano3d/hash @@ -1 +1 @@ -2024-08-28 c4725e2f3c20c6479e4fc8d380b70bd9aa3a1642 +2024-10-29 f8e1d99330927e56c3f76bd91bcedd828e85b8c0 diff --git a/repos/gems/recipes/src/osci/hash b/repos/gems/recipes/src/osci/hash index 175623d71d..c304317b26 100644 --- a/repos/gems/recipes/src/osci/hash +++ b/repos/gems/recipes/src/osci/hash @@ -1 +1 @@ -2024-08-28 286362662b44fbbc485e3bb335ca10ea2ec121ff +2024-11-04 d21739956a87a54decf6cf26f812016125d899e4 diff --git a/repos/gems/recipes/src/rom_osci/hash b/repos/gems/recipes/src/rom_osci/hash index fa392b43d1..c0ea14409d 100644 --- a/repos/gems/recipes/src/rom_osci/hash +++ b/repos/gems/recipes/src/rom_osci/hash @@ -1 +1 @@ -2024-08-28 69bc3feb42a0ef8436a93d76698961d5f9e888aa +2024-11-04 079d9f672d29874d50b31ac0a86e8286de631f7e diff --git a/repos/gems/recipes/src/screenshot_trigger/hash b/repos/gems/recipes/src/screenshot_trigger/hash index 8ebdf5b7b0..20587ae0f4 100644 --- a/repos/gems/recipes/src/screenshot_trigger/hash +++ b/repos/gems/recipes/src/screenshot_trigger/hash @@ -1 +1 @@ -2024-08-28 287a862f194666c01add094c9bb00166f48fa537 +2024-11-04 eac2549765608ddecb020918592b6b3b6821549c diff --git a/repos/gems/recipes/src/sculpt_manager/hash b/repos/gems/recipes/src/sculpt_manager/hash index e765bed632..d37633c8e7 100644 --- a/repos/gems/recipes/src/sculpt_manager/hash +++ b/repos/gems/recipes/src/sculpt_manager/hash @@ -1 +1 @@ -2024-08-28 e0f6afc6782b432ee03b634299fc14c8c8822c62 +2024-11-05 63ea2e1e236fe381a2c47ea40df825764007b355 diff --git a/repos/gems/recipes/src/tcp_terminal/hash b/repos/gems/recipes/src/tcp_terminal/hash index acda98c155..05a3803733 100644 --- a/repos/gems/recipes/src/tcp_terminal/hash +++ b/repos/gems/recipes/src/tcp_terminal/hash @@ -1 +1 @@ -2024-08-28 499af9b0030e0f127fe0267e90336d76e5caf101 +2024-10-07 d52c83ad285ada383d82a345ddd9ee4ddbef8f68 diff --git a/repos/gems/recipes/src/terminal/hash b/repos/gems/recipes/src/terminal/hash index 1056435590..8784e65ead 100644 --- a/repos/gems/recipes/src/terminal/hash +++ b/repos/gems/recipes/src/terminal/hash @@ -1 +1 @@ -2024-08-28 638415a10a23e9128fb63214e576daf9b20fca34 +2024-11-04 f7b9874f2aa64676737e620b95c8d5a6053abb2e diff --git a/repos/gems/recipes/src/test-tiled_wm/hash b/repos/gems/recipes/src/test-tiled_wm/hash index 0dcf03bd2a..54e62f6e0c 100644 --- a/repos/gems/recipes/src/test-tiled_wm/hash +++ b/repos/gems/recipes/src/test-tiled_wm/hash @@ -1 +1 @@ -2024-08-28 efb459e98c9c807e7c4524fa8bd82859bd126609 +2024-10-29 0ca3dcde5cb933da2a158862d040c9f4befdfe14 diff --git a/repos/gems/recipes/src/test-tiled_wm_qt6/hash b/repos/gems/recipes/src/test-tiled_wm_qt6/hash index d8e4758bde..12b70d004d 100644 --- a/repos/gems/recipes/src/test-tiled_wm_qt6/hash +++ b/repos/gems/recipes/src/test-tiled_wm_qt6/hash @@ -1 +1 @@ -2024-08-28 182c37e66f22bd76aa7ccbcfe0229cfd9fa14302 +2024-10-29 28f6501aa6aad89ae7d4339e732106158d7864f1 diff --git a/repos/gems/recipes/src/text_area/hash b/repos/gems/recipes/src/text_area/hash index 2fc55f7d37..6286ccbbec 100644 --- a/repos/gems/recipes/src/text_area/hash +++ b/repos/gems/recipes/src/text_area/hash @@ -1 +1 @@ -2024-08-28 c489c9eb56f1635d53c45a6fa6c58bcdf79bad0f +2024-11-04 5a65000bba0acf7e7776eb45c751414e1bedd0f0 diff --git a/repos/gems/recipes/src/themed_decorator/hash b/repos/gems/recipes/src/themed_decorator/hash index 7cb76c7288..5bebf69efb 100644 --- a/repos/gems/recipes/src/themed_decorator/hash +++ b/repos/gems/recipes/src/themed_decorator/hash @@ -1 +1 @@ -2024-08-28 e1f78de7a91d9a006e1ba0beef267803990375ad +2024-11-04 3dec6249d0627f3be6d6303ed052c25bfb3431e3 diff --git a/repos/gems/recipes/src/touch_keyboard/hash b/repos/gems/recipes/src/touch_keyboard/hash index b0420c8514..0feb45aaac 100644 --- a/repos/gems/recipes/src/touch_keyboard/hash +++ b/repos/gems/recipes/src/touch_keyboard/hash @@ -1 +1 @@ -2024-08-28 c8d7ebed1ff069ba7ae982287376f20393660d86 +2024-11-04 4e2e933760a9dbecc8d9d3693d4ebe5f79524d93 diff --git a/repos/gems/recipes/src/trace_recorder/hash b/repos/gems/recipes/src/trace_recorder/hash index 8908f05593..a468239348 100644 --- a/repos/gems/recipes/src/trace_recorder/hash +++ b/repos/gems/recipes/src/trace_recorder/hash @@ -1 +1 @@ -2024-08-28 0837827edb214e9c2e6c0a37b6a68379185e915f +2024-10-07 7193fa188f5ae02451faac226d22c11b6fb9d4ea diff --git a/repos/gems/recipes/src/trace_recorder_policy/hash b/repos/gems/recipes/src/trace_recorder_policy/hash index 43b816986a..acae378cab 100644 --- a/repos/gems/recipes/src/trace_recorder_policy/hash +++ b/repos/gems/recipes/src/trace_recorder_policy/hash @@ -1 +1 @@ -2024-08-28 cae0a592c2b6a0a7bf0c4a49eb60e2e408f238a2 +2024-10-07 defa1e47b0427922420d8db3c5dc8602c634c041 diff --git a/repos/gems/recipes/src/tresor/hash b/repos/gems/recipes/src/tresor/hash index aa545d39f4..498e4b86d1 100644 --- a/repos/gems/recipes/src/tresor/hash +++ b/repos/gems/recipes/src/tresor/hash @@ -1 +1 @@ -2024-08-28 059ec3712d55a0f917d427e41b54645c4f4ba40a +2024-10-07 e7a9086e88543fdf7a1d308643f7e047c528420c diff --git a/repos/gems/recipes/src/vfs_audit/hash b/repos/gems/recipes/src/vfs_audit/hash index 6655a25db3..8359309d31 100644 --- a/repos/gems/recipes/src/vfs_audit/hash +++ b/repos/gems/recipes/src/vfs_audit/hash @@ -1 +1 @@ -2024-08-28 6c95d8f4b5bd58bc6e9de30ca53e28906acdbabf +2024-11-04 9500dfcbb3d75bc4f66e3e21e502883775df11cd diff --git a/repos/gems/recipes/src/vfs_gpu/hash b/repos/gems/recipes/src/vfs_gpu/hash index d6f88edcd7..4d40e81e5c 100644 --- a/repos/gems/recipes/src/vfs_gpu/hash +++ b/repos/gems/recipes/src/vfs_gpu/hash @@ -1 +1 @@ -2024-08-28 6fd7c6d7e2da470df4fbe6ed855fbd8876b5a37d +2024-11-04 bbd2777861c108a70b0aeafc5d79464049bf98aa diff --git a/repos/gems/recipes/src/vfs_import/hash b/repos/gems/recipes/src/vfs_import/hash index 737d84def7..dc50e73eee 100644 --- a/repos/gems/recipes/src/vfs_import/hash +++ b/repos/gems/recipes/src/vfs_import/hash @@ -1 +1 @@ -2024-08-28 429b3e4545dcdee5014676fa1ad0bd6716e49707 +2024-11-04 a5a41d0d2f118244cce9cd20bf95ab235160e839 diff --git a/repos/gems/recipes/src/vfs_oss/hash b/repos/gems/recipes/src/vfs_oss/hash index aea33776bb..3705a42347 100644 --- a/repos/gems/recipes/src/vfs_oss/hash +++ b/repos/gems/recipes/src/vfs_oss/hash @@ -1 +1 @@ -2024-08-28 c5491cc8eff3aba76fa285aab1babadd819a1dc5 +2024-11-04 701bd1bc2031c85b796aaeb26e39a8adb38cb2af diff --git a/repos/gems/recipes/src/vfs_pipe/hash b/repos/gems/recipes/src/vfs_pipe/hash index 985b205a01..20f229c9dd 100644 --- a/repos/gems/recipes/src/vfs_pipe/hash +++ b/repos/gems/recipes/src/vfs_pipe/hash @@ -1 +1 @@ -2024-08-28 9535e2e705d816992383e07e9ee7e253507e883e +2024-10-07 af8549e4e0e582ee8c77c64a81f64ea06aa448b7 diff --git a/repos/gems/recipes/src/vfs_trace/hash b/repos/gems/recipes/src/vfs_trace/hash index d7f0c3c43c..a2ed61c20f 100644 --- a/repos/gems/recipes/src/vfs_trace/hash +++ b/repos/gems/recipes/src/vfs_trace/hash @@ -1 +1 @@ -2024-08-28 c6ada446ea2a4eaf88f7fe2ef75d8abdcedf1a48 +2024-11-04 5c8808ea2a3441606506bfd86985fe4be2baf3e9 diff --git a/repos/gems/recipes/src/vfs_ttf/hash b/repos/gems/recipes/src/vfs_ttf/hash index e82e6f968f..612209aefa 100644 --- a/repos/gems/recipes/src/vfs_ttf/hash +++ b/repos/gems/recipes/src/vfs_ttf/hash @@ -1 +1 @@ -2024-08-28 8c7c798ac0d1d7e29c1fd8f9bb6ba75d471075bb +2024-11-04 0757f1b0bada35c6991a2009185e4388fbb046b3 diff --git a/repos/gems/recipes/src/window_layouter/hash b/repos/gems/recipes/src/window_layouter/hash index 8384091dde..9e9d950a67 100644 --- a/repos/gems/recipes/src/window_layouter/hash +++ b/repos/gems/recipes/src/window_layouter/hash @@ -1 +1 @@ -2024-08-28 334a2e6d83cb4a7b1e949d3afffc06abf3a6395d +2024-10-29 ae609775883e8aa8e89f7a31b420614922404a3a diff --git a/repos/gems/recipes/src/wm/hash b/repos/gems/recipes/src/wm/hash index 1a2dcdae2b..a8facfbd31 100644 --- a/repos/gems/recipes/src/wm/hash +++ b/repos/gems/recipes/src/wm/hash @@ -1 +1 @@ -2024-08-28 b88935dca6b2b5a2762b2c6ea750b5655af1e643 +2024-11-04 f1f330838199fffe4d8eecebf018b89fd89f0602 diff --git a/repos/gems/run/depot_autopilot.run b/repos/gems/run/depot_autopilot.run index 46f5bf6f7f..c93006ac5f 100644 --- a/repos/gems/run/depot_autopilot.run +++ b/repos/gems/run/depot_autopilot.run @@ -672,6 +672,7 @@ set default_test_pkgs { test-init_loop test-ldso test-libc + test-libc_alarm test-libc_connect_lwip test-libc_connect_lxip test-libc_connect_vfs_server_lwip @@ -681,6 +682,7 @@ set default_test_pkgs { test-libc_fifo_pipe test-libc_fork test-libc_getenv + test-libc_kqueue test-libc_pipe test-libc_vfs test-libc_vfs_audit @@ -840,7 +842,7 @@ init_previous_results # set max_nr_of_tests_per_boot 0 if {[have_spec sel4]} { - set max_nr_of_tests_per_boot 20 + set max_nr_of_tests_per_boot 22 } # generic preparation for each system boot diff --git a/repos/gems/run/nano3d.run b/repos/gems/run/nano3d.run index d4cebff5c0..34cc8c1412 100644 --- a/repos/gems/run/nano3d.run +++ b/repos/gems/run/nano3d.run @@ -59,7 +59,7 @@ install_config { </config> </start> - <start name="backdrop"> + <start name="backdrop" caps="130"> <resource name="RAM" quantum="20M"/> <config> <libc/> diff --git a/repos/gems/run/sculpt.run b/repos/gems/run/sculpt.run index 5435e2759a..850a193866 100644 --- a/repos/gems/run/sculpt.run +++ b/repos/gems/run/sculpt.run @@ -7,7 +7,7 @@ # # Note: the string must be exactly 5 bytes long. # -proc sculpt_version { } { return "24.06" } +proc sculpt_version { } { return "24.10" } proc assert_platform_supported { } { @@ -15,6 +15,7 @@ proc assert_platform_supported { } { if {[have_board pc]} return if {[have_board imx8q_evk]} return if {[have_board mnt_reform2]} return + if {[have_board mnt_pocket]} return if {[have_board linux]} return if {[have_board pinephone]} return @@ -188,13 +189,28 @@ proc driver_routes { } { <service name="ROM" label="mmc.dtb"> <parent label="imx8mq_sd_card-mnt_reform2.dtb"/> </service> <service name="ROM" label="nic"> <parent label="fec_nic"/> </service> <service name="ROM" label="nic.dtb"> <parent label="fec_nic-mnt_reform2.dtb"/> </service> - <service name="ROM" label="usb"> <parent label="imx8mq_usb_host"/> </service> - <service name="ROM" label="usb.dtb"> <parent label="imx8mq_usb_host-mnt_reform2.dtb"/> </service> + <service name="ROM" label="usb"> <parent label="imx8m_usb_host"/> </service> + <service name="ROM" label="usb.dtb"> <parent label="imx8m_usb_host-mnt_reform2.dtb"/> </service> <service name="ROM" label="wifi.lib.so"> <parent label="imx8mq_wifi.lib.so"/> </service> <service name="ROM" label="wifi_firmware.tar"> <parent label="imx8mq_wifi_firmware.tar"/> </service> <service name="I2c"> <child name="drivers"/> </service> } + set result(mnt_pocket) { + <service name="ROM" label="fb"> <parent label="imx8mq_fb"/> </service> + <service name="ROM" label="fb.dtb"> <parent label="imx8mq_fb-mnt_pocket.dtb"/> </service> + <service name="ROM" label="mmc"> <parent label="imx8mq_sd_card"/> </service> + <service name="ROM" label="mmc.dtb"> <parent label="imx8mq_sd_card-mnt_pocket.dtb"/> </service> + <service name="ROM" label="nic"> <parent label="stmmac_nic"/> </service> + <service name="ROM" label="nic.dtb"> <parent label="stmmac_nic-mnt_pocket.dtb"/> </service> + <service name="ROM" label="usb"> <parent label="imx8m_usb_host"/> </service> + <service name="ROM" label="usb.dtb"> <parent label="imx8m_usb_host-mnt_pocket.dtb"/> </service> + <service name="ROM" label="wifi.dtb"> <parent label="wifi-mnt_pocket.dtb"/> </service> + <service name="ROM" label="wifi.lib.so"> <parent label="imx8mp_qcacld2_wifi.lib.so"/> </service> + <service name="ROM" label="wifi_firmware.tar"> <parent label="imx8mp_qcacld2_wifi_firmware.tar"/> </service> + <service name="I2c"> <child name="drivers"/> </service> + } + set result(imx8q_evk) { <service name="ROM" label="nic"> <parent label="fec_nic"/> </service> <service name="ROM" label="nic.dtb"> <parent label="fec_nic-imx8q_evk.dtb"/> </service> @@ -459,7 +475,7 @@ install_config { </start> <start name="nitpicker" caps="1000" priority="-1"> - <resource name="RAM" quantum="12M"/> + <resource name="RAM" quantum="18M"/> <resource name="CPU" quantum="10"/> <affinity xpos="1" width="1"/> <!-- decouple nitpicker from boot CPU --> <provides> @@ -467,9 +483,11 @@ install_config { </provides> <route> <service name="ROM" label="config"> - <child name="config_fs_rom" label="nitpicker"/> </service> + <child name="config_fs_rom" label="managed/nitpicker"/> </service> <service name="ROM" label="focus"> <child name="nit_focus"/> </service> + <service name="Report" label="panorama"> + <child name="fs_report"/> </service> <service name="Report" label="keystate"> <child name="report_logger"/> </service> <service name="Report"> <child name="report_rom"/> </service> @@ -713,8 +731,8 @@ install_config { } [log_route] [driver_routes] { <service name="Event" label="leitzentrale"> <child name="leitzentrale"/> </service> <service name="Event"> <child name="event_filter"/> </service> - <service name="Capture" label="global"> <child name="nitpicker"/> </service> <service name="Capture" label="leitzentrale"> <child name="leitzentrale"/> </service> + <service name="Capture"> <child name="nitpicker"/> </service> <service name="Pin_state"> <child name="drivers"/> </service> <service name="Pin_control"> <child name="drivers"/> </service> <service name="Terminal"> <child name="terminal_monitor"/> </service> @@ -830,7 +848,7 @@ set fd [open [managed_config_path depot_query] w] puts $fd "<query/>" close $fd -foreach config { fonts wifi runtime event_filter system } { +foreach config { fonts wifi runtime event_filter system nitpicker } { set ingredient [single_ingredient $config "default"] if {$ingredient != ""} { set from [ingredient_path $config $ingredient] diff --git a/repos/gems/run/sculpt/index b/repos/gems/run/sculpt/index index 5a6596288f..309cfc2833 100644 --- a/repos/gems/run/sculpt/index +++ b/repos/gems/run/sculpt/index @@ -14,18 +14,18 @@ </index> <index name="Tools"> - <pkg path="system_shell" info="command-line interface to the system"/> - <pkg path="system_clock-pc" info="real-time-clock service" arch="x86_64"/> - <pkg path="qt5_textedit" info="Qt5-based text editor"/> - <pkg path="report_dump" info="save periodic snapshots of the report fs"/> - <pkg path="recall_fs" info="component-specific file-system view"/> - <pkg path="file_vault" info="encrypted file store"/> - <pkg path="black_hole" info="pseudo service provider"/> - <pkg path="usb_webcam" info="USB webcam"/> - <pkg path="bsd_audio" info="audio driver" arch="x86_64"/> - <pkg path="mixer" info="audio mixer"/> - <pkg path="terminal" info="graphical terminal"/> - <pkg path="gdb_x86" info="GNU debugger" arch="x86_64"/> + <pkg path="system_shell" info="command-line interface to the system"/> + <pkg path="system_clock-pc" info="real-time-clock service" arch="x86_64"/> + <pkg path="qt5_textedit" info="Qt5-based text editor"/> + <pkg path="report_dump" info="save periodic snapshots of the report fs"/> + <pkg path="recall_fs" info="component-specific file-system view"/> + <pkg path="file_vault" info="encrypted file store"/> + <pkg path="black_hole" info="pseudo service provider"/> + <pkg path="usb_webcam" info="USB webcam"/> + <pkg path="bsd_audio" info="audio driver" arch="x86_64"/> + <pkg path="record_play_mixer" info="audio mixer"/> + <pkg path="terminal" info="graphical terminal"/> + <pkg path="gdb_x86" info="GNU debugger" arch="x86_64"/> </index> <index name="Demos"> diff --git a/repos/gems/run/sculpt_image.run b/repos/gems/run/sculpt_image.run index ea059ddf33..f565a0896e 100644 --- a/repos/gems/run/sculpt_image.run +++ b/repos/gems/run/sculpt_image.run @@ -6,6 +6,7 @@ proc board_supported { } { if {[have_board pinephone]} { return true } if {[have_board pc]} { return true } if {[have_board mnt_reform2]} { return true } + if {[have_board mnt_pocket]} { return true } return false } @@ -45,6 +46,12 @@ if {[have_board mnt_reform2]} { assert_run_arg "--image-uboot-gzip-best" } +if {[have_board mnt_pocket]} { + assert_include image/uboot + assert_include image/mnt_pocket_sdcard + assert_run_arg "--image-uboot-gzip-best" +} + source ${genode_dir}/repos/gems/run/sculpt.run set image_name "sculpt-$board_var-[build_date]" diff --git a/repos/gems/run/tiled_wm.run b/repos/gems/run/tiled_wm.run index e7da79b378..45dc3813fd 100644 --- a/repos/gems/run/tiled_wm.run +++ b/repos/gems/run/tiled_wm.run @@ -1,5 +1,7 @@ source ${genode_dir}/repos/libports/run/qt5_common.inc +build { test/tiled_wm } + import_from_depot [depot_user]/src/qt5_component \ [depot_user]/src/qt5_textedit \ [depot_user]/src/dynamic_rom \ @@ -194,7 +196,7 @@ install_config { <any-service> <parent /> <any-child/> </any-service> </route> </start> - <start name="textedit" caps="250"> + <start name="textedit" caps="350"> <resource name="RAM" quantum="70M"/> <config> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> @@ -219,7 +221,7 @@ install_config { </config> } -build_boot_image [qt5_boot_modules] +build_boot_image [list {*}[build_artifacts] {*}[qt5_boot_modules]] append qemu_args " -device nec-usb-xhci,id=xhci -device usb-tablet" diff --git a/repos/gems/run/tiled_wm_qt6.run b/repos/gems/run/tiled_wm_qt6.run index fc6426f35a..2b2cfc589f 100644 --- a/repos/gems/run/tiled_wm_qt6.run +++ b/repos/gems/run/tiled_wm_qt6.run @@ -194,7 +194,7 @@ install_config { <any-service> <parent /> <any-child/> </any-service> </route> </start> - <start name="textedit" caps="250"> + <start name="textedit" caps="350"> <resource name="RAM" quantum="70M"/> <config> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> diff --git a/repos/gems/run/wm.run b/repos/gems/run/wm.run index 9db7234587..4b05218668 100644 --- a/repos/gems/run/wm.run +++ b/repos/gems/run/wm.run @@ -63,6 +63,8 @@ install_config { <policy label_prefix="pointer" domain="pointer"/> <default-policy domain="default"/> + + <global-key name="KEY_SCREEN" label="wm -> wm -> decorator" /> </config> </start> @@ -108,7 +110,7 @@ install_config { </route> </start> - <start name="backdrop" priority="-1"> + <start name="backdrop" priority="-1" caps="120"> <resource name="RAM" quantum="24M"/> <config> <libc/> @@ -127,7 +129,7 @@ install_config { </route> </start> - <start name="wm_backdrop" priority="-1"> + <start name="wm_backdrop" priority="-1" caps="120"> <binary name="backdrop" /> <resource name="RAM" quantum="32M"/> <config> @@ -154,7 +156,9 @@ set fd [open [run_dir]/genode/focus w] puts $fd "<focus label=\"wm -> focus\"/>" close $fd -copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/wm.config [run_dir]/genode/ +copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/wm.config [run_dir]/genode/ +copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/layouter.config [run_dir]/genode/ +copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/decorator_init.config [run_dir]/genode/ build { app/window_layouter app/decorator server/nitpicker server/wm test/nitpicker } diff --git a/repos/gems/sculpt/default-pc.sculpt b/repos/gems/sculpt/default-pc.sculpt index 1cdcee7185..68bf658ab2 100644 --- a/repos/gems/sculpt/default-pc.sculpt +++ b/repos/gems/sculpt/default-pc.sculpt @@ -12,7 +12,7 @@ launcher: audio mixer system_clock acpi_support recall_fs touchpad # selection of accepted depot-package providers depot: genodelabs cnuke alex-ab mstein nfeske cproc chelmuth jschlatow -depot: ssumpf skalk +depot: ssumpf skalk atopia # preconfigured example scenarios presets: empty nano3d window_manager falkon_web_browser goa_testbed diff --git a/repos/gems/sculpt/deploy/falkon_web_browser b/repos/gems/sculpt/deploy/falkon_web_browser index f8915f63a9..0f32302cbf 100644 --- a/repos/gems/sculpt/deploy/falkon_web_browser +++ b/repos/gems/sculpt/deploy/falkon_web_browser @@ -61,7 +61,7 @@ </config> </start> - <start name="falkon-jemalloc" priority="-2" pkg="cproc/pkg/falkon-jemalloc/2024-04-16"> + <start name="falkon-jemalloc" priority="-2" pkg="cproc/pkg/falkon-jemalloc/2024-10-28"> <route> <service name="Nic"> <child name="nic_router"/> </service> <service name="Rtc"> <child name="system_clock"/> </service> diff --git a/repos/gems/sculpt/depot/atopia/download b/repos/gems/sculpt/depot/atopia/download new file mode 100644 index 0000000000..fc75210b14 --- /dev/null +++ b/repos/gems/sculpt/depot/atopia/download @@ -0,0 +1 @@ +https://depot.genode.org diff --git a/repos/gems/sculpt/depot/atopia/pubkey b/repos/gems/sculpt/depot/atopia/pubkey new file mode 100644 index 0000000000..f59d385127 --- /dev/null +++ b/repos/gems/sculpt/depot/atopia/pubkey @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBGM9aNABEACdVjdMokz8NrtETaRd+ockpQpjeRg8KMRGxH7+p0lttJXjz6Cq +boZcor7nrvKMV8kXnHoJBvMZJvmxRZUnn/9yC8FzU1C2c8UAqJ7cWtQhZevrIMOp +KEufiOythb8ylGhomdyLjCDivsWnijW+Cy9TBQbQROZ54/L3mAv3uCkkbQbhs7Wg +hflEx78FiEDaoe0q/0jF0Argx4/t1ztnUHzyvnWU2VMITvzZcLiSZi49cwi5l6LH +jQHdtcMMMR5E8jWpEUOSBATWrp0gilt4IM0EDYq4OVwiehqR1sxBqZfzgbe+w+KH +IMxd16th2sQtt1ypXd27tts6xakchuWsZ7uH3T6KlLngdafvzfoy8KStppF8mkQK +QIpkgsW1OBRfveRJERAWYPMwAGVQUwyGXFq8d+bb2C9nvQz3S0WyyervMvaMtf8T +lrQL6gtKzyzFiog0i1zDbFtgSe0LmKANVStBnzXZPtHyCmdccvqTb5hyOT/FOe24 +nVDOMHTKSXZ18RkWBHyKCjJoSFOJMv2t2zzJkN90+dKrNrap9C9bGhZ51CxsnWv2 +RI++7fW5zYUW0yN0LwzPIvjRCX5EWkLj4jqgzWtgt/+eU6EPG2S3lkdFr9AIHa0Y +8SI/l1UHFlnfM9/Wzgk5c3/3Wfj6LGTvgyVE4AmdmUsg2HdlY6SUPbck+QARAQAB +tDVCZW5qYW1pbiBMYW1vd3NraSA8YmVuamFtaW4ubGFtb3dza2lAZ2Vub2RlLWxh +YnMuY29tPokCVAQTAQgAPhYhBG5FHmDqtr+LkCkQWni3QG21KBpNBQJjPWjQAhsD +BQkFo5qABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEHi3QG21KBpNdkIQAIG2 +nBKUXx+r2DsmgdGYr7q3GiwA23zLwhTae2zvVvpCk4qQZa0/hkfnVCSDY+Yo1amR +rQDMVSE+hbXsj05uNYAZITMeU61/8kJrwRQSQaTYKpfpvVOKTUpD+dWiFEzMiu6H +wYBcgyYfKAcmnPteM/puS41sPJBc2Av+vdzzHdW3ZzppBwGqJlHg8VctfyjkKIyT +FQNvwhEiT5/pvrPjUAZR31tYVxOGvdQRv2fn4zu+ySgTGYdnmCpY0Pxmu4nReZ5u +aIoettzlBWSZpWbTwPr5IseRnWTPaBNS2wUuG8CfA7DduCr61/mR3bPCBaRWqZsC +XM1Of56cPiYfBs/qUA/JIaSk+ISCd5sihgGuCwo0WRCLrsEP+/McEh4gbnsyrpoV +kBSy/2ipQASuMfUca2hmPK42VOVTVWt8rwHJ41DJocwkJa1wGzLvqXcDrZZvYMKE +946qvm3lJ8nBjH1z2vAyElRd66vzQIbQOrMW00NDMXNzDBP8UR8geo6lptk+nbfT +DZiRI3XsaGc8NvNKV83cQ/jxTbynlruY9KdJu+OUn7T4J3l7RZjMHIfMNYmURfKy +fwB53Gp/55fV/pyPw5fjk2PMb5+iNC4jP4HRcTzSGrexCHuEfKe1Jh9SdaysYyxt +IztFPdrqTMoUkW8pGYEC9HXz1uG38P59FvgYxNH8uQINBGM9aNABEADkwh2qneuZ +9OVScywMcsW3uXtheqmsllbUuAl2Xm/lhuKpHMDt43jUVXOoTIIqYIwtAAStfnHG +ytZVxSHk4HugIYqfI/jJesjPwDZnF8xjswaWKbqjn5e6o1poYqsSkH1HJxXgZ9Ui +WUqMPFaNm1XM12XS0eQy0gSwwGzXWplkkBx9l7cvqIQ3rNa9KOKbtn8T9lWdHVZ5 +4VzYAS7Y9eBIRbeJBBGg7iNYTQ/8SAX8T2LSLVpEBIILVrB2GLdOm+mIf21VGoEC +CD6AHORF26g6gTE+lQkE+jevSVZDrUYIbyFZ5mUiwPibYo1ITHlaPrzRNAAQIafz +vMMuMM+S6DgkXma2jbZXVHNfXF9FVkNSuWxIfxZVlCHXLZN1Ddp8eQhX6zbFcuLU +y1nPF22ReyqjlB2F4pWdWYbhb6bJoS1QFTKkOlwCsAUMNpCksYVDZnB+1XMBwEmE +/PhMgNLtrx3dCORRTJelv/PUOy1o0LcMPzf/hzB7pEUInncPN79lX4XOi8dfafhI +cw3721NTVES8Ru183/mHXaC+GcdC13pObLBDulJDadtYV8WLIBJbBmZSEYIstiJZ +/0d5hrphzknxdrlIKz2mVQWRcSsKkArx9Ve7VQH2tPcBm1iKZO2uKQDaCMglCEif +apZgoVHz7vBr+CAtWC30r1pme07QPjocrwARAQABiQI8BBgBCAAmFiEEbkUeYOq2 +v4uQKRBaeLdAbbUoGk0FAmM9aNACGwwFCQWjmoAACgkQeLdAbbUoGk0YCxAAlzlJ ++TLIv5cQlSP1C8PvSNZdvF8XzO2rI+vZrWS6+2i++oFZOReyvYAw2wNhP23fSWTl +LxO1sJ72+h+iNs/udNYnr1HdExIzrFQoJO8saPyV8cQLc8T8XgejyGK/FVwB8xiJ +jzSGjXsB2xNzet278FipLvwl2GQP0VyAxka5ZPaBQaB9cJOKjBl6cVC9TmGnGLin +sfwAEFHvdOK4JRAtpYvF5aQYlgSF2Dvh9hb93U4Z0CmjDhRlim4py13VZ4L9yZMO +scQr20iaGsfU6XNdQZWJ+gsEvWeNoUzH1gVci4uLgLkIDWrctXBUCnLx40HbrbOJ +EOZm1/2hjuHFjFHCxKKGCp8zyvcm2ZCkh1i8xPi2x/rl73WGlhDlxhPp3Ve+oZ6c +jdbOPe+csrnWRNijUNjib1Zhpr4fe9sTEorKrjVc6JpX3WtUvX5PvG6W8opeAP8p +1ec47MtonUfY8SE8a1OqRhHt4e95+mGGonUG4XLS9r572P1awvRvkGSqC8464082 +0iemYv6AKeOjWs6iCnmbBho+VNzJpr1L5Y3ciBIfQoMi8IWcDVYWTzv5pgPUBr0G +/CWd0Grbr6POJrzPJ+iQtAeuGZ/9tUVJH153qaVhwmJW4eb6qSXahAF72MDF8fdV +jmPs+5Q/o4+DWQ0O1pc55VlbrKXF4RFP9J1XJQo= +=TJqO +-----END PGP PUBLIC KEY BLOCK----- diff --git a/repos/gems/sculpt/fb/default b/repos/gems/sculpt/fb/default index f5ed6f1195..daa6eecd19 100644 --- a/repos/gems/sculpt/fb/default +++ b/repos/gems/sculpt/fb/default @@ -1,5 +1,3 @@ <config width="1024" height="768" max_width="3840" max_height="2160"> <report connectors="yes"/> - <!-- <connector name="eDP-1" width="1920" height="1080" enabled="true" brightness="75"/> --> - <!-- <connector name="HDMI-A-1" width="1024" height="768" hz="75" enabled="true"/> --> </config> diff --git a/repos/gems/sculpt/gpu/intel b/repos/gems/sculpt/gpu/intel index 27068b043f..9537060485 100644 --- a/repos/gems/sculpt/gpu/intel +++ b/repos/gems/sculpt/gpu/intel @@ -1,4 +1,4 @@ -<config system="yes"> +<config system="yes" max_framebuffer_memory="96M"> <device vendor="0x8086" device="0x1606" generation="8" platform="broadwell" description="HD Graphics (BDW GT1 ULT)"/> <device vendor="0x8086" device="0x1616" generation="8" platform="broadwell" description="HD Graphics 5500 (BDW GT2 ULT)"/> <device vendor="0x8086" device="0x1622" generation="8" platform="broadwell" description="Iris Pro Graphics 6200 (BDW GT3e)"/> diff --git a/repos/gems/sculpt/launcher/audio b/repos/gems/sculpt/launcher/audio index c4caf2f4c4..a0041920ed 100644 --- a/repos/gems/sculpt/launcher/audio +++ b/repos/gems/sculpt/launcher/audio @@ -13,6 +13,5 @@ <service name="Record"> <child name="mixer"/> </service> <service name="Play"> <child name="mixer"/> </service> <service name="Report"> <parent/> </service> - <service name="RM"> <parent/> </service> </route> </launcher> diff --git a/repos/gems/sculpt/launcher/touchpad b/repos/gems/sculpt/launcher/touchpad index 65a2ac0b3b..6becbec54b 100644 --- a/repos/gems/sculpt/launcher/touchpad +++ b/repos/gems/sculpt/launcher/touchpad @@ -1,4 +1,4 @@ -<launcher pkg="chelmuth/pkg/pc_i2c_hid_drv/2024-04-24" priority="-1"> +<launcher pkg="chelmuth/pkg/pc_i2c_hid/2024-10-23" priority="-1"> <config info="Fujtisu U7411 (SYNAPTICS)"/> <!-- <config gpio_pin="266" bus_addr="21" hid_addr="1" info="Fujtisu U7511 (ELAN)"/> diff --git a/repos/gems/sculpt/leitzentrale/default b/repos/gems/sculpt/leitzentrale/default index 323b127b96..39d841370c 100644 --- a/repos/gems/sculpt/leitzentrale/default +++ b/repos/gems/sculpt/leitzentrale/default @@ -77,8 +77,8 @@ <resource name="RAM" quantum="33M"/> <resource name="CPU" quantum="20"/> <provides> <service name="Framebuffer"/> <service name="Input"/> </provides> - <config/> <route> + <service name="ROM" label="config"> <child name="report_rom"/> </service> <service name="Gui"> <child name="fader"/> </service> <any-service> <parent/> </any-service> </route> @@ -120,6 +120,7 @@ <policy label="manager -> window_list" report="wm -> window_list"/> <policy label="manager -> decorator_margins" report="decorator -> decorator_margins"/> <policy label="nitpicker -> focus" report="manager -> focus"/> + <policy label="gui_fb -> config" report="manager -> gui_fb_config"/> <policy label="runtime -> leitzentrale -> diag_dialog" report="manager -> diag_dialog"/> @@ -142,8 +143,8 @@ </config> </start> - <start name="wm" caps="300" priority="-1"> - <resource name="RAM" quantum="4M"/> + <start name="wm" caps="150" priority="-1"> + <resource name="RAM" quantum="2M"/> <provides> <service name="Gui"/> <service name="Report"/> <service name="ROM"/> </provides> @@ -160,7 +161,7 @@ </route> </start> - <start name="decorator" caps="400" priority="-1"> + <start name="decorator" caps="580" priority="-1"> <binary name="themed_decorator"/> <resource name="RAM" quantum="20M"/> <resource name="CPU" quantum="20"/> @@ -178,15 +179,15 @@ </dir> <dir name="dev"> <log/> </dir> </vfs> - <policy label="log" decoration="yes" motion="20"/> - <policy label="runtime -> leitzentrale -> settings_dialog" decoration="no" motion="20"/> - <policy label="runtime -> leitzentrale -> system_dialog" decoration="no" motion="20"/> - <policy label="runtime -> leitzentrale -> file_browser_dialog" decoration="no" motion="30"/> - <policy label="runtime -> leitzentrale -> network_dialog" decoration="no" motion="20"/> - <policy label="runtime -> leitzentrale -> runtime_dialog" decoration="no" motion="30"/> - <policy label="runtime -> leitzentrale -> diag_dialog" decoration="no" motion="30"/> - <policy label="runtime -> leitzentrale -> popup_dialog" decoration="no" motion="20"/> - <policy label="runtime -> leitzentrale -> panel_dialog" decoration="no" motion="20"/> + <policy label="log" decoration="yes" motion="40"/> + <policy label="runtime -> leitzentrale -> settings_dialog" decoration="no" motion="40"/> + <policy label="runtime -> leitzentrale -> system_dialog" decoration="no" motion="40"/> + <policy label="runtime -> leitzentrale -> file_browser_dialog" decoration="no" motion="60"/> + <policy label="runtime -> leitzentrale -> network_dialog" decoration="no" motion="40"/> + <policy label="runtime -> leitzentrale -> runtime_dialog" decoration="no" motion="60"/> + <policy label="runtime -> leitzentrale -> diag_dialog" decoration="no" motion="60"/> + <policy label="runtime -> leitzentrale -> popup_dialog" decoration="no" motion="40"/> + <policy label="runtime -> leitzentrale -> panel_dialog" decoration="no" motion="40"/> <policy label_prefix="logo" decoration="no"/> <default-policy/> </config> @@ -231,6 +232,8 @@ <child name="config_fs_report" label="managed -> nic_router"/> </service> <service name="Report" label="fb_config"> <child name="config_fs_report" label="managed -> fb"/> </service> + <service name="Report" label="nitpicker_config"> + <child name="config_fs_report" label="managed -> nitpicker"/> </service> <service name="Report" label="usb_config"> <child name="config_fs_report" label="managed -> usb"/> </service> <service name="Report" label="system_config"> @@ -264,7 +267,7 @@ </route> </start> - <start name="log_terminal" priority="-1"> + <start name="log_terminal" priority="-1" caps="120"> <binary name="terminal"/> <resource name="RAM" quantum="8M"/> <provides> <service name="Terminal"/> </provides> diff --git a/repos/gems/sculpt/nitpicker/default b/repos/gems/sculpt/nitpicker/default index f48a9807fe..80f455ea6b 100644 --- a/repos/gems/sculpt/nitpicker/default +++ b/repos/gems/sculpt/nitpicker/default @@ -1,6 +1,6 @@ <config focus="rom"> <capture/> <event/> - <report hover="yes" focus="yes" clicked="yes" keystate="no"/> + <report hover="yes" focus="yes" clicked="yes" keystate="no" panorama="yes"/> <background color="#000000"/> <domain name="overlay" layer="0" label="no" hover="always" focus="transient" content="client"/> diff --git a/repos/gems/sculpt/wifi/default b/repos/gems/sculpt/wifi/default index 361d2eaff4..6161e61352 100644 --- a/repos/gems/sculpt/wifi/default +++ b/repos/gems/sculpt/wifi/default @@ -1,3 +1,3 @@ -<wifi connected_scan_interval="0" scan_interval="5" rfkill="no" verbose="no"> - <network ssid="" protection="NONE" passphrase=""/> +<wifi scan_interval="5" rfkill="no" verbose="no"> + <!-- <network ssid="" protection="NONE" passphrase=""/> --> </wifi> diff --git a/repos/gems/src/app/backdrop/main.cc b/repos/gems/src/app/backdrop/main.cc index a78883ae4c..5333e63455 100644 --- a/repos/gems/src/app/backdrop/main.cc +++ b/repos/gems/src/app/backdrop/main.cc @@ -47,6 +47,8 @@ struct Backdrop::Main Gui::Connection _gui { _env, "backdrop" }; + Gui::Rect _gui_win { }; + struct Buffer { Gui::Connection &gui; @@ -59,18 +61,13 @@ struct Backdrop::Main Dataspace_capability _ds_cap(Gui::Connection &gui) { /* setup virtual framebuffer mode */ - gui.buffer(mode, false); + gui.buffer(mode); return gui.framebuffer.dataspace(); } Attached_dataspace fb_ds; - Genode::size_t surface_num_bytes() const - { - return size().count()*mode.bytes_per_pixel(); - } - Attached_ram_dataspace surface_ds; /** @@ -79,7 +76,7 @@ struct Backdrop::Main Buffer(Genode::Env &env, Gui::Connection &gui, Framebuffer::Mode mode) : gui(gui), mode(mode), fb_ds(env.rm(), _ds_cap(gui)), - surface_ds(env.ram(), env.rm(), surface_num_bytes()) + surface_ds(env.ram(), env.rm(), mode.num_bytes()) { } /** @@ -100,11 +97,10 @@ struct Backdrop::Main void flush_surface() { /* blit back to front buffer */ - blit(surface_ds.local_addr<void>(), - (unsigned)surface_num_bytes(), - fb_ds.local_addr<void>(), - (unsigned)surface_num_bytes(), - (unsigned)surface_num_bytes(), 1); + unsigned const num_bytes = unsigned(mode.num_bytes()); + blit(surface_ds.local_addr<void>(), num_bytes, + fb_ds.local_addr<void>(), num_bytes, + num_bytes, 1); } }; @@ -118,7 +114,7 @@ struct Backdrop::Main using Command = Gui::Session::Command; _gui.enqueue<Command::Background>(_view_id); - Gui::Rect rect(Gui::Point(), _buffer->size()); + Gui::Rect rect(_gui_win.at, _buffer->size()); _gui.enqueue<Command::Geometry>(_view_id, rect); _gui.enqueue<Command::Back>(_view_id); _gui.execute(); @@ -135,11 +131,6 @@ struct Backdrop::Main Signal_handler<Main> _config_handler = { _env.ep(), *this, &Main::_handle_config_signal }; - void _handle_sync(); - - Signal_handler<Main> _sync_handler = { - _env.ep(), *this, &Main::_handle_sync}; - template <typename PT> void _paint_texture(Surface<PT> &, Texture<PT> const &, Surface_base::Point, bool); @@ -150,8 +141,7 @@ struct Backdrop::Main { _gui.view(_view_id, { }); - _gui.mode_sigh(_config_handler); - + _gui.info_sigh(_config_handler); _config.sigh(_config_handler); _handle_config(); @@ -318,10 +308,14 @@ void Backdrop::Main::_handle_config() { _config.update(); - Framebuffer::Mode const phys_mode = _gui.mode(); - Framebuffer::Mode const - mode { .area = { _config.xml().attribute_value("width", phys_mode.area.w), - _config.xml().attribute_value("height", phys_mode.area.h) } }; + _gui_win = _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 640, 480 } }; }); + + _gui_win.area = { _config.xml().attribute_value("width", _gui_win.w()), + _config.xml().attribute_value("height", _gui_win.h()) }; + + Framebuffer::Mode const mode { .area = _gui_win.area, .alpha = false }; _buffer.construct(_env, _gui, mode); @@ -345,20 +339,10 @@ void Backdrop::Main::_handle_config() } }); - /* schedule buffer refresh */ - _gui.framebuffer.sync_sigh(_sync_handler); -} - - -void Backdrop::Main::_handle_sync() -{ Libc::with_libc([&] () { _buffer->flush_surface(); _update_view(); }); - - /* disable sync signal until the next call of 'handle_config' */ - _gui.framebuffer.sync_sigh(Signal_context_capability()); } diff --git a/repos/gems/src/app/decorator/main.cc b/repos/gems/src/app/decorator/main.cc index 43c284bf8e..0013a91c66 100644 --- a/repos/gems/src/app/decorator/main.cc +++ b/repos/gems/src/app/decorator/main.cc @@ -17,6 +17,7 @@ #include <base/heap.h> #include <base/attached_rom_dataspace.h> #include <gui_session/connection.h> +#include <timer_session/connection.h> #include <os/pixel_rgb888.h> #include <os/reporter.h> @@ -39,37 +40,84 @@ struct Decorator::Main : Window_factory_base { Env &_env; + Timer::Connection _timer { _env }; + + /* + * Time base for animations, which are computed in steps of 10 ms + */ + struct Ticks { uint64_t cs; /* centi-seconds (10 ms) */ }; + + Ticks _now() + { + return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 }; + } + Gui::Connection _gui { _env }; struct Canvas { - Framebuffer::Mode const mode; - Attached_dataspace fb_ds; - Decorator::Canvas<Pixel_rgb888> canvas; + Env &_env; + Gui::Connection &_gui; - Canvas(Env &env, Gui::Connection &gui) - : - mode(gui.mode()), - fb_ds(env.rm(), - (gui.buffer(mode, false), gui.framebuffer.dataspace())), - canvas(fb_ds.local_addr<Pixel_rgb888>(), mode.area, env.ram(), env.rm()) - { } + Gui::Area const scr_area = _gui.panorama().convert<Gui::Area>( + [&] (Gui::Rect rect) { return rect.area; }, + [&] (Gui::Undefined) { return Gui::Area { 1, 1 }; }); + + /* + * The GUI connection's buffer is split into two parts. The upper + * part contains the front buffer displayed by the GUI server + * whereas the lower part contains the back buffer targeted by + * the Decorator::Canvas. + */ + Dataspace_capability _buffer_ds() const + { + _gui.buffer({ .area = { .w = scr_area.w, .h = scr_area.h*2 }, + .alpha = false }); + return _gui.framebuffer.dataspace(); + } + + Attached_dataspace fb_ds { _env.rm(), _buffer_ds() }; + + Pixel_rgb888 *_canvas_pixels_ptr() + { + return fb_ds.local_addr<Pixel_rgb888>() + scr_area.count(); + } + + Decorator::Canvas<Pixel_rgb888> canvas { + _canvas_pixels_ptr(), scr_area, _env.ram(), _env.rm() }; + + Canvas(Env &env, Gui::Connection &gui) : _env(env), _gui(gui) { } }; Reconstructible<Canvas> _canvas { _env, _gui }; + void _back_to_front(Dirty_rect dirty) + { + if (!_canvas.constructed()) + return; + + Rect const canvas_rect { { }, _canvas->scr_area }; + + dirty.flush([&] (Rect const &r) { + + Rect const clipped = Rect::intersect(r, canvas_rect); + Point const from_p1 = clipped.p1() + Point { 0, int(canvas_rect.h()) }; + Point const to_p1 = clipped.p1(); + + _gui.framebuffer.blit({ from_p1, clipped.area }, to_p1); }); + } + Signal_handler<Main> _mode_handler { _env.ep(), *this, &Main::_handle_mode }; void _handle_mode() { _canvas.construct(_env, _gui); - _window_stack.mark_as_dirty(Rect(Point(0, 0), _canvas->mode.area)); + _window_stack.mark_as_dirty(Rect(Point(0, 0), _canvas->scr_area)); Dirty_rect dirty = _window_stack.draw(_canvas->canvas); - dirty.flush([&] (Rect const &r) { - _gui.framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h()); }); + _back_to_front(dirty); } Window_stack _window_stack = { *this }; @@ -104,33 +152,31 @@ struct Decorator::Main : Window_factory_base Animator _animator { }; - /** - * Process the update every 'frame_period' GUI sync signals. The - * 'frame_cnt' holds the counter of the GUI sync signals. - * - * A lower 'frame_period' value makes the decorations more responsive - * but it also puts more load on the system. - * - * If the GUI sync signal fires every 10 milliseconds, a - * 'frame_period' of 2 results in an update rate of 1000/20 = 50 frames per - * second. - */ - unsigned _frame_cnt = 0; - unsigned _frame_period = 2; - - /** - * Install handler for responding to GUI sync events - */ - void _handle_gui_sync(); - - void _trigger_sync_handling() - { - _gui.framebuffer.sync_sigh(_gui_sync_handler); - } + Ticks _previous_sync { }; Signal_handler<Main> _gui_sync_handler = { _env.ep(), *this, &Main::_handle_gui_sync }; + void _handle_gui_sync(); + + bool _gui_sync_enabled = false; + + void _trigger_gui_sync() + { + Ticks const now = _now(); + bool const idle = now.cs - _previous_sync.cs > 3; + + if (!_gui_sync_enabled) { + _gui.framebuffer.sync_sigh(_gui_sync_handler); + _gui_sync_enabled = true; + } + + if (idle) { + _previous_sync = now; + _gui_sync_handler.local_submit(); + } + } + Heap _heap { _env.ram(), _env.rm() }; Attached_rom_dataspace _config { _env, "config" }; @@ -150,7 +196,7 @@ struct Decorator::Main : Window_factory_base _config.sigh(_config_handler); _handle_config(); - _gui.mode_sigh(_mode_handler); + _gui.info_sigh(_mode_handler); _window_layout.sigh(_window_layout_handler); _pointer.sigh(_pointer_handler); @@ -267,16 +313,15 @@ void Decorator::Main::_handle_window_layout_update() _window_layout_update_needed = true; - _trigger_sync_handling(); + _trigger_gui_sync(); } void Decorator::Main::_handle_gui_sync() { - if (_frame_cnt++ < _frame_period) - return; + Ticks const now = _now(); - _frame_cnt = 0; + Ticks const passed_ticks { now.cs - _previous_sync.cs }; bool model_updated = false; @@ -300,31 +345,27 @@ void Decorator::Main::_handle_gui_sync() bool const windows_animated = _window_stack.schedule_animated_windows(); - /* - * To make the perceived animation speed independent from the setting of - * 'frame_period', we update the animation as often as the GUI - * sync signal occurs. - */ - for (unsigned i = 0; i < _frame_period; i++) + for (unsigned i = 0; i < passed_ticks.cs; i++) _animator.animate(); - if (!model_updated && !windows_animated) - return; + if (model_updated || windows_animated) { - Dirty_rect dirty = _window_stack.draw(_canvas->canvas); + Dirty_rect dirty = _window_stack.draw(_canvas->canvas); + _back_to_front(dirty); - _window_stack.update_gui_views(); - - _gui.execute(); - - dirty.flush([&] (Rect const &r) { - _gui.framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h()); }); + _window_stack.update_gui_views(); + _gui.execute(); + } /* * Disable sync handling when becoming idle */ - if (!_animator.active()) + if (!_animator.active()) { _gui.framebuffer.sync_sigh(Signal_context_capability()); + _gui_sync_enabled = false; + } + + _previous_sync = now; } diff --git a/repos/gems/src/app/decorator/window_element.h b/repos/gems/src/app/decorator/window_element.h index 6865fb5f17..d51cf99b71 100644 --- a/repos/gems/src/app/decorator/window_element.h +++ b/repos/gems/src/app/decorator/window_element.h @@ -99,10 +99,10 @@ class Decorator::Window_element : public Animator::Item /* medium fade-in when gaining the focus or hover highlight */ if ((!_state.focused && state.focused) || (!_state.highlighted && state.highlighted)) - return 15; + return 30; /* slow fade-out when leaving focus or hover highlight */ - return 20; + return 40; } public: diff --git a/repos/gems/src/app/fs_query/for_each_subdir_name.h b/repos/gems/src/app/fs_query/for_each_subdir_name.h index 3a300f33bd..be20df8676 100644 --- a/repos/gems/src/app/fs_query/for_each_subdir_name.h +++ b/repos/gems/src/app/fs_query/for_each_subdir_name.h @@ -16,9 +16,7 @@ /* Genode includes */ #include <os/vfs.h> - -/* local includes */ -#include <sorted_for_each.h> +#include <util/dictionary.h> namespace Genode { @@ -31,43 +29,35 @@ template <typename FN> static void Genode::for_each_subdir_name(Allocator &alloc, Directory const &dir, FN const &fn) { - using Dirname = Directory::Entry::Name; + using Name = Directory::Entry::Name; - struct Name : Interface, private Dirname + struct Dirname : Dictionary<Dirname, Name>::Element { - using Dirname::string; - - Name(Dirname const &name) : Dirname(name) { } - - bool higher(Name const &other) const - { - return (strcmp(other.string(), string()) > 0); - } + Dirname(Dictionary<Dirname, Name> & dict, Name const & name) + : Dictionary<Dirname, Name>::Element(dict, name) + { } }; - /* obtain list of sub directory names */ - Registry<Registered<Name>> names { }; + /* obtain dictionary of sub directory names */ + Dictionary<Dirname, Name> names { }; dir.for_each_entry([&] (Directory::Entry const &entry) { if (entry.dir()) - new (alloc) Registered<Name>(names, entry.name()); }); + new (alloc) Dirname(names, entry.name()); }); - auto destroy_names = [&] () - { - names.for_each([&] (Registered<Name> &name) { - destroy(alloc, &name); }); - }; + auto destroy_element = [&] (Dirname &element) { + destroy(alloc, &element); }; - /* iterate over sorted list */ + /* iterate over dictionary */ try { - sorted_for_each(alloc, names, [&] (Name const &name) { - fn(name.string()); }); + names.for_each([&] (Dirname const &element) { + fn(element.name.string()); }); } catch (...) { - destroy_names(); + while (names.with_any_element(destroy_element)) { } throw; } - destroy_names(); + while (names.with_any_element(destroy_element)) { } } #endif /* _FOR_EACH_SUBDIR_NAME_H_ */ diff --git a/repos/gems/src/app/fs_query/main.cc b/repos/gems/src/app/fs_query/main.cc index 0d23332a93..2438c2484c 100644 --- a/repos/gems/src/app/fs_query/main.cc +++ b/repos/gems/src/app/fs_query/main.cc @@ -21,6 +21,7 @@ #include <os/vfs.h> /* local includes */ +#include <sorted_for_each.h> #include <for_each_subdir_name.h> namespace Fs_query { @@ -39,10 +40,9 @@ struct Fs_query::Watched_file /** * Support for 'sorted_for_each' */ - bool higher(Watched_file const &other) const - { - return (strcmp(other._name.string(), _name.string()) > 0); - } + using Name = File_content::Path; + + Name const &name() const { return _name; } Node_rwx const _rwx; diff --git a/repos/gems/src/app/fs_query/sorted_for_each.h b/repos/gems/src/app/fs_query/sorted_for_each.h index a4f4c5dd05..ce27eae757 100644 --- a/repos/gems/src/app/fs_query/sorted_for_each.h +++ b/repos/gems/src/app/fs_query/sorted_for_each.h @@ -16,6 +16,7 @@ #include <base/registry.h> #include <base/allocator.h> +#include <util/dictionary.h> namespace Genode { template <typename T, typename FN> @@ -26,55 +27,52 @@ namespace Genode { /** * Execute 'fn' for each registry element * - * The type T must be equipped with a method that defines the sort criterion: + * The type T must be equipped with a method name() and a type Name: * - * bool higher(T const &other) const + * const & Name name() const * - * It must implement a strict order over all registry elements. E.g., if the - * registry contains a set of names, no name must occur twice. The allocator - * passed as 'alloc' is used to for temporary allocations. + * The allocator passed as 'alloc' is used to for temporary allocations. */ template <typename T, typename FN> static inline void Genode::sorted_for_each(Allocator &alloc, Registry<T> const ®istry, FN const &fn) { - struct Sorted_item : Avl_node<Sorted_item> + using Name = T::Name; + struct SortedItem : Dictionary<SortedItem, Name>::Element { T const &element; - Sorted_item(T const &element) : element(element) { } - - bool higher(Sorted_item const *item) const - { - return item ? element.higher(item->element) : false; - } + SortedItem(Dictionary<SortedItem, Name> & dict, Name const & name, T const & element) + : Dictionary<SortedItem, Name>::Element(dict, name), + element(element) + { } }; - /* build temporary AVL tree of sorted elements */ - Avl_tree<Sorted_item> sorted { }; + /* build temporary Dictionary of sorted and unique elements */ + using Dict = Dictionary<SortedItem, Name>; + Dict sorted { }; registry.for_each([&] (T const &element) { - sorted.insert(new (alloc) Sorted_item(element)); }); + /* skip duplicates */ + if (sorted.exists(element.name())) return; - auto destroy_sorted = [&] () - { - while (Sorted_item *item = sorted.first()) { - sorted.remove(item); - destroy(alloc, item); - } - }; + new (alloc) SortedItem(sorted, element.name(), element); + }); + + auto destroy_element = [&] (SortedItem &item) { + destroy(alloc, &item); }; /* iterate over sorted elements, 'fn' may throw */ try { - sorted.for_each([&] (Sorted_item const &item) { + sorted.for_each([&] (SortedItem const &item) { fn(item.element); }); } catch (...) { - destroy_sorted(); + while (sorted.with_any_element(destroy_element)) { } throw; } - destroy_sorted(); + while (sorted.with_any_element(destroy_element)) { } } #endif /* _SORTED_FOR_EACH_H_ */ diff --git a/repos/gems/src/app/menu_view/button_widget.h b/repos/gems/src/app/menu_view/button_widget.h index 4d8f4bf6e8..016c1214ab 100644 --- a/repos/gems/src/app/menu_view/button_widget.h +++ b/repos/gems/src/app/menu_view/button_widget.h @@ -85,7 +85,7 @@ struct Menu_view::Button_widget : Widget, Animator::Item * or changing the selection state of a button, the transition * must be quick to provide a responsive feel. */ - enum { SLOW = 80, MEDIUM = 40, FAST = 3 }; + enum { SLOW = 40, MEDIUM = 20, FAST = 2 }; int steps = SLOW; if (_hovered && !new_hovered) steps = MEDIUM; if (!_hovered && new_hovered) steps = FAST; diff --git a/repos/gems/src/app/menu_view/cursor.h b/repos/gems/src/app/menu_view/cursor.h index 9b0c8b5dde..981a88232c 100644 --- a/repos/gems/src/app/menu_view/cursor.h +++ b/repos/gems/src/app/menu_view/cursor.h @@ -70,7 +70,7 @@ class Menu_view::Cursor : List_model<Cursor>::Element void _move_to(int position, Steps steps) { - _position.move_to(Rect::compound(Point(position, 0), Point()), steps); + _position.move_to(Rect { { position, 0 }, { 1, 1 } }, steps); } /* @@ -122,7 +122,7 @@ class Menu_view::Cursor : List_model<Cursor>::Element void update(Xml_node const &node) { - _move_to(_position_from_xml_node(node), Steps{12}); + _move_to(_position_from_xml_node(node), Steps{6}); } }; diff --git a/repos/gems/src/app/menu_view/dialog.h b/repos/gems/src/app/menu_view/dialog.h index 8e61fa020e..7571541a40 100644 --- a/repos/gems/src/app/menu_view/dialog.h +++ b/repos/gems/src/app/menu_view/dialog.h @@ -47,9 +47,9 @@ struct Menu_view::Dialog : List_model<Dialog>::Element struct Action : Interface { - virtual void trigger_redraw() = 0; virtual void hover_changed() = 0; virtual void observed_seq_number(Input::Seq_number) = 0; + virtual Ticks now() = 0; }; Action &_action; @@ -72,6 +72,15 @@ struct Menu_view::Dialog : List_model<Dialog>::Element void _handle_input(); + Signal_handler<Dialog> _gui_sync_handler { + _env.ep(), *this, &Dialog::_handle_gui_sync }; + + void _handle_gui_sync(); + + bool _gui_sync_enabled = false; + + Ticks _previous_sync { }; + Constructible<Gui_buffer> _buffer { }; Gui::View_ref _view_ref { }; @@ -151,7 +160,7 @@ struct Menu_view::Dialog : List_model<Dialog>::Element _root_widget.gen_hover_model(xml, _hovered_position); } - void redraw() + void _redraw() { if (!_redraw_scheduled) return; @@ -182,7 +191,7 @@ struct Menu_view::Dialog : List_model<Dialog>::Element }); _buffer->flush_surface(); - _gui.framebuffer.refresh(0, 0, _buffer->size().w, _buffer->size().h); + _gui.framebuffer.refresh({ { 0, 0 }, _buffer->size() }); _update_view(Rect(_position, size)); _redraw_scheduled = false; @@ -190,7 +199,7 @@ struct Menu_view::Dialog : List_model<Dialog>::Element bool hovered() const { return _hovered; } - void animate() + void _animate() { bool const progress = _local_animator.active(); @@ -200,9 +209,14 @@ struct Menu_view::Dialog : List_model<Dialog>::Element _redraw_scheduled = true; } - bool animation_in_progress() const { return _local_animator.active(); } + void enforce_font_sytle_change() + { + _handle_dialog(); - bool redraw_scheduled() const { return _redraw_scheduled; } + /* fast-forward geometry animation */ + while (_local_animator.active()) + _animate(); + } /* * List_model @@ -214,10 +228,22 @@ struct Menu_view::Dialog : List_model<Dialog>::Element void update(Xml_node const &node) { + Point const orig_position = _position; + Area const orig_configured_size = _configured_size; + bool const orig_opaque = _opaque; + Color const orig_background_color = _background_color; + _position = Point::from_xml(node); _configured_size = Area ::from_xml(node); _opaque = node.attribute_value("opaque", false); _background_color = node.attribute_value("background", Color(127, 127, 127, 255)); + + bool const any_change = (orig_position != _position + || orig_configured_size != _configured_size + || orig_opaque != _opaque + || orig_background_color != _background_color); + if (any_change) + _dialog_handler.local_submit(); } }; @@ -237,7 +263,13 @@ void Menu_view::Dialog::_handle_dialog() _redraw_scheduled = true; _action.hover_changed(); - _action.trigger_redraw(); + + if (!_gui_sync_enabled) { + _gui.framebuffer.sync_sigh(_gui_sync_handler); + _gui_sync_enabled = true; + } + + _handle_gui_sync(); } @@ -287,4 +319,25 @@ void Menu_view::Dialog::_handle_input() _action.hover_changed(); } + +void Menu_view::Dialog::_handle_gui_sync() +{ + Ticks const now = _action.now(); + + Ticks const passed_ticks { now.cs - _previous_sync.cs }; + + for (unsigned i = 0; i < passed_ticks.cs; i++) + _animate(); + + if (passed_ticks.cs) + _redraw(); + + /* deactivate sync signalling when idle */ + if (_gui_sync_enabled && !_local_animator.active()) { + _gui.framebuffer.sync_sigh(Signal_context_capability()); + _gui_sync_enabled = false; + } + _previous_sync = now; +} + #endif /* _DIALOG_H_ */ diff --git a/repos/gems/src/app/menu_view/label_widget.h b/repos/gems/src/app/menu_view/label_widget.h index b640ec5d01..817bdc00fc 100644 --- a/repos/gems/src/app/menu_view/label_widget.h +++ b/repos/gems/src/app/menu_view/label_widget.h @@ -89,7 +89,7 @@ struct Menu_view::Label_widget : Widget, Cursor::Glyph_position _hover = node.attribute_value("hover", false); _factory.styles.with_label_style(node, [&] (Label_style style) { - _color.fade_to(style.color, Animated_color::Steps{80}); }); + _color.fade_to(style.color, Animated_color::Steps{40}); }); if (node.has_attribute("text")) { _text = node.attribute_value("text", _text); diff --git a/repos/gems/src/app/menu_view/main.cc b/repos/gems/src/app/menu_view/main.cc index e220ad1cc8..dee982d66a 100644 --- a/repos/gems/src/app/menu_view/main.cc +++ b/repos/gems/src/app/menu_view/main.cc @@ -83,45 +83,14 @@ struct Menu_view::Main : Dialog::Action } _input_seq_number { }; - struct Frame { uint64_t count; }; - - /* - * Timer used for animating widgets - */ - struct Frame_timer : Timer::Connection - { - enum { PERIOD = 10 }; - - Frame curr_frame() const { return { elapsed_ms() / PERIOD }; } - - void schedule() { trigger_once((Genode::uint64_t)Frame_timer::PERIOD*1000); } - - Frame_timer(Env &env) : Timer::Connection(env) { } - - } _timer { _env }; - - void _handle_frame_timer(); + Timer::Connection _timer { _env }; /** * Dialog::Action */ - void trigger_redraw() override + Ticks now() override { - /* - * If we have not processed a period for at least one frame, perform the - * processing immediately. This way, we avoid latencies when the dialog - * model is updated sporadically. - */ - Frame const curr_frame = _timer.curr_frame(); - if (curr_frame.count != _last_frame.count) { - - if (curr_frame.count - _last_frame.count > 10) - _last_frame = curr_frame; - - _handle_frame_timer(); - } else { - _timer.schedule(); - } + return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 }; } /** @@ -137,38 +106,16 @@ struct Menu_view::Main : Dialog::Action _input_seq_number.update(seq); } - Signal_handler<Main> _frame_timer_handler = { - _env.ep(), *this, &Main::_handle_frame_timer}; - Constructible<Genode::Expanding_reporter> _hover_reporter { }; void _update_hover_report(); - /** - * Frame of last call of 'handle_frame_timer' - */ - Frame _last_frame { }; - - /** - * Number of frames between two redraws - */ - static constexpr unsigned REDRAW_PERIOD = 2; - - /** - * Counter used for triggering redraws. Incremented in each frame-timer - * period, wraps at 'REDRAW_PERIOD'. The redraw is performed when the - * counter wraps. - */ - unsigned _frame_cnt = 0; - Main(Env &env, Vfs::Env &libc_vfs_env) : _env(env), _vfs_env(libc_vfs_env) { _config.sigh(_config_handler); _config_handler.local_submit(); /* apply initial configuration */ - - _timer.sigh(_frame_timer_handler); } }; @@ -239,57 +186,10 @@ void Menu_view::Main::_handle_config() /* re-assign font pointers in labels (needed due to font style change) */ if (!_styles.up_to_date()) { _dialogs.for_each([&] (Dialog &dialog) { - dialog._handle_dialog(); - - /* fast-forward geometry animation on font changes */ - while (dialog.animation_in_progress()) - dialog.animate(); - }); + dialog.enforce_font_sytle_change(); }); _styles.flush_outdated_styles(); } - trigger_redraw(); -} - - -void Menu_view::Main::_handle_frame_timer() -{ - _frame_cnt++; - - Frame const curr_frame = _timer.curr_frame(); - - unsigned const passed_frames = - max(unsigned(curr_frame.count - _last_frame.count), 4U); - - if (passed_frames > 0) - _dialogs.for_each([&] (Dialog &dialog) { - for (unsigned i = 0; i < passed_frames; i++) - dialog.animate(); }); - - bool any_redraw_scheduled = false; - _dialogs.for_each([&] (Dialog const &dialog) { - any_redraw_scheduled |= dialog.redraw_scheduled(); }); - - _last_frame = curr_frame; - - bool const redraw_skipped = any_redraw_scheduled && (_frame_cnt < REDRAW_PERIOD); - - if (!redraw_skipped) { - _frame_cnt = 0; - _dialogs.for_each([&] (Dialog &dialog) { - dialog.redraw(); }); - } - - bool any_animation_in_progress = false; - _dialogs.for_each([&] (Dialog const &dialog) { - any_animation_in_progress |= dialog.animation_in_progress(); }); - - /* - * Deactivate timer periods when idle, activate timer when an animation is - * in progress or a redraw is pending. - */ - if (any_animation_in_progress || redraw_skipped) - _timer.schedule(); } diff --git a/repos/gems/src/app/menu_view/styles/button/vconn/default.png b/repos/gems/src/app/menu_view/styles/button/vconn/default.png new file mode 100644 index 0000000000..0cc68605fa Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vconn/default.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vconn/hovered.png b/repos/gems/src/app/menu_view/styles/button/vconn/hovered.png new file mode 100644 index 0000000000..be207ad270 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vconn/hovered.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vconn/hselected.png b/repos/gems/src/app/menu_view/styles/button/vconn/hselected.png new file mode 100644 index 0000000000..b55edb0672 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vconn/hselected.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vconn/selected.png b/repos/gems/src/app/menu_view/styles/button/vconn/selected.png new file mode 100644 index 0000000000..ac09f5e328 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vconn/selected.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vswap/default.png b/repos/gems/src/app/menu_view/styles/button/vswap/default.png new file mode 100644 index 0000000000..4139170a3a Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vswap/default.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vswap/hovered.png b/repos/gems/src/app/menu_view/styles/button/vswap/hovered.png new file mode 100644 index 0000000000..8f1a555a62 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vswap/hovered.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vswap/hselected.png b/repos/gems/src/app/menu_view/styles/button/vswap/hselected.png new file mode 100644 index 0000000000..8fb1b960a8 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vswap/hselected.png differ diff --git a/repos/gems/src/app/menu_view/styles/button/vswap/selected.png b/repos/gems/src/app/menu_view/styles/button/vswap/selected.png new file mode 100644 index 0000000000..68f49c25f0 Binary files /dev/null and b/repos/gems/src/app/menu_view/styles/button/vswap/selected.png differ diff --git a/repos/gems/src/app/menu_view/types.h b/repos/gems/src/app/menu_view/types.h index a2cf878a0f..10449caafe 100644 --- a/repos/gems/src/app/menu_view/types.h +++ b/repos/gems/src/app/menu_view/types.h @@ -36,6 +36,8 @@ namespace Menu_view { using Point = Surface_base::Point; using Area = Surface_base::Area; using Rect = Surface_base::Rect; + + struct Ticks { uint64_t cs; /* centi-seconds (10 ms) */ }; } #endif /* _TYPES_H_ */ diff --git a/repos/gems/src/app/menu_view/widget.h b/repos/gems/src/app/menu_view/widget.h index 2c2fa64a0d..9b5d01de77 100644 --- a/repos/gems/src/app/menu_view/widget.h +++ b/repos/gems/src/app/menu_view/widget.h @@ -110,7 +110,7 @@ class Menu_view::Widget : List_model<Widget>::Element return node.attribute_value("version", Version()); } - static Animated_rect::Steps motion_steps() { return { 60 }; }; + static Animated_rect::Steps motion_steps() { return { 30 }; }; protected: diff --git a/repos/gems/src/app/osci/main.cc b/repos/gems/src/app/osci/main.cc index 2a70ec9e9f..ccdd089209 100644 --- a/repos/gems/src/app/osci/main.cc +++ b/repos/gems/src/app/osci/main.cc @@ -159,7 +159,7 @@ struct Osci::Main _gui_buffer->flush_surface(); - _gui.framebuffer.refresh(0, 0, _size.w, _size.h); + _gui.framebuffer.refresh({ { 0, 0 }, _size }); } Main(Env &env) : _env(env) diff --git a/repos/gems/src/app/phone_manager/main.cc b/repos/gems/src/app/phone_manager/main.cc index 9e8f23da72..087e4cc0d5 100644 --- a/repos/gems/src/app/phone_manager/main.cc +++ b/repos/gems/src/app/phone_manager/main.cc @@ -376,10 +376,11 @@ struct Sculpt::Main : Input_event_handler, */ bool ap_list_hovered() const override { - return _main_view.if_hovered([&] (Hovered_at const &at) { - return _network_widget.if_hovered(at, [&] (Hovered_at const &at) { - return _network_widget.hosted.if_hovered(at, [&] (Hovered_at const &at) { - return _network_widget.hosted.ap_list_hovered(at); }); }); }); + /* + * For now always report false so that scan-results + * will always be presented. + */ + return false; } /** @@ -650,6 +651,8 @@ struct Sculpt::Main : Input_event_handler, bool _leitzentrale_visible = false; + Fb_connectors::Name _hovered_display { }; + Color const _background_color { 62, 62, 67, 255 }; Affinity::Space _affinity_space { 1, 1 }; @@ -811,8 +814,8 @@ struct Sculpt::Main : Input_event_handler, Conditional_widget<Graph> _graph { Id { "graph" }, _runtime_state, _cached_runtime_config, _storage._storage_devices, - _storage._selected_target, _storage._ram_fs_state, - _popup.state, _deploy._children }; + _storage._selected_target, _storage._ram_fs_state, _fb_connectors, + _fb_config, _hovered_display, _popup.state, _deploy._children }; Conditional_widget<Network_widget> _network_widget { Conditional_widget<Network_widget>::Attr { .centered = true }, @@ -1994,6 +1997,30 @@ struct Sculpt::Main : Input_event_handler, } + /********************************** + ** Display driver configuration ** + **********************************/ + + Fb_connectors _fb_connectors { }; + + Fb_config _fb_config { }; + + /** + * Fb_driver::Action interface + */ + void fb_connectors_changed() override { } + + /** + * Fb_widget::Action interface + */ + void select_fb_mode (Fb_connectors::Name const &, + Fb_connectors::Connector::Mode::Id const &) override { } + void disable_fb_connector (Fb_connectors::Name const &) override { } + void toggle_fb_merge_discrete(Fb_connectors::Name const &) override { } + void swap_fb_connector (Fb_connectors::Name const &) override { } + void fb_brightness (Fb_connectors::Name const &, unsigned) override { } + + /******************* ** Runtime graph ** *******************/ @@ -2007,7 +2034,7 @@ struct Sculpt::Main : Input_event_handler, _drivers.update_soc(_soc); _gui.input.sigh(_input_handler); - _gui.mode_sigh(_gui_mode_handler); + _gui.info_sigh(_gui_mode_handler); _handle_gui_mode(); _system_config.with_manual_config([&] (Xml_node const &system) { @@ -2078,12 +2105,6 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, return Area(win.attribute_value("width", 0U), win.attribute_value("height", 0U)); }; - Framebuffer::Mode const mode = _gui.mode(); - - /* suppress intermediate boot-time states before the framebuffer driver is up */ - if (mode.area.count() <= 1) - return; - _window_layout.generate([&] (Xml_generator &xml) { auto gen_window = [&] (Xml_node win, Rect rect) { @@ -2105,8 +2126,8 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, Area const size = win_size(win); Point const pos = _touch_keyboard.visible - ? Point(0, int(mode.area.h) - int(size.h)) - : Point(0, int(mode.area.h)); + ? Point(0, int(_screen_size.h) - int(size.h)) + : Point(0, int(_screen_size.h)); gen_window(win, Rect(pos, size)); }); @@ -2122,16 +2143,19 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, void Sculpt::Main::_handle_gui_mode() { - Framebuffer::Mode const mode = _gui.mode(); + auto const panorama = _gui.panorama(); - _screensaver.display_driver_ready(mode.area.count() > 1); + _screensaver.display_driver_ready(panorama.ok()); - if (mode.area.count() > 1) - _gui_mode_ready = true; - - _screen_size = mode.area; - _main_view.min_width = _screen_size.w; - _main_view.min_height = _screen_size.h; + panorama.with_result( + [&] (Gui::Rect const rect) { + _gui_mode_ready = true; + _screen_size = rect.area; + _main_view.min_width = _screen_size.w; + _main_view.min_height = _screen_size.h; + }, + [&] (Gui::Undefined) { } + ); generate_runtime_config(); _update_window_layout(); diff --git a/repos/gems/src/app/rom_osci/main.cc b/repos/gems/src/app/rom_osci/main.cc index 16c4d492e6..9d5ee4aeb4 100644 --- a/repos/gems/src/app/rom_osci/main.cc +++ b/repos/gems/src/app/rom_osci/main.cc @@ -305,7 +305,7 @@ struct Osci::Main channel.render(pixel, alpha, phase_lock); }); }); _gui_buffer->flush_surface(); - _gui.framebuffer.refresh(0, 0, _size.w, _size.h); + _gui.framebuffer.refresh({ { 0, 0 }, _size }); } Main(Env &env) : _env(env) diff --git a/repos/gems/src/app/sculpt_manager/deploy.h b/repos/gems/src/app/sculpt_manager/deploy.h index 2db79f9e49..5ec2326dc7 100644 --- a/repos/gems/src/app/sculpt_manager/deploy.h +++ b/repos/gems/src/app/sculpt_manager/deploy.h @@ -263,6 +263,9 @@ struct Sculpt::Deploy void restart() { + cached_depot_rom_state .trigger_restart(); + uncached_depot_rom_state.trigger_restart(); + /* ignore stale query results */ _depot_query.trigger_depot_query(); diff --git a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h index 850c153e3e..6c1ab0ca16 100644 --- a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h +++ b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h @@ -53,7 +53,7 @@ class Dialog::Distant_runtime : Noncopyable Start_name const _start_name { "runtime_view" }; Ram_quota const _initial_ram { 52*1024*1024 }; - Cap_quota const _initial_caps { 300 }; + Cap_quota const _initial_caps { 330 }; Ram_quota _ram = _initial_ram; Cap_quota _caps = _initial_caps; @@ -105,7 +105,7 @@ class Dialog::Distant_runtime : Noncopyable return false; if (child.has_sub_node("ram") && child.sub_node("ram").has_attribute("requested")) { - _ram.value = min(2*_ram.value, 32*1024*1024u); + _ram.value = min(2*_ram.value, 64*1024*1024u); result = true; } diff --git a/repos/gems/src/app/sculpt_manager/driver/fb.h b/repos/gems/src/app/sculpt_manager/driver/fb.h index bbc4d1f8c2..94c60fe394 100644 --- a/repos/gems/src/app/sculpt_manager/driver/fb.h +++ b/repos/gems/src/app/sculpt_manager/driver/fb.h @@ -14,24 +14,50 @@ #ifndef _DRIVER__FB_H_ #define _DRIVER__FB_H_ +#include <i2c_session/i2c_session.h> + namespace Sculpt { struct Fb_driver; } struct Sculpt::Fb_driver : private Noncopyable { + using Fb_name = String<16>; + + struct Action : Interface + { + virtual void fb_connectors_changed() = 0; + }; + + Env &_env; + Action &_action; + Constructible<Child_state> _intel_gpu { }, _intel_fb { }, _vesa_fb { }, _boot_fb { }, _soc_fb { }; + Constructible<Rom_handler<Fb_driver>> _connectors { }; + + void _handle_connectors(Xml_node const &) { _action.fb_connectors_changed(); } + + Fb_name _fb_name() const + { + return _intel_fb.constructed() ? "intel_fb" + : _vesa_fb .constructed() ? "vesa_fb" + : _boot_fb .constructed() ? "boot_fb" + : _soc_fb .constructed() ? "fb" + : ""; + } + + Fb_driver(Env &env, Action &action) : _env(env), _action(action) { } + void gen_start_nodes(Xml_generator &xml) const { auto gen_capture_route = [&] (Xml_generator &xml) { gen_service_node<Capture::Session>(xml, [&] { - xml.node("parent", [&] { - xml.attribute("label", "global"); }); }); + xml.node("parent", [] { }); }); }; auto start_node = [&] (auto const &driver, auto const &binary, auto const &fn) @@ -124,6 +150,8 @@ struct Sculpt::Fb_driver : private Noncopyable bool const use_vesa = !use_intel_fb && !suspending && board_info.detected.vga && !use_boot_fb; + Fb_name const orig_fb_name = _fb_name(); + _intel_gpu.conditional(use_intel_gpu, registry, "intel_gpu", Priority::MULTIMEDIA, Ram_quota { 32*1024*1024 }, Cap_quota { 1400 }); @@ -149,6 +177,12 @@ struct Sculpt::Fb_driver : private Noncopyable Boot_fb::with_mode(platform, [&] (Boot_fb::Mode mode) { _boot_fb.construct(registry, "boot_fb", Priority::MULTIMEDIA, mode.ram_quota(), Cap_quota { 100 }); }); + + if (orig_fb_name != _fb_name()) { + Session_label label { "report -> runtime/", _fb_name(), "/connectors" }; + _connectors.conditional((label.length() > 1), _env, label, + *this, &Fb_driver::_handle_connectors); + } } static bool suspend_supported(Board_info const &board_info) @@ -157,6 +191,12 @@ struct Sculpt::Fb_driver : private Noncopyable return board_info.detected.intel_gfx && !board_info.options.suppress.intel_gpu; } + + void with_connectors(auto const &fn) const + { + if (_connectors.constructed()) + _connectors->with_xml(fn); + } }; #endif /* _DRIVER__FB_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/driver/wifi.h b/repos/gems/src/app/sculpt_manager/driver/wifi.h index b078cd604e..d6d3f68d6f 100644 --- a/repos/gems/src/app/sculpt_manager/driver/wifi.h +++ b/repos/gems/src/app/sculpt_manager/driver/wifi.h @@ -52,7 +52,7 @@ struct Sculpt::Wifi_driver : private Noncopyable }); xml.node("libc", [&] { - xml.attribute("stdout", "/dev/null"); + xml.attribute("stdout", "/dev/log"); xml.attribute("stderr", "/dev/null"); xml.attribute("rtc", "/dev/rtc"); }); @@ -97,7 +97,7 @@ struct Sculpt::Wifi_driver : private Noncopyable && !board_info.options.suspending; _wifi.conditional(use_wifi, registry, "wifi", Priority::DEFAULT, - Ram_quota { 16*1024*1024 }, Cap_quota { 250 }); + Ram_quota { 16*1024*1024 }, Cap_quota { 260 }); } }; diff --git a/repos/gems/src/app/sculpt_manager/drivers.cc b/repos/gems/src/app/sculpt_manager/drivers.cc index 58cd1e3b98..352cf777c9 100644 --- a/repos/gems/src/app/sculpt_manager/drivers.cc +++ b/repos/gems/src/app/sculpt_manager/drivers.cc @@ -100,7 +100,7 @@ class Sculpt::Drivers::Instance : Noncopyable, Ps2_driver _ps2_driver { }; Touch_driver _touch_driver { }; - Fb_driver _fb_driver { }; + Fb_driver _fb_driver { _env, _action }; Usb_driver _usb_driver { _env, *this, *this }; Ahci_driver _ahci_driver { _env, *this }; Nvme_driver _nvme_driver { _env, *this }; @@ -168,7 +168,8 @@ class Sculpt::Drivers::Instance : Noncopyable, } void with(With_board_info::Callback const &fn) const { fn(_board_info); } - void with(With_platform_info::Callback const &fn) const { fn(_platform.xml()); } + void with_platform_info(With_xml::Callback const &fn) const { fn(_platform.xml()); } + void with_fb_connectors(With_xml::Callback const &fn) const { _fb_driver.with_connectors(fn); } bool suspend_supported() const { @@ -202,9 +203,10 @@ Sculpt::Drivers::Drivers(Env &env, Children &children, Info const &info, Action _instance(_construct_instance(env, children, info, action)) { } -void Drivers::_with(With_storage_devices::Callback const &fn) const { _instance.with(fn); } -void Drivers::_with(With_board_info::Callback const &fn) const { _instance.with(fn); } -void Drivers::_with(With_platform_info::Callback const &fn) const { _instance.with(fn); } +void Drivers::_with(With_storage_devices::Callback const &fn) const { _instance.with(fn); } +void Drivers::_with(With_board_info::Callback const &fn) const { _instance.with(fn); } +void Drivers::_with_platform_info(With_xml::Callback const &fn) const { _instance.with_platform_info(fn); } +void Drivers::_with_fb_connectors(With_xml::Callback const &fn) const { _instance.with_fb_connectors(fn); } void Drivers::update_usb () { _instance.update_usb(); } void Drivers::update_soc (Board_info::Soc soc) { _instance.update_soc(soc); } diff --git a/repos/gems/src/app/sculpt_manager/drivers.h b/repos/gems/src/app/sculpt_manager/drivers.h index 09bea3fa25..17b2853a42 100644 --- a/repos/gems/src/app/sculpt_manager/drivers.h +++ b/repos/gems/src/app/sculpt_manager/drivers.h @@ -18,6 +18,7 @@ #include <xml.h> #include <model/child_state.h> #include <model/board_info.h> +#include <driver/fb.h> namespace Sculpt { struct Drivers; } @@ -26,7 +27,7 @@ class Sculpt::Drivers : Noncopyable { public: - struct Action : Interface + struct Action : virtual Fb_driver::Action { virtual void handle_device_plug_unplug() = 0; }; @@ -53,11 +54,12 @@ class Sculpt::Drivers : Noncopyable using With_storage_devices = With<Storage_devices const &>; using With_board_info = With<Board_info const &>; - using With_platform_info = With<Xml_node const &>; + using With_xml = With<Xml_node const &>; void _with(With_storage_devices::Callback const &) const; void _with(With_board_info::Callback const &) const; - void _with(With_platform_info::Callback const &) const; + void _with_platform_info(With_xml::Callback const &) const; + void _with_fb_connectors(With_xml::Callback const &) const; public: @@ -71,7 +73,8 @@ class Sculpt::Drivers : Noncopyable void with_storage_devices(auto const &fn) const { _with(With_storage_devices::Fn { fn }); } void with_board_info (auto const &fn) const { _with(With_board_info::Fn { fn }); } - void with_platform_info (auto const &fn) const { _with(With_platform_info::Fn { fn }); } + void with_platform_info (auto const &fn) const { _with_platform_info(With_xml::Fn { fn }); } + void with_fb_connectors (auto const &fn) const { _with_fb_connectors(With_xml::Fn { fn }); } /* true if hardware is suspend/resume capable */ bool suspend_supported() const; diff --git a/repos/gems/src/app/sculpt_manager/graph.cc b/repos/gems/src/app/sculpt_manager/graph.cc index d90f52a24a..48cfaf540c 100644 --- a/repos/gems/src/app/sculpt_manager/graph.cc +++ b/repos/gems/src/app/sculpt_manager/graph.cc @@ -100,6 +100,9 @@ void Graph::_view_selected_node_content(Scope<Depgraph, Frame, Vbox> &s, if (name == "ram_fs") s.widget(_ram_fs_widget, _selected_target, _ram_fs_state); + if (name == "intel_fb") + s.widget(_fb_widget, _fb_connectors, _fb_config, _hovered_display); + String<100> const ram (Capacity{info.assigned_ram - info.avail_ram}, " / ", Capacity{info.assigned_ram}), @@ -257,6 +260,7 @@ void Graph::click(Clicked_at const &at, Action &action) }); _ram_fs_widget .propagate(at, _selected_target, action); + _fb_widget .propagate(at, _fb_connectors, action); _ahci_devices_widget.propagate(at, action); _nvme_devices_widget.propagate(at, action); _mmc_devices_widget .propagate(at, action); diff --git a/repos/gems/src/app/sculpt_manager/graph.h b/repos/gems/src/app/sculpt_manager/graph.h index d9a850e84a..5a71cea8a7 100644 --- a/repos/gems/src/app/sculpt_manager/graph.h +++ b/repos/gems/src/app/sculpt_manager/graph.h @@ -25,6 +25,7 @@ #include <types.h> #include <view/storage_widget.h> #include <view/ram_fs_widget.h> +#include <view/fb_widget.h> #include <model/capacity.h> #include <model/popup.h> #include <model/runtime_config.h> @@ -42,6 +43,9 @@ struct Sculpt::Graph : Widget<Depgraph> Storage_devices const &_storage_devices; Storage_target const &_selected_target; Ram_fs_state const &_ram_fs_state; + Fb_connectors const &_fb_connectors; + Fb_config const &_fb_config; + Fb_connectors::Name const &_hovered_display; Popup::State const &_popup_state; Depot_deploy::Children const &_deploy_children; @@ -50,6 +54,9 @@ struct Sculpt::Graph : Widget<Depgraph> Hosted<Depgraph, Frame, Vbox, Ram_fs_widget> _ram_fs_widget { Id { "ram_fs" } }; + Hosted<Depgraph, Frame, Vbox, Fb_widget> + _fb_widget { Id { "fb" } }; + Hosted<Depgraph, Frame, Vbox, Frame, Hbox, Deferred_action_button> _remove { Id { "Remove" } }, _restart { Id { "Restart" } }; @@ -81,18 +88,23 @@ struct Sculpt::Graph : Widget<Depgraph> Storage_devices const &storage_devices, Storage_target const &selected_target, Ram_fs_state const &ram_fs_state, + Fb_connectors const &fb_connectors, + Fb_config const &fb_config, + Fb_connectors::Name const &hovered_display, Popup::State const &popup_state, Depot_deploy::Children const &deploy_children) : _runtime_state(runtime_state), _runtime_config(runtime_config), _storage_devices(storage_devices), _selected_target(selected_target), - _ram_fs_state(ram_fs_state), _popup_state(popup_state), - _deploy_children(deploy_children) + _ram_fs_state(ram_fs_state), _fb_connectors(fb_connectors), + _fb_config(fb_config), _hovered_display(hovered_display), + _popup_state(popup_state), _deploy_children(deploy_children) { } void view(Scope<Depgraph> &) const; - struct Action : virtual Storage_device_widget::Action + struct Action : virtual Storage_device_widget::Action, + virtual Fb_widget::Action { virtual void remove_deployed_component(Start_name const &) = 0; virtual void restart_deployed_component(Start_name const &) = 0; diff --git a/repos/gems/src/app/sculpt_manager/gui.cc b/repos/gems/src/app/sculpt_manager/gui.cc index 0174dbb385..1ceb254509 100644 --- a/repos/gems/src/app/sculpt_manager/gui.cc +++ b/repos/gems/src/app/sculpt_manager/gui.cc @@ -49,7 +49,8 @@ static bool clack(Input::Event const &event) } -struct Gui::Session_component : Rpc_object<Gui::Session> +struct Gui::Session_component : Rpc_object<Gui::Session>, + private Input::Session_component::Action { Env &_env; @@ -63,7 +64,16 @@ struct Gui::Session_component : Rpc_object<Gui::Session> Input::Session_client _gui_input { _env.rm(), _gui_session.input() }; - Input::Session_component _input_component { _env, _env.ram() }; + Input::Session_component _input_component { + _env.ep(), _env.ram(), _env.rm(), *this }; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool enabled) override + { + _gui_input.exclusive(enabled); + } Signal_handler<Session_component> _input_handler { _env.ep(), *this, &Session_component::_handle_input }; @@ -104,12 +114,9 @@ struct Gui::Session_component : Rpc_object<Gui::Session> _connection(env, session_label_from_args(args), Ram_quota { 36*1024 }, { }) { _gui_input.sigh(_input_handler); - _env.ep().manage(_input_component); _input_component.event_queue().enabled(true); } - ~Session_component() { _env.ep().dissolve(_input_component); } - void upgrade(Session::Resources const &resources) { _connection.upgrade(resources); @@ -145,14 +152,11 @@ struct Gui::Session_component : Rpc_object<Gui::Session> void execute() override { _gui_session.execute(); } - Framebuffer::Mode mode() override { - return _gui_session.mode(); } + Info_result info() override { + return _gui_session.info(); } - void mode_sigh(Signal_context_capability sigh) override { - _gui_session.mode_sigh(sigh); } - - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override { - return _gui_session.buffer(mode, use_alpha); } + Buffer_result buffer(Framebuffer::Mode mode) override { + return _gui_session.buffer(mode); } void focus(Capability<Gui::Session> session) override { _gui_session.focus(session); } diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc index a205ac1260..ca2847ba01 100644 --- a/repos/gems/src/app/sculpt_manager/main.cc +++ b/repos/gems/src/app/sculpt_manager/main.cc @@ -40,6 +40,8 @@ #include <model/presets.h> #include <model/screensaver.h> #include <model/system_state.h> +#include <model/fb_config.h> +#include <model/panorama_config.h> #include <view/download_status_widget.h> #include <view/popup_dialog.h> #include <view/panel_dialog.h> @@ -88,6 +90,7 @@ struct Sculpt::Main : Input_event_handler, Build_info::from_xml(Attached_rom_dataspace(_env, "build_info").xml()); bool const _mnt_reform = (_build_info.board == "mnt_reform2"); + bool const _mnt_pocket = (_build_info.board == "mnt_pocket"); Registry<Child_state> _child_states { }; @@ -104,7 +107,10 @@ struct Sculpt::Main : Input_event_handler, Gui::Connection _gui { _env, "input" }; - bool _gui_mode_ready = false; /* becomes true once the graphics driver is up */ + Gui::Connection::Panorama_result _panorama = Gui::Undefined { }; + + /* becomes true once the graphics driver is up */ + bool _gui_mode_ready() const { return _panorama.ok(); }; Gui::Root _gui_root { _env, _heap, *this, _global_input_seq_number }; @@ -145,6 +151,18 @@ struct Sculpt::Main : Input_event_handler, void _handle_gui_mode(); + Rom_handler<Main> _leitzentrale_rom { + _env, "leitzentrale", *this, &Main::_handle_leitzentrale }; + + void _handle_leitzentrale(Xml_node const &leitzentrale) + { + bool const orig_leitzentrale_visibile = _leitzentrale_visible; + _leitzentrale_visible = leitzentrale.attribute_value("enabled", false); + + if (orig_leitzentrale_visibile != _leitzentrale_visible) + _handle_gui_mode(); + } + Rom_handler<Main> _config { _env, "config", *this, &Main::_handle_config }; void _handle_config(Xml_node const &config) @@ -276,13 +294,13 @@ struct Sculpt::Main : Input_event_handler, **********************/ Board_info::Soc _soc { - .fb = _mnt_reform, + .fb = _mnt_reform || _mnt_pocket, .touch = false, - .wifi = false, /* initialized via PCI */ - .usb = _mnt_reform, - .mmc = _mnt_reform, + .wifi = _mnt_pocket, /* initialized via PCI on Reform */ + .usb = _mnt_reform || _mnt_pocket, + .mmc = _mnt_reform || _mnt_pocket, .modem = false, - .nic = _mnt_reform, + .nic = _mnt_reform || _mnt_pocket, }; Drivers _drivers { _env, _child_states, *this, *this }; @@ -290,10 +308,10 @@ struct Sculpt::Main : Input_event_handler, Drivers::Resumed _resumed = _drivers.resumed(); Board_info::Options _driver_options { - .display = _mnt_reform, + .display = _mnt_reform || _mnt_pocket, .usb_net = false, .nic = false, - .wifi = false, + .wifi = _mnt_pocket, .suppress {}, .suspending = false, }; @@ -733,7 +751,28 @@ struct Sculpt::Main : Input_event_handler, double _font_size_px = 14; - Area _screen_size { }; + Area _screen_size { }; + Point _screen_pos { }; + + bool _leitzentrale_visible = false; + + Rom_handler<Main> _nitpicker_hover_handler { + _env, "nitpicker_hover", *this, &Main::_handle_nitpicker_hover }; + + Expanding_reporter _gui_fb_config { _env, "config", "gui_fb_config" }; + + Constructible<Gui::Point> _pointer_pos { }; + + Fb_connectors::Name _hovered_display { }; + + void _handle_nitpicker_hover(Xml_node const &hover) + { + if (hover.has_attribute("xpos")) + _pointer_pos.construct(Gui::Point::from_xml(hover)); + + /* place leitzentrale at the display under the pointer */ + _handle_gui_mode(); + } Panel_dialog::Tab _selected_tab = Panel_dialog::Tab::COMPONENTS; @@ -907,6 +946,9 @@ struct Sculpt::Main : Input_event_handler, */ void handle_input_event(Input::Event const &ev) override { + ev.handle_absolute_motion([&] (int x, int y) { + _pointer_pos.construct(x, y); }); + Keyboard_focus_guard focus_guard { *this }; Dialog::Event::Seq_number const seq_number { _global_input_seq_number.value }; @@ -953,8 +995,10 @@ struct Sculpt::Main : Input_event_handler, ev.handle_wheel([&] (int, int y) { dy = y*32; }); - if (ev.key_press(Input::KEY_PAGEUP)) dy = int(_gui.mode().area.h / 3); - if (ev.key_press(Input::KEY_PAGEDOWN)) dy = -int(_gui.mode().area.h / 3); + int const vscroll_step = int(_screen_size.h) / 3; + + if (ev.key_press(Input::KEY_PAGEUP)) dy = vscroll_step; + if (ev.key_press(Input::KEY_PAGEDOWN)) dy = -vscroll_step; if (dy != 0) { scroll_ypos += dy; @@ -1555,18 +1599,6 @@ struct Sculpt::Main : Input_event_handler, _cached_runtime_config, _file_browser_state, *this }; - Managed_config<Main> _fb_config { - _env, "config", "fb", *this, &Main::_handle_fb_config }; - - void _handle_fb_config(Xml_node const &node) - { - _fb_config.generate([&] (Xml_generator &xml) { - xml.attribute("system", "yes"); - copy_attributes(xml, node); - node.for_each_sub_node([&] (Xml_node const &sub_node) { - copy_node(xml, sub_node, { 5 }); }); }); - } - void _update_window_layout(Xml_node const &, Xml_node const &); void _update_window_layout() @@ -1610,6 +1642,127 @@ struct Sculpt::Main : Input_event_handler, Signal_handler<Main> _wheel_handler { _env.ep(), *this, &Main::_update_window_layout }; + /********************************** + ** Display driver configuration ** + **********************************/ + + Managed_config<Main> _nitpicker_config { + _env, "config", "nitpicker", *this, &Main::_handle_nitpicker_config }; + + void _handle_nitpicker_config(Xml_node const &node) + { + _nitpicker_config.generate([&] (Xml_generator &xml) { + copy_attributes(xml, node); + node.for_each_sub_node([&] (Xml_node const &sub_node) { + if (sub_node.has_type("capture") && sub_node.num_sub_nodes() == 0) { + xml.node("capture", [&] { + + /* generate panorama of fb-driver sessions */ + Panorama_config(_fb_config).gen_policy_entries(xml); + + /* default policy for capture applications like screenshot */ + xml.node("default-policy", [&] { }); + }); + } else { + copy_node(xml, sub_node, { 5 }); + } + }); + }); + } + + Panorama_config _panorama_config { }; + + Fb_connectors _fb_connectors { }; + + Rom_handler<Main> _manual_fb_handler { _env, "config -> fb", *this, &Main::_handle_manual_fb }; + + Expanding_reporter _managed_fb_reporter { _env, "config", "fb_config"}; + + Fb_config _fb_config { }; + + void _generate_fb_config() + { + _managed_fb_reporter.generate([&] (Xml_generator &xml) { + _fb_config.generate_managed_fb(xml); }); + + /* update nitpicker config if the new fb config affects the panorama */ + Panorama_config const orig = _panorama_config; + _panorama_config = Panorama_config(_fb_config); + if (orig != Panorama_config(_fb_config)) + _nitpicker_config.trigger_update(); + } + + void _handle_manual_fb(Xml_node const &node) + { + _fb_config = { }; + _fb_config.import_manual_config(node); + _fb_config.apply_connectors(_fb_connectors); + + _generate_fb_config(); + } + + /** + * Fb_driver::Action interface + */ + void fb_connectors_changed() override + { + _drivers.with_fb_connectors([&] (Xml_node const &node) { + if (_fb_connectors.update(_heap, node).progress) { + _fb_config.apply_connectors(_fb_connectors); + _generate_fb_config(); + _handle_gui_mode(); + _graph_view.refresh(); + } + }); + } + + /** + * Fb_widget::Action interface + */ + void select_fb_mode(Fb_connectors::Name const &conn, + Fb_connectors::Connector::Mode::Id const &mode) override + { + _fb_config.select_fb_mode(conn, mode, _fb_connectors); + _generate_fb_config(); + } + + /** + * Fb_widget::Action interface + */ + void disable_fb_connector(Fb_connectors::Name const &conn) override + { + _fb_config.disable_connector(conn); + _generate_fb_config(); + } + + /** + * Fb_widget::Action interface + */ + void toggle_fb_merge_discrete(Fb_connectors::Name const &conn) override + { + _fb_config.toggle_merge_discrete(conn); + _generate_fb_config(); + } + + /** + * Fb_widget::Action interface + */ + void swap_fb_connector(Fb_connectors::Name const &conn) override + { + _fb_config.swap_connector(conn); + _generate_fb_config(); + } + + /** + * Fb_widget::Action interface + */ + void fb_brightness(Fb_connectors::Name const &conn, unsigned percent) override + { + _fb_config.brightness(conn, percent); + _generate_fb_config(); + } + + /******************* ** Runtime graph ** *******************/ @@ -1617,8 +1770,8 @@ struct Sculpt::Main : Input_event_handler, Popup _popup { }; Graph _graph { _runtime_state, _cached_runtime_config, _storage._storage_devices, - _storage._selected_target, _storage._ram_fs_state, - _popup.state, _deploy._children }; + _storage._selected_target, _storage._ram_fs_state, _fb_connectors, + _fb_config, _hovered_display, _popup.state, _deploy._children }; struct Graph_dialog : Dialog::Top_level_dialog { @@ -1647,9 +1800,9 @@ struct Sculpt::Main : Input_event_handler, { _drivers.update_soc(_soc); _gui.input.sigh(_input_handler); - _gui.mode_sigh(_gui_mode_handler); + _gui.info_sigh(_gui_mode_handler); _handle_gui_mode(); - _fb_config.trigger_update(); + _nitpicker_config.trigger_update(); /* * Generate initial configurations @@ -1680,7 +1833,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, Xml_node const &window_list) { /* skip window-layout handling (and decorator activity) while booting */ - if (!_gui_mode_ready) + if (!_gui_mode_ready()) return; struct Decorator_margins @@ -1726,18 +1879,16 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, if (panel_height == 0) return; - Framebuffer::Mode const mode = _gui.mode(); - /* suppress intermediate boot-time states before the framebuffer driver is up */ - if (mode.area.count() <= 1) + if (!_screen_size.valid()) return; /* area reserved for the panel */ - Rect const panel = Rect(Point(0, 0), Area(mode.area.w, panel_height)); + Rect const panel = Rect(Point(0, 0), Area(_screen_size.w, panel_height)); /* available space on the right of the menu */ Rect avail = Rect::compound(Point(0, panel.h()), - Point(mode.area.w - 1, mode.area.h - 1)); + Point(_screen_size.w - 1, _screen_size.h - 1)); Point const log_offset = _log_visible ? Point(0, 0) @@ -1745,8 +1896,8 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, Point const log_p1(avail.x2() - log_min_w - margins.right + 1 + log_offset.x, avail.y1() + margins.top); - Point const log_p2(mode.area.w - margins.right - 1 + log_offset.x, - mode.area.h - margins.bottom - 1); + Point const log_p2(_screen_size.w - margins.right - 1 + log_offset.x, + _screen_size.h - margins.bottom - 1); /* position of the inspect window */ Point const inspect_p1(avail.x1() + margins.left, avail.y1() + margins.top); @@ -1812,7 +1963,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, Area const size = win_size(win); Point const pos = _network_visible ? Point(log_p1.x - size.w, avail.y1()) - : Point(mode.area.w, avail.y1()); + : Point(_screen_size.w, avail.y1()); gen_window(win, Rect(pos, size)); }); @@ -1918,7 +2069,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, _with_window(window_list, logo_label, [&] (Xml_node const &win) { Area const size = win_size(win); - Point const pos(mode.area.w - size.w, mode.area.h - size.h); + Point const pos(_screen_size.w - size.w, _screen_size.h - size.h); gen_window(win, Rect(pos, size)); }); }); @@ -1945,18 +2096,65 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins, void Sculpt::Main::_handle_gui_mode() { - Framebuffer::Mode const mode = _gui.mode(); + _panorama = _gui.panorama(); - if (mode.area.count() > 1) - _gui_mode_ready = true; + /* place leitzentrale at pointed display */ + Rect const orig_screen_rect { _screen_pos, _screen_size }; + Fb_connectors::Name const orig_hovered_display = _hovered_display; + { + Rect rect { }; - _update_window_layout(); + _gui.with_info([&] (Xml_node const &info) { + rect = Rect::from_xml(info); /* entire panorama */ + + if (!_pointer_pos.constructed()) + return; + + Gui::Point const at = *_pointer_pos; + + info.for_each_sub_node("capture", [&] (Xml_node const &capture) { + Rect const display = Rect::from_xml(capture); + if (display.contains(at)) { + rect = display; + Session_label label { capture.attribute_value("name", String<64>()) }; + _hovered_display = label.last_element(); + } + }); + }); + + _screen_pos = rect.at; + _screen_size = rect.area; + } + + bool const screen_changed = (orig_screen_rect != Rect { _screen_pos, _screen_size }) + || (orig_hovered_display != _hovered_display); + + if (screen_changed) { + _gui_fb_config.generate([&] (Xml_generator &xml) { + xml.attribute("xpos", _screen_pos.x); + xml.attribute("ypos", _screen_pos.y); + xml.attribute("width", _screen_size.w); + xml.attribute("height", _screen_size.h); + }); + + _panel_dialog.min_width = _screen_size.w; + unsigned const menu_width = max((unsigned)(_font_size_px*21.0), 320u); + _diag_dialog.min_width = menu_width; + _network_dialog.min_width = menu_width; + + _panel_dialog.refresh(); + _network_dialog.refresh(); + _diag_dialog.refresh(); + _update_window_layout(); + } _settings.manual_fonts_config = _fonts_config.try_generate_manually_managed(); if (!_settings.manual_fonts_config) { - _font_size_px = (double)mode.area.h / 60.0; + double const orig_font_size_px = _font_size_px; + + _font_size_px = (double)_screen_size.h / 60.0; if (_settings.font_size == Settings::Font_size::SMALL) _font_size_px *= 0.85; if (_settings.font_size == Settings::Font_size::LARGE) _font_size_px *= 1.35; @@ -1967,58 +2165,53 @@ void Sculpt::Main::_handle_gui_mode() */ _font_size_px = max(_font_size_px, _min_font_size_px); - _fonts_config.generate([&] (Xml_generator &xml) { - xml.attribute("copy", true); - xml.attribute("paste", true); - xml.node("vfs", [&] { - gen_named_node(xml, "rom", "Vera.ttf"); - gen_named_node(xml, "rom", "VeraMono.ttf"); - gen_named_node(xml, "dir", "fonts", [&] { + if (orig_font_size_px != _font_size_px) { + _fonts_config.generate([&] (Xml_generator &xml) { + xml.attribute("copy", true); + xml.attribute("paste", true); + xml.node("vfs", [&] { + gen_named_node(xml, "rom", "Vera.ttf"); + gen_named_node(xml, "rom", "VeraMono.ttf"); + gen_named_node(xml, "dir", "fonts", [&] { - auto gen_ttf_dir = [&] (char const *dir_name, - char const *ttf_path, double size_px) { + auto gen_ttf_dir = [&] (char const *dir_name, + char const *ttf_path, double size_px) { - gen_named_node(xml, "dir", dir_name, [&] { - gen_named_node(xml, "ttf", "regular", [&] { - xml.attribute("path", ttf_path); - xml.attribute("size_px", size_px); - xml.attribute("cache", "256K"); + gen_named_node(xml, "dir", dir_name, [&] { + gen_named_node(xml, "ttf", "regular", [&] { + xml.attribute("path", ttf_path); + xml.attribute("size_px", size_px); + xml.attribute("cache", "256K"); + }); }); - }); - }; + }; - gen_ttf_dir("title", "/Vera.ttf", _font_size_px*1.25); - gen_ttf_dir("text", "/Vera.ttf", _font_size_px); - gen_ttf_dir("annotation", "/Vera.ttf", _font_size_px*0.8); - gen_ttf_dir("monospace", "/VeraMono.ttf", _font_size_px); - }); - }); - xml.node("default-policy", [&] { xml.attribute("root", "/fonts"); }); - - auto gen_color = [&] (unsigned index, Color color) { - xml.node("palette", [&] { - xml.node("color", [&] { - xml.attribute("index", index); - xml.attribute("value", String<16>(color)); + gen_ttf_dir("title", "/Vera.ttf", _font_size_px*1.25); + gen_ttf_dir("text", "/Vera.ttf", _font_size_px); + gen_ttf_dir("annotation", "/Vera.ttf", _font_size_px*0.8); + gen_ttf_dir("monospace", "/VeraMono.ttf", _font_size_px); }); }); - }; + xml.node("default-policy", [&] { xml.attribute("root", "/fonts"); }); - Color const background = Color::rgb(0x1c, 0x22, 0x32); + auto gen_color = [&] (unsigned index, Color color) { + xml.node("palette", [&] { + xml.node("color", [&] { + xml.attribute("index", index); + xml.attribute("value", String<16>(color)); + }); + }); + }; - gen_color(0, background); - gen_color(8, background); - }); + Color const background = Color::rgb(0x1c, 0x22, 0x32); + + gen_color(0, background); + gen_color(8, background); + }); + /* propagate fonts config of runtime view */ + generate_runtime_config(); + } } - - _screen_size = mode.area; - _panel_dialog.min_width = _screen_size.w; - unsigned const menu_width = max((unsigned)(_font_size_px*21.0), 320u); - _diag_dialog.min_width = menu_width; - _network_dialog.min_width = menu_width; - - /* font size may has changed, propagate fonts config of runtime view */ - generate_runtime_config(); } diff --git a/repos/gems/src/app/sculpt_manager/model/fb_config.h b/repos/gems/src/app/sculpt_manager/model/fb_config.h new file mode 100644 index 0000000000..aaca4ed9a6 --- /dev/null +++ b/repos/gems/src/app/sculpt_manager/model/fb_config.h @@ -0,0 +1,412 @@ +/* + * \brief Model for the framebuffer driver configuration + * \author Norman Feske + * \date 2024-10-23 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _MODEL__FB_CONFIG_H_ +#define _MODEL__FB_CONFIG_H_ + +#include <model/fb_connectors.h> + +namespace Sculpt { struct Fb_config; }; + + +struct Sculpt::Fb_config +{ + struct Entry + { + using Name = Fb_connectors::Name; + using Mode_id = Fb_connectors::Connector::Mode::Id; + using Mode_attr = Fb_connectors::Connector::Mode::Attr; + using Brightness = Fb_connectors::Brightness; + + bool defined; + bool present; /* false if imported from config but yet unused */ + Name name; + Mode_id mode_id; + Mode_attr mode_attr; + Brightness brightness; + + static Entry from_connector(Fb_connectors::Connector const &connector) + { + Mode_attr mode_attr { }; + Mode_id mode_id { }; + connector.with_used_mode([&] (Fb_connectors::Connector::Mode const &mode) { + mode_attr = mode.attr; + mode_id = mode.id; }); + + return { .defined = true, + .present = true, + .name = connector.name, + .mode_id = mode_id, + .mode_attr = mode_attr, + .brightness = connector.brightness }; + } + + static Entry from_manual_xml(Xml_node const &node) + { + return { .defined = true, + .present = false, + .name = node.attribute_value("name", Name()), + .mode_id = node.attribute_value("mode", Mode_id()), + .mode_attr = Mode_attr::from_xml(node), + .brightness = Brightness::from_xml(node) }; + } + + void generate(Xml_generator &xml) const + { + if (!defined) + return; + + xml.node("connector", [&] { + xml.attribute("name", name); + if (mode_attr.px.valid()) { + xml.attribute("width", mode_attr.px.w); + xml.attribute("height", mode_attr.px.h); + if (mode_attr.hz) + xml.attribute("hz", mode_attr.hz); + if (brightness.defined) + xml.attribute("brightness", brightness.percent); + if (mode_id.length() > 1) + xml.attribute("mode", mode_id); + } else { + xml.attribute("enabled", "no"); + } + }); + } + + bool smaller_than(Entry const &other) const + { + return mode_attr.px.count() < other.mode_attr.px.count(); + } + }; + + static constexpr unsigned MAX_ENTRIES = 16; + Entry _entries[MAX_ENTRIES]; + + struct Manual_attr + { + Area max_px; /* upper bound of framebuffer allocation */ + Area px; /* for vesa_fb */ + + static Manual_attr from_xml(Xml_node const &node) + { + return { .max_px = { .w = node.attribute_value("max_width", 0u), + .h = node.attribute_value("max_height", 0u) }, + .px = Area::from_xml(node) }; + } + + void generate(Xml_generator &xml) const + { + if (max_px.w) xml.attribute("max_width", max_px.w); + if (max_px.h) xml.attribute("max_height", max_px.h); + if (px.w) xml.attribute("width", px.w); + if (px.h) xml.attribute("height", px.h); + } + }; + + Manual_attr _manual_attr { }; + + unsigned _num_merged = 0; + + bool _known(Fb_connectors::Connector const &connector) + { + for (Entry const &entry : _entries) + if (entry.name == connector.name) + return true; + return false; + } + + void _with_known(Fb_connectors::Connector const &connector, auto const &fn) + { + for (Entry &entry : _entries) + if (entry.name == connector.name) + fn(entry); + } + + void _insert_at(unsigned at, Entry const &entry) + { + if (at >= MAX_ENTRIES) { + warning("maximum number of ", MAX_ENTRIES, " fb config entries exeeded"); + return; + } + + for (unsigned i = MAX_ENTRIES - 1; i > at; i--) + _entries[i] = _entries[i - 1]; + + _entries[at] = entry; + } + + /* + * A new merged connector such that the smallest mode stays in front + */ + void _add_unknown_merged(Entry const &new_entry) + { + unsigned at = 0; + for (; at < _num_merged && _entries[at].smaller_than(new_entry); at++); + + _insert_at(at, new_entry); + + if (_num_merged < MAX_ENTRIES) + _num_merged++; + } + + void _add_unknown_discrete(Entry const &new_entry) + { + unsigned at = 0; + for (; at < MAX_ENTRIES && _entries[at].defined; at++); + + _insert_at(at, new_entry); + } + + void import_manual_config(Xml_node const &config) + { + _manual_attr = Manual_attr::from_xml(config); + + unsigned count = 0; + + auto add_connectors = [&] (Xml_node const &node) + { + node.for_each_sub_node("connector", [&] (Xml_node const &node) { + Entry const e = Entry::from_manual_xml(node); + if (!_known(e.name) && count < MAX_ENTRIES) { + _entries[count] = e; + count++; + } + }); + }; + + /* import merged nodes */ + config.with_optional_sub_node("merge", [&] (Xml_node const &merge) { + add_connectors(merge); }); + + _num_merged = count; + + /* import discrete nodes */ + add_connectors(config); + } + + void apply_connectors(Fb_connectors const &connectors) + { + /* apply information for connectors known from the manual config */ + connectors.for_each([&] (Fb_connectors::Connector const &conn) { + _with_known(conn.name, [&] (Entry &e) { + + if (e.present) /* apply config only once */ + return; + + if (!e.mode_attr.px.valid()) { /* switched off by config */ + e.mode_id = { }; + e.mode_attr = { }; + e.present = true; + return; + } + + conn.with_matching_mode(e.mode_id, e.mode_attr, + [&] (Fb_connectors::Connector::Mode const &mode) { + e.mode_id = mode.id; + e.mode_attr = mode.attr; + e.present = true; }); + }); + }); + + /* detect unplugging */ + for (Entry &entry : _entries) { + bool connected = false; + connectors.with_connector(entry.name, [&] (auto &) { connected = true; }); + if (!connected) + entry.present = false; + } + + connectors._merged.for_each([&] (Fb_connectors::Connector const &conn) { + if (!_known(conn.name)) + _add_unknown_merged(Entry::from_connector(conn)); }); + + connectors._discrete.for_each([&] (Fb_connectors::Connector const &conn) { + if (!_known(conn.name)) + _add_unknown_discrete(Entry::from_connector(conn)); }); + } + + void _with_entry(Entry::Name const &name, auto const &fn) + { + for (Entry &entry : _entries) + if (entry.name == name) + fn(entry); + } + + void select_fb_mode(Fb_connectors::Name const &conn, + Fb_connectors::Connector::Mode::Id const &mode_id, + Fb_connectors const &connectors) + { + connectors.with_mode_attr(conn, mode_id, [&] (Entry::Mode_attr const &attr) { + _with_entry(conn, [&] (Entry &entry) { + entry.mode_attr = attr; + entry.mode_id = mode_id; }); }); + } + + void disable_connector(Fb_connectors::Name const &conn) + { + _with_entry(conn, [&] (Entry &entry) { + entry.mode_attr = { }; }); + } + + void brightness(Fb_connectors::Name const &conn, unsigned percent) + { + _with_entry(conn, [&] (Entry &entry) { + entry.brightness.percent = percent; }); + } + + void _with_idx(Fb_connectors::Name const &conn, auto const &fn) const + { + for (unsigned i = 0; i < MAX_ENTRIES; i++) + if (_entries[i].name == conn && _entries[i].defined) { + fn(i); + return; + } + } + + void _swap_entries(unsigned i, unsigned j) + { + Entry tmp = _entries[i]; + _entries[i] = _entries[j]; + _entries[j] = tmp; + } + + /** + * Swap connector with next present predecessor + */ + void swap_connector(Fb_connectors::Name const &conn) + { + _with_idx(conn, [&] (unsigned const conn_idx) { + + if (conn_idx < 1) /* first entry cannot have a predecessor */ + return; + + /* search present predecessor */ + unsigned prev_idx = conn_idx - 1; + while (prev_idx > 0 && !_entries[prev_idx].present) + prev_idx--; + + _swap_entries(conn_idx, prev_idx); + }); + } + + void toggle_merge_discrete(Fb_connectors::Name const &conn) + { + _with_idx(conn, [&] (unsigned const idx) { + + if (idx < _num_merged) { + + /* + * Turn merged entry into discrete entry. + * + * There may be (non-present) merge entries following idx. + * Bubble up the entry so that it becomes the last merge + * entry before turning it into the first discrete entry by + * decreasing '_num_merged'. + */ + if (_num_merged > 0) { + for (unsigned i = idx; i < _num_merged - 1; i++) + _swap_entries(i, i + 1); + _num_merged--; + } + } else { + + /* + * Turn discrete entry into merged entry + */ + if (_num_merged < MAX_ENTRIES) { + for (unsigned i = idx; i > _num_merged; i--) + _swap_entries(i, i - 1); + _num_merged++; + } + } + }); + } + + struct Merge_info { Entry::Name name; Area px; }; + + void with_merge_info(auto const &fn) const + { + /* merged screen size and name corresponds to first enabled connector */ + for (unsigned i = 0; i < _num_merged; i++) { + if (_entries[i].present && _entries[i].mode_attr.px.valid()) { + fn({ .name = _entries[i].name, + .px = _entries[i].mode_attr.px }); + return; + } + } + + /* if all merged connectors are switched off, use name of first present one */ + for (unsigned i = 0; i < _num_merged; i++) { + if (_entries[i].present) { + fn({ .name = _entries[i].name, .px = { }}); + return; + } + } + }; + + void _gen_merge_node(Xml_generator &xml) const + { + with_merge_info([&] (Merge_info const &info) { + xml.node("merge", [&] { + xml.attribute("width", info.px.w); + xml.attribute("height", info.px.h); + xml.attribute("name", info.name); + + for (unsigned i = 0; i < _num_merged; i++) + _entries[i].generate(xml); + }); + }); + } + + void generate_managed_fb(Xml_generator &xml) const + { + _manual_attr.generate(xml); + + xml.attribute("system", "yes"); /* for screen blanking on suspend */ + + xml.node("report", [&] { xml.attribute("connectors", "yes"); }); + + _gen_merge_node(xml); + + /* nodes for discrete connectors */ + for (unsigned i = _num_merged; i < MAX_ENTRIES; i++) + _entries[i].generate(xml); + } + + void for_each_present_connector(Fb_connectors const &connectors, auto const &fn) const + { + for (Entry const &entry : _entries) + if (entry.defined && entry.present) + connectors.with_connector(entry.name, fn); + } + + void for_each_discrete_entry(auto const &fn) const + { + for (unsigned i = _num_merged; i < MAX_ENTRIES; i++) { + Entry const &entry = _entries[i]; + if (entry.defined && entry.present) + fn(entry); + } + } + + unsigned num_present_merged() const + { + unsigned count = 0; + for (unsigned i = 0; i < _num_merged; i++) + if (_entries[i].defined && _entries[i].present) + count++; + return count; + } +}; + +#endif /* _MODEL__FB_CONFIG_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/model/fb_connectors.h b/repos/gems/src/app/sculpt_manager/model/fb_connectors.h new file mode 100644 index 0000000000..596214ad07 --- /dev/null +++ b/repos/gems/src/app/sculpt_manager/model/fb_connectors.h @@ -0,0 +1,279 @@ +/* + * \brief Representation of connectors reported by the framebuffer driver + * \author Norman Feske + * \date 2024-10-23 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _MODEL__FB_CONNECTORS_H_ +#define _MODEL__FB_CONNECTORS_H_ + +#include <types.h> + +namespace Sculpt { struct Fb_connectors; }; + + +struct Sculpt::Fb_connectors : private Noncopyable +{ + using Area = Gui::Area; + using Name = String<16>; + + struct Connector; + using Connectors = List_model<Connector>; + + struct Brightness + { + bool defined; + unsigned percent; + + bool operator != (Brightness const &other) const + { + return defined != other.defined || percent != other.percent; + } + + static Brightness from_xml(Xml_node const &node) + { + return { .defined = node.has_attribute("brightness"), + .percent = node.attribute_value("brightness", 0u) }; + } + }; + + struct Connector : Connectors::Element + { + Name const name; + Area mm { }; + Brightness brightness { }; + + struct Mode; + using Modes = List_model<Mode>; + + Modes _modes { }; + + struct Mode : Modes::Element + { + using Id = String<16>; + + Id const id; + + struct Attr + { + Name name; + Area px; + Area mm; + bool used; + unsigned hz; + + bool operator != (Attr const &other) const + { + return name != other.name + || px != other.px + || mm != other.mm + || used != other.used + || hz != other.hz; + } + + static Attr from_xml(Xml_node const &node) + { + return { + .name = node.attribute_value("name", Name()), + .px = { .w = node.attribute_value("width", 0u), + .h = node.attribute_value("height", 0u) }, + .mm = { .w = node.attribute_value("width_mm", 0u), + .h = node.attribute_value("height_mm", 0u) }, + .used = node.attribute_value("used", false), + .hz = node.attribute_value("hz", 0u) + }; + } + }; + + Attr attr { }; + + Mode(Id id) : id(id) { }; + + static Id id_from_xml(Xml_node const &node) + { + return node.attribute_value("id", Mode::Id()); + } + + bool matches(Xml_node const &node) const + { + return id_from_xml(node) == id; + } + + static bool type_matches(Xml_node const &node) + { + return node.has_type("mode"); + } + + bool has_resolution(Area px) const { return attr.px == px; } + bool has_hz (unsigned hz) const { return attr.hz == hz; } + }; + + Connector(Name const &name) : name(name) { } + + void _with_mode(auto const &match_fn, auto const &fn) const + { + bool found = false; + _modes.for_each([&] (Mode const &mode) { + if (!found && match_fn(mode.attr)) { + fn(mode); + found = true; } }); + } + + void with_used_mode(auto const &fn) const + { + _with_mode([&] (Mode::Attr const &attr) { return attr.used; }, fn); + } + + void with_matching_mode(Mode::Id const &preferred_id, + Mode::Attr const &attr, auto const &fn) const + { + auto matches_resolution_and_id = [&] (Mode const &mode) + { + return mode.has_resolution(attr.px) && (mode.id == preferred_id); + }; + + auto matches_resolution_and_hz = [&] (Mode const &mode) + { + return mode.has_resolution(attr.px) && mode.has_hz(attr.hz); + }; + + auto matches_resolution = [&] (Mode const &mode) + { + return mode.has_resolution(attr.px); + }; + + bool matched = false; + auto with_match_once = [&] (auto const &matches_fn, auto const &fn) + { + if (!matched) + _modes.for_each([&] (Mode const &mode) { + if (matches_fn(mode)) { + fn(mode); + matched = true; } }); + }; + + with_match_once(matches_resolution_and_id, fn); + with_match_once(matches_resolution_and_hz, fn); + with_match_once(matches_resolution, fn); + + if (!matched) + with_used_mode([&] (Mode const &used) { + fn(used); + matched = true; }); + } + + bool update(Allocator &alloc, Xml_node const &node) + { + Area const orig_mm = mm; + Brightness const orig_brightness = brightness; + + mm.w = node.attribute_value("width_mm", 0u); + mm.h = node.attribute_value("height_mm", 0u); + brightness = Brightness::from_xml(node); + + bool progress = (orig_mm != mm || orig_brightness != brightness); + + _modes.update_from_xml(node, + [&] (Xml_node const &node) -> Mode & { + progress = true; + return *new (alloc) Mode(Mode::id_from_xml(node)); + }, + [&] (Mode &mode) { + progress = true; + destroy(alloc, &mode); + }, + [&] (Mode &mode, Xml_node const &node) { + Mode::Attr const orig_attr = mode.attr; + mode.attr = Mode::Attr::from_xml(node); + progress |= (orig_attr != mode.attr); + } + ); + + return progress; + } + + bool matches(Xml_node const &node) const + { + return node.attribute_value("name", Name()) == name; + } + + static bool type_matches(Xml_node const &node) + { + return node.has_type("connector") + && node.attribute_value("connected", false) + && node.has_sub_node("mode"); + } + }; + + Connectors _merged { }; + Connectors _discrete { }; + + [[nodiscard]] Progress update(Allocator &alloc, Xml_node const &connectors) + { + bool progress = false; + + auto update = [&] (Connectors &model, Xml_node const &node) + { + model.update_from_xml(node, + [&] (Xml_node const &node) -> Connector & { + progress = true; + return *new (alloc) Connector(node.attribute_value("name", Name())); + }, + [&] (Connector &conn) { + progress = true; + conn.update(alloc, Xml_node("<empty/>")); + destroy(alloc, &conn); + }, + [&] (Connector &conn, Xml_node const &node) { + progress |= conn.update(alloc, node); + }); + }; + + update(_discrete, connectors); + + connectors.with_sub_node("merge", + [&] (Xml_node const &merge) { update(_merged, merge); }, + [&] { update(_merged, Xml_node("<merge/>")); }); + + return { progress }; + } + + static unsigned _count(Connectors const &connectors) + { + unsigned count = 0; + connectors.for_each([&] (Connector const &) { count++; }); + return count; + } + + unsigned num_merged() const { return _count(_merged); } + + void for_each(auto const &fn) const + { + _merged .for_each(fn); + _discrete.for_each(fn); + } + + void with_connector(Name const &conn_name, auto const &fn) const + { + for_each([&] (Connector const &connector) { + if (connector.name == conn_name) + fn(connector); }); + } + + void with_mode_attr(Name const &conn_name, Connector::Mode::Id const &id, auto const &fn) const + { + with_connector(conn_name, [&] (Connector const &connector) { + connector._modes.for_each([&] (Connector::Mode const &mode) { + if (mode.id == id) + fn(mode.attr); }); }); + } +}; + +#endif /* _MODEL__FB_CONNECTORS_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/model/panorama_config.h b/repos/gems/src/app/sculpt_manager/model/panorama_config.h new file mode 100644 index 0000000000..36aa10ed47 --- /dev/null +++ b/repos/gems/src/app/sculpt_manager/model/panorama_config.h @@ -0,0 +1,100 @@ +/* + * \brief Representation of nitpicker's <capture> configuration + * \author Norman Feske + * \date 2024-10-25 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _MODEL__PANORAMA_CONFIG_H_ +#define _MODEL__PANORAMA_CONFIG_H_ + +#include <types.h> +#include <model/fb_config.h> + +namespace Sculpt { struct Panorama_config; }; + + +struct Sculpt::Panorama_config +{ + struct Entry + { + using Name = Fb_config::Entry::Name; + + Name name; + Rect rect; + + bool operator != (Entry const &other) const + { + return (name != other.name) || (rect != other.rect); + } + + void gen_policy(Xml_generator &xml) const + { + xml.node("policy", [&] { + xml.attribute("label_suffix", name); + xml.attribute("xpos", rect.x1()); + xml.attribute("ypos", rect.y1()); + xml.attribute("width", rect.w()); + xml.attribute("height", rect.h()); + }); + } + }; + + static constexpr unsigned MAX_ENTRIES = 16; + + Entry _entries[MAX_ENTRIES] { }; + + unsigned _num_entries = 0; + + Panorama_config() { }; + + Panorama_config(Fb_config const &fb_config) + { + int xpos = 0; + + auto append = [&] (auto const &name, auto const area) + { + if (_num_entries == MAX_ENTRIES) + return; + + _entries[_num_entries] = Entry { + .name = name, + .rect = { .at = { .x = xpos, .y = 0 }, .area = area } }; + + _num_entries++; + xpos += area.w; + }; + + fb_config.with_merge_info([&] (Fb_config::Merge_info const &info) { + append(info.name, info.px); }); + + fb_config.for_each_discrete_entry([&] (Fb_config::Entry const &entry) { + append(entry.name, entry.mode_attr.px); }); + } + + void gen_policy_entries(Xml_generator &xml) const + { + for (unsigned i = 0; i < _num_entries; i++) + _entries[i].gen_policy(xml); + } + + bool operator != (Panorama_config const &other) const + { + if (other._num_entries != _num_entries) + return true; + + for (unsigned i = 0; i < _num_entries; i++) + if (other._entries[i] != _entries[i]) + return true; + + return false; + } +}; + +#endif /* _MODEL__PANORAMA_CONFIG_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/network.h b/repos/gems/src/app/sculpt_manager/network.h index 4647ef233a..20690639c1 100644 --- a/repos/gems/src/app/sculpt_manager/network.h +++ b/repos/gems/src/app/sculpt_manager/network.h @@ -141,12 +141,11 @@ struct Sculpt::Network : Noncopyable _wlan_config.generate([&] (Xml_generator &xml) { - xml.attribute("connected_scan_interval", 0U); xml.attribute("scan_interval", 10U); xml.attribute("update_quality_interval", 30U); - xml.attribute("verbose_state", false); - xml.attribute("verbose", false); + xml.attribute("verbose", false); + xml.attribute("log_level", "error"); xml.node("network", [&]() { xml.attribute("ssid", ap.ssid); @@ -172,19 +171,11 @@ struct Sculpt::Network : Noncopyable _wlan_config.generate([&] (Xml_generator &xml) { - xml.attribute("connected_scan_interval", 0U); xml.attribute("scan_interval", 10U); xml.attribute("update_quality_interval", 30U); - xml.attribute("verbose_state", false); - xml.attribute("verbose", false); - - xml.node("network", [&]() { - /* generate attributes to ease subsequent manual tweaking */ - xml.attribute("ssid", ""); - xml.attribute("protection", "NONE"); - xml.attribute("passphrase", ""); - }); + xml.attribute("verbose", false); + xml.attribute("log_level", "error"); }); _runtime_config_generator.generate_runtime_config(); diff --git a/repos/gems/src/app/sculpt_manager/runtime/inspect_view.cc b/repos/gems/src/app/sculpt_manager/runtime/inspect_view.cc index a8a3e46cee..7f1fe24ed1 100644 --- a/repos/gems/src/app/sculpt_manager/runtime/inspect_view.cc +++ b/repos/gems/src/app/sculpt_manager/runtime/inspect_view.cc @@ -28,7 +28,7 @@ static void for_each_inspected_storage_target(Storage_devices const &devices, au static void gen_terminal_start(Xml_generator &xml) { gen_common_start_content(xml, "terminal", - Cap_quota{110}, Ram_quota{36*1024*1024}, + Cap_quota{140}, Ram_quota{36*1024*1024}, Priority::NESTED_MAX); gen_provides<Terminal::Session>(xml); diff --git a/repos/gems/src/app/sculpt_manager/view/fb_widget.h b/repos/gems/src/app/sculpt_manager/view/fb_widget.h new file mode 100644 index 0000000000..cf957533e3 --- /dev/null +++ b/repos/gems/src/app/sculpt_manager/view/fb_widget.h @@ -0,0 +1,202 @@ +/* + * \brief Framebuffer settings + * \author Norman Feske + * \date 2024-10-23 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _VIEW__FB_WIDGET_H_ +#define _VIEW__FB_WIDGET_H_ + +#include <view/dialog.h> +#include <model/fb_config.h> + +namespace Sculpt { struct Fb_widget; } + +struct Sculpt::Fb_widget : Widget<Vbox> +{ + using Connector = Fb_connectors::Connector; + using Mode = Connector::Mode; + using Hosted_choice = Hosted<Vbox, Choice<Mode::Id>>; + using Mode_radio = Hosted<Radio_select_button<Mode::Id>>; + + struct Action : Interface + { + virtual void select_fb_mode(Fb_connectors::Name const &, Mode::Id const &) = 0; + virtual void disable_fb_connector(Fb_connectors::Name const &) = 0; + virtual void toggle_fb_merge_discrete(Fb_connectors::Name const &) = 0; + virtual void swap_fb_connector(Fb_connectors::Name const &) = 0; + virtual void fb_brightness(Fb_connectors::Name const &, unsigned) = 0; + }; + + Fb_connectors::Name _selected_connector { }; + + struct Bar : Widget<Right_floating_hbox> + { + void view(Scope<Right_floating_hbox> &s, unsigned const percent) const + { + for (unsigned i = 0; i < 10; i++) { + s.sub_scope<Button>(Id { i }, [&] (Scope<Right_floating_hbox, Button> &s) { + + if (s.hovered()) s.attribute("hovered", "yes"); + + if (i*10 <= percent) + s.attribute("selected", "yes"); + else + s.attribute("style", "unimportant"); + + s.sub_scope<Float>([&] (auto &) { }); + }); + } + } + + void click(Clicked_at const &at, auto const &fn) + { + Id const id = at.matching_id<Right_floating_hbox, Button>(); + unsigned value = 0; + if (!ascii_to(id.value.string(), value)) + return; + + unsigned const percent = max(10u, min(100u, value*10 + 9)); + fn(percent); + } + }; + + using Hosted_brightness = Hosted<Bar>; + + void view(Scope<Vbox> &s, Fb_connectors const &connectors, Fb_config const &config, + Fb_connectors::Name const &hovered_display) const + { + auto view_connector = [&] (Connector const &conn) + { + Hosted_choice choice { Id { conn.name }, conn.name }; + + Mode::Id selected_mode { "off" }; + conn._modes.for_each([&] (Mode const &mode) { + if (mode.attr.used) + selected_mode = mode.id; }); + + s.widget(choice, + Hosted_choice::Attr { + .left_ex = 12, .right_ex = 28, + .unfolded = _selected_connector, + .selected_item = selected_mode + }, + [&] (Hosted_choice::Sub_scope &s) { + + if (conn.brightness.defined) { + Hosted_brightness brightness { Id { "brightness" } }; + s.widget(brightness, conn.brightness.percent); + } + + conn._modes.for_each([&] (Mode const &mode) { + String<32> text { mode.attr.name }; + if (mode.attr.hz) + text = { text, " (", mode.attr.hz, " Hz)" }; + + s.widget(Mode_radio { Id { mode.id }, mode.id }, + selected_mode, text); + }); + if (conn.name != hovered_display) + s.widget(Mode_radio { Id { "off" }, "off" }, selected_mode, "off"); + }); + }; + + unsigned const num_merged = config.num_present_merged(); + + auto view_controls = [&] (Scope<Vbox> &s, unsigned const count, Id const &id) + { + if (count <= 1) + return; + + s.sub_scope<Float>([&] (Scope<Vbox, Float> &s) { + s.sub_scope<Hbox>(id, [&] (Scope<Vbox, Float, Hbox> &s) { + + /* + * Restrict merge/unmerge toggle to last merged and first + * discrete connector. + */ + bool const toggle_allowed = (count == num_merged || count == num_merged + 1); + Id const equal_id { toggle_allowed ? "equal" : "_equal" }; + + s.sub_scope<Float>(equal_id, + [&] (Scope<Vbox, Float, Hbox, Float> &s) { + s.sub_scope<Button>([&] (Scope<Vbox, Float, Hbox, Float, Button> &s) { + s.attribute("style", "vconn"); + if (count <= num_merged) + s.attribute("selected", "yes"); + if (toggle_allowed) { + if (s.hovered() && !s.dragged()) + s.attribute("hovered", "yes"); + } + s.sub_node("hbox", [&] { }); + }); + }); + s.sub_scope<Float>(Id { "swap" }, [&] (Scope<Vbox, Float, Hbox, Float> &s) { + s.sub_scope<Button>([&] (Scope<Vbox, Float, Hbox, Float, Button> &s) { + s.attribute("style", "vswap"); + if (s.hovered() && !s.dragged()) + s.attribute("hovered", "yes"); + if (s.hovered() && s.dragged()) + s.attribute("selected", "yes"); + s.sub_node("hbox", [&] { }); + }); + }); + }); + }); + }; + + unsigned count = 0; + + config.for_each_present_connector(connectors, [&] (Connector const &conn) { + count++; + view_controls(s, count, Id { conn.name }); + view_connector(conn); + }); + } + + void click(Clicked_at const &at, Fb_connectors const &connectors, Action &action) + { + auto click_connector = [&] (Connector const &conn) + { + Hosted_choice choice { Id { conn.name }, conn.name }; + + choice.propagate(at, _selected_connector, + [&] { _selected_connector = { }; }, + [&] (Clicked_at const &at) { + Id const id = at.matching_id<Mode_radio>(); + if (id.value == "brightness") { + Hosted_brightness brightness { Id { "brightness" } }; + brightness.propagate(at, [&] (unsigned percent) { + action.fb_brightness(conn.name, percent); }); + } else if (id.value == "off") + action.disable_fb_connector(conn.name); + else if (id.valid()) + action.select_fb_mode(conn.name, id); + }); + }; + + connectors._merged.for_each([&] (Connector const &conn) { + click_connector(conn); }); + + connectors._discrete.for_each([&] (Connector const &conn) { + click_connector(conn); }); + + /* operation buttons */ + { + Id const conn = at.matching_id<Vbox, Float, Hbox>(); + Id const op = at.matching_id<Vbox, Float, Hbox, Float>(); + + if (op.value == "equal") action.toggle_fb_merge_discrete(conn.value); + if (op.value == "swap") action.swap_fb_connector(conn.value); + } + } +}; + +#endif /* _VIEW__FB_WIDGET_H_ */ diff --git a/repos/gems/src/app/themed_decorator/main.cc b/repos/gems/src/app/themed_decorator/main.cc index 5361aa819f..5bcbe84687 100644 --- a/repos/gems/src/app/themed_decorator/main.cc +++ b/repos/gems/src/app/themed_decorator/main.cc @@ -17,6 +17,7 @@ #include <base/heap.h> #include <base/attached_rom_dataspace.h> #include <os/reporter.h> +#include <timer_session/connection.h> /* decorator includes */ #include <decorator/window_stack.h> @@ -36,6 +37,18 @@ struct Decorator::Main : Window_factory_base { Env &_env; + Timer::Connection _timer { _env }; + + /* + * Time base for animations, which are computed in steps of 10 ms + */ + struct Ticks { uint64_t cs; /* centi-seconds (10 ms) */ }; + + Ticks _now() + { + return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 }; + } + Window_stack _window_stack = { *this }; /** @@ -77,19 +90,7 @@ struct Decorator::Main : Window_factory_base Reporter _decorator_margins_reporter = { _env, "decorator_margins" }; - /** - * Process the update every 'frame_period' GUI sync signals. The - * 'frame_cnt' holds the counter of the GUI sync signals. - * - * A lower 'frame_period' value makes the decorations more responsive - * but it also puts more load on the system. - * - * If the GUI sync signal fires every 10 milliseconds, a - * 'frame_period' of 2 results in an update rate of 1000/20 = 50 frames per - * second. - */ - unsigned _frame_cnt = 0; - unsigned _frame_period = 2; + Ticks _previous_sync { }; /** * Install handler for responding to GUI sync events @@ -99,9 +100,22 @@ struct Decorator::Main : Window_factory_base Signal_handler<Main> _gui_sync_handler = { _env.ep(), *this, &Main::_handle_gui_sync }; - void _trigger_sync_handling() + bool _gui_sync_enabled = false; + + void _trigger_gui_sync() { - _gui.framebuffer.sync_sigh(_gui_sync_handler); + Ticks const now = _now(); + bool const idle = now.cs - _previous_sync.cs > 3; + + if (!_gui_sync_enabled) { + _gui.framebuffer.sync_sigh(_gui_sync_handler); + _gui_sync_enabled = true; + } + + if (idle) { + _previous_sync = now; + _gui_sync_handler.local_submit(); + } } Attached_rom_dataspace _config { _env, "config" }; @@ -141,7 +155,7 @@ struct Decorator::Main : Window_factory_base Genode::log("pointer information unavailable"); } - _trigger_sync_handling(); + _trigger_gui_sync(); _hover_reporter.enabled(true); @@ -252,16 +266,15 @@ void Decorator::Main::_handle_window_layout_update() _window_layout_update_needed = true; - _trigger_sync_handling(); + _trigger_gui_sync(); } void Decorator::Main::_handle_gui_sync() { - if (_frame_cnt++ < _frame_period) - return; + Ticks const now = _now(); - _frame_cnt = 0; + Ticks const passed_ticks { now.cs - _previous_sync.cs }; bool model_updated = false; @@ -286,25 +299,23 @@ void Decorator::Main::_handle_gui_sync() bool const windows_animated = _window_stack.schedule_animated_windows(); - /* - * To make the perceived animation speed independent from the setting of - * 'frame_period', we update the animation as often as the GUI sync signal - * occurs. - */ - for (unsigned i = 0; i < _frame_period; i++) + for (unsigned i = 0; i < passed_ticks.cs; i++) _animator.animate(); - if (!model_updated && !windows_animated) - return; - - _window_stack.update_gui_views(); - _gui.execute(); + if (model_updated || windows_animated) { + _window_stack.update_gui_views(); + _gui.execute(); + } /* * Disable sync handling when becoming idle */ - if (!_animator.active()) + if (!_animator.active()) { _gui.framebuffer.sync_sigh(Signal_context_capability()); + _gui_sync_enabled = false; + } + + _previous_sync = now; } diff --git a/repos/gems/src/app/themed_decorator/window.h b/repos/gems/src/app/themed_decorator/window.h index 3c35413546..7abdf8fb02 100644 --- a/repos/gems/src/app/themed_decorator/window.h +++ b/repos/gems/src/app/themed_decorator/window.h @@ -286,8 +286,6 @@ class Decorator::Window : public Window_base, public Animator::Item }); buffer.flush_surface(); - - buffer.gui.framebuffer.refresh(0, 0, buffer.size().w, buffer.size().h); } void _repaint_decorations() @@ -300,17 +298,15 @@ class Decorator::Window : public Window_base, public Animator::Item void _reallocate_gui_buffers() { - bool const use_alpha = true; - Area const size_top_bottom = _visible_top_bottom_area(geometry().area); if (size_top_bottom.w > _size_top_bottom.w || size_top_bottom.h > _size_top_bottom.h || !_buffer_top_bottom.constructed()) { - _gui_top_bottom.buffer(Framebuffer::Mode { .area = { size_top_bottom.w, - size_top_bottom.h } }, - use_alpha); + _gui_top_bottom.buffer({ .area = { size_top_bottom.w, + size_top_bottom.h }, + .alpha = true }); _buffer_top_bottom.construct(_gui_top_bottom, size_top_bottom, _env.ram(), _env.rm()); @@ -324,9 +320,9 @@ class Decorator::Window : public Window_base, public Animator::Item || size_left_right.h > _size_left_right.h || !_buffer_left_right.constructed()) { - _gui_left_right.buffer(Framebuffer::Mode { .area = { size_left_right.w, - size_left_right.h } }, - use_alpha); + _gui_left_right.buffer({ .area = { size_left_right.w, + size_left_right.h }, + .alpha = true }); _buffer_left_right.construct(_gui_left_right, size_left_right, _env.ram(), _env.rm()); diff --git a/repos/gems/src/app/window_layouter/action.h b/repos/gems/src/app/window_layouter/action.h index 45890aa426..995274b6ac 100644 --- a/repos/gems/src/app/window_layouter/action.h +++ b/repos/gems/src/app/window_layouter/action.h @@ -49,6 +49,7 @@ class Window_layouter::Action PREV_TAB, TOOGLE_OVERLAY, SCREEN, + RELEASE_GRAB, }; private: @@ -64,6 +65,7 @@ class Window_layouter::Action if (string == "raise_window") return RAISE_WINDOW; if (string == "toggle_fullscreen") return TOGGLE_FULLSCREEN; if (string == "screen") return SCREEN; + if (string == "release_grab") return RELEASE_GRAB; Genode::warning("cannot convert \"", string, "\" to action type"); return NONE; diff --git a/repos/gems/src/app/window_layouter/main.cc b/repos/gems/src/app/window_layouter/main.cc index b6ac16d19e..123428445f 100644 --- a/repos/gems/src/app/window_layouter/main.cc +++ b/repos/gems/src/app/window_layouter/main.cc @@ -196,6 +196,12 @@ struct Window_layouter::Main : Operations, _gen_focus(); } + void release_grab() override + { + /* wm revokes exclusive input on each focus update */ + _gen_focus(); + } + void toggle_fullscreen(Window_id id) override { /* make sure that the specified window is the front-most one */ @@ -325,9 +331,9 @@ struct Window_layouter::Main : Operations, void _handle_mode_change() { /* determine maximized window geometry */ - Framebuffer::Mode const mode = _gui.mode(); - - _screen_size = mode.area; + _screen_size = _gui.panorama().convert<Gui::Area>( + [&] (Gui::Rect rect) { return rect.area; }, + [&] (Gui::Undefined) { return Gui::Area { 1, 1 }; }); _update_window_layout(); } @@ -373,7 +379,7 @@ struct Window_layouter::Main : Operations, */ Main(Env &env) : _env(env) { - _gui.mode_sigh(_mode_change_handler); + _gui.info_sigh(_mode_change_handler); _handle_mode_change(); _drop_timer.sigh(_drop_timer_handler); diff --git a/repos/gems/src/app/window_layouter/operations.h b/repos/gems/src/app/window_layouter/operations.h index 4ed9922d13..5cf7da46cc 100644 --- a/repos/gems/src/app/window_layouter/operations.h +++ b/repos/gems/src/app/window_layouter/operations.h @@ -28,6 +28,7 @@ struct Window_layouter::Operations : Interface virtual void close(Window_id) = 0; virtual void toggle_fullscreen(Window_id) = 0; virtual void focus(Window_id) = 0; + virtual void release_grab() = 0; virtual void to_front(Window_id) = 0; virtual void drag(Window_id, Window::Element, Point clicked, Point curr) = 0; virtual void finalize_drag(Window_id, Window::Element, Point clicked, Point final) = 0; diff --git a/repos/gems/src/app/window_layouter/user_state.h b/repos/gems/src/app/window_layouter/user_state.h index 255b17dca8..edb2d8cf8e 100644 --- a/repos/gems/src/app/window_layouter/user_state.h +++ b/repos/gems/src/app/window_layouter/user_state.h @@ -332,6 +332,10 @@ void Window_layouter::User_state::_handle_event(Input::Event const &e, _operations.screen(action.target_name()); return; + case Action::RELEASE_GRAB: + _operations.release_grab(); + return; + default: warning("action ", (int)action.type(), " unhanded"); } diff --git a/repos/gems/src/lib/dialog/sandboxed_runtime.cc b/repos/gems/src/lib/dialog/sandboxed_runtime.cc index ff460a3ad8..d8e204ae14 100644 --- a/repos/gems/src/lib/dialog/sandboxed_runtime.cc +++ b/repos/gems/src/lib/dialog/sandboxed_runtime.cc @@ -66,7 +66,14 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session> Input::Session_client _gui_input { _env.rm(), _gui_session.input() }; - Input::Session_component _input_component { _env, _env.ram() }; + struct Input_action : Input::Session_component::Action + { + void exclusive_input_requested(bool) override { }; + + } _input_action { }; + + Input::Session_component _input_component { + _env.ep(), _env.ram(), _env.rm(), _input_action }; Signal_handler<Gui_session> _input_handler { _env.ep(), *this, &Gui_session::_handle_input }; @@ -109,12 +116,9 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session> _connection(env, _label, Ram_quota { 36*1024 }, { }) { _gui_input.sigh(_input_handler); - _env.ep().manage(_input_component); _input_component.event_queue().enabled(true); } - ~Gui_session() { _env.ep().dissolve(_input_component); } - void upgrade(Session::Resources const &resources) { _connection.upgrade(resources); @@ -150,14 +154,11 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session> void execute() override { _gui_session.execute(); } - Framebuffer::Mode mode() override { - return _gui_session.mode(); } + Info_result info() override { + return _gui_session.info(); } - void mode_sigh(Signal_context_capability sigh) override { - _gui_session.mode_sigh(sigh); } - - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override { - return _gui_session.buffer(mode, use_alpha); } + Buffer_result buffer(Framebuffer::Mode mode) override { + return _gui_session.buffer(mode); } void focus(Capability<Gui::Session> session) override { _gui_session.focus(session); } diff --git a/repos/gems/src/server/gui_fader/main.cc b/repos/gems/src/server/gui_fader/main.cc index e6225e2df7..1d713f8034 100644 --- a/repos/gems/src/server/gui_fader/main.cc +++ b/repos/gems/src/server/gui_fader/main.cc @@ -23,6 +23,7 @@ #include <os/static_root.h> #include <util/reconstructible.h> #include <nitpicker_gfx/texture_painter.h> +#include <blit/painter.h> #include <util/lazy_value.h> #include <timer_session/connection.h> @@ -42,6 +43,7 @@ namespace Gui_fader { using Rect = Genode::Surface_base::Rect; using Genode::size_t; + using Genode::uint8_t; using Genode::Xml_node; using Genode::Dataspace_capability; using Genode::Attached_ram_dataspace; @@ -64,9 +66,9 @@ class Gui_fader::Src_buffer using Pixel = Pixel_rgb888; - bool const _use_alpha; Attached_ram_dataspace _ds; Texture<Pixel> _texture; + bool _warned_once = false; static size_t _needed_bytes(Area size) { @@ -74,25 +76,40 @@ class Gui_fader::Src_buffer return size.count() * (1 + 1 + sizeof(Pixel)); } + void _with_pixel_surface(auto const &fn) + { + Surface<Pixel_rgb888> pixel { _ds.local_addr<Pixel_rgb888>(), _texture.size() }; + fn(pixel); + } + public: - /** - * Constructor - */ - Src_buffer(Genode::Env &env, Area size, bool use_alpha) + Src_buffer(Genode::Env &env, Framebuffer::Mode mode) : - _use_alpha(use_alpha), - _ds(env.ram(), env.rm(), _needed_bytes(size)), + _ds(env.ram(), env.rm(), _needed_bytes(mode.area)), _texture(_ds.local_addr<Pixel>(), - _ds.local_addr<unsigned char>() + size.count()*sizeof(Pixel), - size) + mode.alpha ? _ds.local_addr<uint8_t>() + mode.area.count()*sizeof(Pixel) + : nullptr, + mode.area) { } Dataspace_capability dataspace() { return _ds.cap(); } Texture<Pixel> const &texture() const { return _texture; } - bool use_alpha() const { return _use_alpha; } + bool use_alpha() const { return _texture.alpha(); } + + void blit(Rect from, Point to) + { + if (_texture.alpha() && !_warned_once) { + Genode::warning("Framebuffer::Session::blit does not support alpha blending"); + _warned_once = true; + } + + _with_pixel_surface([&] (Surface<Pixel_rgb888> &surface) { + surface.clip({ to, from.area }); + Blit_painter::paint(surface, _texture, to - from.p1()); }); + } }; @@ -142,7 +159,6 @@ class Gui_fader::Framebuffer_session_component Constructible<Dst_buffer> _dst_buffer { }; - Lazy_value<int> _fade { }; public: @@ -207,7 +223,7 @@ class Gui_fader::Framebuffer_session_component transfer_src_to_dst_alpha(rect); - _gui.framebuffer.refresh(rect.x1(), rect.y1(), rect.w(), rect.h()); + _gui.framebuffer.refresh(rect); /* keep animating as long as the destination value is not reached */ return _fade != _fade.dst(); @@ -238,18 +254,44 @@ class Gui_fader::Framebuffer_session_component _gui.framebuffer.mode_sigh(sigh); } - void refresh(int x, int y, int w, int h) override + void refresh(Rect rect) override { - transfer_src_to_dst_pixel(Rect(Point(x, y), Area(w, h))); - transfer_src_to_dst_alpha(Rect(Point(x, y), Area(w, h))); + transfer_src_to_dst_pixel(rect); + transfer_src_to_dst_alpha(rect); - _gui.framebuffer.refresh(x, y, w, h); + _gui.framebuffer.refresh(rect); + } + + Blit_result blit(Framebuffer::Blit_batch const &batch) override + { + Framebuffer::Mode const mode { .area = _src_buffer.texture().size(), + .alpha = false }; + for (Framebuffer::Transfer const &transfer : batch.transfer) { + if (transfer.valid(mode)) { + _src_buffer.blit(transfer.from, transfer.to); + Rect const to_rect { transfer.to, transfer.from.area }; + refresh(to_rect); + } + } + return Blit_result::OK; + } + + void panning(Point pos) override + { + Rect const rect { { }, _src_buffer.texture().size() }; + + transfer_src_to_dst_pixel(rect); + transfer_src_to_dst_alpha(rect); + + _gui.framebuffer.panning(pos); } void sync_sigh(Genode::Signal_context_capability sigh) override { _gui.framebuffer.sync_sigh(sigh); } + + void sync_source(Genode::Session_label const &) override { } }; @@ -264,7 +306,8 @@ class Gui_fader::Gui_session_component Genode::Env &_env; - Reconstructible<Src_buffer> _src_buffer { _env, Area(1, 1), false }; + Reconstructible<Src_buffer> _src_buffer { + _env, Framebuffer::Mode { .area = { 1, 1 }, .alpha = false } }; Gui::Connection _gui { _env }; @@ -412,25 +455,15 @@ class Gui_fader::Gui_session_component return _gui.execute(); } - Framebuffer::Mode mode() override + Info_result info() override { return _gui.info_rom_cap(); } + + Buffer_result buffer(Framebuffer::Mode mode) override { - return _gui.mode(); - } + _src_buffer.construct(_env, mode); - void mode_sigh(Genode::Signal_context_capability sigh) override - { - _gui.mode_sigh(sigh); - } + _gui.buffer({ .area = mode.area, .alpha = true }); - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override - { - Area const size = mode.area; - - _src_buffer.construct(_env, size, use_alpha); - - _gui.buffer(mode, true); - - _fb_session.dst_buffer(_gui.framebuffer.dataspace(), size); + _fb_session.dst_buffer(_gui.framebuffer.dataspace(), mode.area); return Buffer_result::OK; } diff --git a/repos/gems/src/server/terminal/main.cc b/repos/gems/src/server/terminal/main.cc index f81db3a24b..5a62f8e56a 100644 --- a/repos/gems/src/server/terminal/main.cc +++ b/repos/gems/src/server/terminal/main.cc @@ -100,9 +100,33 @@ struct Terminal::Main : Character_consumer Signal_handler<Main> _config_handler { _env.ep(), *this, &Main::_handle_config }; + Gui::Area _initial_mode { }; + + Gui::Rect _gui_window_rect() + { + return _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { + Gui::Area const area = + _initial_mode.valid() ? _initial_mode + : Gui::Area { 1, 1 }; + return Gui::Rect { { }, area }; + }); + } + void _handle_mode_change() { - _fb_mode = _gui.mode(); + Rect const orig_win_rect = _win_rect; + + _win_rect = _gui_window_rect(); + + /* shrink view before shrinking the buffer to prevent tiling artifacts */ + Rect const intersection = Rect::intersect(orig_win_rect, _win_rect); + if (intersection != orig_win_rect) { + _gui.enqueue<Gui::Session::Command::Geometry>(_view, intersection); + _gui.execute(); + } + _handle_config(); } @@ -114,7 +138,7 @@ struct Terminal::Main : Character_consumer Constructible<Attached_dataspace> _fb_ds { }; - Framebuffer::Mode _fb_mode { }; + Gui::Rect _win_rect { }; Gui::View_id _view { }; @@ -143,7 +167,7 @@ struct Terminal::Main : Character_consumer bool _flush_scheduled = false; - Framebuffer::Mode _flushed_fb_mode { }; + Gui::Rect _flushed_win_rect { }; void _handle_flush() { @@ -151,22 +175,22 @@ struct Terminal::Main : Character_consumer if (_text_screen_surface.constructed() && _fb_ds.constructed()) { - Surface<PT> surface(_fb_ds->local_addr<PT>(), _fb_mode.area); + Surface<PT> surface(_fb_ds->local_addr<PT>(), _win_rect.area); Rect const dirty = _text_screen_surface->redraw(surface); - _gui.framebuffer.refresh(dirty.x1(), dirty.y1(), dirty.w(), dirty.h()); + _gui.framebuffer.refresh(dirty); } /* update view geometry after mode change */ - if (_fb_mode.area != _flushed_fb_mode.area) { + if (_win_rect != _flushed_win_rect) { using Command = Gui::Session::Command; - _gui.enqueue<Command::Geometry>(_view, Rect(Point(0, 0), _fb_mode.area)); + _gui.enqueue<Command::Geometry>(_view, _win_rect); _gui.enqueue<Command::Front>(_view); _gui.execute(); - _flushed_fb_mode = _fb_mode; + _flushed_win_rect = _win_rect; } } @@ -215,16 +239,16 @@ struct Terminal::Main : Character_consumer _config.sigh(_config_handler); _gui.input.sigh(_input_handler); - _gui.mode_sigh(_mode_change_handler); - - _fb_mode = _gui.mode(); + _gui.info_sigh(_mode_change_handler); /* apply initial size from config, if provided */ _config.xml().with_optional_sub_node("initial", [&] (Xml_node const &initial) { - _fb_mode.area = Area(initial.attribute_value("width", _fb_mode.area.w), - initial.attribute_value("height", _fb_mode.area.h)); + _initial_mode = { initial.attribute_value("width", _win_rect.w()), + initial.attribute_value("height", _win_rect.h()) }; }); + _win_rect = _gui_window_rect(); + _handle_config(); /* announce service at our parent */ @@ -259,9 +283,9 @@ void Terminal::Main::_handle_config() /* * Adapt terminal to font or framebuffer mode changes */ - _gui.buffer(_fb_mode, false); + _gui.buffer({ .area = _win_rect.area, .alpha = false }); - if (_fb_mode.area.count() > 0) + if (_win_rect.valid()) _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); /* @@ -276,7 +300,7 @@ void Terminal::Main::_handle_config() */ try { - Text_screen_surface<PT>::Geometry const new_geometry(_font->font(), _fb_mode.area); + Text_screen_surface<PT>::Geometry const new_geometry(_font->font(), _win_rect.area); bool const reconstruct = !_text_screen_surface.constructed() || _text_screen_surface->size() != new_geometry.size(); @@ -307,7 +331,7 @@ void Terminal::Main::_handle_config() : Position(); _text_screen_surface.construct(_heap, _font->font(), - _color_palette, _fb_mode.area); + _color_palette, _win_rect.area); if (snapshot.constructed()) _text_screen_surface->import(*snapshot); diff --git a/repos/gems/src/server/wm/decorator_gui.h b/repos/gems/src/server/wm/decorator_gui.h index 394b289392..43ad1fe9d6 100644 --- a/repos/gems/src/server/wm/decorator_gui.h +++ b/repos/gems/src/server/wm/decorator_gui.h @@ -21,25 +21,14 @@ #include <input/component.h> /* local includes */ +#include <types.h> #include <window_registry.h> #include <pointer.h> #include <real_gui.h> -namespace Wm { class Main; - using Genode::size_t; - using Genode::Allocator; - using Genode::Arg_string; - using Genode::Object_pool; - using Genode::Attached_dataspace; - using Genode::Attached_ram_dataspace; - using Genode::Signal_handler; - using Genode::Reporter; - using Genode::Interface; -} - - namespace Wm { + class Main; struct Decorator_gui_session; struct Decorator_content_callback; struct Decorator_content_registry; @@ -58,8 +47,9 @@ struct Wm::Decorator_content_callback : Interface }; -struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, - private List<Decorator_gui_session>::Element +struct Wm::Decorator_gui_session : Session_object<Gui::Session>, + private List<Decorator_gui_session>::Element, + private Upgradeable { friend class List<Decorator_gui_session>; using List<Decorator_gui_session>::Element::next; @@ -80,17 +70,19 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, Gui::View_ids _content_view_ids { }; - Genode::Env &_env; + Env &_env; - Genode::Heap _heap { _env.ram(), _env.rm() }; + Constrained_ram_allocator _ram { _env.ram(), _ram_quota_guard(), _cap_quota_guard() }; - Genode::Ram_allocator &_ram; + Sliced_heap _session_alloc { _ram, _env.rm() }; - Real_gui _gui { _env, "decorator" }; + Slab<Content_view_ref, 4000> _content_view_ref_alloc { _session_alloc }; - Input::Session_client _input_session { _env.rm(), _gui.session.input() }; + Real_gui _real_gui { _env, "decorator" }; - Genode::Signal_context_capability _mode_sigh { }; + Input::Session_client _input_session { _env.rm(), _real_gui.session.input() }; + + Signal_context_capability _mode_sigh { }; Attached_ram_dataspace _client_command_ds { _ram, _env.rm(), sizeof(Command_buffer) }; @@ -102,48 +94,46 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, Decorator_content_callback &_content_callback; - Allocator &_md_alloc; + struct Dummy_input_action : Input::Session_component::Action + { + void exclusive_input_requested(bool) override { }; + + } _input_action { }; /* Gui::Connection requires a valid input session */ - Input::Session_component _dummy_input_component { _env, _env.ram() }; - Input::Session_capability _dummy_input_component_cap = - _env.ep().manage(_dummy_input_component); + Input::Session_component _dummy_input_component { + _env.ep(), _env.ram(), _env.rm(), _input_action }; Signal_handler<Decorator_gui_session> _input_handler { _env.ep(), *this, &Decorator_gui_session::_handle_input }; - Window_registry::Id _win_id_from_title(Gui::Title const &title) + void _with_win_id_from_title(Gui::Title const &title, auto const &fn) { unsigned value = 0; - Genode::ascii_to(title.string(), value); - return { value }; + if (ascii_to(title.string(), value)) + fn(Window_registry::Id { value }); } - /** - * Constructor - * - * \param ep entrypoint used for dispatching signals - */ - Decorator_gui_session(Genode::Env &env, - Genode::Ram_allocator &ram, - Allocator &md_alloc, - Pointer::Tracker &pointer_tracker, - Input::Session_component &window_layouter_input, + Decorator_gui_session(Env &env, + Resources const &resources, + Label const &label, + Diag const &diag, + Pointer::Tracker &pointer_tracker, + Input::Session_component &window_layouter_input, Decorator_content_callback &content_callback) : + Session_object<Gui::Session>(env.ep(), resources, label, diag), _env(env), - _ram(ram), _pointer_state(pointer_tracker), _window_layouter_input(window_layouter_input), - _content_callback(content_callback), - _md_alloc(md_alloc) + _content_callback(content_callback) { _input_session.sigh(_input_handler); } - ~Decorator_gui_session() + void upgrade_local_or_remote(Resources const &resources) { - _env.ep().dissolve(_dummy_input_component); + _upgrade_local_or_remote(resources, *this, _real_gui); } void _handle_input() @@ -171,7 +161,7 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, [&] { }); /* forward command */ - _gui.enqueue(cmd); + _real_gui.enqueue(cmd); return; case Command::OFFSET: @@ -182,7 +172,7 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, */ _content_view_ids.apply<Content_view_ref const>(cmd.geometry.view, [&] (Content_view_ref const &) { }, - [&] { _gui.enqueue(cmd); }); + [&] { _real_gui.enqueue(cmd); }); return; case Command::FRONT: @@ -190,28 +180,24 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, case Command::FRONT_OF: case Command::BEHIND_OF: + _real_gui.enqueue(cmd); _content_view_ids.apply<Content_view_ref const>(cmd.front.view, [&] (Content_view_ref const &view_ref) { + _real_gui.execute(); _content_callback.update_content_child_views(view_ref.win_id); }, [&] { }); - _gui.enqueue(cmd); return; case Command::TITLE: case Command::BACKGROUND: case Command::NOP: - _gui.enqueue(cmd); + _real_gui.enqueue(cmd); return; } } - void upgrade(const char *args) - { - _gui.connection.upgrade(Genode::session_resources_from_args(args)); - } - Pointer::Position last_observed_pointer_pos() const { return _pointer_state.last_observed_pos(); @@ -224,7 +210,7 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, Framebuffer::Session_capability framebuffer() override { - return _gui.session.framebuffer(); + return _real_gui.session.framebuffer(); } Input::Session_capability input() override @@ -233,7 +219,12 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, * Deny input to the decorator. User input referring to the * window decorations is routed to the window manager. */ - return _dummy_input_component_cap; + return _dummy_input_component.cap(); + } + + Info_result info() override + { + return _real_gui.session.info(); } View_result view(View_id id, View_attr const &attr) override @@ -243,33 +234,38 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, * as view title. For such views, we import the view from the * corresponding GUI cient instead of creating a new view. */ - Window_registry::Id const win_id = _win_id_from_title(attr.title); - if (win_id.valid()) { + bool out_of_ram = false, out_of_caps = false, associated = false; + _with_win_id_from_title(attr.title, [&] (Window_registry::Id win_id) { try { - Content_view_ref &view_ref_ptr = *new (_heap) + Content_view_ref &view_ref_ptr = *new (_content_view_ref_alloc) Content_view_ref(Window_registry::Id(win_id), _content_view_ids, id); View_capability view_cap = _content_callback.content_view(win_id); - Associate_result result = _gui.session.associate(id, view_cap); + Associate_result result = _real_gui.session.associate(id, view_cap); if (result != Associate_result::OK) - destroy(_heap, &view_ref_ptr); + destroy(_content_view_ref_alloc, &view_ref_ptr); switch (result) { - case Associate_result::OUT_OF_RAM: return View_result::OUT_OF_RAM; - case Associate_result::OUT_OF_CAPS: return View_result::OUT_OF_CAPS; - case Associate_result::OK: return View_result::OK; + case Associate_result::OUT_OF_RAM: out_of_ram = true; break; + case Associate_result::OUT_OF_CAPS: out_of_caps = true; break; + case Associate_result::OK: associated = true; break; case Associate_result::INVALID: break; /* fall back to regular view */ }; } - catch (Genode::Out_of_ram) { return View_result::OUT_OF_RAM; } - catch (Genode::Out_of_caps) { return View_result::OUT_OF_CAPS; } - } - return _gui.session.view(id, attr); + catch (Out_of_ram) { _starved_for_ram = out_of_ram = true; } + catch (Out_of_caps) { _starved_for_caps = out_of_caps = true; } + }); + + if (out_of_ram) return View_result::OUT_OF_RAM; + if (out_of_caps) return View_result::OUT_OF_CAPS; + if (associated) return View_result::OK; + + return _real_gui.session.view(id, attr); } Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override { - return _gui.session.child_view(id, parent, attr); + return _real_gui.session.child_view(id, parent, attr); } void destroy_view(View_id view) override @@ -283,36 +279,36 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, _content_callback.hide_content_child_views(view_ref.win_id); Gui::Rect rect(Gui::Point(0, 0), Gui::Area(0, 0)); - _gui.enqueue<Gui::Session::Command::Geometry>(view, rect); - _gui.execute(); + _real_gui.enqueue<Gui::Session::Command::Geometry>(view, rect); + _real_gui.execute(); - destroy(_heap, &view_ref); + destroy(_content_view_ref_alloc, &view_ref); }, [&] { }); - _gui.session.destroy_view(view); + _real_gui.session.destroy_view(view); } Associate_result associate(View_id id, View_capability view_cap) override { - return _gui.session.associate(id, view_cap); + return _real_gui.session.associate(id, view_cap); } View_capability_result view_capability(View_id view) override { - return _gui.session.view_capability(view); + return _real_gui.session.view_capability(view); } void release_view_id(View_id view) override { _content_view_ids.apply<Content_view_ref>(view, - [&] (Content_view_ref &view_ref) { destroy(_heap, &view_ref); }, + [&] (Content_view_ref &view_ref) { destroy(_content_view_ref_alloc, &view_ref); }, [&] { }); - _gui.session.release_view_id(view); + _real_gui.session.release_view_id(view); } - Genode::Dataspace_capability command_dataspace() override + Dataspace_capability command_dataspace() override { return _client_command_ds.cap(); } @@ -322,30 +318,15 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>, for (unsigned i = 0; i < _client_command_buffer.num(); i++) _execute_command(_client_command_buffer.get(i)); - _gui.execute(); + _real_gui.execute(); } - Framebuffer::Mode mode() override + Buffer_result buffer(Framebuffer::Mode mode) override { - return _gui.session.mode(); + return _real_gui.session.buffer(mode); } - void mode_sigh(Genode::Signal_context_capability sigh) override - { - /* - * Remember signal-context capability to keep NOVA from revoking - * transitive delegations of the capability. - */ - _mode_sigh = sigh; - _gui.session.mode_sigh(sigh); - } - - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override - { - return _gui.session.buffer(mode, use_alpha); - } - - void focus(Genode::Capability<Gui::Session>) override { } + void focus(Capability<Gui::Session>) override { } }; #endif /* _DECORATOR_GUI_H_ */ diff --git a/repos/gems/src/server/wm/direct_gui.h b/repos/gems/src/server/wm/direct_gui.h index d1080a126b..76b0f134f8 100644 --- a/repos/gems/src/server/wm/direct_gui.h +++ b/repos/gems/src/server/wm/direct_gui.h @@ -21,16 +21,14 @@ namespace Wm { class Direct_gui_session; } -class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session> +class Wm::Direct_gui_session : public Session_object<Gui::Session> { private: - Genode::Env &_env; + Env &_env; - Genode::Session_label _label; - - Genode::Connection<Gui::Session> _connection { - _env, _label, Genode::Ram_quota { 36*1024 }, /* Args */ { } }; + Connection<Gui::Session> _connection { + _env, _label, Ram_quota { 36*1024 }, /* Args */ { } }; Gui::Session_client _session { _connection.cap() }; @@ -39,12 +37,10 @@ class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session> public: - /** - * Constructor - */ - Direct_gui_session(Genode::Env &env, Genode::Session_label const &label) + Direct_gui_session(Env &env, auto &&... args) : - _env(env), _label(label) + Session_object<Gui::Session>(env.ep(), args...), + _env(env) { } void upgrade(char const *args) @@ -98,7 +94,7 @@ class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session> _session.release_view_id(view); } - Genode::Dataspace_capability command_dataspace() override + Dataspace_capability command_dataspace() override { return _session.command_dataspace(); } @@ -108,22 +104,17 @@ class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session> _session.execute(); } - Framebuffer::Mode mode() override + Info_result info() override { - return _session.mode(); + return _session.info(); } - void mode_sigh(Genode::Signal_context_capability sigh) override + Buffer_result buffer(Framebuffer::Mode mode) override { - _session.mode_sigh(sigh); + return _session.buffer(mode); } - Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override - { - return _session.buffer(mode, use_alpha); - } - - void focus(Genode::Capability<Gui::Session> session) override + void focus(Capability<Gui::Session> session) override { _session.focus(session); } diff --git a/repos/gems/src/server/wm/gui.h b/repos/gems/src/server/wm/gui.h index 3379749ae4..8819828f89 100644 --- a/repos/gems/src/server/wm/gui.h +++ b/repos/gems/src/server/wm/gui.h @@ -15,17 +15,11 @@ #define _GUI_H_ /* Genode includes */ -#include <util/list.h> -#include <base/tslab.h> -#include <os/surface.h> -#include <base/attached_ram_dataspace.h> -#include <os/session_policy.h> -#include <os/reporter.h> -#include <os/session_policy.h> #include <root/component.h> #include <gui_session/connection.h> #include <input_session/capability.h> #include <input/component.h> +#include <os/dynamic_rom_session.h> /* local includes */ #include <window_registry.h> @@ -33,26 +27,6 @@ #include <layouter_gui.h> #include <direct_gui.h> - -namespace Wm { - - using Genode::Rpc_object; - using Genode::List; - using Genode::Allocator; - using Genode::Affinity; - using Genode::static_cap_cast; - using Genode::Signal_handler; - using Genode::Weak_ptr; - using Genode::Locked_ptr; - using Genode::Tslab; - using Genode::Attached_ram_dataspace; - using Genode::Signal_context_capability; - using Genode::Signal_transmitter; - using Genode::Reporter; - using Genode::Capability; - using Genode::Interface; -} - namespace Wm { namespace Gui { using namespace ::Gui; @@ -65,10 +39,6 @@ namespace Wm { namespace Gui { class Session_control_fn; class Session_component; class Root; - - using Rect = Genode::Surface_base::Rect; - using Point = Genode::Surface_base::Point; - using Session_label = Genode::Session_label; } } @@ -97,13 +67,12 @@ struct Wm::Gui::Input_origin_changed_handler : Interface }; -class Wm::Gui::View : private Genode::Weak_object<View>, - public Genode::Rpc_object< ::Gui::View> +class Wm::Gui::View : private Weak_object<View>, public Rpc_object< ::Gui::View> { private: - friend class Genode::Weak_ptr<View>; - friend class Genode::Locked_ptr<View>; + friend class Weak_ptr<View>; + friend class Locked_ptr<View>; protected: @@ -121,6 +90,7 @@ class Wm::Gui::View : private Genode::Weak_object<View>, Weak_ptr<View> _neighbor_ptr { }; bool _neighbor_behind { }; bool _has_alpha; + bool _layouted = false; void _with_temporary_view_id(View_capability cap, auto const &fn) { @@ -141,12 +111,11 @@ class Wm::Gui::View : private Genode::Weak_object<View>, }; View(Real_gui &real_gui, - View_id const &real_view_id, Session_label const &session_label, bool has_alpha) : _session_label(session_label), _real_gui(real_gui), - _real_view(_real_view_ref, _real_gui.view_ids, real_view_id), + _real_view(_real_view_ref, _real_gui.view_ids), _has_alpha(has_alpha) { } @@ -197,8 +166,8 @@ class Wm::Gui::View : private Genode::Weak_object<View>, _real_gui.session.destroy_view(_real_view.id()); } - using Genode::Weak_object<View>::weak_ptr; - using Genode::Weak_object<View>::lock_for_destruction; + using Weak_object<View>::weak_ptr; + using Weak_object<View>::lock_for_destruction; Point virtual_position() const { return _geometry.at; } @@ -241,16 +210,22 @@ class Wm::Gui::View : private Genode::Weak_object<View>, } bool has_alpha() const { return _has_alpha; } + + bool layouted() const { return _layouted; } }; class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Element { + public: + + using View_result = Gui::Session::View_result; + private: friend class List<Top_level_view>; - Window_registry::Id _win_id { }; + Window_registry::Create_result _win_id = Window_registry::Create_error::IDS_EXHAUSTED; Window_registry &_window_registry; @@ -268,37 +243,46 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme Session_label const _session_label; + View_result _init_real_view() + { + return _real_gui.session.view(_real_view.id(), { .title = _title, + .rect = { }, + .front = false }); + } + + View_result const _real_view_result = _init_real_view(); + using Command = Gui::Session::Command; + void _with_optional_win_id(auto const &fn) const + { + _win_id.with_result([&] (Window_registry::Id id) { fn(id); }, + [&] (Window_registry::Create_error) { }); + } + public: Top_level_view(Real_gui &real_gui, - View_id view_id, bool has_alpha, Window_registry &window_registry, Input_origin_changed_handler &input_origin_changed_handler) : - View(real_gui, view_id, real_gui.label, has_alpha), + View(real_gui, real_gui.label, has_alpha), _window_registry(window_registry), _input_origin_changed_handler(input_origin_changed_handler), _session_label(real_gui.label) - { - /* - * Create and configure physical GUI view. - */ - _real_gui.session.view(_real_view.id(), { .title = _title, - .rect = { }, - .front = false }); - } + { } ~Top_level_view() { - if (_win_id.valid()) - _window_registry.destroy(_win_id); + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.destroy(id); }); View::lock_for_destruction(); } + View_result real_view_result() const { return _real_view_result; } + using List<Top_level_view>::Element::next; void _propagate_view_geometry() override { } @@ -310,16 +294,20 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme * defer the creation of the window ID until the time when the * initial geometry is known. */ - if (!_win_id.valid()) { - _win_id = _window_registry.create(); - _window_registry.title(_win_id, _window_title); - _window_registry.label(_win_id, _session_label); - _window_registry.has_alpha(_win_id, View::has_alpha()); - _window_registry.resizeable(_win_id, _resizeable); + if (!_win_id.ok()) { + _win_id = _window_registry.create({ + .title = _window_title, + .label = _session_label, + .area = geometry.area, + .alpha = { View::has_alpha() }, + .hidden = { }, + .resizeable = { _resizeable } + }); + } else { + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.area(id, geometry.area); }); } - _window_registry.size(_win_id, geometry.area); - View::geometry(geometry); } @@ -331,11 +319,17 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme _window_title = title; - if (_win_id.valid()) - _window_registry.title(_win_id, _window_title); + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.title(id, _window_title); }); } - bool has_win_id(Window_registry::Id id) const { return id == _win_id; } + bool has_win_id(Window_registry::Id id) const + { + bool result = false; + _with_optional_win_id([&] (Window_registry::Id this_id) { + result = (this_id == id); }); + return result; + } bool belongs_to_win_id(Window_registry::Id id) const override { @@ -353,26 +347,36 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme _content_geometry = rect; + _layouted = true; + if (position_changed) _input_origin_changed_handler.input_origin_changed(); } View_capability content_view() { return real_view_cap(); } - void hidden(bool hidden) { _window_registry.hidden(_win_id, hidden); } + void hidden(bool hidden) + { + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.hidden(id, hidden); }); + } void resizeable(bool resizeable) { _resizeable = resizeable; - if (_win_id.valid()) - _window_registry.resizeable(_win_id, resizeable); + _with_optional_win_id([&] (Window_registry::Id id) { + _window_registry.resizeable(id, resizeable); }); } }; class Wm::Gui::Child_view : public View, private List<Child_view>::Element { + public: + + using View_result = Gui::Session::Child_view_result; + private: friend class List<Child_view>; @@ -381,23 +385,24 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element bool _visible = false; + View_result _real_view_result = try_to_init_real_view(); + public: Child_view(Real_gui &real_gui, - View_id real_gui_id, bool has_alpha, Weak_ptr<View> parent) : - View(real_gui, real_gui_id, real_gui.label, has_alpha), _parent(parent) - { - try_to_init_real_view(); - } + View(real_gui, real_gui.label, has_alpha), _parent(parent) + { } ~Child_view() { View::lock_for_destruction(); } + View_result real_view_result() const { return _real_view_result; } + using List<Child_view>::Element::next; void _propagate_view_geometry() override @@ -410,7 +415,14 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element _neighbor_ptr = neighbor_ptr; _neighbor_behind = behind; - _apply_view_config(); + auto parent_position_known = [&] + { + Locked_ptr<View> parent(_parent); + return parent.valid() && parent->layouted(); + }; + + if (parent_position_known()) + _apply_view_config(); } bool belongs_to_win_id(Window_registry::Id id) const override @@ -428,11 +440,15 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element return Point(); } - void try_to_init_real_view() + View_result try_to_init_real_view() { + using Child_view_result = Gui::Session::Child_view_result; + + Child_view_result result = Child_view_result::INVALID; + Locked_ptr<View> parent(_parent); if (!parent.valid()) - return; + return result; _with_temporary_view_id(parent->real_view_cap(), [&] (View_id parent_id) { @@ -443,22 +459,24 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element .rect = _geometry, .front = false }; - switch (_real_gui.session.child_view(_real_view.id(), parent_id, attr)) { - case Gui::Session::Child_view_result::OUT_OF_RAM: - case Gui::Session::Child_view_result::OUT_OF_CAPS: - case Gui::Session::Child_view_result::INVALID: + result = _real_gui.session.child_view(_real_view.id(), parent_id, attr); + + if (result != Child_view_result::OK) { warning("unable to create child view"); return; - case Gui::Session::Child_view_result::OK: - break; - }; + } + _visible = true; }); - if (_neighbor_ptr == _parent) - _unsynchronized_apply_view_config(parent); - else - _apply_view_config(); + if (parent->layouted()) { + if (_neighbor_ptr == _parent) + _unsynchronized_apply_view_config(parent); + else + _apply_view_config(); + } + + return result; } void update_child_stacking() @@ -474,10 +492,20 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element }; -class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, +class Wm::Gui::Session_component : public Session_object<Gui::Session>, private List<Session_component>::Element, - private Input_origin_changed_handler + private Input_origin_changed_handler, + private Upgradeable, + private Dynamic_rom_session::Xml_producer, + private Input::Session_component::Action { + public: + + struct Action : Interface + { + virtual void gen_screen_area_info(Xml_generator &) const = 0; + }; + private: friend class List<Session_component>; @@ -513,30 +541,90 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, } }; - Genode::Env &_env; + Env &_env; + Action &_action; - Session_label _session_label; - Genode::Ram_allocator &_ram; - Real_gui _real_gui { _env, _session_label }; + Constrained_ram_allocator _ram { + _env.ram(), _ram_quota_guard(), _cap_quota_guard() }; + + Sliced_heap _session_alloc { _ram, _env.rm() }; + Real_gui _real_gui { _env, _label }; Window_registry &_window_registry; - Tslab<Top_level_view, 8000> _top_level_view_alloc; - Tslab<Child_view, 7000> _child_view_alloc; - Tslab<View_ref, 4000> _view_ref_alloc; + Slab<Top_level_view, 8000> _top_level_view_alloc { _session_alloc }; + Slab<Child_view, 7000> _child_view_alloc { _session_alloc }; + Slab<View_ref, 4000> _view_ref_alloc { _session_alloc }; List<Top_level_view> _top_level_views { }; List<Child_view> _child_views { }; View_ids _view_ids { }; - Input::Session_component _input_session { _env, _ram }; - Input::Session_capability _input_session_cap; - Click_handler &_click_handler; - Signal_context_capability _mode_sigh { }; - Area _requested_size { }; - bool _resize_requested = false; - bool _has_alpha = false; - Pointer::State _pointer_state; - Point const _initial_pointer_pos { -1, -1 }; - Point _pointer_pos = _initial_pointer_pos; - Point _virtual_pointer_pos { }; - unsigned _key_cnt = 0; + + Input::Session_component _input_session { + _env.ep(), _ram, _env.rm(), *this }; + + bool _exclusive_input_requested = false, + _exclusive_input_granted = false; + + /* used for hiding the click-to-grab event from the client */ + bool _consume_one_btn_left_release = false; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool const requested) override + { + if (requested == _exclusive_input_requested) + return; + + /* + * Allow immediate changes when + * + * 1. Exclusive input is already granted by the user having clicked + * into the window, or + * 2. The client yields the exclusivity, or + * 3. Transient exclusive input is requested while a button is held. + * In this case, exclusive input will be revoked as soon as the + * last button/key is released. + */ + if (_exclusive_input_granted || _key_cnt || !requested) + _gui_input.exclusive(requested); + + _exclusive_input_requested = requested; + } + + Click_handler &_click_handler; + + struct Info_rom_session : Dynamic_rom_session + { + Session_component &_session; + + Info_rom_session(Session_component &session, auto &&... args) + : Dynamic_rom_session(args...), _session(session) { } + + void sigh(Signal_context_capability sigh) override + { + Dynamic_rom_session::sigh(sigh); + + /* + * We consider a window as resizable if the client shows interest + * in mode-change notifications. + */ + _session._resizeable = sigh.valid(); + for (Top_level_view *v = _session._top_level_views.first(); v; v = v->next()) + v->resizeable(_session._resizeable); + } + }; + + Constructible<Info_rom_session> _info_rom { }; + + bool _resizeable = false; + Area _requested_size { }; + bool _resize_requested = false; + bool _close_requested = false; + bool _has_alpha = false; + Pointer::State _pointer_state; + Point const _initial_pointer_pos { -1, -1 }; + Point _pointer_pos = _initial_pointer_pos; + Point _virtual_pointer_pos { }; + unsigned _key_cnt = 0; auto _with_view(View_id id, auto const &fn, auto const &missing_fn) -> decltype(missing_fn()) @@ -568,9 +656,6 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, Signal_handler<Session_component> _input_handler { _env.ep(), *this, &Session_component::_handle_input }; - Signal_handler<Session_component> _mode_handler { - _env.ep(), *this, &Session_component::_handle_mode_change }; - Point _input_origin() const { if (Top_level_view const *v = _top_level_views.first()) @@ -675,20 +760,78 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, if (propagate_to_pointer_state) _pointer_state.apply_event(ev); + /* + * Handle pointer grabbing/ungrabbing + */ + + /* revoke transient exclusive input (while clicked) */ + if (ev.release() && _key_cnt == 0) + if (_exclusive_input_requested && !_exclusive_input_granted) + _gui_input.exclusive(false); + + /* grant exclusive input when clicking into window */ + if (ev.key_press(Input::BTN_LEFT) && _key_cnt == 1) { + if (_exclusive_input_requested && !_exclusive_input_granted) { + _gui_input.exclusive(true); + _exclusive_input_granted = true; + _consume_one_btn_left_release = true; + continue; + } + } + if (ev.key_release(Input::BTN_LEFT)) { + if (_consume_one_btn_left_release) { + _consume_one_btn_left_release = false; + continue; + } + } + /* submit event to the client */ _input_session.submit(_translate_event(ev, input_origin)); } } } - void _handle_mode_change() + /** + * Dynamic_rom_session::Xml_producer interface + */ + void produce_xml(Xml_generator &xml) override { - /* - * Inform a viewless client about the upstream - * mode change. - */ - if (_mode_sigh.valid() && !_top_level_views.first()) - Signal_transmitter(_mode_sigh).submit(); + _action.gen_screen_area_info(xml); + + if (_close_requested) { + xml.node("capture", [&] { xml.attribute("closed", "yes"); }); + return; + } + + auto virtual_capture_area = [&] + { + /* + * While resizing the window, return requested window size as + * mode + */ + if (_resize_requested) + return _requested_size; + + /* + * If the first top-level view has a defined size, use it + * as the size of the virtualized GUI session. + */ + if (Top_level_view const *v = _top_level_views.first()) + if (v->size().valid()) + return v->size(); + + return Area { }; + }; + + auto gen_attr = [&] (Area const area) + { + if (area.valid()) { + xml.attribute("width", area.w); + xml.attribute("height", area.h); + } + }; + + xml.node("capture", [&] { gen_attr(virtual_capture_area()); }); } /** @@ -704,18 +847,26 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _input_session.submit(Input::Absolute_motion { pos.x, pos.y }); } + void _dissolve_view_from_ep(View &view) + { + if (view.cap().valid()) { + _env.ep().dissolve(view); + replenish(Cap_quota { 1 }); + } + } + void _destroy_top_level_view(Top_level_view &view) { _top_level_views.remove(&view); - _env.ep().dissolve(view); - Genode::destroy(&_top_level_view_alloc, &view); + _dissolve_view_from_ep(view); + destroy(&_top_level_view_alloc, &view); } void _destroy_child_view(Child_view &view) { _child_views.remove(&view); - _env.ep().dissolve(view); - Genode::destroy(&_child_view_alloc, &view); + _dissolve_view_from_ep(view); + destroy(&_child_view_alloc, &view); } void _execute_command(Command const &command) @@ -764,8 +915,8 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, char sanitized_title[args.title.capacity()]; - Genode::copy_cstring(sanitized_title, command.title.title.string(), - sizeof(sanitized_title)); + copy_cstring(sanitized_title, command.title.title.string(), + sizeof(sanitized_title)); for (char *c = sanitized_title; *c; c++) if (*c == '"') @@ -785,32 +936,23 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, public: - /** - * Constructor - * - * \param ep entrypoint used for managing the views - */ - Session_component(Genode::Env &env, - Genode::Ram_allocator &ram, - Window_registry &window_registry, - Allocator &session_alloc, - Session_label const &session_label, - Pointer::Tracker &pointer_tracker, - Click_handler &click_handler) + Session_component(Env &env, + Action &action, + Resources const &resources, + Label const &label, + Diag const diag, + Window_registry &window_registry, + Pointer::Tracker &pointer_tracker, + Click_handler &click_handler) : - _env(env), - _session_label(session_label), - _ram(ram), + Session_object<Gui::Session>(env.ep(), resources, label, diag), + Xml_producer("panorama"), + _env(env), _action(action), _window_registry(window_registry), - _top_level_view_alloc(&session_alloc), - _child_view_alloc(&session_alloc), - _view_ref_alloc(&session_alloc), - _input_session_cap(env.ep().manage(_input_session)), _click_handler(click_handler), _pointer_state(pointer_tracker) { _gui_input.sigh(_input_handler); - _real_gui.session.mode_sigh(_mode_handler); _input_session.event_queue().enabled(true); } @@ -824,15 +966,13 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, while (Child_view *view = _child_views.first()) _destroy_child_view(*view); - - _env.ep().dissolve(_input_session); } using List<Session_component>::Element::next; - void upgrade(char const *args) + void upgrade_local_or_remote(Resources const &resources) { - _real_gui.connection.upgrade(Genode::session_resources_from_args(args)); + _upgrade_local_or_remote(resources, *this, _real_gui); } void try_to_init_real_child_views() @@ -869,13 +1009,13 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, View_capability content_view(Window_registry::Id id) { for (Top_level_view *v = _top_level_views.first(); v; v = v->next()) - if (v->has_win_id(id.value)) + if (v->has_win_id(id)) return v->content_view(); return View_capability(); } - bool has_win_id(unsigned id) const + bool has_win_id(Window_registry::Id id) const { for (Top_level_view const *v = _top_level_views.first(); v; v = v->next()) if (v->has_win_id(id)) @@ -884,8 +1024,6 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, return false; } - Session_label session_label() const { return _session_label; } - bool matches_session_label(char const *selector) const { using namespace Genode; @@ -896,7 +1034,7 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, * * The code snippet originates from nitpicker's 'gui_session.h'. */ - String<Session_label::capacity() + 4> const label(_session_label, " ->"); + String<Session_label::capacity() + 4> const label(_label, " ->"); return strcmp(label.string(), selector, strlen(selector)) == 0; } @@ -905,9 +1043,12 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _requested_size = size; _resize_requested = true; + if (_requested_size.count() == 0) + _close_requested = true; + /* notify client */ - if (_mode_sigh.valid()) - Signal_transmitter(_mode_sigh).submit(); + if (_info_rom.constructed()) + _info_rom->trigger_update(); } void hidden(bool hidden) @@ -926,6 +1067,20 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, */ Capability<Session> session() { return _real_gui.connection.cap(); } + void propagate_mode_change() + { + if (_info_rom.constructed()) + _info_rom->trigger_update(); + } + + void revoke_exclusive_input() + { + if (_exclusive_input_granted) { + _gui_input.exclusive(false); + _exclusive_input_granted = false; + } + } + /*************************** ** GUI session interface ** @@ -938,39 +1093,64 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, Input::Session_capability input() override { - return _input_session_cap; + return _input_session.cap(); } template <typename VIEW> - View_result _create_view_with_id(auto &dealloc, View_id id, View_attr const &attr, auto const &create_fn) + VIEW::View_result _create_view_with_id(auto &dealloc, View_id id, View_attr const &attr, auto const &create_fn) { + using Result = VIEW::View_result; + + /* precondition for obtaining 'real_view_cap' */ + if (!try_withdraw(Cap_quota { 1 })) { + _starved_for_caps = true; + return Result::OUT_OF_CAPS; + } + release_view_id(id); - View_result error { }; + Result error { }; VIEW *view_ptr = nullptr; try { view_ptr = &create_fn(); } - catch (Out_of_ram) { error = View_result::OUT_OF_RAM; } - catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; } + catch (Out_of_ram) { + _starved_for_ram = true; + error = Result::OUT_OF_RAM; + } + catch (Out_of_caps) { + _starved_for_caps = true; + error = Result::OUT_OF_CAPS; + } if (!view_ptr) return error; + /* _real_gui view creation may return OUT_OF_RAM or OUT_OF_CAPS */ + if (view_ptr->real_view_result() != Result::OK) { + error = view_ptr->real_view_result(); + destroy(dealloc, view_ptr); + return error; + } + View_ref *view_ref_ptr = nullptr; try { view_ref_ptr = new (_view_ref_alloc) View_ref(view_ptr->weak_ptr(), _view_ids, id); } - catch (Out_of_ram) { error = View_result::OUT_OF_RAM; } - catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; } + catch (Out_of_ram) { + _starved_for_ram = true; + error = Result::OUT_OF_RAM; + } + catch (Out_of_caps) { + _starved_for_caps = true; + error = Result::OUT_OF_CAPS; + } if (!view_ref_ptr) { destroy(dealloc, view_ptr); return error; } - _env.ep().manage(*view_ptr); - /* apply initial view attributes */ _execute_command(Command::Title { id, attr.title }); _execute_command(Command::Geometry { id, attr.rect }); @@ -979,7 +1159,7 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _window_registry.flush(); } - return View_result::OK; + return Result::OK; } View_result view(View_id id, View_attr const &attr) override @@ -990,13 +1170,13 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _create_view_with_id<Top_level_view>(_top_level_view_alloc, id, attr, [&] () -> Top_level_view & { view_ptr = new (_top_level_view_alloc) - Top_level_view(_real_gui, id, _has_alpha, + Top_level_view(_real_gui, _has_alpha, _window_registry, *this); return *view_ptr; }); if (result == View_result::OK && view_ptr) { - view_ptr->resizeable(_mode_sigh.valid()); + view_ptr->resizeable(_resizeable); _top_level_views.insert(view_ptr); } return result; @@ -1009,24 +1189,18 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, Child_view *view_ptr = nullptr; - View_result const result = + Child_view_result const result = _create_view_with_id<Child_view>(_child_view_alloc, id, attr, [&] () -> Child_view & { view_ptr = new (_child_view_alloc) - Child_view(_real_gui, id, _has_alpha, parent.weak_ptr()); + Child_view(_real_gui, _has_alpha, parent.weak_ptr()); return *view_ptr; }); - switch (result) { - case View_result::OUT_OF_RAM: return Child_view_result::OUT_OF_RAM; - case View_result::OUT_OF_CAPS: return Child_view_result::OUT_OF_CAPS; - case View_result::OK: break; - } - - if (view_ptr) + if (result == Child_view_result::OK && view_ptr) _child_views.insert(view_ptr); - return Child_view_result::OK; + return result; }, [&] () -> Child_view_result { return Child_view_result::INVALID; }); } @@ -1038,11 +1212,13 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, for (Child_view *v = _child_views.first(); v; v = v->next()) if (&view == v) { _destroy_child_view(*v); + replenish(Cap_quota { 1 }); return; } for (Top_level_view *v = _top_level_views.first(); v; v = v->next()) if (&view == v) { _destroy_top_level_view(*v); + replenish(Cap_quota { 1 }); return; } }, @@ -1064,16 +1240,32 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, new (_view_ref_alloc) View_ref(view_ptr->weak_ptr(), _view_ids, id); return Associate_result::OK; } - catch (Out_of_ram) { return Associate_result::OUT_OF_RAM; } - catch (Out_of_caps) { return Associate_result::OUT_OF_CAPS; } + catch (Out_of_ram) { + _starved_for_ram = true; + return Associate_result::OUT_OF_RAM; + } + catch (Out_of_caps) { + _starved_for_caps = true; + return Associate_result::OUT_OF_CAPS; + } }); } View_capability_result view_capability(View_id id) override { return _with_view(id, - [&] (View &view) { return view.cap(); }, - [&] /* view does not exist */ { return View_capability(); }); + [&] (View &view) -> View_capability_result + { + if (!view.cap().valid()) { + if (!try_withdraw(Cap_quota { 1 })) { + _starved_for_caps = true; + return View_capability_error::OUT_OF_CAPS; + } + _env.ep().manage(view); + } + return view.cap(); + }, + [&] () -> View_capability_result { return View_capability(); }); } void release_view_id(View_id id) override @@ -1083,7 +1275,7 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, [&] { }); } - Genode::Dataspace_capability command_dataspace() override + Dataspace_capability command_dataspace() override { return _command_ds.cap(); } @@ -1097,46 +1289,38 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, _window_registry.flush(); } - Framebuffer::Mode mode() override + Info_result info() override { - Framebuffer::Mode const real_mode = _real_gui.session.mode(); + if (!_info_rom.constructed()) { + Cap_quota const needed_caps { 2 }; + if (!_cap_quota_guard().have_avail(needed_caps)) { + _starved_for_caps = true; + return Info_error::OUT_OF_CAPS; + } - /* - * While resizing the window, return requested window size as - * mode - */ - if (_resize_requested) - return Framebuffer::Mode { .area = _requested_size }; + Ram_quota const needed_ram { 8*1024 }; + if (!_ram_quota_guard().have_avail(needed_ram)) { + _starved_for_ram = true; + return Info_error::OUT_OF_RAM; + } - /* - * If the first top-level view has a defined size, use it - * as the size of the virtualized GUI session. - */ - if (Top_level_view const *v = _top_level_views.first()) - if (v->size().valid()) - return Framebuffer::Mode { .area = v->size() }; + try { + Dynamic_rom_session::Content_producer &rom_producer = *this; + _info_rom.construct(*this, _env.ep(), _ram, _env.rm(), rom_producer); + _info_rom->dataspace(); /* eagerly consume RAM and caps */ + } + catch (Out_of_ram) { _starved_for_ram = true; } + catch (Out_of_caps) { _starved_for_caps = true; } - /* - * If top-level view has yet been defined, return the real mode. - */ - return real_mode; + if (_starved_for_ram || _starved_for_caps) { + if (_starved_for_ram) return Info_error::OUT_OF_RAM; + if (_starved_for_caps) return Info_error::OUT_OF_CAPS; + } + } + return _info_rom->cap(); } - void mode_sigh(Genode::Signal_context_capability sigh) override - { - _mode_sigh = sigh; - - /* - * We consider a window as resizable if the client shows interest - * in mode-change notifications. - */ - bool const resizeable = _mode_sigh.valid(); - - for (Top_level_view *v = _top_level_views.first(); v; v = v->next()) - v->resizeable(resizeable); - } - - Buffer_result buffer(Framebuffer::Mode mode, bool has_alpha) override + Buffer_result buffer(Framebuffer::Mode mode) override { /* * We must not perform the 'buffer' operation on the connection @@ -1147,20 +1331,21 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>, * wrapped GUI session. Otherwise, we would perform session * upgrades initiated by the wm client's buffer operation twice. */ - _has_alpha = has_alpha; + _has_alpha = mode.alpha; - Buffer_result const result = _real_gui.session.buffer(mode, has_alpha); + Buffer_result const result = _real_gui.session.buffer(mode); _window_registry.flush(); return result; } - void focus(Genode::Capability<Gui::Session>) override { } + void focus(Capability<Gui::Session>) override { } }; -class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> >, - public Decorator_content_callback +class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >, + public Decorator_content_callback, + private Input::Session_component::Action { private: @@ -1170,27 +1355,27 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> Root(Root const &); Root &operator = (Root const &); - Genode::Env &_env; + Env &_env; - Genode::Attached_rom_dataspace _config { _env, "config" }; + Session_component::Action &_action; - Allocator &_md_alloc; + Attached_rom_dataspace _config { _env, "config" }; - Genode::Ram_allocator &_ram; + Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; enum { STACK_SIZE = 1024*sizeof(long) }; Pointer::Tracker &_pointer_tracker; - Reporter &_focus_request_reporter; - - unsigned _focus_request_cnt = 0; - Window_registry &_window_registry; - Input::Session_component _window_layouter_input { _env, _env.ram() }; + Input::Session_component _window_layouter_input { + _env.ep(), _env.ram(), _env.rm(), *this }; - Input::Session_capability _window_layouter_input_cap { _env.ep().manage(_window_layouter_input) }; + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool) override { } /* handler that forwards clicks into unfocused windows to the layouter */ struct Click_handler : Gui::Click_handler @@ -1232,16 +1417,13 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> /** * Constructor */ - Root(Genode::Env &env, - Window_registry &window_registry, Allocator &md_alloc, - Genode::Ram_allocator &ram, - Pointer::Tracker &pointer_tracker, Reporter &focus_request_reporter, - Gui::Connection &focus_gui_session) + Root(Env &env, Session_component::Action &action, + Window_registry &window_registry, + Pointer::Tracker &pointer_tracker, + Gui::Connection &focus_gui_session) : - _env(env), - _md_alloc(md_alloc), _ram(ram), + _env(env), _action(action), _pointer_tracker(pointer_tracker), - _focus_request_reporter(focus_request_reporter), _window_registry(window_registry), _focus_gui_session(focus_gui_session) { @@ -1273,11 +1455,16 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> ** Root interface ** ********************/ + static_assert(Gui::Session::CAP_QUOTA == 9); + Genode::Session_capability session(Session_args const &args, Affinity const &) override { - Genode::Session_label const session_label = - Genode::label_from_args(args.string()); + using Session = Genode::Session; + + Session::Label label = label_from_args(args.string()); + Session::Resources resources = session_resources_from_args(args.string()); + Session::Diag diag = session_diag_from_args(args.string()); enum Role { ROLE_DECORATOR, ROLE_LAYOUTER, ROLE_REGULAR, ROLE_DIRECT }; Role role = ROLE_REGULAR; @@ -1286,8 +1473,7 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> * Determine session policy */ try { - Genode::Xml_node policy = - Genode::Session_policy(session_label, _config.xml()); + Xml_node policy = Session_policy(label, _config.xml()); auto const value = policy.attribute_value("role", String<16>()); @@ -1297,44 +1483,76 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> } catch (...) { } + if (role == ROLE_REGULAR || role == ROLE_DECORATOR) { + + size_t const needed_ram = Real_gui::RAM_QUOTA + + sizeof(Session_component) + + _sliced_heap.overhead(sizeof(Session_component)) + + 8*1024; + + if (resources.ram_quota.value < needed_ram) + throw Insufficient_ram_quota(); + resources.ram_quota.value -= needed_ram; + + static constexpr unsigned needed_caps = + 1 + /* Sliced_heap alloc of Session_component */ + 1 + /* Session_component RPC cap */ + 9 + /* Wrapped nitpicker GUI session (_real_gui) */ + 1 + /* Input_session RPC cap (_input_session) */ + 1 + /* Input_session events dataspace (_input_session) */ + 1 + /* Command buffer (_command_buffer) */ + 1 + /* Input signal handler (_input_handler) */ + 1; /* Content-view capability */ + + if (resources.cap_quota.value < needed_caps) + throw Insufficient_cap_quota(); + /* preserve caps for content_view and command buffer ds */ + resources.cap_quota.value -= needed_caps - 2; + } + switch (role) { case ROLE_REGULAR: - { - auto session = new (_md_alloc) - Session_component(_env, _ram, _window_registry, - _md_alloc, session_label, + try { + Session_component &session = *new (_sliced_heap) + Session_component(_env, _action, resources, label, diag, + _window_registry, _pointer_tracker, _click_handler); - _sessions.insert(session); - return _env.ep().manage(*session); + _sessions.insert(&session); + return session.cap(); } + catch (Out_of_ram) { throw Insufficient_ram_quota(); } + catch (Out_of_caps) { throw Insufficient_cap_quota(); } case ROLE_DECORATOR: - { - auto session = new (_md_alloc) - Decorator_gui_session(_env, _ram, _md_alloc, + try { + Decorator_gui_session &session = *new (_sliced_heap) + Decorator_gui_session(_env, resources, label, diag, _pointer_tracker, _window_layouter_input, *this); - _decorator_sessions.insert(session); - return _env.ep().manage(*session); + _decorator_sessions.insert(&session); + return session.cap(); } + catch (Out_of_ram) { throw Insufficient_ram_quota(); } + catch (Out_of_caps) { throw Insufficient_cap_quota(); } case ROLE_LAYOUTER: { - _layouter_session = new (_md_alloc) - Layouter_gui_session(_env, _window_layouter_input_cap); + _layouter_session = new (_sliced_heap) + Layouter_gui_session(_env, resources, label, diag, + _window_layouter_input.cap()); - return _env.ep().manage(*_layouter_session); + return _layouter_session->cap(); } case ROLE_DIRECT: { - Direct_gui_session *session = new (_md_alloc) - Direct_gui_session(_env, session_label); + Direct_gui_session &session = *new (_sliced_heap) + Direct_gui_session(_env, resources, label, diag); - return _env.ep().manage(*session); + return session.cap(); } } @@ -1347,7 +1565,7 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> auto lambda = [&] (Rpc_object_base *session) { if (!session) { - Genode::warning("session lookup failed"); + warning("session lookup failed"); return; } @@ -1355,13 +1573,13 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> dynamic_cast<Session_component *>(session); if (regular_session) - regular_session->upgrade(args.string()); + regular_session->upgrade_local_or_remote(session_resources_from_args(args.string())); Decorator_gui_session *decorator_session = dynamic_cast<Decorator_gui_session *>(session); if (decorator_session) - decorator_session->upgrade(args.string()); + decorator_session->upgrade_local_or_remote(session_resources_from_args(args.string())); Direct_gui_session *direct_session = dynamic_cast<Direct_gui_session *>(session); @@ -1374,54 +1592,46 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> void close(Genode::Session_capability session_cap) override { - Genode::Rpc_entrypoint &ep = _env.ep().rpc_ep(); + Rpc_entrypoint &ep = _env.ep().rpc_ep(); Session_component *regular_session = ep.apply(session_cap, [this] (Session_component *session) { - if (session) { + if (session) _sessions.remove(session); - _env.ep().dissolve(*session); - } return session; }); if (regular_session) { - Genode::destroy(_md_alloc, regular_session); + destroy(_sliced_heap, regular_session); return; } Direct_gui_session *direct_session = ep.apply(session_cap, [this] (Direct_gui_session *session) { - if (session) { - _env.ep().dissolve(*session); - } return session; }); if (direct_session) { - Genode::destroy(_md_alloc, direct_session); + destroy(_sliced_heap, direct_session); return; } Decorator_gui_session *decorator_session = ep.apply(session_cap, [this] (Decorator_gui_session *session) { - if (session) { + if (session) _decorator_sessions.remove(session); - _env.ep().dissolve(*session); - } return session; }); if (decorator_session) { - Genode::destroy(_md_alloc, decorator_session); + destroy(_sliced_heap, decorator_session); return; } auto layouter_lambda = [this] (Layouter_gui_session *session) { - this->_env.ep().dissolve(*_layouter_session); _layouter_session = nullptr; return session; }; if (ep.apply(session_cap, layouter_lambda) == _layouter_session) { - Genode::destroy(_md_alloc, _layouter_session); + destroy(_sliced_heap, _layouter_session); return; } } @@ -1444,8 +1654,8 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> * calling 's->content_view'. */ for (Session_component *s = _sessions.first(); s; s = s->next()) - if (s->has_win_id(id.value)) - return s->content_view(id.value); + if (s->has_win_id(id)) + return s->content_view(id); return View_capability(); } @@ -1486,21 +1696,33 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session> s->content_geometry(id, rect); } - Capability<Gui::Session> lookup_gui_session(unsigned win_id) + void with_gui_session(Window_registry::Id id, auto const &fn) { for (Session_component *s = _sessions.first(); s; s = s->next()) - if (s->has_win_id(win_id)) - return s->session(); - - return { }; + if (s->has_win_id(id)) { + fn(s->session()); + return; + } } - void request_resize(unsigned win_id, Area size) + void request_resize(Window_registry::Id win_id, Area size) { for (Session_component *s = _sessions.first(); s; s = s->next()) if (s->has_win_id(win_id)) return s->request_resize(size); } + + void propagate_mode_change() + { + for (Session_component *s = _sessions.first(); s; s = s->next()) + s->propagate_mode_change(); + } + + void revoke_exclusive_input() + { + for (Session_component *s = _sessions.first(); s; s = s->next()) + s->revoke_exclusive_input(); + } }; #endif /* _GUI_H_ */ diff --git a/repos/gems/src/server/wm/layouter_gui.h b/repos/gems/src/server/wm/layouter_gui.h index 4878a56a23..4bfc231c25 100644 --- a/repos/gems/src/server/wm/layouter_gui.h +++ b/repos/gems/src/server/wm/layouter_gui.h @@ -24,11 +24,8 @@ namespace Wm { } -struct Wm::Layouter_gui_session : Genode::Rpc_object<Gui::Session> +struct Wm::Layouter_gui_session : Session_object<Gui::Session> { - using View_capability = Gui::View_capability; - using View_id = Gui::View_id; - Input::Session_capability _input_session_cap; /* @@ -36,13 +33,15 @@ struct Wm::Layouter_gui_session : Genode::Rpc_object<Gui::Session> */ Gui::Connection _mode_sigh_gui; - Genode::Signal_context_capability _mode_sigh { }; - Attached_ram_dataspace _command_ds; - Layouter_gui_session(Genode::Env &env, + Layouter_gui_session(Env &env, + Resources const &resources, + Label const &label, + Diag const &diag, Input::Session_capability input_session_cap) : + Session_object<Gui::Session>(env.ep(), resources, label, diag), _input_session_cap(input_session_cap), _mode_sigh_gui(env), _command_ds(env.ram(), env.rm(), 4096) { } @@ -62,53 +61,45 @@ struct Wm::Layouter_gui_session : Genode::Rpc_object<Gui::Session> return _input_session_cap; } - View_result view(View_id, View_attr const &) override + Info_result info() override + { + return _mode_sigh_gui.info_rom_cap(); + } + + View_result view(Gui::View_id, View_attr const &) override { return View_result::OK; } - Child_view_result child_view(View_id, View_id, View_attr const &) override + Child_view_result child_view(Gui::View_id, Gui::View_id, View_attr const &) override { return Child_view_result::OK; } - void destroy_view(View_id) override { } + void destroy_view(Gui::View_id) override { } - Associate_result associate(View_id, View_capability) override + Associate_result associate(Gui::View_id, Gui::View_capability) override { return Associate_result::OK; } - View_capability_result view_capability(View_id) override + View_capability_result view_capability(Gui::View_id) override { - return View_capability(); + return Gui::View_capability(); } - void release_view_id(View_id) override { } + void release_view_id(Gui::View_id) override { } - Genode::Dataspace_capability command_dataspace() override + Dataspace_capability command_dataspace() override { return _command_ds.cap(); } void execute() override { } - Framebuffer::Mode mode() override { return _mode_sigh_gui.mode(); } + Buffer_result buffer(Framebuffer::Mode) override { return Buffer_result::OK; } - void mode_sigh(Genode::Signal_context_capability sigh) override - { - /* - * Remember signal-context capability to keep NOVA from revoking - * transitive delegations of the capability. - */ - _mode_sigh = sigh; - - _mode_sigh_gui.mode_sigh(sigh); - } - - Buffer_result buffer(Framebuffer::Mode, bool) override { return Buffer_result::OK; } - - void focus(Genode::Capability<Gui::Session>) override { } + void focus(Capability<Gui::Session>) override { } }; #endif /* _LAYOUTER_GUI_H_ */ diff --git a/repos/gems/src/server/wm/main.cc b/repos/gems/src/server/wm/main.cc index 82d0fdbd49..02cde0a789 100644 --- a/repos/gems/src/server/wm/main.cc +++ b/repos/gems/src/server/wm/main.cc @@ -15,109 +15,101 @@ #include <gui_session/client.h> #include <framebuffer_session/client.h> #include <base/component.h> -#include <base/attached_rom_dataspace.h> -#include <base/heap.h> -#include <util/reconstructible.h> -#include <util/xml_node.h> /* local includes */ #include <gui.h> #include <report_forwarder.h> #include <rom_forwarder.h> -namespace Wm { - - class Main; - - using Genode::size_t; - using Genode::Rom_session_client; - using Genode::Rom_connection; - using Genode::Xml_node; - using Genode::Attached_rom_dataspace; -} +namespace Wm { class Main; } -struct Wm::Main : Pointer::Tracker +struct Wm::Main : Pointer::Tracker, Gui::Session_component::Action { - Genode::Env &env; + Env &_env; - Genode::Heap heap { env.ram(), env.rm() }; + Heap _heap { _env.ram(), _env.rm() }; /* currently focused window, reported by the layouter */ - Attached_rom_dataspace focus_rom { env, "focus" }; + Attached_rom_dataspace _focus_rom { _env, "focus" }; /* resize requests, issued by the layouter */ - Attached_rom_dataspace resize_request_rom { env, "resize_request" }; + Attached_rom_dataspace _resize_request_rom { _env, "resize_request" }; /* pointer position to be consumed by the layouter */ - Reporter pointer_reporter = { env, "pointer" }; + Expanding_reporter _pointer_reporter { _env, "pointer", "pointer" }; /* list of present windows, to be consumed by the layouter */ - Reporter window_list_reporter = { env, "window_list" }; + Expanding_reporter _window_list_reporter { _env, "window_list", "window_list" }; - /* request to the layouter to set the focus */ - Reporter focus_request_reporter = { env, "focus_request" }; + Window_registry _window_registry { _heap, _window_list_reporter }; - Window_registry window_registry { heap, window_list_reporter }; + Gui::Connection _focus_gui_session { _env }; - Gui::Connection focus_gui_session { env }; + Gui::Area _screen_area { }; - Gui::Root gui_root { env, window_registry, heap, env.ram(), - *this, focus_request_reporter, - focus_gui_session }; + Signal_handler<Main> _mode_handler { + _env.ep(), *this, &Main::_handle_mode }; - void handle_focus_update() + void _handle_mode() { - focus_rom.update(); - - focus_rom.xml().with_optional_sub_node("window", [&] (Xml_node const &window) { - - unsigned const win_id = window.attribute_value("id", 0u); - - if (win_id) { - try { - Gui::Session_capability session_cap = - gui_root.lookup_gui_session(win_id); - - focus_gui_session.focus(session_cap); - } catch (...) { } - } - }); + _focus_gui_session.with_info([&] (Xml_node const &info) { + _screen_area = Area::from_xml(info); }); + _gui_root.propagate_mode_change(); } - Genode::Signal_handler<Main> focus_handler = { - env.ep(), *this, &Main::handle_focus_update }; - - void handle_resize_request_update() + /** + * Gui::Session_component::Action interface + */ + void gen_screen_area_info(Xml_generator &xml) const override { - resize_request_rom.update(); - - resize_request_rom.xml().for_each_sub_node("window", [&] (Xml_node window) { - - unsigned const - win_id = window.attribute_value("id", 0U), - width = window.attribute_value("width", 0U), - height = window.attribute_value("height", 0U); - - gui_root.request_resize(win_id, Area(width, height)); - }); + xml.attribute("width", _screen_area.w); + xml.attribute("height", _screen_area.h); } - Genode::Signal_handler<Main> resize_request_handler = - { env.ep(), *this, &Main::handle_resize_request_update }; + Gui::Root _gui_root { _env, *this, _window_registry, *this, _focus_gui_session }; - Report_forwarder _report_forwarder { env, heap }; - Rom_forwarder _rom_forwarder { env, heap }; + static void _with_win_id_from_xml(Xml_node const &window, auto const &fn) + { + if (window.has_attribute("id")) + fn(Window_registry::Id { window.attribute_value("id", 0u) }); + } - Genode::Signal_handler<Main> _update_pointer_report_handler = - { env.ep(), *this, &Main::_handle_update_pointer_report }; + void _handle_focus_update() + { + _gui_root.revoke_exclusive_input(); + _focus_rom.update(); + _focus_rom.xml().with_optional_sub_node("window", [&] (Xml_node const &window) { + _with_win_id_from_xml(window, [&] (Window_registry::Id id) { + _gui_root.with_gui_session(id, [&] (Capability<Gui::Session> cap) { + _focus_gui_session.focus(cap); }); }); }); + } + + Signal_handler<Main> _focus_handler { + _env.ep(), *this, &Main::_handle_focus_update }; + + void _handle_resize_request_update() + { + _resize_request_rom.update(); + _resize_request_rom.xml().for_each_sub_node("window", [&] (Xml_node const &window) { + _with_win_id_from_xml(window, [&] (Window_registry::Id id) { + _gui_root.request_resize(id, Area::from_xml(window)); }); }); + } + + Signal_handler<Main> _resize_request_handler { + _env.ep(), *this, &Main::_handle_resize_request_update }; + + Report_forwarder _report_forwarder { _env, _heap }; + Rom_forwarder _rom_forwarder { _env, _heap }; + + Signal_handler<Main> _update_pointer_report_handler { + _env.ep(), *this, &Main::_handle_update_pointer_report }; void _handle_update_pointer_report() { - Pointer::Position pos = gui_root.last_observed_pointer_pos(); + Pointer::Position const pos = _gui_root.last_observed_pointer_pos(); - Reporter::Xml_generator xml(pointer_reporter, [&] () - { + _pointer_reporter.generate([&] (Xml_generator &xml) { if (pos.valid) { xml.attribute("xpos", pos.value.x); xml.attribute("ypos", pos.value.y); @@ -140,28 +132,17 @@ struct Wm::Main : Pointer::Tracker _update_pointer_report_handler.local_submit(); } - Main(Genode::Env &env) : env(env) + Main(Env &env) : _env(env) { - pointer_reporter.enabled(true); - /* initially report an empty window list */ - window_list_reporter.enabled(true); - Genode::Reporter::Xml_generator xml(window_list_reporter, [&] () { }); + _window_list_reporter.generate([&] (Xml_generator &) { }); - focus_request_reporter.enabled(true); - - focus_rom.sigh(focus_handler); - resize_request_rom.sigh(resize_request_handler); + _focus_rom.sigh(_focus_handler); + _resize_request_rom.sigh(_resize_request_handler); + _focus_gui_session.info_sigh(_mode_handler); + _handle_mode(); } }; -/*************** - ** Component ** - ***************/ - -Genode::size_t Component::stack_size() { - return 16*1024*sizeof(long); } - -void Component::construct(Genode::Env &env) { - static Wm::Main desktop(env); } +void Component::construct(Genode::Env &env) { static Wm::Main desktop(env); } diff --git a/repos/gems/src/server/wm/pointer.h b/repos/gems/src/server/wm/pointer.h index fbff2b7b12..25a5c9efbc 100644 --- a/repos/gems/src/server/wm/pointer.h +++ b/repos/gems/src/server/wm/pointer.h @@ -14,7 +14,8 @@ #ifndef _POINTER_H_ #define _POINTER_H_ -#include <util/noncopyable.h> +/* local includes */ +#include <types.h> namespace Wm { struct Pointer; } @@ -28,13 +29,13 @@ struct Wm::Pointer }; - struct Tracker : Genode::Interface, Genode::Noncopyable + struct Tracker : Interface, Noncopyable { virtual void update_pointer_report() = 0; }; - class State : Genode::Noncopyable + class State : Noncopyable { private: diff --git a/repos/gems/src/server/wm/real_gui.h b/repos/gems/src/server/wm/real_gui.h index f41af24b0e..ec9643af50 100644 --- a/repos/gems/src/server/wm/real_gui.h +++ b/repos/gems/src/server/wm/real_gui.h @@ -17,7 +17,6 @@ /* Genode includes */ #include <base/connection.h> #include <base/attached_dataspace.h> -#include <gui_session/client.h> namespace Wm { struct Real_gui; } @@ -26,29 +25,31 @@ struct Wm::Real_gui { private: - Genode::Env &_env; + Env &_env; public: - Genode::Session_label const &label; + Session_label const &label; using Command_buffer = Gui::Session::Command_buffer; + static constexpr size_t RAM_QUOTA = 36*1024; + public: - Real_gui(Genode::Env &env, Genode::Session_label const &label) + Real_gui(Env &env, Session_label const &label) : _env(env), label(label) { } - Genode::Connection<Gui::Session> connection { - _env, label, Genode::Ram_quota { 36*1024 }, /* Args */ { } }; + Connection<Gui::Session> connection { + _env, label, Genode::Ram_quota { RAM_QUOTA }, /* Args */ { } }; Gui::Session_client session { connection.cap() }; private: - Genode::Attached_dataspace _command_ds { _env.rm(), session.command_dataspace() }; + Attached_dataspace _command_ds { _env.rm(), session.command_dataspace() }; Command_buffer &_command_buffer { *_command_ds.local_addr<Command_buffer>() }; diff --git a/repos/gems/src/server/wm/report_forwarder.h b/repos/gems/src/server/wm/report_forwarder.h index ddf90d1471..796b731653 100644 --- a/repos/gems/src/server/wm/report_forwarder.h +++ b/repos/gems/src/server/wm/report_forwarder.h @@ -32,19 +32,17 @@ namespace Wm { struct Report_forwarder; } struct Wm::Report_forwarder { - struct Session : Genode::Rpc_object<Report::Session> + struct Session : Session_object<Report::Session> { - Genode::Env &_env; Report::Connection _connection; - Session(Genode::Env &env, Genode::Session_label const &label, - size_t buffer_size) - : _env(env), _connection(env, label.string(), buffer_size) - { _env.ep().manage(*this); } + Session(Env &env, size_t buffer_size, auto &&... args) + : + Session_object<Report::Session>(env.ep(), args...), + _connection(env, label(), buffer_size) + { } - ~Session() { _env.ep().dissolve(*this); } - - void upgrade(Genode::Session::Resources const &resources) + void upgrade(Session::Resources const &resources) { _connection.upgrade(resources); } @@ -54,47 +52,49 @@ struct Wm::Report_forwarder ** Report::Session interface ** *******************************/ - Genode::Dataspace_capability dataspace() override + Dataspace_capability dataspace() override { return _connection.dataspace(); } - void submit(Genode::size_t length) override + void submit(size_t length) override { _connection.submit(length); } - void response_sigh(Genode::Signal_context_capability sigh) override + void response_sigh(Signal_context_capability sigh) override { _connection.response_sigh(sigh); } - Genode::size_t obtain_response() override + size_t obtain_response() override { return _connection.obtain_response(); } }; - struct Root : Genode::Root_component<Session> + struct Root : Root_component<Session> { - Genode::Env &_env; - Genode::Allocator &_alloc; + Env &_env; + Allocator &_alloc; Session *_create_session(char const *args) override { return new (md_alloc()) - Session(_env, Genode::label_from_args(args), - Arg_string::find_arg(args, "buffer_size").ulong_value(0)); + Session(_env, Arg_string::find_arg(args, "buffer_size").ulong_value(0), + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args)); } void _upgrade_session(Session *session, const char *args) override { - session->upgrade(Genode::session_resources_from_args(args)); + session->upgrade(session_resources_from_args(args)); } - Root(Genode::Env &env, Genode::Allocator &alloc) + Root(Env &env, Allocator &alloc) : - Genode::Root_component<Session>(env.ep(), alloc), + Root_component<Session>(env.ep(), alloc), _env(env), _alloc(alloc) { _env.parent().announce(env.ep().manage(*this)); @@ -102,8 +102,7 @@ struct Wm::Report_forwarder } _root; - Report_forwarder(Genode::Env &env, Genode::Allocator &alloc) - : _root(env, alloc) { } + Report_forwarder(Env &env, Allocator &alloc) : _root(env, alloc) { } }; #endif /* _REPORT_FORWARDER_H_ */ diff --git a/repos/gems/src/server/wm/rom_forwarder.h b/repos/gems/src/server/wm/rom_forwarder.h index b73c7d8513..783dd3698f 100644 --- a/repos/gems/src/server/wm/rom_forwarder.h +++ b/repos/gems/src/server/wm/rom_forwarder.h @@ -27,18 +27,17 @@ namespace Wm { struct Rom_forwarder; } struct Wm::Rom_forwarder { - struct Session : Genode::Rpc_object<Genode::Rom_session> + struct Session : Session_object<Rom_session> { - Genode::Env &_env; - Genode::Rom_connection _connection; + Rom_connection _connection; - Session(Genode::Env &env, Genode::Session_label const &label) - : _env(env), _connection(env, label.string()) - { _env.ep().manage(*this); } + Session(Env &env, auto &&... args) + : + Session_object<Rom_session>(env.ep(), args...), + _connection(env, label()) + { } - ~Session() { _env.ep().dissolve(*this); } - - void upgrade(Genode::Session::Resources const &resources) + void upgrade(Session::Resources const &resources) { _connection.upgrade(resources); } @@ -48,7 +47,7 @@ struct Wm::Rom_forwarder ** Rom_session interface ** ***************************/ - Genode::Rom_dataspace_capability dataspace() override + Rom_dataspace_capability dataspace() override { return _connection.dataspace(); } @@ -64,24 +63,26 @@ struct Wm::Rom_forwarder } }; - struct Root : Genode::Root_component<Session> + struct Root : Root_component<Session> { - Genode::Env &_env; - Genode::Allocator &_alloc; + Env &_env; + Allocator &_alloc; Session *_create_session(char const *args) override { - return new (md_alloc()) Session(_env, Genode::label_from_args(args)); + return new (md_alloc()) Session(_env, session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args)); } void _upgrade_session(Session *session, const char *args) override { - session->upgrade(Genode::session_resources_from_args(args)); + session->upgrade(session_resources_from_args(args)); } - Root(Genode::Env &env, Genode::Allocator &alloc) + Root(Env &env, Allocator &alloc) : - Genode::Root_component<Session>(env.ep(), alloc), + Root_component<Session>(env.ep(), alloc), _env(env), _alloc(alloc) { _env.parent().announce(env.ep().manage(*this)); @@ -89,8 +90,7 @@ struct Wm::Rom_forwarder } _root; - Rom_forwarder(Genode::Env &env, Genode::Allocator &alloc) - : _root(env, alloc) { } + Rom_forwarder(Env &env, Allocator &alloc) : _root(env, alloc) { } }; #endif /* _ROM_FORWARDER_H_ */ diff --git a/repos/gems/src/server/wm/types.h b/repos/gems/src/server/wm/types.h new file mode 100644 index 0000000000..4274a972d1 --- /dev/null +++ b/repos/gems/src/server/wm/types.h @@ -0,0 +1,78 @@ +/* + * \brief Common types used within the window manager + * \author Norman Feske + * \date 2024-09-04 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +/* Genode includes */ +#include <util/reconstructible.h> +#include <util/list.h> +#include <base/tslab.h> +#include <base/attached_rom_dataspace.h> +#include <base/attached_ram_dataspace.h> +#include <base/heap.h> +#include <base/session_object.h> +#include <os/surface.h> +#include <os/reporter.h> +#include <os/session_policy.h> +#include <gui_session/gui_session.h> + +namespace Wm { + + using namespace Genode; + + using Area = Surface_base::Area; + using Point = Surface_base::Point; + using Rect = Surface_base::Rect; + + /* + * Slab allocator that includes an initial block as member + */ + template <size_t BLOCK_SIZE> + struct Initial_slab_block { uint8_t buf[BLOCK_SIZE]; }; + template <typename T, size_t BLOCK_SIZE> + struct Slab : private Initial_slab_block<BLOCK_SIZE>, Tslab<T, BLOCK_SIZE> + { + Slab(Allocator &block_alloc) + : Tslab<T, BLOCK_SIZE>(block_alloc, Initial_slab_block<BLOCK_SIZE>::buf) { }; + }; + + struct Upgradeable : Noncopyable + { + bool _starved_for_ram = false, _starved_for_caps = false; + + void _upgrade_local_or_remote(auto const &resources, auto &session_obj, auto &real_gui) + { + Ram_quota ram = resources.ram_quota; + Cap_quota caps = resources.cap_quota; + + if (_starved_for_caps && caps.value) { + session_obj.upgrade(caps); + _starved_for_caps = false; + caps = { }; + } + + if (_starved_for_ram && ram.value) { + session_obj.upgrade(ram); + _starved_for_ram = false; + ram = { }; + } + + if (ram.value || caps.value) { + real_gui.connection.upgrade({ ram, caps }); + } + } + }; +} + +#endif /* _TYPES_H_ */ diff --git a/repos/gems/src/server/wm/window_registry.h b/repos/gems/src/server/wm/window_registry.h index 3f62bd27c0..2b734d29be 100644 --- a/repos/gems/src/server/wm/window_registry.h +++ b/repos/gems/src/server/wm/window_registry.h @@ -16,102 +16,89 @@ /* Genode includes */ #include <util/bit_allocator.h> -#include <util/list.h> -#include <base/allocator.h> -#include <os/surface.h> -#include <os/reporter.h> -#include <os/session_policy.h> +#include <base/id_space.h> /* gems includes */ #include <gems/local_reporter.h> +/* local includes */ +#include <types.h> + namespace Wm { class Window_registry; } -namespace Wm { - using Genode::Allocator; - using Genode::List; - using Genode::Xml_generator; - using Genode::Reporter; - - using Area = Genode::Surface_base::Area; - using Point = Genode::Surface_base::Point; - using Rect = Genode::Surface_base::Rect; -} - - class Wm::Window_registry { public: - struct Id - { - unsigned value; + class Window; - Id(unsigned value) : value(value) { } + using Windows = Id_space<Window>; + using Id = Windows::Id; - Id() /* invalid */ : value(0) { } + struct Alpha { bool value; }; + struct Hidden { bool value; }; + struct Resizeable { bool value; }; - bool operator == (Id const &other) const { return value == other.value; } - - bool valid() const { return value != 0; } - }; - - class Window : public List<Window>::Element + class Window : Noncopyable { public: - using Title = Gui::Title; - using Session_label = Genode::Session_label; - - enum Has_alpha { HAS_ALPHA, HAS_NO_ALPHA }; - - enum Hidden { HIDDEN, NOT_HIDDEN }; - - enum Resizeable { RESIZEABLE, NOT_RESIZEABLE }; - - private: - - Id const _id; - struct Attr { - Title title { }; - Session_label label { }; - Area size { }; - Has_alpha has_alpha = HAS_NO_ALPHA; - Hidden hidden = NOT_HIDDEN; - Resizeable resizeable = NOT_RESIZEABLE; + Gui::Title title; + Session_label label; + Area area; + Alpha alpha; + Hidden hidden; + Resizeable resizeable; bool operator == (Attr const &other) const { - return title == other.title - && label == other.label - && size == other.size - && has_alpha == other.has_alpha - && hidden == other.hidden - && resizeable == other.resizeable; + return title == other.title + && label == other.label + && area == other.area + && alpha.value == other.alpha.value + && hidden.value == other.hidden.value + && resizeable.value == other.resizeable.value; + } + + void gen_window_attr(Xml_generator &xml) const + { + xml.attribute("label", label); + xml.attribute("title", title); + xml.attribute("width", area.w); + xml.attribute("height", area.h); + + if (alpha.value) xml.attribute("has_alpha", "yes"); + if (hidden.value) xml.attribute("hidden", "yes"); + if (resizeable.value) xml.attribute("resizeable", "yes"); } }; - Attr _attr { }; + private: + + Windows::Element _id; + + Attr _attr; Attr mutable _flushed_attr { }; friend class Window_registry; - Window(Id id) : _id(id) { } + Window(Windows &windows, Id id, Attr const &attr) + : _id(*this, windows, id), _attr(attr) { } public: - Id id() const { return _id; } + Id id() const { return _id.id(); } /* * Accessors for setting attributes */ - void attr(Title const &title) { _attr.title = title; } + void attr(Gui::Title const &title) { _attr.title = title; } void attr(Session_label const &label) { _attr.label = label; } - void attr(Area size) { _attr.size = size; } - void attr(Has_alpha has_alpha) { _attr.has_alpha = has_alpha; } + void attr(Area area) { _attr.area = area; } + void attr(Alpha alpha) { _attr.alpha = alpha; } void attr(Hidden hidden) { _attr.hidden = hidden; } void attr(Resizeable resizeable) { _attr.resizeable = resizeable; } @@ -120,28 +107,17 @@ class Wm::Window_registry void generate_window_list_entry_xml(Xml_generator &xml) const { /* - * Skip windows that have no defined size, which happens - * between the creation of a new window and the first - * time when the window's properties are assigned. + * Skip windows that have no defined size, which may happen + * between the creation of a new window for a view w/o size + * and the first time when the top-level view's size is + * assigned. */ - if (!_attr.size.valid()) + if (!_attr.area.valid()) return; xml.node("window", [&] () { - xml.attribute("id", _id.value); - xml.attribute("label", _attr.label.string()); - xml.attribute("title", _attr.title.string()); - xml.attribute("width", _attr.size.w); - xml.attribute("height", _attr.size.h); - - if (_attr.has_alpha == HAS_ALPHA) - xml.attribute("has_alpha", "yes"); - - if (_attr.hidden == HIDDEN) - xml.attribute("hidden", "yes"); - - if (_attr.resizeable == RESIZEABLE) - xml.attribute("resizeable", "yes"); + xml.attribute("id", id().value); + _attr.gen_window_attr(xml); }); } @@ -151,61 +127,49 @@ class Wm::Window_registry bool _flushed() const { bool result = true; - for (Window const *w = _windows.first(); w; w = w->next()) - result &= w->flushed(); - + _windows.for_each<Window const>([&] (Window const &w) { + result &= w.flushed(); }); return result; } private: - Allocator &_alloc; - Reporter &_window_list_reporter; + Allocator &_alloc; + Expanding_reporter &_window_list_reporter; static constexpr unsigned MAX_WINDOWS = 1024; - Genode::Bit_allocator<MAX_WINDOWS> _window_ids { }; + Bit_allocator<MAX_WINDOWS> _window_ids { }; unsigned _next_id = 0; /* used to alloc subsequent numbers */ - List<Window> _windows { }; + Windows _windows { }; - Window *_lookup(Id id) + void _with_window(Id id, auto const &fn, auto const &missing_fn) { - for (Window *w = _windows.first(); w; w = w->next()) - if (w->id() == id) - return w; - - return 0; + _windows.apply<Window>(id, fn, missing_fn); } void _report_updated_window_list_model() const { - Reporter::Xml_generator xml(_window_list_reporter, [&] () - { - for (Window const *w = _windows.first(); w; w = w->next()) { - w->generate_window_list_entry_xml(xml); - w->mark_as_flushed(); - } + _window_list_reporter.generate([&] (Xml_generator &xml) { + _windows.for_each<Window>([&] (Window const &w) { + w.generate_window_list_entry_xml(xml); + w.mark_as_flushed(); + }); }); } - template <typename ATTR> - void _set_attr(Id const id, ATTR const &value) + void _set_attr(Id const id, auto const &value) { - Window * const win = _lookup(id); - - if (!win) { - Genode::warning("lookup for window ID ", id.value, " failed"); - return; - } - - win->attr(value); + _with_window(id, + [&] (Window &window) { window.attr(value); }, + [&] { warning("lookup for window ID ", id.value, " failed"); }); } public: - Window_registry(Allocator &alloc, Reporter &window_list_reporter) + Window_registry(Allocator &alloc, Expanding_reporter &window_list_reporter) : _alloc(alloc), _window_list_reporter(window_list_reporter) { @@ -213,72 +177,60 @@ class Wm::Window_registry _window_ids.alloc(); } - Id create() + enum class Create_error { IDS_EXHAUSTED }; + using Create_result = Attempt<Id, Create_error>; + + Create_result create(Window::Attr const &attr) { - auto alloc_id = [&] + auto alloc_id = [&] () -> Create_result { - for (;;) { + for (unsigned i = 0; i < MAX_WINDOWS; i++) { unsigned try_id = _next_id; _next_id = (_next_id + 1) % MAX_WINDOWS; try { _window_ids.alloc_addr(try_id); - return try_id; + return Id { try_id }; } catch (...) { } } + return Create_error::IDS_EXHAUSTED; }; - Window * const win = new (_alloc) Window(alloc_id()); + Create_result const result = alloc_id(); - _windows.insert(win); + result.with_result( + [&] (Id id) { + new (_alloc) Window(_windows, id, attr); + _report_updated_window_list_model(); + }, + [&] (Create_error) { } + ); - /* - * Even though we change the window-list model by adding a - * window, we don't call '_report_updated_window_list_model' here - * because the window does not have any useful properties before - * the 'size' function has been called. - * - * XXX should we pass the initial size as argument to this function? - */ - - return win->id(); + return result; } void destroy(Id id) { - Window * const win = _lookup(id); - if (!win) + Window *win_ptr = nullptr; + _with_window(id, [&] (Window &window) { win_ptr = &window; }, [&] { }); + + if (!win_ptr) return; - _windows.remove(win); + _window_ids.free(win_ptr->id().value); - _window_ids.free(win->id().value); - - Genode::destroy(&_alloc, win); + Genode::destroy(&_alloc, win_ptr); _report_updated_window_list_model(); } - void size(Id id, Area size) { _set_attr(id, size); } + void area (Id id, Area const area) { _set_attr(id, area); } + void title(Id id, Gui::Title const &title) { _set_attr(id, title); } + void label(Id id, Session_label const &label) { _set_attr(id, label); } - void title(Id id, Window::Title const &title) { _set_attr(id, title); } - - void label(Id id, Window::Session_label const &label) { _set_attr(id, label); } - - void has_alpha(Id id, bool has_alpha) - { - _set_attr(id, has_alpha ? Window::HAS_ALPHA : Window::HAS_NO_ALPHA); - } - - void hidden(Id id, bool hidden) - { - _set_attr(id, hidden ? Window::HIDDEN : Window::NOT_HIDDEN); - } - - void resizeable(Id id, bool resizeable) - { - _set_attr(id, resizeable ? Window::RESIZEABLE : Window::NOT_RESIZEABLE); - } + void alpha (Id id, bool value) { _set_attr(id, Alpha { value }); } + void hidden (Id id, bool value) { _set_attr(id, Hidden { value }); } + void resizeable(Id id, bool value) { _set_attr(id, Resizeable { value }); } void flush() { diff --git a/repos/gems/src/test/text_painter/main.cc b/repos/gems/src/test/text_painter/main.cc index 6ad5a28685..fd0455ef5c 100644 --- a/repos/gems/src/test/text_painter/main.cc +++ b/repos/gems/src/test/text_painter/main.cc @@ -80,7 +80,7 @@ struct Test::Main Vfs_font _font_4 { _heap, _root, "fonts/regular" }; - void _refresh() { _fb.refresh(0, 0, _size.w, _size.h); } + void _refresh() { _fb.refresh({ { 0, 0 }, _size }); } Main(Env &env) : _env(env) { diff --git a/repos/gems/src/test/tiled_wm/app/app.pro b/repos/gems/src/test/tiled_wm/app/app.pro index 0953a7bf26..c3c3b64c40 100644 --- a/repos/gems/src/test/tiled_wm/app/app.pro +++ b/repos/gems/src/test/tiled_wm/app/app.pro @@ -5,3 +5,5 @@ CONFIG += c++2a SOURCES += main.cpp app.cpp HEADERS += app.h ../util.h RESOURCES = app.qrc + +INCLUDEPATH = .. diff --git a/repos/gems/src/test/tiled_wm/overlay/overlay.pro b/repos/gems/src/test/tiled_wm/overlay/overlay.pro index 5f06b5e8ea..a743fe6927 100644 --- a/repos/gems/src/test/tiled_wm/overlay/overlay.pro +++ b/repos/gems/src/test/tiled_wm/overlay/overlay.pro @@ -5,3 +5,5 @@ CONFIG += c++2a SOURCES += main.cpp overlay.cpp HEADERS += overlay.h ../util.h RESOURCES = overlay.qrc + +INCLUDEPATH = .. diff --git a/repos/gems/src/test/tiled_wm/panel/panel.pro b/repos/gems/src/test/tiled_wm/panel/panel.pro index 40b1fe3d5a..a803db8416 100644 --- a/repos/gems/src/test/tiled_wm/panel/panel.pro +++ b/repos/gems/src/test/tiled_wm/panel/panel.pro @@ -5,3 +5,5 @@ CONFIG += c++2a SOURCES += main.cpp panel.cpp HEADERS += panel.h icon.h ../util.h RESOURCES = panel.qrc + +INCLUDEPATH = .. diff --git a/repos/gems/src/test/tiled_wm/target.inc b/repos/gems/src/test/tiled_wm/target.inc index 258fdcad73..de6ed49956 100644 --- a/repos/gems/src/test/tiled_wm/target.inc +++ b/repos/gems/src/test/tiled_wm/target.inc @@ -8,8 +8,6 @@ QT5_GENODE_LIBS_APP += ld.lib.so qmake_prepared.tag: $(addprefix build_dependencies/lib/,$(QT5_GENODE_LIBS_APP)) -INC_DIR += $(PRG_DIR)/.. - # # We need Qt headers in a local directory for MOC to work correctly # diff --git a/repos/libports/lib/import/import-qt5_cmake.mk b/repos/libports/lib/import/import-qt5_cmake.mk index 18984a9e8a..66e279b01f 100644 --- a/repos/libports/lib/import/import-qt5_cmake.mk +++ b/repos/libports/lib/import/import-qt5_cmake.mk @@ -23,7 +23,7 @@ GENODE_CMAKE_CFLAGS += \ $(CC_OPT_NOSTDINC) \ $(CC_MARCH) \ $(CC_OPT_PIC) \ - $(filter-out -I.,$(INCLUDES)) \ + $(filter-out -I. $(foreach i,$(INCLUDES),$(if $(findstring /base-$(KERNEL)/include,$(i)),$(i))),$(INCLUDES)) \ -I$(CURDIR)/build_dependencies/include/QtCore/spec/$(QT_PLATFORM) GENODE_CMAKE_LFLAGS_APP += \ diff --git a/repos/libports/lib/import/import-qt5_qmake.mk b/repos/libports/lib/import/import-qt5_qmake.mk index fb1d6c485a..49732bd3e5 100644 --- a/repos/libports/lib/import/import-qt5_qmake.mk +++ b/repos/libports/lib/import/import-qt5_qmake.mk @@ -25,7 +25,7 @@ GENODE_QMAKE_CFLAGS += \ $(CC_OPT_NOSTDINC) \ $(CC_MARCH) \ $(CC_OPT_PIC) \ - $(filter-out -I.,$(INCLUDES)) \ + $(filter-out -I. $(foreach i,$(INCLUDES),$(if $(findstring /base-$(KERNEL)/include,$(i)),$(i))),$(INCLUDES)) \ -I$(CURDIR)/build_dependencies/include/QtCore/spec/$(QT_PLATFORM) GENODE_QMAKE_LFLAGS_APP += \ diff --git a/repos/libports/lib/import/import-qt6_cmake.mk b/repos/libports/lib/import/import-qt6_cmake.mk index e9ef66d25b..0b1f35bdae 100644 --- a/repos/libports/lib/import/import-qt6_cmake.mk +++ b/repos/libports/lib/import/import-qt6_cmake.mk @@ -23,7 +23,7 @@ GENODE_CMAKE_CFLAGS += \ $(CC_OPT_NOSTDINC) \ $(CC_MARCH) \ $(CC_OPT_PIC) \ - $(filter-out -I.,$(INCLUDES)) \ + $(filter-out -I. $(foreach i,$(INCLUDES),$(if $(findstring /base-$(KERNEL)/include,$(i)),$(i))),$(INCLUDES)) \ -I$(CURDIR)/build_dependencies/mkspecs/$(QT_PLATFORM) GENODE_CMAKE_LFLAGS_APP += \ diff --git a/repos/libports/lib/import/import-qt6_qmake.mk b/repos/libports/lib/import/import-qt6_qmake.mk index 5b4e340444..0c100e9312 100644 --- a/repos/libports/lib/import/import-qt6_qmake.mk +++ b/repos/libports/lib/import/import-qt6_qmake.mk @@ -25,7 +25,7 @@ GENODE_QMAKE_CFLAGS += \ $(CC_OPT_NOSTDINC) \ $(CC_MARCH) \ $(CC_OPT_PIC) \ - $(filter-out -I.,$(INCLUDES)) \ + $(filter-out -I. $(foreach i,$(INCLUDES),$(if $(findstring /base-$(KERNEL)/include,$(i)),$(i))),$(INCLUDES)) \ -I$(CURDIR)/build_dependencies/include/QtCore/spec/$(QT_PLATFORM) GENODE_QMAKE_LFLAGS_APP += \ diff --git a/repos/libports/lib/mk/libc.mk b/repos/libports/lib/mk/libc.mk index e491954a97..efa6a790a8 100644 --- a/repos/libports/lib/mk/libc.mk +++ b/repos/libports/lib/mk/libc.mk @@ -12,14 +12,14 @@ LIBS += base vfs # Back end # SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc \ - issetugid.cc errno.cc gai_strerror.cc time.cc \ + issetugid.cc errno.cc gai_strerror.cc time.cc alarm.cc \ malloc.cc progname.cc fd_alloc.cc file_operations.cc \ plugin.cc plugin_registry.cc select.cc exit.cc environ.cc sleep.cc \ pread_pwrite.cc readv_writev.cc poll.cc \ vfs_plugin.cc dynamic_linker.cc signal.cc \ socket_operations.cc socket_fs_plugin.cc syscall.cc \ getpwent.cc getrandom.cc fork.cc execve.cc kernel.cc component.cc \ - genode.cc spinlock.cc + genode.cc spinlock.cc kqueue.cc # # Pthreads diff --git a/repos/libports/lib/mk/mesa.inc b/repos/libports/lib/mk/mesa.inc index 33211dcad7..fa9451eeaa 100644 --- a/repos/libports/lib/mk/mesa.inc +++ b/repos/libports/lib/mk/mesa.inc @@ -691,6 +691,7 @@ SRC_C += c11/impl/threads_posix.c \ util/format/u_format_other.c \ util/format/u_format_rgtc.c \ util/format/u_format_s3tc.c \ + util/format/u_format_unpack_neon.c \ util/format/u_format_yuv.c \ util/format/u_format_zs.c \ util/half_float.c \ diff --git a/repos/libports/lib/symbols/libc b/repos/libports/lib/symbols/libc index 445452a50d..0bde0b6ea0 100644 --- a/repos/libports/lib/symbols/libc +++ b/repos/libports/lib/symbols/libc @@ -5,6 +5,7 @@ # # libc # +_Exit T ___mb_cur_max D 50 ___runetype T ___tolower T @@ -39,7 +40,6 @@ __stdoutp D 8 __swbuf T __test_sse T __xuname T -_Exit T _exit T _getlong T _getshort T @@ -412,8 +412,10 @@ iswupper T iswxdigit T isxdigit T jrand48 T +kevent T kill W killpg T +kqueue T ksem_init T l64a T l64a_r T @@ -500,8 +502,8 @@ posix_fadvise T posix_madvise T posix_memalign T posix_spawn T -posix_spawn_file_actions_addclose T posix_spawn_file_actions_addchdir_np T +posix_spawn_file_actions_addclose T posix_spawn_file_actions_adddup2 T posix_spawn_file_actions_addopen T posix_spawn_file_actions_destroy T diff --git a/repos/libports/ports/mesa.hash b/repos/libports/ports/mesa.hash index 19666da459..c80c193080 100644 --- a/repos/libports/ports/mesa.hash +++ b/repos/libports/ports/mesa.hash @@ -1 +1 @@ -3aef4a625536591a08a8579caec868abe0115106 +9b5223fd7e5948d6c6e2dc2ad16605f3d539a27a diff --git a/repos/libports/ports/qt5.hash b/repos/libports/ports/qt5.hash index d345afade6..c1bc22cd7a 100644 --- a/repos/libports/ports/qt5.hash +++ b/repos/libports/ports/qt5.hash @@ -1 +1 @@ -e23cb2bb7b48d139b8ada3f2f9fec60637212f38 +0f70c667591b15b2bc5b89a2ce227fbf1a26896f diff --git a/repos/libports/ports/qt5.port b/repos/libports/ports/qt5.port index 5e9b55374a..69842b785b 100644 --- a/repos/libports/ports/qt5.port +++ b/repos/libports/ports/qt5.port @@ -4,5 +4,5 @@ VERSION := 5.15.2 DOWNLOADS := qt5.git URL(qt5) := https://github.com/cproc/qt5.git -REV(qt5) := issue5242 +REV(qt5) := issue5372 DIR(qt5) := src/lib/qt5 diff --git a/repos/libports/ports/qt6-host.hash b/repos/libports/ports/qt6-host.hash index 6010c9fc10..c186fb474c 100644 --- a/repos/libports/ports/qt6-host.hash +++ b/repos/libports/ports/qt6-host.hash @@ -1 +1 @@ -65bfe06368aa913897c75ac819acb9d1efdf367f +1a0072de9fae10738f0d32d367ffff063e6cdc7b diff --git a/repos/libports/ports/qt6-host.port b/repos/libports/ports/qt6-host.port index 107b9edb78..b79721f5f8 100644 --- a/repos/libports/ports/qt6-host.port +++ b/repos/libports/ports/qt6-host.port @@ -3,6 +3,6 @@ VERSION := 6.6.2 DOWNLOADS := qt6.archive -URL(qt6) := https://download.qt.io/official_releases/qt/6.6/6.6.2/single/qt-everywhere-src-6.6.2.tar.xz +URL(qt6) := https://download.qt.io/archive/qt/6.6/6.6.2/single/qt-everywhere-src-6.6.2.tar.xz SHA(qt6) := 3c1e42b3073ade1f7adbf06863c01e2c59521b7cc2349df2f74ecd7ebfcb922d DIR(qt6) := src/lib/qt6 diff --git a/repos/libports/ports/qt6.hash b/repos/libports/ports/qt6.hash index b19de305d9..3d15ae44d4 100644 --- a/repos/libports/ports/qt6.hash +++ b/repos/libports/ports/qt6.hash @@ -1 +1 @@ -22e90c4bc425795166ebec55fd1853311862bc99 +80566257f49fe4c8a44fd699b544e0b4e38fe38a diff --git a/repos/libports/ports/qt6.port b/repos/libports/ports/qt6.port index a4f5229ba8..7b11fd05f8 100644 --- a/repos/libports/ports/qt6.port +++ b/repos/libports/ports/qt6.port @@ -4,5 +4,5 @@ VERSION := 6.6.2 DOWNLOADS := qt6.git URL(qt6) := https://github.com/cproc/qt6.git -REV(qt6) := issue5325 +REV(qt6) := issue5372 DIR(qt6) := src/lib/qt6 diff --git a/repos/libports/recipes/api/libc/hash b/repos/libports/recipes/api/libc/hash index daa176ea06..3e711ee8ba 100644 --- a/repos/libports/recipes/api/libc/hash +++ b/repos/libports/recipes/api/libc/hash @@ -1 +1 @@ -2024-08-28 9379c5dffb979872b30bd0eb4b1c25f8d48aa2c1 +2024-10-07 a6e2ece598616bef586df2a764ec3eb3f04e9912 diff --git a/repos/libports/recipes/api/qt5_base/hash b/repos/libports/recipes/api/qt5_base/hash index 98caf4b75b..94bd77b744 100644 --- a/repos/libports/recipes/api/qt5_base/hash +++ b/repos/libports/recipes/api/qt5_base/hash @@ -1 +1 @@ -2024-08-28 8102f6383f9a553220ca2517b91e503f61504a0d +2024-10-08 7995b0bc72b98634581a2fdf01fa8b7ef45c8f68 diff --git a/repos/libports/recipes/api/qt6_base/hash b/repos/libports/recipes/api/qt6_base/hash index 271db52a32..b5cd7493fc 100644 --- a/repos/libports/recipes/api/qt6_base/hash +++ b/repos/libports/recipes/api/qt6_base/hash @@ -1 +1 @@ -2024-08-28 35586b2d126274d93cd9ba9c5fdc562ba839e2f0 +2024-10-08 b3fc4960265c42de87bc1c770046fb7f3b9f071d diff --git a/repos/libports/recipes/pkg/acpica/hash b/repos/libports/recipes/pkg/acpica/hash index 459cdd4e9c..3098b5e4a4 100644 --- a/repos/libports/recipes/pkg/acpica/hash +++ b/repos/libports/recipes/pkg/acpica/hash @@ -1 +1 @@ -2024-08-28 1ee2d143d5c06464cd106807bca73882397b24ba +2024-10-07 8375000b5531e0e9a73d31175a00b926c9168ece diff --git a/repos/libports/recipes/pkg/gcov/hash b/repos/libports/recipes/pkg/gcov/hash index 8a44bd427d..d3d0a0f088 100644 --- a/repos/libports/recipes/pkg/gcov/hash +++ b/repos/libports/recipes/pkg/gcov/hash @@ -1 +1 @@ -2024-08-28 5cdec0dd8c3a3516d907b10646388d67598b6150 +2024-10-29 2d739053a4eee45449bc7854a282d17ed57de897 diff --git a/repos/libports/recipes/pkg/mesa_gears/hash b/repos/libports/recipes/pkg/mesa_gears/hash index 00c2722926..ff46091f1b 100644 --- a/repos/libports/recipes/pkg/mesa_gears/hash +++ b/repos/libports/recipes/pkg/mesa_gears/hash @@ -1 +1 @@ -2024-08-28 3510c564a279f4c4d1b8fb0916e36404fcb0b197 +2024-11-04 4983b0da01327998cc0d70573e3a67e43f5a3838 diff --git a/repos/libports/recipes/pkg/mesa_gears/runtime b/repos/libports/recipes/pkg/mesa_gears/runtime index 10ad36f9e2..a75fad3dd5 100644 --- a/repos/libports/recipes/pkg/mesa_gears/runtime +++ b/repos/libports/recipes/pkg/mesa_gears/runtime @@ -1,4 +1,4 @@ -<runtime ram="40M" caps="400" binary="gears"> +<runtime ram="52M" caps="400" binary="gears"> <requires> <gui/> diff --git a/repos/libports/recipes/pkg/mesa_gpu-cpu/hash b/repos/libports/recipes/pkg/mesa_gpu-cpu/hash index 9eb3f338c1..e63a4094a2 100644 --- a/repos/libports/recipes/pkg/mesa_gpu-cpu/hash +++ b/repos/libports/recipes/pkg/mesa_gpu-cpu/hash @@ -1 +1 @@ -2024-08-28 e7434626ac0bc82f9a84912c0547517825509065 +2024-10-29 7f27d4a339459e3dbb25239c6d1dff2fcaf48a9d diff --git a/repos/libports/recipes/pkg/mesa_gpu-etnaviv/hash b/repos/libports/recipes/pkg/mesa_gpu-etnaviv/hash index 57bf54be50..412e5e5302 100644 --- a/repos/libports/recipes/pkg/mesa_gpu-etnaviv/hash +++ b/repos/libports/recipes/pkg/mesa_gpu-etnaviv/hash @@ -1 +1 @@ -2024-08-28 f539670a9aac5e2c6a8d0e4e3e1d3d73ce2e9c5e +2024-10-29 782fbf038339f1c2080832dc560f2a28d832ccb0 diff --git a/repos/libports/recipes/pkg/mesa_gpu-intel/hash b/repos/libports/recipes/pkg/mesa_gpu-intel/hash index fd4ab2d710..b53d7a8596 100644 --- a/repos/libports/recipes/pkg/mesa_gpu-intel/hash +++ b/repos/libports/recipes/pkg/mesa_gpu-intel/hash @@ -1 +1 @@ -2024-08-28 cf4031a18d658db8221ece9e838cae7030c84c7b +2024-10-29 4652ff90a26001bb34177a4840e650a3fafdda76 diff --git a/repos/libports/recipes/pkg/mesa_gpu-lima/hash b/repos/libports/recipes/pkg/mesa_gpu-lima/hash index b28ac65539..916217dcd0 100644 --- a/repos/libports/recipes/pkg/mesa_gpu-lima/hash +++ b/repos/libports/recipes/pkg/mesa_gpu-lima/hash @@ -1 +1 @@ -2024-08-28 3db59b0f7fde31a625191a3b049c7b633b6df06e +2024-10-29 ad2d304a6b3844fc1c38c2e17a9cb02faff069e3 diff --git a/repos/libports/recipes/pkg/pdf_view/hash b/repos/libports/recipes/pkg/pdf_view/hash index 5b3f785b69..43c0888dbe 100644 --- a/repos/libports/recipes/pkg/pdf_view/hash +++ b/repos/libports/recipes/pkg/pdf_view/hash @@ -1 +1 @@ -2024-08-28 b0b695aa384655b242ffc55e87e15a80cdb33d18 +2024-10-29 e0238c3c4854fa79d361322b3478b3454cf04fc9 diff --git a/repos/libports/recipes/pkg/qt5_textedit/hash b/repos/libports/recipes/pkg/qt5_textedit/hash index d9edd703e6..0f42c086d2 100644 --- a/repos/libports/recipes/pkg/qt5_textedit/hash +++ b/repos/libports/recipes/pkg/qt5_textedit/hash @@ -1 +1 @@ -2024-08-28 c49e99d322ee3a06253dd84bd6de12f31a76586b +2024-11-04 8279ed4dc21d9f3335b250aaff5dd8bb30a2a2e4 diff --git a/repos/libports/recipes/pkg/sntp_dummy_rtc/hash b/repos/libports/recipes/pkg/sntp_dummy_rtc/hash index 954806c415..b7ed12d620 100644 --- a/repos/libports/recipes/pkg/sntp_dummy_rtc/hash +++ b/repos/libports/recipes/pkg/sntp_dummy_rtc/hash @@ -1 +1 @@ -2024-08-28 9c221f3f3960e012155bb0e9a884bcc79a918059 +2024-10-29 e15015cf4d50a2f2dba4bfe5086df11f46999fd4 diff --git a/repos/libports/recipes/pkg/stdin2out/hash b/repos/libports/recipes/pkg/stdin2out/hash index 3d5802b4fd..b4a74b78d4 100644 --- a/repos/libports/recipes/pkg/stdin2out/hash +++ b/repos/libports/recipes/pkg/stdin2out/hash @@ -1 +1 @@ -2024-08-28 59c1e981b6eb839e967fac60fb5eb5d2db2de5de +2024-10-29 ad05db48e0677a765bb145c8c2f1b852ae5b3196 diff --git a/repos/libports/recipes/pkg/system_clock-dummy/hash b/repos/libports/recipes/pkg/system_clock-dummy/hash index a0460021e7..d551505c3b 100644 --- a/repos/libports/recipes/pkg/system_clock-dummy/hash +++ b/repos/libports/recipes/pkg/system_clock-dummy/hash @@ -1 +1 @@ -2024-08-28 26d008dde90d8f2cc8fb344b8ca68a0a45b91cec +2024-10-29 1b712f3c570bd68a9f03f7f6b7679aae089dee01 diff --git a/repos/libports/recipes/pkg/system_clock-pc/hash b/repos/libports/recipes/pkg/system_clock-pc/hash index 493980f3e5..5a02370af5 100644 --- a/repos/libports/recipes/pkg/system_clock-pc/hash +++ b/repos/libports/recipes/pkg/system_clock-pc/hash @@ -1 +1 @@ -2024-08-28 a872253f6c55b71c4778c580033cfb6469d650b2 +2024-10-29 80ada162915e2d5d01d930cee0c4b21d8b3b1e5e diff --git a/repos/libports/recipes/pkg/system_rtc-linux/hash b/repos/libports/recipes/pkg/system_rtc-linux/hash index 7d567eafa4..bb26fc1fed 100644 --- a/repos/libports/recipes/pkg/system_rtc-linux/hash +++ b/repos/libports/recipes/pkg/system_rtc-linux/hash @@ -1 +1 @@ -2024-08-28 bc61dcc556e69667fe8f996bed5342723109e90c +2024-10-07 eb1d46b9b2399d7b78a80bb0746179c049923ef6 diff --git a/repos/libports/recipes/pkg/system_rtc-pc/hash b/repos/libports/recipes/pkg/system_rtc-pc/hash index 8ecf07363e..7d9e9fed1e 100644 --- a/repos/libports/recipes/pkg/system_rtc-pc/hash +++ b/repos/libports/recipes/pkg/system_rtc-pc/hash @@ -1 +1 @@ -2024-08-28 4e0a2ae8d9997100bfc261f78d0e5122346227f1 +2024-10-07 d65603b5d26fd6d69271159d41e92637a38b6b27 diff --git a/repos/libports/recipes/pkg/test-expat/hash b/repos/libports/recipes/pkg/test-expat/hash index d031ee157d..f0aba79ae5 100644 --- a/repos/libports/recipes/pkg/test-expat/hash +++ b/repos/libports/recipes/pkg/test-expat/hash @@ -1 +1 @@ -2024-08-28 44da74de0017a93c29bae0efc0c987a1090e2129 +2024-10-29 d7294c9b65c7bf18cb21b52ea7b62be3d6228368 diff --git a/repos/libports/recipes/pkg/test-ldso/hash b/repos/libports/recipes/pkg/test-ldso/hash index 47a467b2b7..05ef496ec2 100644 --- a/repos/libports/recipes/pkg/test-ldso/hash +++ b/repos/libports/recipes/pkg/test-ldso/hash @@ -1 +1 @@ -2024-08-28 7474fb492dbc0d22c766cbec7646b8ece3d1595a +2024-10-29 c288963b72a660a8cbf8be25740925da6e48a42e diff --git a/repos/libports/recipes/pkg/test-libc/hash b/repos/libports/recipes/pkg/test-libc/hash index 4e8a6cf4d1..244d8502e7 100644 --- a/repos/libports/recipes/pkg/test-libc/hash +++ b/repos/libports/recipes/pkg/test-libc/hash @@ -1 +1 @@ -2024-08-28 a6696dfc682e12a5a3bf9b82ae20e10b47cfc3da +2024-10-29 0ccb78912e33492d8b1996d961c3997d24708f98 diff --git a/repos/libports/recipes/pkg/test-libc_alarm/README b/repos/libports/recipes/pkg/test-libc_alarm/README new file mode 100644 index 0000000000..77680bcf90 --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/README @@ -0,0 +1 @@ +Libc alarm() test. diff --git a/repos/libports/recipes/pkg/test-libc_alarm/archives b/repos/libports/recipes/pkg/test-libc_alarm/archives new file mode 100644 index 0000000000..170cda551e --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/archives @@ -0,0 +1,5 @@ +_/src/init +_/src/test-libc_alarm +_/src/libc +_/src/posix +_/src/vfs diff --git a/repos/libports/recipes/pkg/test-libc_alarm/hash b/repos/libports/recipes/pkg/test-libc_alarm/hash new file mode 100644 index 0000000000..facc84dd4e --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/hash @@ -0,0 +1 @@ +2024-10-29 dc05e5a6933f53cba4c51628c6ba92b091acb793 diff --git a/repos/libports/recipes/pkg/test-libc_alarm/runtime b/repos/libports/recipes/pkg/test-libc_alarm/runtime new file mode 100644 index 0000000000..24bf4b4bce --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_alarm/runtime @@ -0,0 +1,22 @@ +<runtime ram="3M" caps="200" binary="test-libc_alarm"> + + <requires> <timer/> </requires> + + <fail after_seconds="13"/> + <succeed>triggered_alarms=3</succeed> + + <content> + <rom label="ld.lib.so"/> + <rom label="test-libc_alarm"/> + <rom label="libc.lib.so"/> + <rom label="libm.lib.so"/> + <rom label="vfs.lib.so"/> + <rom label="posix.lib.so"/> + </content> + + <config> + <vfs> <dir name="dev"> <log/> </dir> </vfs> + <libc stdout="/dev/log" stderr="/dev/log"/> + <arg value="test-libc_alarm"/> + </config> +</runtime> diff --git a/repos/libports/recipes/pkg/test-libc_connect_lwip/hash b/repos/libports/recipes/pkg/test-libc_connect_lwip/hash index 9fefa5a06e..470c67c2e7 100644 --- a/repos/libports/recipes/pkg/test-libc_connect_lwip/hash +++ b/repos/libports/recipes/pkg/test-libc_connect_lwip/hash @@ -1 +1 @@ -2024-08-28 80bcf60784c0414a9c23d0f96a87d1ea58b26d1b +2024-10-29 cb4692abe7489da31936b4c39466e95d04fde44b diff --git a/repos/libports/recipes/pkg/test-libc_connect_lxip/hash b/repos/libports/recipes/pkg/test-libc_connect_lxip/hash index 03833dae5e..bdb790b804 100644 --- a/repos/libports/recipes/pkg/test-libc_connect_lxip/hash +++ b/repos/libports/recipes/pkg/test-libc_connect_lxip/hash @@ -1 +1 @@ -2024-08-28 00e9c32ef8ad6637042b647d1f3e0199aacc3931 +2024-10-29 6ac5a6c849bc885dccf26fc1bb7f8369e69b7ed6 diff --git a/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lwip/hash b/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lwip/hash index 641c18f6d1..221bbff956 100644 --- a/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lwip/hash +++ b/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lwip/hash @@ -1 +1 @@ -2024-08-28 9a85a1c95c43016d5d5e6ab157efb7166948bda1 +2024-10-29 ab2aa5744a62d04b326e610f20a938141a70147f diff --git a/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lxip/hash b/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lxip/hash index 5df68c449b..3c791bfb75 100644 --- a/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lxip/hash +++ b/repos/libports/recipes/pkg/test-libc_connect_vfs_server_lxip/hash @@ -1 +1 @@ -2024-08-28 278fb455c44f616f22c74eee623bcdef841a251a +2024-10-29 9b25196204000defbd5b4fbda7ded0b07ff0fcab diff --git a/repos/libports/recipes/pkg/test-libc_counter/hash b/repos/libports/recipes/pkg/test-libc_counter/hash index 31d468e8bc..41e3a47dc2 100644 --- a/repos/libports/recipes/pkg/test-libc_counter/hash +++ b/repos/libports/recipes/pkg/test-libc_counter/hash @@ -1 +1 @@ -2024-08-28 241918fa6247f5ecdd582489a2ca361b486533c0 +2024-10-29 a321f4f33e545dcaacc91a613e41c611eb5f0916 diff --git a/repos/libports/recipes/pkg/test-libc_deferred_unlink/hash b/repos/libports/recipes/pkg/test-libc_deferred_unlink/hash index ddecb890e2..e43b74a859 100644 --- a/repos/libports/recipes/pkg/test-libc_deferred_unlink/hash +++ b/repos/libports/recipes/pkg/test-libc_deferred_unlink/hash @@ -1 +1 @@ -2024-08-28 b6fdd7ee35ef64dbe95d9bc596e7be3a3b2aa14f +2024-10-29 dd1c8492bd96c29bf4f9e86b512da2ff1a260f18 diff --git a/repos/libports/recipes/pkg/test-libc_execve/hash b/repos/libports/recipes/pkg/test-libc_execve/hash index 554f156e3f..dffabbc5c3 100644 --- a/repos/libports/recipes/pkg/test-libc_execve/hash +++ b/repos/libports/recipes/pkg/test-libc_execve/hash @@ -1 +1 @@ -2024-08-28 afb55f4e983a0b7ca78390aa26dcb01da3f539d7 +2024-10-29 c53dd687af0eddc86ad879807d647340a4402f0a diff --git a/repos/libports/recipes/pkg/test-libc_fifo_pipe/hash b/repos/libports/recipes/pkg/test-libc_fifo_pipe/hash index a4911daf0e..593e789025 100644 --- a/repos/libports/recipes/pkg/test-libc_fifo_pipe/hash +++ b/repos/libports/recipes/pkg/test-libc_fifo_pipe/hash @@ -1 +1 @@ -2024-08-28 0aa7429c224923424e5c38f1dac97c01eb4895e5 +2024-10-29 8f24c8c9a30d47d0806dbb7e1d48f7fc80c95096 diff --git a/repos/libports/recipes/pkg/test-libc_fork/hash b/repos/libports/recipes/pkg/test-libc_fork/hash index aa762556f3..c5822e5553 100644 --- a/repos/libports/recipes/pkg/test-libc_fork/hash +++ b/repos/libports/recipes/pkg/test-libc_fork/hash @@ -1 +1 @@ -2024-08-28 dc3035dfb5ac1aaf1b5e8792dd3f42e5a62db693 +2024-10-29 4721e98ca8e201a53a8aa3425de93f2e1547fb8f diff --git a/repos/libports/recipes/pkg/test-libc_getenv/hash b/repos/libports/recipes/pkg/test-libc_getenv/hash index 9a6a2bc161..7aab439d15 100644 --- a/repos/libports/recipes/pkg/test-libc_getenv/hash +++ b/repos/libports/recipes/pkg/test-libc_getenv/hash @@ -1 +1 @@ -2024-08-28 c40edbbd8af8cd5abb52febe5d2cb57c463a50ab +2024-10-29 7629089ba47da7b8da4e3f13e655a0275770a3ff diff --git a/repos/libports/recipes/pkg/test-libc_kqueue/README b/repos/libports/recipes/pkg/test-libc_kqueue/README new file mode 100644 index 0000000000..441a3c17f2 --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_kqueue/README @@ -0,0 +1 @@ +Libc kqueue() test. diff --git a/repos/libports/recipes/pkg/test-libc_kqueue/archives b/repos/libports/recipes/pkg/test-libc_kqueue/archives new file mode 100644 index 0000000000..ba509bbbea --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_kqueue/archives @@ -0,0 +1,5 @@ +_/src/init +_/src/libc +_/src/posix +_/src/test-libc_kqueue +_/src/vfs diff --git a/repos/libports/recipes/pkg/test-libc_kqueue/hash b/repos/libports/recipes/pkg/test-libc_kqueue/hash new file mode 100644 index 0000000000..47dcfc6a6d --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_kqueue/hash @@ -0,0 +1 @@ +2024-10-29 873660af71b4c98d09d89ba206a87d098b124295 diff --git a/repos/libports/recipes/pkg/test-libc_kqueue/runtime b/repos/libports/recipes/pkg/test-libc_kqueue/runtime new file mode 100644 index 0000000000..c2f00c7caf --- /dev/null +++ b/repos/libports/recipes/pkg/test-libc_kqueue/runtime @@ -0,0 +1,24 @@ +<runtime ram="3M" caps="200" binary="test-libc_kqueue"> + + <requires> <timer/> </requires> + + <fail after_seconds="8"/> + <succeed>--- test succeeded ---</succeed> + + <content> + <rom label="ld.lib.so"/> + <rom label="libc.lib.so"/> + <rom label="libm.lib.so"/> + <rom label="posix.lib.so"/> + <rom label="test-libc_kqueue"/> + <rom label="vfs.lib.so"/> + </content> + + <config> + <vfs> <dir name="dev"> <log/> <inline name="rtc">2019-08-20 15:01</inline> </dir> </vfs> + <libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc"/> + <arg value="test-libc_kqueue"/> + <arg value="/dev/log"/> + </config> + +</runtime> diff --git a/repos/libports/recipes/pkg/test-libc_pipe/hash b/repos/libports/recipes/pkg/test-libc_pipe/hash index cabfdf1256..b4c3beceb8 100644 --- a/repos/libports/recipes/pkg/test-libc_pipe/hash +++ b/repos/libports/recipes/pkg/test-libc_pipe/hash @@ -1 +1 @@ -2024-08-28 f55cc506f155d11f4f5c01bacbd218b231a66df4 +2024-10-29 829136cecf209699cc42f3e1e09467260d925ce9 diff --git a/repos/libports/recipes/pkg/test-libc_vfs/hash b/repos/libports/recipes/pkg/test-libc_vfs/hash index 193cc2c87f..0557114252 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs/hash @@ -1 +1 @@ -2024-08-28 c22a975e629999c616087dcee53c15ec492334cd +2024-10-29 3a58d7c98ffe751cd95e4d303448337bcf1e07aa diff --git a/repos/libports/recipes/pkg/test-libc_vfs_block/hash b/repos/libports/recipes/pkg/test-libc_vfs_block/hash index b0fd157325..924f901372 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_block/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_block/hash @@ -1 +1 @@ -2024-08-28 d446f17a8d192495a99dfaea37cd4aa61bfcf7b2 +2024-11-04 92ceb0775e3631cd948ef6d53e686d11c9febdc3 diff --git a/repos/libports/recipes/pkg/test-libc_vfs_counter/hash b/repos/libports/recipes/pkg/test-libc_vfs_counter/hash index 24061b66f6..ea1fd6a3aa 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_counter/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_counter/hash @@ -1 +1 @@ -2024-08-28 30c1a830a974b89d6929e5aaff8f63d3269f1b98 +2024-10-29 a33c3e17af4b25eda529234535410b74f5b71782 diff --git a/repos/libports/recipes/pkg/test-libc_vfs_fs/hash b/repos/libports/recipes/pkg/test-libc_vfs_fs/hash index 91ebe3e84e..a651aac973 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_fs/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_fs/hash @@ -1 +1 @@ -2024-08-28 e21f251b902d518ea7c55eaa7772751d4dfd740c +2024-10-29 7649778d31dc042c4e156ed8603669258c6df8be diff --git a/repos/libports/recipes/pkg/test-libc_vfs_fs_chained/hash b/repos/libports/recipes/pkg/test-libc_vfs_fs_chained/hash index d0c1c726ac..b198a4f8eb 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_fs_chained/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_fs_chained/hash @@ -1 +1 @@ -2024-08-28 a9a1c3c394fbf08746779b2a843defe692e1c66e +2024-10-29 46bfb4d0aee8744aa17b33e2f00de288212175b4 diff --git a/repos/libports/recipes/pkg/test-libc_vfs_oss/hash b/repos/libports/recipes/pkg/test-libc_vfs_oss/hash index 8c2d68e1c3..e6132d98f6 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_oss/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_oss/hash @@ -1 +1 @@ -2024-08-28 a49d4d2740107d776c5b6e96472eec3aaab10469 +2024-11-04 15205253a56332dcfbd11b0e37a4523b5275e22c diff --git a/repos/libports/recipes/pkg/test-libc_vfs_ram/hash b/repos/libports/recipes/pkg/test-libc_vfs_ram/hash index 4518e8ed8d..dc4e0bde5d 100644 --- a/repos/libports/recipes/pkg/test-libc_vfs_ram/hash +++ b/repos/libports/recipes/pkg/test-libc_vfs_ram/hash @@ -1 +1 @@ -2024-08-28 17e6617df1e36fb7c1ec28fcc9912cc0b603f526 +2024-10-29 8862e0a908801303192a754e428ffaf0707938a8 diff --git a/repos/libports/recipes/pkg/test-pipe_read_ready/hash b/repos/libports/recipes/pkg/test-pipe_read_ready/hash index 0a74e6c366..0f6c4121f5 100644 --- a/repos/libports/recipes/pkg/test-pipe_read_ready/hash +++ b/repos/libports/recipes/pkg/test-pipe_read_ready/hash @@ -1 +1 @@ -2024-08-28 0c3c755a179011155c23cbb541a054a1a3e758cb +2024-10-29 def53655c3faca62a46ec9b2b3931f4198d9956e diff --git a/repos/libports/recipes/pkg/test-pthread/hash b/repos/libports/recipes/pkg/test-pthread/hash index 13eaab2ede..a4ea265e32 100644 --- a/repos/libports/recipes/pkg/test-pthread/hash +++ b/repos/libports/recipes/pkg/test-pthread/hash @@ -1 +1 @@ -2024-08-28 96de69554cb3993d7f907077bdcacf8ff21a3cc7 +2024-10-29 a8286b25a2ffdc69b4626f17526903a1994ebd82 diff --git a/repos/libports/recipes/pkg/test-sequence/hash b/repos/libports/recipes/pkg/test-sequence/hash index 3e54e14fd3..64333cade1 100644 --- a/repos/libports/recipes/pkg/test-sequence/hash +++ b/repos/libports/recipes/pkg/test-sequence/hash @@ -1 +1 @@ -2024-08-28 9acdab39ff9c7930a34696300097d6c085afe016 +2024-10-29 4f5e8403ed02657469b245ef10a115ff7d6b4213 diff --git a/repos/libports/recipes/pkg/test-spark/hash b/repos/libports/recipes/pkg/test-spark/hash index 51c09c4037..7f928a8bd8 100644 --- a/repos/libports/recipes/pkg/test-spark/hash +++ b/repos/libports/recipes/pkg/test-spark/hash @@ -1 +1 @@ -2024-08-28 dba38ef565a0a5c2aef8e0186184ccd2e97b73b8 +2024-10-29 7e1615ee2e09d21d91937a8db9481c0cc6708be7 diff --git a/repos/libports/recipes/pkg/test-spark_exception/hash b/repos/libports/recipes/pkg/test-spark_exception/hash index 0be527b8b2..91aa12809f 100644 --- a/repos/libports/recipes/pkg/test-spark_exception/hash +++ b/repos/libports/recipes/pkg/test-spark_exception/hash @@ -1 +1 @@ -2024-08-28 eff0e5679067aa3ffef960656d6b60fca51f715a +2024-10-29 579e9fe0082580f683379d387801bbf2a7abd552 diff --git a/repos/libports/recipes/pkg/test-spark_secondary_stack/hash b/repos/libports/recipes/pkg/test-spark_secondary_stack/hash index 27595ff18e..0b2ee77835 100644 --- a/repos/libports/recipes/pkg/test-spark_secondary_stack/hash +++ b/repos/libports/recipes/pkg/test-spark_secondary_stack/hash @@ -1 +1 @@ -2024-08-28 045922085f23518bd50d625fc8ccd6812b982fae +2024-10-29 1e53e14046a7b4abeaded270d72634105350ea46 diff --git a/repos/libports/recipes/pkg/test-stdcxx/hash b/repos/libports/recipes/pkg/test-stdcxx/hash index 5046fda7b2..9ec94359da 100644 --- a/repos/libports/recipes/pkg/test-stdcxx/hash +++ b/repos/libports/recipes/pkg/test-stdcxx/hash @@ -1 +1 @@ -2024-08-28 38263ab7a5902d67f6d71800f94102b692b4fb26 +2024-10-29 cd2ebdce5a6d65bc9ad179ff15cf53165dfc6198 diff --git a/repos/libports/recipes/pkg/test-tcp_bulk_lwip/hash b/repos/libports/recipes/pkg/test-tcp_bulk_lwip/hash index a82822416d..d6a31be708 100644 --- a/repos/libports/recipes/pkg/test-tcp_bulk_lwip/hash +++ b/repos/libports/recipes/pkg/test-tcp_bulk_lwip/hash @@ -1 +1 @@ -2024-08-28 a349b37e9cfbf9417a97158e36472f800e9f67d3 +2024-10-29 abc626c90051a2d0d45c09f85da89fe936591845 diff --git a/repos/libports/recipes/pkg/test-tcp_bulk_lxip/hash b/repos/libports/recipes/pkg/test-tcp_bulk_lxip/hash index 4a9aa11485..e6c68664c5 100644 --- a/repos/libports/recipes/pkg/test-tcp_bulk_lxip/hash +++ b/repos/libports/recipes/pkg/test-tcp_bulk_lxip/hash @@ -1 +1 @@ -2024-08-28 33b2b5af63001370de24d181be08bb46299a261e +2024-10-29 61e14ec44c69c38042bd27f44b0728b83a208c91 diff --git a/repos/libports/recipes/pkg/usb_webcam/hash b/repos/libports/recipes/pkg/usb_webcam/hash index e3e09adb9b..cd7559725e 100644 --- a/repos/libports/recipes/pkg/usb_webcam/hash +++ b/repos/libports/recipes/pkg/usb_webcam/hash @@ -1 +1 @@ -2024-08-28 de8ba1e0f36a99c560ce60d382ae4cc57f553094 +2024-11-04 ca2fcc26aa587d2d42954819ef413eba8659bf92 diff --git a/repos/libports/recipes/pkg/usb_webcam/runtime b/repos/libports/recipes/pkg/usb_webcam/runtime index aa1db16023..2548b7083e 100644 --- a/repos/libports/recipes/pkg/usb_webcam/runtime +++ b/repos/libports/recipes/pkg/usb_webcam/runtime @@ -1,6 +1,6 @@ -<runtime binary="init" caps="800" ram="64M" config="usb_webcam.config"> +<runtime binary="init" caps="900" ram="64M" config="usb_webcam.config"> <provides> <capture /> </provides> - <requires> <timer /> <usb /> <rm /> </requires> + <requires> <timer /> <usb /> </requires> <content> <rom label="ld.lib.so"/> <rom label="init"/> diff --git a/repos/libports/recipes/raw/usb_webcam/hash b/repos/libports/recipes/raw/usb_webcam/hash index 0566bcfa41..23c0ba55c5 100644 --- a/repos/libports/recipes/raw/usb_webcam/hash +++ b/repos/libports/recipes/raw/usb_webcam/hash @@ -1 +1 @@ -2024-04-11 042763e6ad780ed62be632f90d4b6550836ffd14 +2024-10-29 47a96974acde8af769295aaf7f4de1ea4d5a7f15 diff --git a/repos/libports/recipes/raw/usb_webcam/usb_webcam.config b/repos/libports/recipes/raw/usb_webcam/usb_webcam.config index a1cba8a896..44af89888e 100644 --- a/repos/libports/recipes/raw/usb_webcam/usb_webcam.config +++ b/repos/libports/recipes/raw/usb_webcam/usb_webcam.config @@ -21,7 +21,7 @@ <service name="Gui"/> <service name="Capture"/> </provides> <config request_framebuffer="no"> - <report displays="yes"/> + <report panorama="yes"/> <capture/> <domain name="" layer="1" content="client" label="no" /> <default-policy domain=""/> @@ -37,7 +37,7 @@ <resource name="RAM" quantum="2M"/> <provides> <service name="Report"/> <service name="ROM"/> </provides> <config verbose="no"> - <policy label="webcam_config -> displays" report="nitpicker_camera -> displays"/> + <policy label="webcam_config -> panorama" report="nitpicker_camera -> panorama"/> </config> <route> <any-service> <parent /> </any-service> @@ -49,8 +49,8 @@ <resource name="RAM" quantum="1M"/> <provides> <service name="ROM"/> </provides> <config verbose="no"> - <input name="capture_width" rom="displays" node="displays" default=""> - <node type="display"> + <input name="capture_width" rom="panorama" node="panorama" default=""> + <node type="capture"> <attribute name="width"/> </node> </input> @@ -70,8 +70,7 @@ <service name="Gui"/> <service name="Usb"/> </parent-provides> - <default caps="128"/> - <start name="usb_webcam" caps="250"> + <start name="usb_webcam" caps="300"> <resource name="RAM" quantum="52M"/> <config ld_verbose="no" enabled="yes" width="640" height="480" format="yuv" fps="15"> <vfs> @@ -94,12 +93,12 @@ </output> </config> <route> - <service name="ROM" label="displays"> <child name="report_rom"/> </service> + <service name="ROM" label="panorama"> <child name="report_rom"/> </service> <any-service> <parent/> </any-service> </route> </start> - <start name="webcam" caps="350"> + <start name="webcam" caps="400"> <binary name="init"/> <resource name="RAM" quantum="54M"/> <route> diff --git a/repos/libports/recipes/src/acpi_event/hash b/repos/libports/recipes/src/acpi_event/hash index 6d8915f39c..56482d2a29 100644 --- a/repos/libports/recipes/src/acpi_event/hash +++ b/repos/libports/recipes/src/acpi_event/hash @@ -1 +1 @@ -2024-08-28 7e1b511ce667125e75aa285d18601ea9565b4088 +2024-10-07 25541cdca13a91faff6b14c7727e58cdc12e4a08 diff --git a/repos/libports/recipes/src/acpica/hash b/repos/libports/recipes/src/acpica/hash index a663339a34..5cd9cc7e70 100644 --- a/repos/libports/recipes/src/acpica/hash +++ b/repos/libports/recipes/src/acpica/hash @@ -1 +1 @@ -2024-08-28 7ee24b094bbc91f887b71329162bc05402aacea6 +2024-10-07 4b499dbc766f11abdbeee1a5764b2a2bca168462 diff --git a/repos/libports/recipes/src/compat-libc/hash b/repos/libports/recipes/src/compat-libc/hash index 2474e72e96..3b92773039 100644 --- a/repos/libports/recipes/src/compat-libc/hash +++ b/repos/libports/recipes/src/compat-libc/hash @@ -1 +1 @@ -2024-08-28 ac4db2d2a8640919a3a1c78e5cd2b329d66c10ac +2024-10-07 7a13583a59e99b4c22d62cfeabe0f9ce6dba44b6 diff --git a/repos/libports/recipes/src/curl/hash b/repos/libports/recipes/src/curl/hash index 47cfe73fc1..14ed23a560 100644 --- a/repos/libports/recipes/src/curl/hash +++ b/repos/libports/recipes/src/curl/hash @@ -1 +1 @@ -2024-08-28 531347c4babd68aaf68a78266f4a6772b814a390 +2024-10-07 c868b84c7e02011e5471594876e593894ae9573f diff --git a/repos/libports/recipes/src/expat/hash b/repos/libports/recipes/src/expat/hash index 2fac86f6da..8fd584e272 100644 --- a/repos/libports/recipes/src/expat/hash +++ b/repos/libports/recipes/src/expat/hash @@ -1 +1 @@ -2024-08-28 3e8670688ad1d24eb2fc33fe09fe164175a76b56 +2024-10-07 6e42e25ca423dfbfb33f75ef51eb681037f77937 diff --git a/repos/libports/recipes/src/extract/hash b/repos/libports/recipes/src/extract/hash index 477042ce75..905ebba250 100644 --- a/repos/libports/recipes/src/extract/hash +++ b/repos/libports/recipes/src/extract/hash @@ -1 +1 @@ -2024-08-28 f406428767771456b29a7516aa9880b285d961fd +2024-10-07 77ea7e63e13f117aaad2905cdb198f6a5d8d142e diff --git a/repos/libports/recipes/src/fetchurl/hash b/repos/libports/recipes/src/fetchurl/hash index 31527af50a..7643a676c8 100644 --- a/repos/libports/recipes/src/fetchurl/hash +++ b/repos/libports/recipes/src/fetchurl/hash @@ -1 +1 @@ -2024-08-28 38f70f9121762b50fb8e65094097ef11ffa20c91 +2024-10-07 9de8777183b493df2a7c640f999f8cb3d3799461 diff --git a/repos/libports/recipes/src/ffi/hash b/repos/libports/recipes/src/ffi/hash index 51e805f089..11f1666b42 100644 --- a/repos/libports/recipes/src/ffi/hash +++ b/repos/libports/recipes/src/ffi/hash @@ -1 +1 @@ -2024-08-28 88605d93ba05e40bdd08b338a5d927d538b1a1c3 +2024-10-07 d29ca29db529036fe29c64d9cdc80d3bb754a7ae diff --git a/repos/libports/recipes/src/freetype/hash b/repos/libports/recipes/src/freetype/hash index c0f850d1b6..a12b33aa2b 100644 --- a/repos/libports/recipes/src/freetype/hash +++ b/repos/libports/recipes/src/freetype/hash @@ -1 +1 @@ -2024-08-28 e6bf913b0f700c6d8d67cf21662e977309f87d09 +2024-10-07 b71866cbe221054b27f1153038994c2acde19813 diff --git a/repos/libports/recipes/src/fs_utils/hash b/repos/libports/recipes/src/fs_utils/hash index a83cd4d93c..7c6c0f2eea 100644 --- a/repos/libports/recipes/src/fs_utils/hash +++ b/repos/libports/recipes/src/fs_utils/hash @@ -1 +1 @@ -2024-08-28 d3dc1ca871f93023bff9af92c7281b0e53cf79b7 +2024-10-07 534a3e3d2ceeb3a1360afcdd51ad41ced7957762 diff --git a/repos/libports/recipes/src/gcov/hash b/repos/libports/recipes/src/gcov/hash index 760c76402b..306a57afdd 100644 --- a/repos/libports/recipes/src/gcov/hash +++ b/repos/libports/recipes/src/gcov/hash @@ -1 +1 @@ -2024-08-28 c5424892a2de8c3627c5dbbd4273b5b55c40d362 +2024-10-07 6eef7b6df474d8915a24552ef8f90ea558b97027 diff --git a/repos/libports/recipes/src/gmp/hash b/repos/libports/recipes/src/gmp/hash index 35fcc1471e..1cb14b9463 100644 --- a/repos/libports/recipes/src/gmp/hash +++ b/repos/libports/recipes/src/gmp/hash @@ -1 +1 @@ -2024-08-28 30aee7134f40daa37af1412d01edf059e83cfb7a +2024-10-07 f0c7a473461c2c117744186b758ab5e06127017c diff --git a/repos/libports/recipes/src/jbig2dec/hash b/repos/libports/recipes/src/jbig2dec/hash index 2475ea0537..312364e9c2 100644 --- a/repos/libports/recipes/src/jbig2dec/hash +++ b/repos/libports/recipes/src/jbig2dec/hash @@ -1 +1 @@ -2024-08-28 301a9b75bdc32f13deb86695dec0b91dc3c495ed +2024-10-07 423e8f99ab035abe1dfa0a8fc41bdd845e27389e diff --git a/repos/libports/recipes/src/jpeg/hash b/repos/libports/recipes/src/jpeg/hash index 97c0ed36ac..11c97f3505 100644 --- a/repos/libports/recipes/src/jpeg/hash +++ b/repos/libports/recipes/src/jpeg/hash @@ -1 +1 @@ -2024-08-28 ded6125f239a12529ea412417cfbe7bd6e154cc6 +2024-10-07 35fe809179eeb0f0b1bfa6989475638d2f8ab97b diff --git a/repos/libports/recipes/src/libarchive/hash b/repos/libports/recipes/src/libarchive/hash index 9fa9ee5875..20b5136d2e 100644 --- a/repos/libports/recipes/src/libarchive/hash +++ b/repos/libports/recipes/src/libarchive/hash @@ -1 +1 @@ -2024-08-28 830abe72a027ae63fbae0e0d6b2ec21691e4a0cf +2024-10-07 c8111b67a5ec12c38d2d060e8410cc69407f8c6b diff --git a/repos/libports/recipes/src/libc/hash b/repos/libports/recipes/src/libc/hash index a051d4146f..33a0c24eb8 100644 --- a/repos/libports/recipes/src/libc/hash +++ b/repos/libports/recipes/src/libc/hash @@ -1 +1 @@ -2024-08-28 55932a8f55d1976361d935c59267373cb13c9762 +2024-10-29 ce5bfae0d9aa753dae322aaf9ddda52b4b341f26 diff --git a/repos/libports/recipes/src/libdrm/hash b/repos/libports/recipes/src/libdrm/hash index a2b53f4174..663fe7f79f 100644 --- a/repos/libports/recipes/src/libdrm/hash +++ b/repos/libports/recipes/src/libdrm/hash @@ -1 +1 @@ -2024-08-28 ed7f2f4daa888ccd9f9f3315338272a3d90fab38 +2024-10-29 73459f36290de6237f31022bf2b327f66c7706ee diff --git a/repos/libports/recipes/src/libiconv/hash b/repos/libports/recipes/src/libiconv/hash index 8f6b95b42b..3a6ae474ed 100644 --- a/repos/libports/recipes/src/libiconv/hash +++ b/repos/libports/recipes/src/libiconv/hash @@ -1 +1 @@ -2024-08-28 8c8ee799da0cccb3051771f7f15e39fa4f910233 +2024-10-07 029ae793f0b90e886f5f9b0e29de97cee38cc0b6 diff --git a/repos/libports/recipes/src/liblzma/hash b/repos/libports/recipes/src/liblzma/hash index e8fc6f803c..8cb1c6622d 100644 --- a/repos/libports/recipes/src/liblzma/hash +++ b/repos/libports/recipes/src/liblzma/hash @@ -1 +1 @@ -2024-08-28 76cf230175bae7a4ee00766e5ad98b676d970b3b +2024-10-07 8869476b02ff8c4a35ead717bc40b072c9219b29 diff --git a/repos/libports/recipes/src/libpng/hash b/repos/libports/recipes/src/libpng/hash index f8350b531c..f893c683ca 100644 --- a/repos/libports/recipes/src/libpng/hash +++ b/repos/libports/recipes/src/libpng/hash @@ -1 +1 @@ -2024-08-28 8954a7dbe623dd0f36f8bc2e983639dd5db015cb +2024-10-07 8bfa12a828825bbf3d03945b36cd02d9cba068ea diff --git a/repos/libports/recipes/src/libqgenodeviewwidget/hash b/repos/libports/recipes/src/libqgenodeviewwidget/hash index 151a6fe71b..278f3b5804 100644 --- a/repos/libports/recipes/src/libqgenodeviewwidget/hash +++ b/repos/libports/recipes/src/libqgenodeviewwidget/hash @@ -1 +1 @@ -2024-08-28 6d003a0c416b52b05ded4c7ffd2921dcf6b383bd +2024-10-29 44650933ca13c47faed8d291797e085da1b0dbbf diff --git a/repos/libports/recipes/src/libssh/hash b/repos/libports/recipes/src/libssh/hash index 922fe07d81..29cc64c2d5 100644 --- a/repos/libports/recipes/src/libssh/hash +++ b/repos/libports/recipes/src/libssh/hash @@ -1 +1 @@ -2024-08-28 52cdc44f7ff8860ba4a2c5e933577e2d482f73ad +2024-10-07 b0fa4b50929766f9bba3d39247db4b6365d585c5 diff --git a/repos/libports/recipes/src/libusb/hash b/repos/libports/recipes/src/libusb/hash index 9b91a8abda..2d9db6c110 100644 --- a/repos/libports/recipes/src/libusb/hash +++ b/repos/libports/recipes/src/libusb/hash @@ -1 +1 @@ -2024-08-28 1f4e447434d3121b8fb6691f3005af61797cf332 +2024-10-07 8eff02211941fbe10d9ceb0909299d9eeab5e956 diff --git a/repos/libports/recipes/src/libuvc/hash b/repos/libports/recipes/src/libuvc/hash index de2352c589..d8b4b94070 100644 --- a/repos/libports/recipes/src/libuvc/hash +++ b/repos/libports/recipes/src/libuvc/hash @@ -1 +1 @@ -2024-08-28 39d58419db5eb3724de1cd742cb1787eedcb652d +2024-10-07 53a7aa2da338109e7eff1740971b7a6f0d35b897 diff --git a/repos/libports/recipes/src/libyuv/hash b/repos/libports/recipes/src/libyuv/hash index f8907806f3..9835fb7d1b 100644 --- a/repos/libports/recipes/src/libyuv/hash +++ b/repos/libports/recipes/src/libyuv/hash @@ -1 +1 @@ -2024-08-28 5f8e804f74f836b7a1e9e257418f42416b80d814 +2024-10-07 e7f6be6e4d2fff244e10529dee573db460c8cb8d diff --git a/repos/libports/recipes/src/mesa/hash b/repos/libports/recipes/src/mesa/hash index a239bc90e3..3b9a34ef5e 100644 --- a/repos/libports/recipes/src/mesa/hash +++ b/repos/libports/recipes/src/mesa/hash @@ -1 +1 @@ -2024-08-28 980fd81ee76888891f3a0b103be0541a1c2dc617 +2024-10-29 701274ab2d30e7d641b5732391506e3780ad0f12 diff --git a/repos/libports/recipes/src/mesa_gears/hash b/repos/libports/recipes/src/mesa_gears/hash index 84143a1414..c1db270be6 100644 --- a/repos/libports/recipes/src/mesa_gears/hash +++ b/repos/libports/recipes/src/mesa_gears/hash @@ -1 +1 @@ -2024-08-28 1a71604e56d25b64413eec8add614fce51e041f6 +2024-10-29 0d2787dcdf036d3d6b28525963c5489de787dc61 diff --git a/repos/libports/recipes/src/mupdf/hash b/repos/libports/recipes/src/mupdf/hash index 8c4df95482..42043d50ef 100644 --- a/repos/libports/recipes/src/mupdf/hash +++ b/repos/libports/recipes/src/mupdf/hash @@ -1 +1 @@ -2024-08-28 59ac9cce57814450c9cd602dae31b24258183f41 +2024-10-07 2ceae7b51955b01b6411f021559c09bc240cd515 diff --git a/repos/libports/recipes/src/ncurses/hash b/repos/libports/recipes/src/ncurses/hash index a0bf37e2f8..e00763c077 100644 --- a/repos/libports/recipes/src/ncurses/hash +++ b/repos/libports/recipes/src/ncurses/hash @@ -1 +1 @@ -2024-08-28 3ad381419f006510519a6bf61fa20d3134988918 +2024-10-07 b5071cb4904f6302a3a6591c399cf96d668fc74c diff --git a/repos/libports/recipes/src/openjpeg/hash b/repos/libports/recipes/src/openjpeg/hash index 648098a28a..b71eadaa19 100644 --- a/repos/libports/recipes/src/openjpeg/hash +++ b/repos/libports/recipes/src/openjpeg/hash @@ -1 +1 @@ -2024-08-28 75bbd7ec35e57863ab731e5ab7d9a898d7768695 +2024-10-07 11ed245aeb65436ac9096c8ba10f7fd9860fd6c1 diff --git a/repos/libports/recipes/src/openssl/hash b/repos/libports/recipes/src/openssl/hash index 0f94b547d7..1cd73c5e33 100644 --- a/repos/libports/recipes/src/openssl/hash +++ b/repos/libports/recipes/src/openssl/hash @@ -1 +1 @@ -2024-08-28 c1f54d3e33d1be3ef2cd6193523de8536b48ef56 +2024-10-07 765a65aac2202d40fd12b9d54dc7d5b94aaede08 diff --git a/repos/libports/recipes/src/pcre/hash b/repos/libports/recipes/src/pcre/hash index b3aabeffcc..0847c499d9 100644 --- a/repos/libports/recipes/src/pcre/hash +++ b/repos/libports/recipes/src/pcre/hash @@ -1 +1 @@ -2024-08-28 c216336c492d36d2e6265faaf79518c6b5551a21 +2024-10-07 d6a3ba30419d57be5134cb704d845d87c4534acd diff --git a/repos/libports/recipes/src/pcsc-lite/hash b/repos/libports/recipes/src/pcsc-lite/hash index 2b2e9e0dd7..f76cc487d0 100644 --- a/repos/libports/recipes/src/pcsc-lite/hash +++ b/repos/libports/recipes/src/pcsc-lite/hash @@ -1 +1 @@ -2024-08-28 771e16362b305ac03b39687d3be496f5514f8878 +2024-10-07 ef7669e066774fabb8e527a8de96cadc9f8f88f1 diff --git a/repos/libports/recipes/src/pdf_view/hash b/repos/libports/recipes/src/pdf_view/hash index 6f244f7823..d3362d2426 100644 --- a/repos/libports/recipes/src/pdf_view/hash +++ b/repos/libports/recipes/src/pdf_view/hash @@ -1 +1 @@ -2024-08-28 f8ce67b42b779dd951e810466273c51481fa58be +2024-10-29 947fe9d10cea014fc5b4d6fc1a5e5489f5bdf318 diff --git a/repos/libports/recipes/src/posix/hash b/repos/libports/recipes/src/posix/hash index cf7a8ad417..9a59a444c8 100644 --- a/repos/libports/recipes/src/posix/hash +++ b/repos/libports/recipes/src/posix/hash @@ -1 +1 @@ -2024-08-28 09ceef853d6bad4370ed36d17edca31302f34e35 +2024-10-07 52eebe1b5689d83ad7d10d5152e00dba08ca13e2 diff --git a/repos/libports/recipes/src/qt5_base/hash b/repos/libports/recipes/src/qt5_base/hash index b1d4daafeb..c089512d71 100644 --- a/repos/libports/recipes/src/qt5_base/hash +++ b/repos/libports/recipes/src/qt5_base/hash @@ -1 +1 @@ -2024-08-28 f2e9072e10dda467ffb8398fc73e4c03bb528697 +2024-10-29 c562adbd2950e485c9f181a2aca6b0b5ca56ef11 diff --git a/repos/libports/recipes/src/qt5_calculatorform/hash b/repos/libports/recipes/src/qt5_calculatorform/hash index f1c37c889c..31ff1c9cb0 100644 --- a/repos/libports/recipes/src/qt5_calculatorform/hash +++ b/repos/libports/recipes/src/qt5_calculatorform/hash @@ -1 +1 @@ -2024-08-28 3cb0212b000276f539be1b6b729a47d5d73db537 +2024-10-29 b63ce371230fe653fa7a001fc15f21d50bcf0078 diff --git a/repos/libports/recipes/src/qt5_component/hash b/repos/libports/recipes/src/qt5_component/hash index 8d10c3174a..742fcfd77e 100644 --- a/repos/libports/recipes/src/qt5_component/hash +++ b/repos/libports/recipes/src/qt5_component/hash @@ -1 +1 @@ -2024-08-28 ce189c35df3a9ca2ae59d092cd401e041ea1ba30 +2024-10-07 20cefd891e66a43cefcc9ddf4f2d41d30b07671b diff --git a/repos/libports/recipes/src/qt5_declarative/hash b/repos/libports/recipes/src/qt5_declarative/hash index caac9972f9..91915a654a 100644 --- a/repos/libports/recipes/src/qt5_declarative/hash +++ b/repos/libports/recipes/src/qt5_declarative/hash @@ -1 +1 @@ -2024-08-28 a3037d3a3449c5644c471c925dbc288734c5f8a1 +2024-10-29 2ae88aef780d6b8d8c07fb20d27c8d0c01461b1b diff --git a/repos/libports/recipes/src/qt5_graphicaleffects/hash b/repos/libports/recipes/src/qt5_graphicaleffects/hash index 5e21a61a82..9747f3a2be 100644 --- a/repos/libports/recipes/src/qt5_graphicaleffects/hash +++ b/repos/libports/recipes/src/qt5_graphicaleffects/hash @@ -1 +1 @@ -2024-08-28 3b00021cd4d0a7ce04ecfc6ae74a3f195a94b820 +2024-10-29 51455c59fea72b23f47263cfe365b799653f4818 diff --git a/repos/libports/recipes/src/qt5_launchpad/hash b/repos/libports/recipes/src/qt5_launchpad/hash index 188fbc31c2..b1f7e17fdf 100644 --- a/repos/libports/recipes/src/qt5_launchpad/hash +++ b/repos/libports/recipes/src/qt5_launchpad/hash @@ -1 +1 @@ -2024-08-28 3523debd6a94ffe4d04d7a10ed4a7655e7cd7071 +2024-10-29 ea2886e088298bfa6712db897ddb543239dfa1a1 diff --git a/repos/libports/recipes/src/qt5_openglwindow/hash b/repos/libports/recipes/src/qt5_openglwindow/hash index 459c2a37d1..ab84cc04a5 100644 --- a/repos/libports/recipes/src/qt5_openglwindow/hash +++ b/repos/libports/recipes/src/qt5_openglwindow/hash @@ -1 +1 @@ -2024-08-28 47e86b9a1081f717c5a218387ca1cd9b79e4bb1d +2024-10-29 7eb0652c00f2591b0dd800b1f0cca5d5f4e1aad1 diff --git a/repos/libports/recipes/src/qt5_quickcontrols/hash b/repos/libports/recipes/src/qt5_quickcontrols/hash index c19167f9fd..aedaee5111 100644 --- a/repos/libports/recipes/src/qt5_quickcontrols/hash +++ b/repos/libports/recipes/src/qt5_quickcontrols/hash @@ -1 +1 @@ -2024-08-28 08b7f2cbde261a0aee461d6d1a3e0df1661b90e5 +2024-10-29 3050be32fe73381825ef7c72c31631e909863a1f diff --git a/repos/libports/recipes/src/qt5_quickcontrols2/hash b/repos/libports/recipes/src/qt5_quickcontrols2/hash index 1f72a0da32..15c23451d7 100644 --- a/repos/libports/recipes/src/qt5_quickcontrols2/hash +++ b/repos/libports/recipes/src/qt5_quickcontrols2/hash @@ -1 +1 @@ -2024-08-28 63884737aed335e1da22dcf2018dad5252a8adb7 +2024-10-29 9947658aed674f887498431fc6a336c0924a88d5 diff --git a/repos/libports/recipes/src/qt5_samegame/hash b/repos/libports/recipes/src/qt5_samegame/hash index d10ea67d8a..f74ecaafa3 100644 --- a/repos/libports/recipes/src/qt5_samegame/hash +++ b/repos/libports/recipes/src/qt5_samegame/hash @@ -1 +1 @@ -2024-08-28 245d816203ae87c369cde5026fb13119ae3e9104 +2024-10-29 7dbe41e8f254e2d705d5c42d01504cd77f3ee7eb diff --git a/repos/libports/recipes/src/qt5_svg/hash b/repos/libports/recipes/src/qt5_svg/hash index 46f9c8aaeb..eea4bea2f2 100644 --- a/repos/libports/recipes/src/qt5_svg/hash +++ b/repos/libports/recipes/src/qt5_svg/hash @@ -1 +1 @@ -2024-08-28 2898b48fce322aea94510cb7a8cb91b12636baf4 +2024-10-08 40f1b306f15dd31fb081ab19a11077414f47d0dd diff --git a/repos/libports/recipes/src/qt5_testqstring/hash b/repos/libports/recipes/src/qt5_testqstring/hash index 639ee0c344..79ccae9f65 100644 --- a/repos/libports/recipes/src/qt5_testqstring/hash +++ b/repos/libports/recipes/src/qt5_testqstring/hash @@ -1 +1 @@ -2024-08-28 6555f9ee8b84ee2942e3f9fee93fb18165717871 +2024-10-29 7efe449425336227e1b689eecbd724eff5c2f1d5 diff --git a/repos/libports/recipes/src/qt5_tetrix/hash b/repos/libports/recipes/src/qt5_tetrix/hash index 7c230eb61f..a58a02e7cb 100644 --- a/repos/libports/recipes/src/qt5_tetrix/hash +++ b/repos/libports/recipes/src/qt5_tetrix/hash @@ -1 +1 @@ -2024-08-28 92e6a7426b9c3a9ade1a40cf3c8549e32fc04fdd +2024-10-29 6393a4668fb5a3e1f7f370f7e158edecb2518c4d diff --git a/repos/libports/recipes/src/qt5_textedit/hash b/repos/libports/recipes/src/qt5_textedit/hash index 40dcad4d43..15d36b2d09 100644 --- a/repos/libports/recipes/src/qt5_textedit/hash +++ b/repos/libports/recipes/src/qt5_textedit/hash @@ -1 +1 @@ -2024-08-28 d15e17e5e99242e2f6e80345ecac9b2ba5392fde +2024-10-08 f86dfb339b9532c9a46ccc88de6618e526d160ed diff --git a/repos/libports/recipes/src/qt5_tooltips/hash b/repos/libports/recipes/src/qt5_tooltips/hash index dddf68810d..847f420fca 100644 --- a/repos/libports/recipes/src/qt5_tooltips/hash +++ b/repos/libports/recipes/src/qt5_tooltips/hash @@ -1 +1 @@ -2024-08-28 457f580bae3b063a41b4f44eea2a1d27c76c59e3 +2024-10-29 69b1f30f56eed5ca80a2abb5af621fd6a4be84cf diff --git a/repos/libports/recipes/src/qt5_virtualkeyboard/hash b/repos/libports/recipes/src/qt5_virtualkeyboard/hash index e7f68bc83d..211c48a044 100644 --- a/repos/libports/recipes/src/qt5_virtualkeyboard/hash +++ b/repos/libports/recipes/src/qt5_virtualkeyboard/hash @@ -1 +1 @@ -2024-08-28 c4aa72ca1779fdffba3388f1a2ec55dcebf88614 +2024-10-29 193938878855d20270284a04cc181ef4496192b8 diff --git a/repos/libports/recipes/src/qt5_virtualkeyboard_example/hash b/repos/libports/recipes/src/qt5_virtualkeyboard_example/hash index 1265725f99..0e5ff78229 100644 --- a/repos/libports/recipes/src/qt5_virtualkeyboard_example/hash +++ b/repos/libports/recipes/src/qt5_virtualkeyboard_example/hash @@ -1 +1 @@ -2024-08-28 4fe62c6ced9d01a3b4cf8613c7d3c639ff3967b2 +2024-10-29 a4ffa97a7458d6e6dfabb400803c4387c1343ca0 diff --git a/repos/libports/recipes/src/qt6_base/hash b/repos/libports/recipes/src/qt6_base/hash index a829588f3f..f75543108f 100644 --- a/repos/libports/recipes/src/qt6_base/hash +++ b/repos/libports/recipes/src/qt6_base/hash @@ -1 +1 @@ -2024-08-28 3be896bebae38e51e7fb7df8f5d748e2c94eec12 +2024-10-29 a20071440c4c51622c9f55c4b108543c75407d81 diff --git a/repos/libports/recipes/src/qt6_calculatorform/hash b/repos/libports/recipes/src/qt6_calculatorform/hash index ed03a9c3ee..86bb77348e 100644 --- a/repos/libports/recipes/src/qt6_calculatorform/hash +++ b/repos/libports/recipes/src/qt6_calculatorform/hash @@ -1 +1 @@ -2024-08-28 2a9936ed0289096620cb4ade0af398c86f92a261 +2024-10-29 11d7252273dbbd88b47d382b40cc682c149c271c diff --git a/repos/libports/recipes/src/qt6_component/hash b/repos/libports/recipes/src/qt6_component/hash index 4aaca56f5d..a367269d60 100644 --- a/repos/libports/recipes/src/qt6_component/hash +++ b/repos/libports/recipes/src/qt6_component/hash @@ -1 +1 @@ -2024-08-28 9517fad583902de01449eb7add145e7c528f3a15 +2024-10-07 717fd1dedaf0e7efe2a93c83248ed70890763f9c diff --git a/repos/libports/recipes/src/qt6_declarative/hash b/repos/libports/recipes/src/qt6_declarative/hash index c7ddc16f1f..b876454c61 100644 --- a/repos/libports/recipes/src/qt6_declarative/hash +++ b/repos/libports/recipes/src/qt6_declarative/hash @@ -1 +1 @@ -2024-08-28 9b1968e946162b38ad76c2daf7d029be82587b33 +2024-10-29 158ad98027580136a097028cbe9f1b279848117f diff --git a/repos/libports/recipes/src/qt6_launchpad/hash b/repos/libports/recipes/src/qt6_launchpad/hash index b69793af84..f8b4935751 100644 --- a/repos/libports/recipes/src/qt6_launchpad/hash +++ b/repos/libports/recipes/src/qt6_launchpad/hash @@ -1 +1 @@ -2024-08-28 8b63705142327db708d6a1bccedad8c682ad159a +2024-10-29 97e521e9bd7a1189fb740bb2f418bbd77afe6469 diff --git a/repos/libports/recipes/src/qt6_openglwindow/hash b/repos/libports/recipes/src/qt6_openglwindow/hash index 34f1a49d8d..c5cd6e9b36 100644 --- a/repos/libports/recipes/src/qt6_openglwindow/hash +++ b/repos/libports/recipes/src/qt6_openglwindow/hash @@ -1 +1 @@ -2024-08-28 d8c59ad02ae7a00401943527b8e29505ea1f510a +2024-10-29 fcb0260a9c2bc904ded4e5d14ff7d4b6c3996bb1 diff --git a/repos/libports/recipes/src/qt6_samegame/hash b/repos/libports/recipes/src/qt6_samegame/hash index 9087b0bcf4..5484492d2d 100644 --- a/repos/libports/recipes/src/qt6_samegame/hash +++ b/repos/libports/recipes/src/qt6_samegame/hash @@ -1 +1 @@ -2024-08-28 e87b8822dcadc2fa0883b514004123b98a8635dc +2024-10-29 98f8f07b282a346375d85c050189688671e91a32 diff --git a/repos/libports/recipes/src/qt6_shadertools/hash b/repos/libports/recipes/src/qt6_shadertools/hash index 7a69316d12..eda34d01c0 100644 --- a/repos/libports/recipes/src/qt6_shadertools/hash +++ b/repos/libports/recipes/src/qt6_shadertools/hash @@ -1 +1 @@ -2024-08-28 e98e7e2011e1e979fd5819fcf7f7b80d4930bbc2 +2024-10-29 9c021e249534e1678973424a3d588fd46161e396 diff --git a/repos/libports/recipes/src/qt6_svg/hash b/repos/libports/recipes/src/qt6_svg/hash index 3359d21ee2..d8d3bba729 100644 --- a/repos/libports/recipes/src/qt6_svg/hash +++ b/repos/libports/recipes/src/qt6_svg/hash @@ -1 +1 @@ -2024-08-28 45e357c46696dc2ec3388afc48b4677ef4366bfa +2024-10-29 4bf29963a4548bdebe03e1d5460de5cfa8a9d295 diff --git a/repos/libports/recipes/src/qt6_testqstring/hash b/repos/libports/recipes/src/qt6_testqstring/hash index 929ea87cba..6e14b38de4 100644 --- a/repos/libports/recipes/src/qt6_testqstring/hash +++ b/repos/libports/recipes/src/qt6_testqstring/hash @@ -1 +1 @@ -2024-08-28 561246d5cd69b8691a41a9eb818e549c3d5a5c01 +2024-10-29 61ff70fdb603b68d553c3bb9d92fbe8170413a85 diff --git a/repos/libports/recipes/src/qt6_tetrix/hash b/repos/libports/recipes/src/qt6_tetrix/hash index c7dd10e14c..35c576449f 100644 --- a/repos/libports/recipes/src/qt6_tetrix/hash +++ b/repos/libports/recipes/src/qt6_tetrix/hash @@ -1 +1 @@ -2024-08-28 9bcac492dc4f5cfc0345a8d47b9d2005c51eee70 +2024-10-29 ac4ae126f0c6c08680f639837e00d6494effa6b1 diff --git a/repos/libports/recipes/src/qt6_textedit/hash b/repos/libports/recipes/src/qt6_textedit/hash index a92193c8d4..46df5cc1cc 100644 --- a/repos/libports/recipes/src/qt6_textedit/hash +++ b/repos/libports/recipes/src/qt6_textedit/hash @@ -1 +1 @@ -2024-08-28 9378e8bbed51f267817e3ca711e7cd9aedccd009 +2024-10-29 4d1e5c1c5ddb554668b84168265c2e43356676ab diff --git a/repos/libports/recipes/src/sanitizer/hash b/repos/libports/recipes/src/sanitizer/hash index 254d7c4d17..c2cd610a49 100644 --- a/repos/libports/recipes/src/sanitizer/hash +++ b/repos/libports/recipes/src/sanitizer/hash @@ -1 +1 @@ -2024-08-28 e9e915021361f201538bc5d79fc6b80724d8b3a2 +2024-10-07 400fdfc44443c8e2c838b776900dd1f3302e9325 diff --git a/repos/libports/recipes/src/sntp_client/hash b/repos/libports/recipes/src/sntp_client/hash index 6b53659f09..eb59b4bc68 100644 --- a/repos/libports/recipes/src/sntp_client/hash +++ b/repos/libports/recipes/src/sntp_client/hash @@ -1 +1 @@ -2024-08-28 c7e8afbe657f6965c941f78e954c2c925d6b8473 +2024-10-07 cff72e6d31f9179e4d7f2385189bcf92b2a0e1eb diff --git a/repos/libports/recipes/src/spark/hash b/repos/libports/recipes/src/spark/hash index 92d7aaadfb..e5069dbdd8 100644 --- a/repos/libports/recipes/src/spark/hash +++ b/repos/libports/recipes/src/spark/hash @@ -1 +1 @@ -2024-08-28 8d353d12452bbfced681db40b0a6196decc0ddea +2024-10-07 60c65f1960b9fd6a625be1a8d3e9649d11af95e8 diff --git a/repos/libports/recipes/src/stdcxx/hash b/repos/libports/recipes/src/stdcxx/hash index 039067e160..2693a5b727 100644 --- a/repos/libports/recipes/src/stdcxx/hash +++ b/repos/libports/recipes/src/stdcxx/hash @@ -1 +1 @@ -2024-08-28 8d5731b1a5a6ddb256a2220969507b42f15f1b00 +2024-10-07 46226d58601558a46f1d58536f17729cfab63f2a diff --git a/repos/libports/recipes/src/stdin2out/hash b/repos/libports/recipes/src/stdin2out/hash index bb9e94b8a6..1ec2c36d82 100644 --- a/repos/libports/recipes/src/stdin2out/hash +++ b/repos/libports/recipes/src/stdin2out/hash @@ -1 +1 @@ -2024-08-28 a5c319bf73cb3b64b55a1fbc41b18aa06ba3767e +2024-10-07 932abf85634fdce9e09f710134df9d737ad9325c diff --git a/repos/libports/recipes/src/system_rtc/hash b/repos/libports/recipes/src/system_rtc/hash index 24837fb616..a11ffe2193 100644 --- a/repos/libports/recipes/src/system_rtc/hash +++ b/repos/libports/recipes/src/system_rtc/hash @@ -1 +1 @@ -2024-08-28 0da33fc21f63b90043ef541d88244d1f22d16fb9 +2024-10-07 afe6c2158e342f80c5769d7bfe62d12c8c23ef7d diff --git a/repos/libports/recipes/src/test-expat/hash b/repos/libports/recipes/src/test-expat/hash index 31f78b3e08..f456c26fb8 100644 --- a/repos/libports/recipes/src/test-expat/hash +++ b/repos/libports/recipes/src/test-expat/hash @@ -1 +1 @@ -2024-08-28 3219f82afe78a4af9e257db0f2e3b78d0f5a3d4d +2024-10-07 83ff28285252bbe3774df491d56978848f8aa228 diff --git a/repos/libports/recipes/src/test-ldso/hash b/repos/libports/recipes/src/test-ldso/hash index c4fd6ad57d..609edab5b0 100644 --- a/repos/libports/recipes/src/test-ldso/hash +++ b/repos/libports/recipes/src/test-ldso/hash @@ -1 +1 @@ -2024-08-28 6d00f0f00f2ee77a25c55a904a31612023e255c9 +2024-10-07 42cd1af54ba9c3733bd9ab75ff46a878f059e3eb diff --git a/repos/libports/recipes/src/test-libc/hash b/repos/libports/recipes/src/test-libc/hash index 9f0ac6856d..1b7e69efcc 100644 --- a/repos/libports/recipes/src/test-libc/hash +++ b/repos/libports/recipes/src/test-libc/hash @@ -1 +1 @@ -2024-08-28 37b9a30f9a5947013e1403620d1bf6c6b5f9b215 +2024-10-07 e45926149c319d2c116581c1891f726e5f70fa71 diff --git a/repos/libports/recipes/src/test-libc_alarm/content.mk b/repos/libports/recipes/src/test-libc_alarm/content.mk new file mode 100644 index 0000000000..7a6c4ee906 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_alarm/content.mk @@ -0,0 +1,2 @@ +SRC_DIR := src/test/libc_alarm +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/libports/recipes/src/test-libc_alarm/hash b/repos/libports/recipes/src/test-libc_alarm/hash new file mode 100644 index 0000000000..8e220addba --- /dev/null +++ b/repos/libports/recipes/src/test-libc_alarm/hash @@ -0,0 +1 @@ +2024-10-07 b201decd115dad41908d5141d0b96d4f043c0773 diff --git a/repos/libports/recipes/src/test-libc_alarm/used_apis b/repos/libports/recipes/src/test-libc_alarm/used_apis new file mode 100644 index 0000000000..0c483273a8 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_alarm/used_apis @@ -0,0 +1,2 @@ +libc +posix diff --git a/repos/libports/recipes/src/test-libc_connect/hash b/repos/libports/recipes/src/test-libc_connect/hash index 805eef815c..311a24da6b 100644 --- a/repos/libports/recipes/src/test-libc_connect/hash +++ b/repos/libports/recipes/src/test-libc_connect/hash @@ -1 +1 @@ -2024-08-28 d51cfa933a25c73534e8b8626c90e973aa898e50 +2024-10-07 c548d9a82d3ee0bdd029611810e3170512cc9942 diff --git a/repos/libports/recipes/src/test-libc_counter/hash b/repos/libports/recipes/src/test-libc_counter/hash index 834ee0e500..bd7acf08ec 100644 --- a/repos/libports/recipes/src/test-libc_counter/hash +++ b/repos/libports/recipes/src/test-libc_counter/hash @@ -1 +1 @@ -2024-08-28 1fff853bb417793299613c096e7e094570f18034 +2024-10-07 cd07c7ff14217dbcaf32d143cb4f1cbc78fe26c6 diff --git a/repos/libports/recipes/src/test-libc_deferred_unlink/hash b/repos/libports/recipes/src/test-libc_deferred_unlink/hash index f225da861d..549b126bde 100644 --- a/repos/libports/recipes/src/test-libc_deferred_unlink/hash +++ b/repos/libports/recipes/src/test-libc_deferred_unlink/hash @@ -1 +1 @@ -2024-08-28 6b594fb196de81a4b931541d1291539dda1f9df9 +2024-10-07 bff421de28692d4f156c8750f1ae81a3f99be6ba diff --git a/repos/libports/recipes/src/test-libc_execve/hash b/repos/libports/recipes/src/test-libc_execve/hash index 49aa8a9e13..8f8fbc0bc6 100644 --- a/repos/libports/recipes/src/test-libc_execve/hash +++ b/repos/libports/recipes/src/test-libc_execve/hash @@ -1 +1 @@ -2024-08-28 602122954be26a9012f020add6a61cf341294153 +2024-10-07 ae596c3763cf4817987b2886dee19eeceaf7acd1 diff --git a/repos/libports/recipes/src/test-libc_fifo_pipe/hash b/repos/libports/recipes/src/test-libc_fifo_pipe/hash index 136b0969a6..a74dd46fda 100644 --- a/repos/libports/recipes/src/test-libc_fifo_pipe/hash +++ b/repos/libports/recipes/src/test-libc_fifo_pipe/hash @@ -1 +1 @@ -2024-08-28 93a752c4eb40a39262df598a43cedd72de8af7fc +2024-10-07 ac0f212ff44df1c58a89031d9f2aba790e7ab84a diff --git a/repos/libports/recipes/src/test-libc_fork/hash b/repos/libports/recipes/src/test-libc_fork/hash index 40331521d3..601dc65a81 100644 --- a/repos/libports/recipes/src/test-libc_fork/hash +++ b/repos/libports/recipes/src/test-libc_fork/hash @@ -1 +1 @@ -2024-08-28 d9acdc150e8d4d5af47e0e8af72fc7c26a3e802e +2024-10-07 328a83ac2b7ca0ff851a9fda4cd3ebfd278b31fd diff --git a/repos/libports/recipes/src/test-libc_getenv/hash b/repos/libports/recipes/src/test-libc_getenv/hash index d63129c844..8f851c777c 100644 --- a/repos/libports/recipes/src/test-libc_getenv/hash +++ b/repos/libports/recipes/src/test-libc_getenv/hash @@ -1 +1 @@ -2024-08-28 bb880d061f08582b1cbafc61733393f0819b0dce +2024-10-07 6a8be8b83fe469f5651f555f13ac7c72910f0d8a diff --git a/repos/libports/recipes/src/test-libc_kqueue/content.mk b/repos/libports/recipes/src/test-libc_kqueue/content.mk new file mode 100644 index 0000000000..8fcda74a85 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_kqueue/content.mk @@ -0,0 +1,2 @@ +SRC_DIR := src/test/libc_kqueue +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/libports/recipes/src/test-libc_kqueue/hash b/repos/libports/recipes/src/test-libc_kqueue/hash new file mode 100644 index 0000000000..742b0f64d4 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_kqueue/hash @@ -0,0 +1 @@ +2024-10-07 0ca19f64e8a503dbd0c2161001694d3494b03e09 diff --git a/repos/libports/recipes/src/test-libc_kqueue/used_apis b/repos/libports/recipes/src/test-libc_kqueue/used_apis new file mode 100644 index 0000000000..0c483273a8 --- /dev/null +++ b/repos/libports/recipes/src/test-libc_kqueue/used_apis @@ -0,0 +1,2 @@ +libc +posix diff --git a/repos/libports/recipes/src/test-libc_pipe/hash b/repos/libports/recipes/src/test-libc_pipe/hash index 38a5ccdd1f..78a541d5d2 100644 --- a/repos/libports/recipes/src/test-libc_pipe/hash +++ b/repos/libports/recipes/src/test-libc_pipe/hash @@ -1 +1 @@ -2024-08-28 0f22c978023497292a10934052747b15c75a6263 +2024-10-07 c18775f774b4385ee73949342d1231c46f87cfdb diff --git a/repos/libports/recipes/src/test-libc_vfs/hash b/repos/libports/recipes/src/test-libc_vfs/hash index 98f70ed20d..467b770215 100644 --- a/repos/libports/recipes/src/test-libc_vfs/hash +++ b/repos/libports/recipes/src/test-libc_vfs/hash @@ -1 +1 @@ -2024-08-28 93209476f2569b7a77c82d81aafd99d59675d22f +2024-10-07 847b7e168b88c346136a07e129dac21c2dc24f58 diff --git a/repos/libports/recipes/src/test-libc_vfs_block/hash b/repos/libports/recipes/src/test-libc_vfs_block/hash index 0e29b33c98..cfa2c7ef84 100644 --- a/repos/libports/recipes/src/test-libc_vfs_block/hash +++ b/repos/libports/recipes/src/test-libc_vfs_block/hash @@ -1 +1 @@ -2024-08-28 0afcdc23ec3686d4c51360c33ba218f0d0fa1894 +2024-10-07 2708fffa7f62cae67ecc506a28d398763e83e059 diff --git a/repos/libports/recipes/src/test-libc_vfs_oss/hash b/repos/libports/recipes/src/test-libc_vfs_oss/hash index acecbfe856..c9a034d899 100644 --- a/repos/libports/recipes/src/test-libc_vfs_oss/hash +++ b/repos/libports/recipes/src/test-libc_vfs_oss/hash @@ -1 +1 @@ -2024-08-28 36a9e08636a3d9526bcff4a121bbd51d4300d860 +2024-10-07 c0e01c11b02d101074a4045758eacac152351106 diff --git a/repos/libports/recipes/src/test-netty/hash b/repos/libports/recipes/src/test-netty/hash index 7f41c530ab..f235c41a23 100644 --- a/repos/libports/recipes/src/test-netty/hash +++ b/repos/libports/recipes/src/test-netty/hash @@ -1 +1 @@ -2024-08-28 8841096d77f101d480719445c1d7dbd4c36fb34f +2024-10-07 674f97807bdff196246309a015d2e146f4ba69db diff --git a/repos/libports/recipes/src/test-pipe_read_ready/hash b/repos/libports/recipes/src/test-pipe_read_ready/hash index 4327b487f3..781820906c 100644 --- a/repos/libports/recipes/src/test-pipe_read_ready/hash +++ b/repos/libports/recipes/src/test-pipe_read_ready/hash @@ -1 +1 @@ -2024-08-28 c813c7fa864963d61a1f2c232bec466c42c1d60e +2024-10-07 ce434b2161931420eb66f72af0167e805b56679c diff --git a/repos/libports/recipes/src/test-pthread/hash b/repos/libports/recipes/src/test-pthread/hash index 744372ca9c..550ded54f8 100644 --- a/repos/libports/recipes/src/test-pthread/hash +++ b/repos/libports/recipes/src/test-pthread/hash @@ -1 +1 @@ -2024-08-28 41e0b42e078068abba71f0d3ee4f71a0ea78634f +2024-10-07 8eb45881c178ef6f9dc7e71dcd34cd8b6235da35 diff --git a/repos/libports/recipes/src/test-qt6_core/hash b/repos/libports/recipes/src/test-qt6_core/hash index d6dfc0e5c8..bc2e99d061 100644 --- a/repos/libports/recipes/src/test-qt6_core/hash +++ b/repos/libports/recipes/src/test-qt6_core/hash @@ -1 +1 @@ -2024-08-28 85800112501dcda7392b8f56879433615b1cf77f +2024-10-29 8b17045ceb3329dba427d4b6f4ec093ddc4958a0 diff --git a/repos/libports/recipes/src/test-qt6_core_cmake/hash b/repos/libports/recipes/src/test-qt6_core_cmake/hash index 13fb091b06..26ec4064a6 100644 --- a/repos/libports/recipes/src/test-qt6_core_cmake/hash +++ b/repos/libports/recipes/src/test-qt6_core_cmake/hash @@ -1 +1 @@ -2024-08-28 c1f6148ab6f1ce8988647d3b2e1262f93286af15 +2024-10-29 0fefe06c18f6ed8b1b1bf733ac64fc6a9df8381e diff --git a/repos/libports/recipes/src/test-qt6_quick/hash b/repos/libports/recipes/src/test-qt6_quick/hash index eb99303c7d..969b5dc8d1 100644 --- a/repos/libports/recipes/src/test-qt6_quick/hash +++ b/repos/libports/recipes/src/test-qt6_quick/hash @@ -1 +1 @@ -2024-08-28 165f99d428b45639421aeb497314968ed6eb06a0 +2024-10-29 4a75632c210cfc4d49ea73f01b70c1450fd64544 diff --git a/repos/libports/recipes/src/test-qt_core/hash b/repos/libports/recipes/src/test-qt_core/hash index 4c077ba41e..2acbed7d0c 100644 --- a/repos/libports/recipes/src/test-qt_core/hash +++ b/repos/libports/recipes/src/test-qt_core/hash @@ -1 +1 @@ -2024-08-28 332930a41be535701acb76f68359b08e818996f5 +2024-10-29 7a6a496c8d994500aaa45a66846f54411518404b diff --git a/repos/libports/recipes/src/test-qt_core_cmake/hash b/repos/libports/recipes/src/test-qt_core_cmake/hash index 02c4823461..d0b2c099a8 100644 --- a/repos/libports/recipes/src/test-qt_core_cmake/hash +++ b/repos/libports/recipes/src/test-qt_core_cmake/hash @@ -1 +1 @@ -2024-08-28 cd7db522526ea50116d7d429d27910621d92025d +2024-10-29 163f6e7b0ff93dff10e90f7181c8b8b43a05bd07 diff --git a/repos/libports/recipes/src/test-qt_quick/hash b/repos/libports/recipes/src/test-qt_quick/hash index d6118c65eb..dbd71f0302 100644 --- a/repos/libports/recipes/src/test-qt_quick/hash +++ b/repos/libports/recipes/src/test-qt_quick/hash @@ -1 +1 @@ -2024-08-28 c69777fa3176382fbebfda827a2286cdba9fea4c +2024-10-29 ee0652f9f7acc5b8c5481f02c19523ad03b54238 diff --git a/repos/libports/recipes/src/test-spark/hash b/repos/libports/recipes/src/test-spark/hash index 2ca869c6e3..99f40fef88 100644 --- a/repos/libports/recipes/src/test-spark/hash +++ b/repos/libports/recipes/src/test-spark/hash @@ -1 +1 @@ -2024-08-28 5bdb1816b76b49960e355d4ff5e2bf16a14ea3ef +2024-10-07 1b81dcaecfa1791987fd6cb530043806011ae59c diff --git a/repos/libports/recipes/src/test-spark_exception/hash b/repos/libports/recipes/src/test-spark_exception/hash index 8185beb71b..13ca74bb95 100644 --- a/repos/libports/recipes/src/test-spark_exception/hash +++ b/repos/libports/recipes/src/test-spark_exception/hash @@ -1 +1 @@ -2024-08-28 a7de8e483e42ecd1a9e2b279b0d61e6d57b5aae8 +2024-10-07 7bf0c4de6a88556d5c8fefdd384811b5980b0ab9 diff --git a/repos/libports/recipes/src/test-spark_secondary_stack/hash b/repos/libports/recipes/src/test-spark_secondary_stack/hash index 96711934b6..7182463d52 100644 --- a/repos/libports/recipes/src/test-spark_secondary_stack/hash +++ b/repos/libports/recipes/src/test-spark_secondary_stack/hash @@ -1 +1 @@ -2024-08-28 57cc4a8caea44a07bcf82c62f36e1ec0ef5dbc68 +2024-10-07 e2ee92666491441f616a4125cfb4b3b21cb0bf68 diff --git a/repos/libports/recipes/src/test-stdcxx/hash b/repos/libports/recipes/src/test-stdcxx/hash index 7d5e8f8fa2..02d3cb1110 100644 --- a/repos/libports/recipes/src/test-stdcxx/hash +++ b/repos/libports/recipes/src/test-stdcxx/hash @@ -1 +1 @@ -2024-08-28 ef091c54902279fd677c5b7713fd2d66e302dcfc +2024-10-07 1ed13680965bc23094a8d1fc51b5bf304a240d42 diff --git a/repos/libports/recipes/src/test-tcp/hash b/repos/libports/recipes/src/test-tcp/hash index 3d32b3b3d3..4140ae1626 100644 --- a/repos/libports/recipes/src/test-tcp/hash +++ b/repos/libports/recipes/src/test-tcp/hash @@ -1 +1 @@ -2024-08-28 8f8473c640cd2d459def368e2a33f0f107d7146b +2024-10-07 8df87228617c9264ca083ab189ccd29c047e31df diff --git a/repos/libports/recipes/src/usb_webcam/hash b/repos/libports/recipes/src/usb_webcam/hash index d5ca11af04..b4d2e8bbe4 100644 --- a/repos/libports/recipes/src/usb_webcam/hash +++ b/repos/libports/recipes/src/usb_webcam/hash @@ -1 +1 @@ -2024-08-28 65ba8ddf35e5007ae4ff399b6ff1fcb98c196652 +2024-10-29 9275c1c6a134dbde70058bcda993a4495c6c2860 diff --git a/repos/libports/recipes/src/vesa_fb/hash b/repos/libports/recipes/src/vesa_fb/hash index f715ed762f..ac586eda4e 100644 --- a/repos/libports/recipes/src/vesa_fb/hash +++ b/repos/libports/recipes/src/vesa_fb/hash @@ -1 +1 @@ -2024-08-28 9eec382e10dad329e2ddddb86f5f983b9362725a +2024-10-07 293c91a0e3aa005a5292d2bb7b9ce89fc4262b1e diff --git a/repos/libports/recipes/src/vfs_fatfs/hash b/repos/libports/recipes/src/vfs_fatfs/hash index 14934bdc03..107af35c92 100644 --- a/repos/libports/recipes/src/vfs_fatfs/hash +++ b/repos/libports/recipes/src/vfs_fatfs/hash @@ -1 +1 @@ -2024-08-28 bf8fed48bd8a75b76cbf35367cc2bd5b1f49a387 +2024-10-07 5f1d9932ddb67a5ab0692972d1e798833de0e8ab diff --git a/repos/libports/recipes/src/vfs_jitterentropy/hash b/repos/libports/recipes/src/vfs_jitterentropy/hash index ac86af1fc3..49bd950795 100644 --- a/repos/libports/recipes/src/vfs_jitterentropy/hash +++ b/repos/libports/recipes/src/vfs_jitterentropy/hash @@ -1 +1 @@ -2024-08-28 19324aabab5bfcc7b4dec4829282222171bd902e +2024-10-07 c8dce10877e5e54f187def95ec386467954513f3 diff --git a/repos/libports/recipes/src/vfs_legacy_oss/hash b/repos/libports/recipes/src/vfs_legacy_oss/hash index 186baff6d4..ab62c51114 100644 --- a/repos/libports/recipes/src/vfs_legacy_oss/hash +++ b/repos/libports/recipes/src/vfs_legacy_oss/hash @@ -1 +1 @@ -2024-08-28 7d3bfe2dd83c39e4035464c4d9c3c7cbc19aef14 +2024-11-04 a97cc8af9f67f6375f56a316f668c531c794ebcc diff --git a/repos/libports/recipes/src/vfs_libusb/hash b/repos/libports/recipes/src/vfs_libusb/hash index 45f6fa1e18..2daf342b02 100644 --- a/repos/libports/recipes/src/vfs_libusb/hash +++ b/repos/libports/recipes/src/vfs_libusb/hash @@ -1 +1 @@ -2024-08-28 5b199be66b9fde6157c0d19c670898ad54013996 +2024-10-07 3b8019c38c00e1aad94858e4556cadd294c14840 diff --git a/repos/libports/recipes/src/vfs_lwip/hash b/repos/libports/recipes/src/vfs_lwip/hash index 15cbf272f5..296f21b0d1 100644 --- a/repos/libports/recipes/src/vfs_lwip/hash +++ b/repos/libports/recipes/src/vfs_lwip/hash @@ -1 +1 @@ -2024-08-28 bc83e71ddb8dbb52eb648cc3cad07fca45428bcd +2024-10-07 65f4c29a9ba1912625cb5aa8c2c4696e5907f89e diff --git a/repos/libports/recipes/src/zlib/hash b/repos/libports/recipes/src/zlib/hash index c43d08a6e5..a2156ae330 100644 --- a/repos/libports/recipes/src/zlib/hash +++ b/repos/libports/recipes/src/zlib/hash @@ -1 +1 @@ -2024-08-28 12afd01f1bbea9ad8e1f938fe2ab9b4bebb4ab98 +2024-10-07 22198d72e84cdfab5f45815589334c1d34e3ea4e diff --git a/repos/libports/run/mupdf.run b/repos/libports/run/mupdf.run index f6afdc976f..0fd33d44e7 100644 --- a/repos/libports/run/mupdf.run +++ b/repos/libports/run/mupdf.run @@ -1,6 +1,6 @@ build { - lib/libc lib/vfs lib/openjpeg lib/freetype lib/libpng lib/zlib lib/jbig2dec - lib/mupdf lib/jpeg app/pdf_view + lib/libc lib/libm lib/vfs lib/openjpeg lib/freetype lib/libpng lib/zlib + lib/jbig2dec lib/mupdf lib/jpeg app/pdf_view } create_boot_directory diff --git a/repos/libports/run/qt5_common.inc b/repos/libports/run/qt5_common.inc index cc8cda7f3e..873f78a5f4 100644 --- a/repos/libports/run/qt5_common.inc +++ b/repos/libports/run/qt5_common.inc @@ -286,7 +286,7 @@ proc qt5_start_nodes { } { </route> </start> - <start name="layouter"> + <start name="layouter" caps="150"> <binary name="window_layouter"/> <resource name="RAM" quantum="4M"/>} [qt5_layouter_config] { <route> diff --git a/repos/libports/run/qt5_quicktest.run b/repos/libports/run/qt5_quicktest.run index c3daf9def6..24f2ef0922 100644 --- a/repos/libports/run/qt5_quicktest.run +++ b/repos/libports/run/qt5_quicktest.run @@ -14,7 +14,7 @@ install_config { <any-service> <parent/> <any-child/> </any-service> </default-route> } [qt5_start_nodes] { - <start name="test-qt_quick" caps="250"> + <start name="test-qt_quick" caps="300"> <resource name="RAM" quantum="80M"/> <config> <vfs> diff --git a/repos/libports/run/qt5_samegame.run b/repos/libports/run/qt5_samegame.run index 04f59d1f93..27a68825c3 100644 --- a/repos/libports/run/qt5_samegame.run +++ b/repos/libports/run/qt5_samegame.run @@ -15,7 +15,7 @@ install_config { <any-service> <parent/> <any-child/> </any-service> </default-route> } [qt5_start_nodes] { - <start name="samegame" caps="350"> + <start name="samegame" caps="400"> <resource name="RAM" quantum="128M"/> <config> <vfs> diff --git a/repos/libports/run/qt5_textedit.run b/repos/libports/run/qt5_textedit.run index 80f437ecdf..b7b471ae6a 100644 --- a/repos/libports/run/qt5_textedit.run +++ b/repos/libports/run/qt5_textedit.run @@ -25,7 +25,7 @@ install_config { <policy label_prefix="textedit2" root="/" writeable="yes" /> </config> </start> - <start name="textedit" caps="300"> + <start name="textedit" caps="350"> <resource name="RAM" quantum="70M"/> <config> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> @@ -49,7 +49,7 @@ install_config { <any-service> <parent /> <any-child/> </any-service> </route> </start> - <start name="textedit2" caps="300"> + <start name="textedit2" caps="350"> <binary name="textedit" /> <resource name="RAM" quantum="70M"/> <config> diff --git a/repos/libports/run/qt5_virtualkeyboard.run b/repos/libports/run/qt5_virtualkeyboard.run index 9010d498ef..bb86dbc53d 100644 --- a/repos/libports/run/qt5_virtualkeyboard.run +++ b/repos/libports/run/qt5_virtualkeyboard.run @@ -17,7 +17,7 @@ install_config { <any-service> <parent/> <child name="wm"/> <any-child/> </any-service> </default-route> } [qt5_start_nodes] { - <start name="basic" caps="450"> + <start name="basic" caps="500"> <resource name="RAM" quantum="100M"/> <config> <vfs> diff --git a/repos/libports/run/qt6_common.inc b/repos/libports/run/qt6_common.inc index b30cfb9919..10319b5f16 100644 --- a/repos/libports/run/qt6_common.inc +++ b/repos/libports/run/qt6_common.inc @@ -286,7 +286,7 @@ proc qt6_start_nodes { } { </route> </start> - <start name="layouter"> + <start name="layouter" caps="150"> <binary name="window_layouter"/> <resource name="RAM" quantum="4M"/>} [qt6_layouter_config] { <route> diff --git a/repos/libports/run/qt6_textedit.run b/repos/libports/run/qt6_textedit.run index 0a4aef9b99..b187021345 100644 --- a/repos/libports/run/qt6_textedit.run +++ b/repos/libports/run/qt6_textedit.run @@ -25,7 +25,7 @@ install_config { <policy label_prefix="textedit2" root="/" writeable="yes" /> </config> </start> - <start name="textedit" caps="300"> + <start name="textedit" caps="350"> <resource name="RAM" quantum="70M"/> <config> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> @@ -49,7 +49,7 @@ install_config { <any-service> <parent /> <any-child/> </any-service> </route> </start> - <start name="textedit2" caps="300"> + <start name="textedit2" caps="350"> <binary name="textedit" /> <resource name="RAM" quantum="70M"/> <config> diff --git a/repos/libports/run/webcam.inc b/repos/libports/run/webcam.inc index 53f312642e..ea3ec65a76 100644 --- a/repos/libports/run/webcam.inc +++ b/repos/libports/run/webcam.inc @@ -199,7 +199,7 @@ append config { </route> </start> - <start name="webcam" priority="-1" caps="800"> + <start name="webcam" priority="-1" caps="900"> <binary name="init"/> <resource name="RAM" quantum="64M"/> <route> diff --git a/repos/libports/src/app/pdf_view/main.cc b/repos/libports/src/app/pdf_view/main.cc index 904a47183d..f9a456474a 100644 --- a/repos/libports/src/app/pdf_view/main.cc +++ b/repos/libports/src/app/pdf_view/main.cc @@ -87,22 +87,25 @@ class Pdf_view private: - enum { NO_ALPHA = false }; - Genode::Env &_env; Gui::Connection _gui { _env }; - Framebuffer::Mode _nit_mode = _gui.mode(); - Framebuffer::Mode _fb_mode {}; + Gui::Rect _gui_window() + { + return _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 512, 512 } }; }); + } + + Gui::Rect _win_rect = _gui_window(); + + Framebuffer::Mode _fb_mode {}; Genode::Constructible<Genode::Attached_dataspace> _fb_ds { }; - Genode::Signal_handler<Pdf_view> _nit_mode_handler { - _env.ep(), *this, &Pdf_view::_handle_nit_mode }; - - Genode::Signal_handler<Pdf_view> _sync_handler { - _env.ep(), *this, &Pdf_view::_refresh }; + Genode::Signal_handler<Pdf_view> _gui_mode_handler { + _env.ep(), *this, &Pdf_view::_handle_gui_mode }; Genode::Signal_handler<Pdf_view> _input_handler { _env.ep(), *this, &Pdf_view::_handle_input_events }; @@ -115,21 +118,21 @@ class Pdf_view { using namespace Gui; - _nit_mode = _gui.mode(); + _win_rect = _gui_window(); - unsigned max_x = Genode::max(_nit_mode.area.w, _fb_mode.area.w); - unsigned max_y = Genode::max(_nit_mode.area.h, _fb_mode.area.h); + unsigned max_x = Genode::max(_win_rect.area.w, _fb_mode.area.w); + unsigned max_y = Genode::max(_win_rect.area.h, _fb_mode.area.h); if (max_x > _fb_mode.area.w || max_y > _fb_mode.area.h) { - _fb_mode = Mode { .area = { max_x, max_y } }; - _gui.buffer(_fb_mode, NO_ALPHA); + _fb_mode = Mode { .area = { max_x, max_y }, .alpha = false }; + _gui.buffer(_fb_mode); if (_fb_ds.constructed()) _fb_ds.destruct(); _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); } - _pdfapp.scrw = _nit_mode.area.w; - _pdfapp.scrh = _nit_mode.area.h; + _pdfapp.scrw = _win_rect.area.w; + _pdfapp.scrh = _win_rect.area.h; /* * XXX replace heuristics with a meaningful computation @@ -137,17 +140,17 @@ class Pdf_view * The magic values are hand-tweaked manually to accommodating the * use case of showing slides. */ - _pdfapp.resolution = Genode::min(_nit_mode.area.w/5, - _nit_mode.area.h/4); + _pdfapp.resolution = Genode::min(_win_rect.area.w/5, + _win_rect.area.h/4); - _view.area(_nit_mode.area); + _view.area(_win_rect.area); _view.front(); } - void _handle_nit_mode() + void _handle_gui_mode() { _rebuffer(); - pdfapp_onresize(&_pdfapp, _nit_mode.area.w, _nit_mode.area.h); + pdfapp_onresize(&_pdfapp, _win_rect.area.w, _win_rect.area.h); } pdfapp_t _pdfapp { }; @@ -213,14 +216,6 @@ class Pdf_view _handle_input_event(ev); }); }); } - void _refresh() - { - _gui.framebuffer.refresh(0, 0, _nit_mode.area.w, _nit_mode.area.h); - - /* handle one sync signal only */ - _gui.framebuffer.sync_sigh(Genode::Signal_context_capability()); - } - public: /** @@ -231,7 +226,7 @@ class Pdf_view */ Pdf_view(Genode::Env &env) : _env(env) { - _gui.mode_sigh(_nit_mode_handler); + _gui.info_sigh(_gui_mode_handler); _gui.input.sigh(_input_handler); pdfapp_init(&_pdfapp); @@ -304,12 +299,12 @@ void Pdf_view::show() int const tweaked_y_max = y_max - 2; /* center vertically if the dst buffer is higher than the image */ - if ((unsigned)_pdfapp.image->h < _nit_mode.area.h) - dst_line += dst_line_width*((_nit_mode.area.h - _pdfapp.image->h)/2); + if ((unsigned)_pdfapp.image->h < _win_rect.area.h) + dst_line += dst_line_width*((_win_rect.area.h - _pdfapp.image->h)/2); /* center horizontally if the dst buffer is wider than the image */ - if ((unsigned)_pdfapp.image->w < _nit_mode.area.w) - dst_line += (_nit_mode.area.w - _pdfapp.image->w)/2; + if ((unsigned)_pdfapp.image->w < _win_rect.area.w) + dst_line += (_win_rect.area.w - _pdfapp.image->w)/2; for (int y = 0; y < tweaked_y_max; y++) { copy_line_rgba(src_line, dst_line, x_max); @@ -317,8 +312,7 @@ void Pdf_view::show() dst_line += dst_line_width; } - /* refresh after the next sync signal */ - _gui.framebuffer.sync_sigh(_sync_handler); + _gui.framebuffer.refresh({ { 0, 0 }, _win_rect.area }); } diff --git a/repos/libports/src/app/usb_webcam/main.cc b/repos/libports/src/app/usb_webcam/main.cc index 97ea891001..19e15050a2 100644 --- a/repos/libports/src/app/usb_webcam/main.cc +++ b/repos/libports/src/app/usb_webcam/main.cc @@ -19,6 +19,7 @@ #include <base/log.h> #include <gui_session/connection.h> #include <libc/component.h> +#include <libc/args.h> #include <os/pixel_rgb888.h> #pragma GCC diagnostic push @@ -61,7 +62,7 @@ class Viewer _env { env }, _mode { mode } { - _gui.buffer(mode, false); + _gui.buffer(mode); _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); _framebuffer = _fb_ds->local_addr<uint8_t>(); @@ -69,9 +70,7 @@ class Viewer uint8_t *framebuffer() { return _framebuffer; } - void refresh() { - _gui.framebuffer.refresh(0, 0, _mode.area.w, _mode.area.h); - } + void refresh() { _gui.framebuffer.refresh({ { 0, 0 }, _mode.area }); } Framebuffer::Mode const &mode() { return _mode; } }; @@ -277,10 +276,10 @@ class Main if (_webcam.constructed()) _webcam.destruct(); + Framebuffer::Mode mode { .area = { width, height }, .alpha = false }; if (enabled) { try { - _webcam.construct(_env, Framebuffer::Mode { - .area = { width, height } }, frame_format, fps); + _webcam.construct(_env, mode, frame_format, fps); } catch (...) { } } } @@ -297,7 +296,17 @@ class Main }; +extern char **environ; + void Libc::Component::construct(Libc::Env &env) { + int argc = 0; + char **argv = nullptr; + char **envp = nullptr; + + populate_args_and_env(env, argc, argv, envp); + + environ = envp; + static Main main(env); } diff --git a/repos/libports/src/driver/framebuffer/vesa/main.cc b/repos/libports/src/driver/framebuffer/vesa/main.cc index e4dabc3f1a..cc6bf700f0 100644 --- a/repos/libports/src/driver/framebuffer/vesa/main.cc +++ b/repos/libports/src/driver/framebuffer/vesa/main.cc @@ -150,7 +150,11 @@ void Vesa_driver::Main::_handle_config() /* enable pixel capturing */ _fb_ds.construct(_env.rm(), Framebuffer::hw_framebuffer()); - _captured_screen.construct(_capture, _env.rm(), _size); + + using Attr = Capture::Connection::Screen::Attr; + _captured_screen.construct(_capture, _env.rm(), Attr { + .px = _size, + .mm = { } }); unsigned long const period_ms = config.attribute_value("period_ms", 20U); _timer.trigger_periodic(period_ms*1000); diff --git a/repos/libports/src/lib/libc/alarm.cc b/repos/libports/src/lib/libc/alarm.cc new file mode 100644 index 0000000000..250de9a3d6 --- /dev/null +++ b/repos/libports/src/lib/libc/alarm.cc @@ -0,0 +1,118 @@ +/* + * \brief Libc interval timer + * \author Norman Feske + * \date 2024-08-00 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* libc includes */ +#include <sys/time.h> + +/* libc-internal includes */ +#include <internal/signal.h> +#include <internal/timer.h> +#include <internal/init.h> +#include <internal/errno.h> + + +static Libc::Timer_accessor *_timer_accessor_ptr; +static Libc::Signal *_signal_ptr; + +void Libc::init_alarm(Timer_accessor &timer_accessor, Signal &signal) +{ + _timer_accessor_ptr = &timer_accessor; + _signal_ptr = &signal; +} + + +namespace Libc { struct Itimer_real; } + + +struct Libc::Itimer_real : Noncopyable +{ + struct Handler : Timeout_handler + { + Signal &_signal; + + virtual void handle_timeout() override { _signal.charge(SIGALRM); } + + Handler(Signal &signal) : _signal(signal) { } + + } _handler; + + Timer_accessor &_timer_accessor; + + Constructible<Timeout> _timeout { }; + + void arm_or_disarm(timeval tv) + { + Libc::uint64_t const ms = tv.tv_sec*1000 + tv.tv_usec/1000; + + if (ms) { + _timeout.construct(_timer_accessor, _handler); + _timeout->start(ms); + } else { + _timeout.destruct(); + } + } + + timeval current() + { + if (!_timeout.constructed()) + return { }; + + Libc::uint64_t const ms = _timeout->duration_left(); + + return { .tv_sec = long(ms/1000), + .tv_usec = long((ms % 1000)*1000) }; + } + + Itimer_real(Timer_accessor &timer_accessor, Signal &signal) + : + _handler(signal), _timer_accessor(timer_accessor) + { } +}; + + +using namespace Libc; + + +static Itimer_real &itimer_real() +{ + struct Missing_call_of_init_alarm : Exception { }; + if (!_timer_accessor_ptr || !_signal_ptr) + throw Missing_call_of_init_alarm(); + + static Itimer_real itimer { *_timer_accessor_ptr, *_signal_ptr }; + return itimer; +} + + +extern "C" int setitimer(int which, const itimerval *new_value, itimerval *old_value) +{ + if (which != ITIMER_REAL) { + warning("setitimer: timer %d unsupported"); + return Errno(EINVAL); + } + + if (!new_value) + return Errno(EFAULT); + + if (new_value->it_interval.tv_sec || new_value->it_interval.tv_usec) + warning("setitimer: argument 'new_value->it_interval' not handled"); + + if (old_value) { + old_value->it_interval = { }; + old_value->it_value = itimer_real().current(); + } + + itimer_real().arm_or_disarm(new_value->it_value); + + return 0; +} diff --git a/repos/libports/src/lib/libc/dummies.cc b/repos/libports/src/lib/libc/dummies.cc index 8d3606d5ac..1f55acbd58 100644 --- a/repos/libports/src/lib/libc/dummies.cc +++ b/repos/libports/src/lib/libc/dummies.cc @@ -141,7 +141,6 @@ DUMMY(int , -1, seteuid, (uid_t)) DUMMY(int , -1, setgid, (gid_t)) DUMMY(int , -1, setuid, (uid_t)) DUMMY(int , -1, setgroups, (int, const gid_t *)) -DUMMY(int , -1, setitimer, (int, const itimerval *, itimerval *)) DUMMY(int , -1, setpgid, (pid_t, pid_t)) DUMMY(int , -1, setpriority, (int, int, int)) DUMMY(int , -1, setregid, (gid_t, gid_t)) diff --git a/repos/libports/src/lib/libc/internal/init.h b/repos/libports/src/lib/libc/internal/init.h index 433ff7136c..405472a347 100644 --- a/repos/libports/src/lib/libc/internal/init.h +++ b/repos/libports/src/lib/libc/internal/init.h @@ -108,6 +108,7 @@ namespace Libc { */ void init_sleep(Monitor &); void init_time(Current_time &, Current_real_time &); + void init_alarm(Timer_accessor &, Signal &); /** * Socket fs @@ -155,6 +156,11 @@ namespace Libc { * Atexit handling */ void init_atexit(Atexit &); + + /** + * Kqueue support + */ + void init_kqueue(Genode::Allocator &, Monitor &); } #endif /* _LIBC__INTERNAL__INIT_H_ */ diff --git a/repos/libports/src/lib/libc/internal/kernel.h b/repos/libports/src/lib/libc/internal/kernel.h index 2b632a93c7..1261736495 100644 --- a/repos/libports/src/lib/libc/internal/kernel.h +++ b/repos/libports/src/lib/libc/internal/kernel.h @@ -17,6 +17,7 @@ #define _LIBC__INTERNAL__KERNEL_H_ /* base-internal includes */ +#include <util/reconstructible.h> #include <internal/call_func.h> /* libc includes */ @@ -584,6 +585,14 @@ struct Libc::Kernel final : Vfs::Read_ready_response_handler, } } + /** + * Monitor interface + */ + void monitor_async(Job &job) override + { + _monitors.monitor_async(job); + } + void _trigger_monitor_examination() override { if (_main_context()) diff --git a/repos/libports/src/lib/libc/internal/kqueue.h b/repos/libports/src/lib/libc/internal/kqueue.h new file mode 100644 index 0000000000..715cc22dd7 --- /dev/null +++ b/repos/libports/src/lib/libc/internal/kqueue.h @@ -0,0 +1,40 @@ +/* + * \brief kqueue plugin interface + * \author Benjamin Lamowski + * \date 2024-08-07 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__KQUEUE_H_ +#define _LIBC__INTERNAL__KQUEUE_H_ + +/* Libc includes */ +#include <sys/event.h> + +#include <base/allocator.h> +#include <internal/plugin.h> + +namespace Libc { class Kqueue_plugin; } + + +class Libc::Kqueue_plugin : public Libc::Plugin +{ + private: + + Genode::Allocator & _alloc; + + public: + + Kqueue_plugin(Genode::Allocator & alloc) : _alloc(alloc) { } + + int create_kqueue(); + int close(File_descriptor *) override; +}; + +#endif /* _LIBC__INTERNAL__KQUEUE_H_ */ diff --git a/repos/libports/src/lib/libc/internal/monitor.h b/repos/libports/src/lib/libc/internal/monitor.h index 228ea0f8cf..ac6cef1207 100644 --- a/repos/libports/src/lib/libc/internal/monitor.h +++ b/repos/libports/src/lib/libc/internal/monitor.h @@ -17,6 +17,7 @@ /* Genode includes */ #include <base/registry.h> +#include <util/reconstructible.h> /* libc-internal includes */ #include <internal/types.h> @@ -82,6 +83,13 @@ class Libc::Monitor : Interface return _monitor(function, timeout_ms); } + /** + * Monitor asynchronous job execution + * + * Returns immediately after the job is registered for execution. + */ + virtual void monitor_async(Job &job) = 0; + /** * Trigger examination of monitored functions */ @@ -89,19 +97,32 @@ class Libc::Monitor : Interface }; -struct Libc::Monitor::Job +class Libc::Monitor::Job { private: + friend class Pool; + Monitor::Function &_fn; Blockade &_blockade; + Constructible<Registry<Job>::Element> _async_element; + + void _register_async(Registry<Job> ®istry) + { + _async_element.construct(registry, *this); + } + public: Job(Monitor::Function &fn, Blockade &blockade) : _fn(fn), _blockade(blockade) { } - virtual ~Job() { } + virtual ~Job() + { + if (_async_element.constructed()) + _async_element.destruct(); + } bool execute() { return _fn.execute() == Function_result::COMPLETE; } @@ -124,7 +145,12 @@ struct Libc::Monitor::Pool Pool(Monitor &monitor) : _monitor(monitor) { } - /* called by monitor-user context */ + /** + * Monitor synchronous job execution + * + * The function is called by the monitor-user context and returns after + * job completion. + */ void monitor(Job &job) { Registry<Job>::Element element { _jobs, job }; @@ -134,6 +160,18 @@ struct Libc::Monitor::Pool job.wait_for_completion(); } + /** + * Monitor asynchronous job execution + * + * The function is called by the monitor-user context and returns after + * job is registered for execution. Jobs are removed from the pool on + * destruction. + */ + void monitor_async(Job &job) + { + job._register_async(_jobs); + } + enum class State { JOBS_PENDING, ALL_COMPLETE }; /* called by the monitor context itself */ diff --git a/repos/libports/src/lib/libc/internal/signal.h b/repos/libports/src/lib/libc/internal/signal.h index e3675f9259..823c352f83 100644 --- a/repos/libports/src/lib/libc/internal/signal.h +++ b/repos/libports/src/lib/libc/internal/signal.h @@ -16,10 +16,13 @@ /* Genode includes */ #include <util/noncopyable.h> +#include <util/reconstructible.h> #include <base/registry.h> +#include <base/thread.h> /* libc includes */ #include <signal.h> +#include <stdlib.h> /* libc-internal includes */ #include <internal/call_func.h> diff --git a/repos/libports/src/lib/libc/kernel.cc b/repos/libports/src/lib/libc/kernel.cc index e37fee0a93..4b1e236059 100644 --- a/repos/libports/src/lib/libc/kernel.cc +++ b/repos/libports/src/lib/libc/kernel.cc @@ -508,11 +508,13 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap) init_vfs_plugin(*this, _env.rm()); init_file_operations(*this, _libc_env); init_time(*this, *this); + init_alarm(_timer_accessor, _signal); init_poll(_signal, *this); init_select(*this); init_socket_fs(*this, *this); init_passwd(_passwd_config()); init_signal(_signal); + init_kqueue(_heap, *this); _init_file_descriptors(); diff --git a/repos/libports/src/lib/libc/kqueue.cc b/repos/libports/src/lib/libc/kqueue.cc new file mode 100644 index 0000000000..1b69939aa9 --- /dev/null +++ b/repos/libports/src/lib/libc/kqueue.cc @@ -0,0 +1,563 @@ +/* + * \brief kqueue/kevent implementation + * \author Benjamin Lamowski + * \date 2024-06-12 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Libc includes */ +#include <sys/event.h> +#include <errno.h> +#include <assert.h> + +/* internal includes */ +#include <internal/fd_alloc.h> +#include <internal/file.h> +#include <internal/kernel.h> +#include <internal/monitor.h> +#include <internal/kqueue.h> +#include <sys/poll.h> + +/* Genode includes */ +#include <base/mutex.h> +#include <util/avl_tree.h> +#include <util/register.h> + +using namespace Libc; + +namespace Libc { + class Kqueue; + + bool read_ready_from_kernel(File_descriptor *); + void notify_read_ready_from_kernel(File_descriptor *); + bool write_ready_from_kernel(File_descriptor *); +} + +namespace { using Fn = Libc::Monitor::Function_result; } + + +static Monitor *_monitor_ptr; +static Libc::Kqueue_plugin *_kqueue_plugin_ptr; + + +static Libc::Monitor & monitor() +{ + struct Missing_call_of_init_kqueue_support : Genode::Exception { }; + if (!_monitor_ptr) + throw Missing_call_of_init_kqueue_support(); + return *_monitor_ptr; +} + + +/* + * kqueue(2): "A kevent is identified by the (ident, filter) pair; + * there may only be one unique kevent per kqueue. + */ +bool operator==(struct kevent a, struct kevent b) +{ + return ((a.ident == b.ident) && (a.filter == b.filter)); +} + + +bool operator>(struct kevent a, struct kevent b) +{ + if (a.ident > b.ident) + return true; + if ((a.ident == b.ident) && (a.filter > b.filter)) + return true; + + return false; +} + + +static consteval int pos(int flag) +{ + for (size_t i = 0; i < sizeof(flag) * 8; i++) + if ((1 << i) & flag) + return i; +} + + +/* + * Kqueue backend implementation + */ + +struct Libc::Kqueue +{ + const unsigned short flags_whitelist = + EV_ADD | + EV_DELETE | + EV_CLEAR | + EV_ONESHOT | + EV_ENABLE | + EV_DISABLE; + + const int filter_whitelist = + EVFILT_READ | + EVFILT_WRITE; + + struct Kqueue_flags : Genode::Register<32> { + struct Add : Bitfield< pos(EV_ADD), 1> { }; + struct Delete : Bitfield< pos(EV_DELETE), 1> { }; + struct Enable : Bitfield< pos(EV_ENABLE), 1> { }; + struct Disable : Bitfield<pos(EV_DISABLE), 1> { }; + struct Clear : Bitfield< pos(EV_CLEAR), 1> { }; + struct Oneshot : Bitfield<pos(EV_ONESHOT), 1> { }; + }; + + struct Kqueue_elements; + + struct Kqueue_element : kevent, public Avl_node<Kqueue_element> + { + Kqueue_element *find_by_kevent(struct kevent const & k) + { + if (*this == k) return this; + Kqueue_element *ele = this->child(k > *this); + return ele ? ele->find_by_kevent(k) : nullptr; + } + + bool higher(Kqueue_element *e) + { + return *e > *this; + } + + /* + * Run fn arcoss the element's subtree until fn returns false. + */ + bool with_all_elements(auto const &fn) + { + if (!fn(*this)) + return false; + + if (Kqueue_element * l = child(Avl_node<Kqueue_element>::LEFT)) + if (!l->with_all_elements(fn)) + return false; + + if (Kqueue_element * r = child(Avl_node<Kqueue_element>::RIGHT)) + if (!r->with_all_elements(fn)) + return false; + + return true; + } + }; + + struct Kqueue_elements : Avl_tree<Kqueue_element> + { + bool with_any_element(auto const &fn) + { + Kqueue_element *curr_ptr = first(); + if (!curr_ptr) + return false; + + fn(*curr_ptr); + return true; + } + + template <typename FN> + auto with_element(struct kevent const & k, FN const &match_fn, auto const &no_match_fn) + -> typename Trait::Functor<decltype(&FN::operator())>::Return_type + { + Kqueue_element *ele = (this->first()) ? + this->first()->find_by_kevent(k) : + nullptr; + if (ele) + return match_fn(*ele); + else + return no_match_fn(); + } + + /* + * Run fn arcoss the tree until fn returns false. + */ + void with_all_elements(auto const &fn) const + { + if (first()) first()->with_all_elements(fn); + } + }; + + + Genode::Allocator &_alloc; + Mutex _requests_mutex; + Kqueue_elements _requests; + + /* + * Collect invalid elements for deletion. + * This needs to be done out of band because otherwise the reshuffling of the AVL tree + * might lead to missed valid events. + */ + struct Kqueue_element_container : Fifo<Kqueue_element_container>::Element + { + Kqueue_element const & ele; + Kqueue_element_container(Kqueue_element const & e) : ele(e) + { } + }; + + Fifo<Kqueue_element_container> _delete_queue; + + void _queue_for_deletion(Kqueue_element &ele) + { + Kqueue_element_container &c = *new (_alloc) Kqueue_element_container(ele); + _delete_queue.enqueue(c); + } + + /* + * This may be called only when we can safely reshuffle the AVL tree + */ + void _delete_elements() + { + auto cancel_fn = [&](Kqueue_element_container& c) { + /* At this point we are sure that we can reshuffle the AVL tree. */ + Kqueue_element * non_const_ptr = &(const_cast<Kqueue_element &>(c.ele)); + _requests.remove(non_const_ptr); + destroy(_alloc, non_const_ptr); + destroy(_alloc, &c); + }; + + { + Mutex::Guard guard(_requests_mutex); + _delete_queue.dequeue_all(cancel_fn); + } + } + + int _add_event(struct kevent const& k) + { + if (k.filter & ~filter_whitelist) { + warning("kqueue: filter not implemented: ", k.filter); + return EINVAL; + } + + Kqueue_element *ele = new (_alloc) Kqueue_element(k); + { + Mutex::Guard guard(_requests_mutex); + _requests.insert(ele); + } + + return 0; + } + + int _delete_event(struct kevent const& k) + { + Mutex::Guard guard(_requests_mutex); + + auto match_fn = [&](Kqueue_element & ele) { + /* Since we know we won't match another element, we can safely remove the element here. */ + _requests.remove(&ele); + destroy(_alloc, &ele); + + return 0; + }; + + auto no_match_fn = [&]() { + error("kqueue: did not find kevent to delete: ident: ", k.ident, " filter: ", k.filter); + return EINVAL; + }; + + return _requests.with_element(k, match_fn, no_match_fn); + } + + int _enable_event(struct kevent const& k) + { + auto match_fn = [&](Kqueue_element & ele) { + Kqueue_flags::Disable::clear((Kqueue_flags::access_t &)ele.flags); + Kqueue_flags::Enable::set((Kqueue_flags::access_t &)ele.flags); + return 0; + }; + + auto no_match_fn = [&]() { + error("kqueue: did not find kevent to enable: ident: ", k.ident, " filter: ", k.filter); + return EINVAL; + }; + + return _requests.with_element(k, match_fn, no_match_fn); + } + + int _disable_event(struct kevent const& k) + { + auto match_fn = [&](Kqueue_element & ele) { + Kqueue_flags::Enable::clear((Kqueue_flags::access_t &)ele.flags); + Kqueue_flags::Disable::set((Kqueue_flags::access_t &)ele.flags); + return 0; + }; + + auto no_match_fn = [&]() { + error("kqueue: did not find kevent to disable: ident: ", k.ident, " filter: ", k.filter); + return EINVAL; + }; + + return _requests.with_element(k, match_fn, no_match_fn); + } + + Kqueue(Genode::Allocator & alloc) : _alloc(alloc) + { } + + ~Kqueue() + { + auto destroy_fn = [&] (Kqueue_element &e) { + _requests.remove(&e); + destroy(_alloc, &e); }; + while (_requests.with_any_element(destroy_fn)); + } + + int process_events(const struct kevent * changelist, int nchanges, + struct kevent * eventlist, int nevents) + { + int num_errors { 0 }; + + for (int i = 0; i < nchanges; i++) { + const int flags = changelist[i].flags; + int err { 0 }; + + if (flags & ~flags_whitelist) { + error("kqueue: unsupported flags detected: ", flags & ~flags_whitelist); + return Errno(EINVAL); + } + + if (Kqueue_flags::Add::get(flags)) + err = _add_event(changelist[i]); + else if (Kqueue_flags::Delete::get(flags)) + err = _delete_event(changelist[i]); + else if (Kqueue_flags::Enable::get(flags)) + err = _enable_event(changelist[i]); + else if (Kqueue_flags::Disable::get(flags)) + err = _disable_event(changelist[i]); + /* We ignore setting EV_CLEAR for now. */ + + if (err) { + if (num_errors < nevents) { + eventlist[num_errors] = changelist[i]; + eventlist[num_errors].flags = EV_ERROR; + eventlist[num_errors].data = err; + num_errors++; + } else { + return Errno(err); + } + } + } + + return num_errors; + } + + int collect_completed_events(struct kevent * eventlist, int nevents, const struct timespec *timeout) + { + if (nevents == 0) + return 0; + + /* + * event collection mode depending ont 'timeout' + * + * - timeout pointer == nullptr ... block infinitely for events + * - timeout value == 0 ... poll for events and return + * immediately + * - timeout value != 0 ... block for events but don't return + * later than timeout + */ + enum class Mode { INFINITE, POLL, TIMEOUT }; + + Mode mode = Mode::INFINITE; + uint64_t timeout_ms = 0; + + if (timeout) { + timeout_ms = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000; + mode = (timeout_ms == 0) ? Mode::POLL : Mode::TIMEOUT; + } + + int num_events { 0 }; + + auto monitor_fn = [&] () + { + /* + * kqueue(2): + * "The filter is also run when the user attempts to retrieve the kevent + * from the kqueue. If the filter indicates that the condition that triggered + * the event no longer holds, the kevent is removed from the kqueue and is + * not returned." + * + * Since we need to check the condition on retrieval anyway, we *only* check + * the condition on retrieval and not asynchronously. + */ + auto check_fn = [&](Kqueue_element &ele) { + File_descriptor *fd = libc_fd_to_fd(ele.ident, "kevent_collect"); + + /* + * kqueue(2): "Calling close() on a file descriptor will remove any + * kevents that reference the descriptor." + * + * Instead of removing the kqueue entry from close(), we collect + * invalid entries for deletion here. + */ + if (!fd || !fd->plugin || !fd->context) { + _queue_for_deletion(ele); + return true; + } + + /* + * If an event is disabled, ignore it. + */ + if (Kqueue_flags::Disable::get(ele.flags)) + return true; + + /* + * Right now we do not support tracking newly available read data via + * the clear flag, as that would entail tracking the availability of new + * data across file system implementations. For the case that a kqueue + * client sets EV_CLEAR and does not read the available data after receiving + * a kevent, this will lead to extraneous kevents for the already existing data. + */ + switch (ele.filter) { + case EVFILT_READ: + if (Libc::read_ready_from_kernel(fd)) { + eventlist[num_events] = ele; + eventlist[num_events].flags = 0; + num_events++; + } else { + Libc::notify_read_ready_from_kernel(fd); + } + break; + case EVFILT_WRITE: + if (Libc::write_ready_from_kernel(fd)) { + eventlist[num_events] = ele; + eventlist[num_events].flags = 0; + num_events++; + } + break; + default: + assert(false && "Element with unknown filter inserted"); + } + + /* Delete oneshot event */ + if (Kqueue_flags::Oneshot::get(ele.flags)) + _queue_for_deletion(ele); + + return num_events < nevents; + }; + + { + Mutex::Guard guard(_requests_mutex); + _requests.with_all_elements(check_fn); + + } + + _delete_elements(); + + if (mode != Mode::POLL && num_events == 0) + return Monitor::Function_result::INCOMPLETE; + + return Monitor::Function_result::COMPLETE; + }; + + Monitor::Result const monitor_result = + monitor().monitor(monitor_fn, timeout_ms); + + if (monitor_result == Monitor::Result::TIMEOUT) + return 0; + + return num_events; + } +}; + + +void Libc::init_kqueue(Genode::Allocator &alloc, Monitor &monitor) +{ + _kqueue_plugin_ptr = new (alloc) Kqueue_plugin(alloc); + _monitor_ptr = &monitor; +} + + +static Kqueue_plugin *kqueue_plugin() +{ + if (!_kqueue_plugin_ptr) { + error("libc kqueue not initialized - aborting"); + exit(1); + } + + return _kqueue_plugin_ptr; +} + + + +int Libc::Kqueue_plugin::create_kqueue() +{ + Kqueue *kq = new (_alloc) Kqueue(_alloc); + + Plugin_context *context = reinterpret_cast<Libc::Plugin_context *>(kq); + File_descriptor *fd = + file_descriptor_allocator()->alloc(this, context, Libc::ANY_FD); + + return fd->libc_fd; +} + + +int Libc::Kqueue_plugin::close(File_descriptor *fd) +{ + if (fd->plugin != this) + return -1; + + if (fd->context) + _alloc.free(fd->context, sizeof(Kqueue)); + + + file_descriptor_allocator()->free(fd); + + return 0; +} + + +extern "C" int +kevent(int libc_fd, const struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, const struct timespec *timeout) +{ + File_descriptor *fd = libc_fd_to_fd(libc_fd, "kevent"); + + if (fd->plugin != kqueue_plugin()) { + error("File descriptor not reqistered to kqueue plugin"); + return Errno(EBADF); + } + + Kqueue *kq = reinterpret_cast<Libc::Kqueue *>(fd->context); + assert(kq && "Kqueue not set in kqueue file descriptor"); + + if (nchanges < 0 || nevents < 0) + return Errno(EINVAL); + + int err { 0 }; + + if (changelist && nchanges) { + int num_errors = kq->process_events(changelist, nchanges, eventlist, nevents); + + /* + * kqueue(2): + * If an error occurs while processing an element of the + * changelist and there is enough roomin the eventlist, then the + * event will be placed in the eventlist with EV_ERROR set in + * flags and the system error in data. Otherwise, -1 will be + * returned, and errno will be set to indicate the error + * condition. + */ + if (num_errors < 0) + return -1; + + /* reduce space available in the eventlist */ + if (num_errors) { + nevents -= num_errors; + eventlist = &eventlist[num_errors]; + } + } + + if (eventlist && nevents) + err = kq->collect_completed_events(eventlist, nevents, timeout); + + return err; +} + + +extern "C" +int kqueue(void) +{ + return kqueue_plugin()->create_kqueue(); +} diff --git a/repos/libports/src/lib/libc/pthread.cc b/repos/libports/src/lib/libc/pthread.cc index 6e3c5128c7..3903793112 100644 --- a/repos/libports/src/lib/libc/pthread.cc +++ b/repos/libports/src/lib/libc/pthread.cc @@ -1307,52 +1307,119 @@ extern "C" { typeof(pthread_cond_broadcast) _pthread_cond_broadcast __attribute__((alias("pthread_cond_broadcast"))); +} - int pthread_once(pthread_once_t *once, void (*init_once)(void)) +/* + * This implementation is inspired by base/src/lib/cxx/guard.cc and uses the + * same terms for IN_INIT and WAITERS. + */ +struct Pthread_once +{ + using Waiters = Registry<Libc::Blockade>; + + template <typename T> + struct Waiter : T { - if (!once || ((once->state != PTHREAD_NEEDS_INIT) && - (once->state != PTHREAD_DONE_INIT))) - return EINVAL; + Waiters::Element _element; - if (!once->mutex) { - pthread_mutex_t p; - pthread_mutex_init(&p, nullptr); - if (!p) return EINVAL; + Waiter(Waiters &waiters, auto &&... args) + : T(args...), _element(waiters, *this) { } + }; - { - static Mutex mutex; - Mutex::Guard guard(mutex); + int volatile _state; /* pthread_once_t: state */ + addr_t volatile _flags; /* pthread_once_t: *mutex */ - if (!once->mutex) { - once->mutex = p; - p = nullptr; - } - } + bool _in_init() const { return _flags & 0b01; } + bool _waiters() const { return _flags & 0b10; } - /* - * If another thread concurrently allocated a mutex and was faster, - * free our mutex since it is not used. - */ - if (p) pthread_mutex_destroy(&p); - } + void _set_in_init() { _flags |= 0b01; } + void _set_waiters() { _flags |= 0b10; } - once->mutex->lock(); + /* mutex should be locked - returns true if init_once() was called */ + bool init(Mutex &mutex, void (*init_once)(void), Waiters &waiters) + { + if (_state == PTHREAD_DONE_INIT || _in_init()) + return false; - if (once->state == PTHREAD_DONE_INIT) { - once->mutex->unlock(); - return 0; - } + _set_in_init(); + mutex.release(); init_once(); + mutex.acquire(); - once->state = PTHREAD_DONE_INIT; + _state = PTHREAD_DONE_INIT; - once->mutex->unlock(); + if (_waiters()) + waiters.for_each([](Libc::Blockade &b) { b.wakeup(); }); - return 0; + return true; } - typeof(pthread_once) _pthread_once - __attribute__((alias("pthread_once"))); + /* mutex should be locked */ + void wait_for_completion(Mutex &mutex, Waiters &waiters) + { + auto block = [&] (Libc::Blockade &waiter) { + _set_waiters(); + + mutex.release(); + while (_state != PTHREAD_DONE_INIT) + waiter.block(); + mutex.acquire(); + }; + + if (Libc::Kernel::kernel().main_context()) { + Waiter<Main_blockade> w { waiters, 0 }; + block(w); + } else { + Waiter<Pthread_blockade> w { waiters, *_timer_accessor_ptr, 0 }; + block(w); + } + } +}; + +static_assert(sizeof(Pthread_once) <= sizeof(pthread_once_t)); + +/* + * Semantic of pthread_once according to the POSIX standard: + * + * - The first call to pthread_once() by any thread in a process, with a given + * 'once', shall call 'init_once' with no arguments. + * + * - Subsequent * calls of pthread_once() with the same 'once' shall not call + * the 'init_once'. + * + * - On return from pthread_once(), 'init_once' shall have completed. + * + * - 'once' shall determine whether the associated initialization routine has + * been called. + * + * - Recursive calls to pthread_once() (from 'init_once' or after longjmp()) + * will not return. + */ +extern "C" int pthread_once(pthread_once_t *once, void (*init_once)(void)) +{ + static Mutex mutex { }; + static Pthread_once::Waiters waiters { }; + + /* + * POSIX states: The [EINVAL] error for an uninitialized pthread_once_t + * object is removed; this condition results in undefined behavior. + */ + if (!once || ((once->state != PTHREAD_NEEDS_INIT) && + (once->state != PTHREAD_DONE_INIT))) + return EINVAL; + + Mutex::Guard guard(mutex); + + if (once->state == PTHREAD_DONE_INIT) + return 0; + + Pthread_once &o = *(Pthread_once *)once; + if (!o.init(mutex, init_once, waiters)) + o.wait_for_completion(mutex, waiters); + + return 0; } + +extern "C" typeof(pthread_once) _pthread_once __attribute__((alias("pthread_once"))); diff --git a/repos/libports/src/lib/libc/signal.cc b/repos/libports/src/lib/libc/signal.cc index 570c36db3d..76e465d0cc 100644 --- a/repos/libports/src/lib/libc/signal.cc +++ b/repos/libports/src/lib/libc/signal.cc @@ -250,10 +250,7 @@ extern "C" int sigaltstack(stack_t const * const ss, stack_t * const old_ss) warning("leaking secondary stack memory"); } else { - if (ss->ss_sp) - warning(__func__, " using self chosen stack is not" - " supported - stack ptr is ignored !!!"); - + /* ss->ss_sp is ignored, ever use alloc_secondary stack */ void * stack = myself->alloc_secondary_stack("sigaltstack", ss->ss_size); diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index d12acda2ef..33ea35b6b3 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -220,6 +220,13 @@ namespace Libc { return handle->fs().read_ready(*handle); } + void notify_read_ready_from_kernel(File_descriptor *fd) + { + Vfs::Vfs_handle *handle = vfs_handle(fd); + if (handle) + handle->fs().notify_read_ready(handle); + } + bool write_ready_from_kernel(File_descriptor *fd) { Vfs::Vfs_handle const *handle = vfs_handle(fd); @@ -1127,6 +1134,19 @@ Libc::Vfs_plugin::_ioctl_tio(File_descriptor *fd, unsigned long request, char *a termios->c_ispeed = 0; termios->c_ospeed = 0; + handled = true; + + } else if (request == TIOCSETA) { + + /* + * As TIOCGETA above only returns the for now required + * options ignore any attempt to set them. + */ + + handled = true; + + } else if (request == TIOCFLUSH) { + handled = true; } @@ -1921,7 +1941,9 @@ int Libc::Vfs_plugin::ioctl(File_descriptor *fd, unsigned long request, char *ar switch (request) { case TIOCGWINSZ: + case TIOCFLUSH: case TIOCGETA: + case TIOCSETA: result = _ioctl_tio(fd, request, argp); break; case DIOCGMEDIASIZE: diff --git a/repos/libports/src/lib/libdrm/ioctl_etnaviv.cc b/repos/libports/src/lib/libdrm/ioctl_etnaviv.cc index fe342cfe50..df7bca20f0 100644 --- a/repos/libports/src/lib/libdrm/ioctl_etnaviv.cc +++ b/repos/libports/src/lib/libdrm/ioctl_etnaviv.cc @@ -266,11 +266,15 @@ namespace Etnaviv { using namespace Genode; using namespace Gpu; + struct Vram; struct Call; } /* namespace Etnaviv */ -struct Gpu::Vram +struct Gpu::Vram { }; + +/* use separate namespace for Vram implementation */ +struct Etnaviv::Vram : Gpu::Vram { struct Allocation_failed : Genode::Exception { }; @@ -346,7 +350,7 @@ class Etnaviv::Call Gpu::Vram const &_vram; Buffer(Genode::Id_space<Buffer> &space, - Gpu::Vram const &vram) + Vram const &vram) : _elem { *this, space, Genode::Id_space<Buffer>::Id { .value = vram.id().value } }, @@ -440,7 +444,7 @@ class Etnaviv::Call * required by the Gpu session to pass on the driver specific * command buffer. */ - Gpu::Vram *_exec_buffer; + Vram *_exec_buffer; public: @@ -457,8 +461,8 @@ class Etnaviv::Call _fd { _open_gpu() }, _id { _stat_gpu(_fd) }, _elem { *this, space }, - _exec_buffer { new (alloc) Gpu::Vram(_gpu, _exec_buffer_size, - _vram_space) } + _exec_buffer { new (alloc) Vram(_gpu, _exec_buffer_size, + _vram_space) } { } ~Gpu_context() @@ -486,13 +490,13 @@ class Etnaviv::Call Gpu::Vram_capability export_vram(Gpu::Vram_id id) { Gpu::Vram_capability cap { }; - _try_apply(id, [&] (Gpu::Vram const &b) { + _try_apply(id, [&] (Vram const &b) { cap = _gpu.export_vram(b.id()); }); return cap; } - Buffer *import_vram(Gpu::Vram_capability cap, Gpu::Vram const &v) + Buffer *import_vram(Gpu::Vram_capability cap, Vram const &v) { Buffer *b = nullptr; @@ -675,7 +679,7 @@ class Etnaviv::Call [&] () { _main_ctx->gpu().upgrade_ram(donate); }); - } catch (Gpu::Vram::Allocation_failed) { + } catch (Vram::Allocation_failed) { return; } diff --git a/repos/libports/src/lib/libdrm/ioctl_lima.cc b/repos/libports/src/lib/libdrm/ioctl_lima.cc index 5641676558..28fa91da53 100644 --- a/repos/libports/src/lib/libdrm/ioctl_lima.cc +++ b/repos/libports/src/lib/libdrm/ioctl_lima.cc @@ -198,6 +198,7 @@ namespace Lima { using namespace Genode; using namespace Gpu; + struct Vram; struct Call; } /* namespace Lima */ @@ -205,7 +206,11 @@ namespace Lima { /* * Gpu::Vram encapsulates a buffer object allocation */ -struct Gpu::Vram + +struct Gpu::Vram { }; + +/* use separate namespace for Vram implementation */ +struct Lima::Vram : Gpu::Vram { struct Allocation_failed : Genode::Exception { }; @@ -331,10 +336,10 @@ class Lima::Call { Genode::Id_space<Buffer>::Element const _elem; - Gpu::Vram const &_vram; + Vram const &_vram; Buffer(Genode::Id_space<Buffer> &space, - Gpu::Vram const &vram) + Vram const &vram) : _elem { *this, space, Genode::Id_space<Buffer>::Id { .value = vram.id().value } }, @@ -437,7 +442,7 @@ class Lima::Call * required by the Gpu session to pass on driver specific * command buffer. */ - Gpu::Vram *_exec_buffer; + Vram *_exec_buffer; public: @@ -455,9 +460,9 @@ class Lima::Call _id { _stat_gpu(_fd) }, _elem { *this, space }, _va_alloc { va_alloc }, - _exec_buffer { new (alloc) Gpu::Vram(_gpu, _exec_buffer_size, - _va_alloc.alloc(_exec_buffer_size), - _vram_space) } + _exec_buffer { new (alloc) Vram(_gpu, _exec_buffer_size, + _va_alloc.alloc(_exec_buffer_size), + _vram_space) } { } ~Gpu_context() @@ -482,16 +487,16 @@ class Lima::Call return _gpu; } - Gpu::Vram_capability export_vram(Gpu::Vram_id id) + Gpu::Vram_capability export_vram(Vram_id id) { Gpu::Vram_capability cap { }; - _try_apply(id, [&] (Gpu::Vram const &b) { + _try_apply(id, [&] (Vram const &b) { cap = _gpu.export_vram(b.id()); }); return cap; } - Buffer *import_vram(Gpu::Vram_capability cap, Gpu::Vram const &v) + Buffer *import_vram(Gpu::Vram_capability cap, Vram const &v) { Buffer *b = nullptr; @@ -764,7 +769,7 @@ class Lima::Call [&] () { _main_ctx->gpu().upgrade_ram(donate); }); - } catch (Gpu::Vram::Allocation_failed) { + } catch (Vram::Allocation_failed) { _va_alloc.free(va); return; } @@ -802,7 +807,7 @@ class Lima::Call Buffer_space::Id const id = { .value = handle }; if (!gc.buffer_space_contains(id)) { - (void)_apply_handle(handle, [&] (Gpu::Vram const &v) { + (void)_apply_handle(handle, [&] (Vram const &v) { Gpu::Vram_capability cap = _main_ctx->export_vram(v.id()); if (gc.import_vram(cap, v) == nullptr) { Genode::error("could force mapping of buffer ", handle); @@ -824,7 +829,7 @@ class Lima::Call if (!gc.buffer_space_contains(id)) { bool imported = false; - (void)_apply_handle(bo.handle, [&] (Gpu::Vram const &v) { + (void)_apply_handle(bo.handle, [&] (Vram const &v) { Gpu::Vram_capability cap = _main_ctx->export_vram(v.id()); if (gc.import_vram(cap, v) == nullptr) return; @@ -986,7 +991,7 @@ class Lima::Call _gpu_context_space.for_each<Gpu_context>(free_buffer); return _apply_handle(gem_close.handle, - [&] (Gpu::Vram &b) { + [&] (Lima::Vram &b) { _va_alloc.free(b.va); destroy(_heap, &b); }) ? 0 : -1; diff --git a/repos/libports/src/lib/mesa/files.list b/repos/libports/src/lib/mesa/files.list index 63c74aa5cc..e730d973a5 100644 --- a/repos/libports/src/lib/mesa/files.list +++ b/repos/libports/src/lib/mesa/files.list @@ -2010,6 +2010,7 @@ mesa-24.0.8/src/util/format/u_format_s3tc.c mesa-24.0.8/src/util/format/u_format_s3tc.h mesa-24.0.8/src/util/format/u_format_table.py mesa-24.0.8/src/util/format/u_format_tests.h +mesa-24.0.8/src/util/format/u_format_unpack_neon.c mesa-24.0.8/src/util/format/u_format_yuv.c mesa-24.0.8/src/util/format/u_format_yuv.h mesa-24.0.8/src/util/format/u_format_zs.c diff --git a/repos/libports/src/lib/qemu-usb/webcam.cc b/repos/libports/src/lib/qemu-usb/webcam.cc index 8e07b37b7c..a557e28cf3 100644 --- a/repos/libports/src/lib/qemu-usb/webcam.cc +++ b/repos/libports/src/lib/qemu-usb/webcam.cc @@ -130,7 +130,7 @@ struct Capture_webcam /* construct/destruct capture connection and dataspace */ if (on) { _capture.construct(_env, "webcam"); - _capture->buffer(_area); + _capture->buffer({ .px = _area, .mm = { } }); _ds.construct(_env.rm(), _capture->dataspace()); } else { _ds.destruct(); diff --git a/repos/libports/src/test/libc_alarm/main.c b/repos/libports/src/test/libc_alarm/main.c new file mode 100644 index 0000000000..e5a61d9c56 --- /dev/null +++ b/repos/libports/src/test/libc_alarm/main.c @@ -0,0 +1,52 @@ +/* + * \brief Libc alarm test + * \author Norman Feske + * \date 2024-08-30 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include <signal.h> +#include <unistd.h> +#include <stdio.h> + +static unsigned triggered_alarms; + +static void sigalarm_handler(int) +{ + triggered_alarms++; +} + +int main(int, char **) +{ + static struct sigaction sa; + sa.sa_handler = sigalarm_handler; + + int ret = sigaction(SIGALRM, &sa, NULL); + if (ret < 0) { + printf("sigaction unexpectedly returned %d\n", ret); + return 1; + } + + signal(SIGALRM, sigalarm_handler); + + unsigned observed_alarms = 0; + + alarm(2); + + while (observed_alarms != 3) { + sleep(1); + printf("triggered_alarms=%u\n", triggered_alarms); + + if (triggered_alarms != observed_alarms) { + observed_alarms = triggered_alarms; + alarm(2); + } + } + return 0; +} diff --git a/repos/libports/src/test/libc_alarm/target.mk b/repos/libports/src/test/libc_alarm/target.mk new file mode 100644 index 0000000000..77a61b5d6e --- /dev/null +++ b/repos/libports/src/test/libc_alarm/target.mk @@ -0,0 +1,3 @@ +TARGET = test-libc_alarm +SRC_C = main.c +LIBS = posix diff --git a/repos/libports/src/test/libc_kqueue/kqueue.c b/repos/libports/src/test/libc_kqueue/kqueue.c new file mode 100644 index 0000000000..d0de8bbf1c --- /dev/null +++ b/repos/libports/src/test/libc_kqueue/kqueue.c @@ -0,0 +1,505 @@ +/* + * \brief kqueue test + * \author Benjamin Lamowski + * \date 2024-08-20 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* + * Note that our kqueue implementation does support EV_CLEAR + * for EVFILT_READ and EVFILT_WRITE, + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <sys/event.h> + +/* + * Information about the test. + */ +struct Test_info { + char const *name; /* Name of the test */ + char const *path; /* Path of the file to open */ + int open_flags; /* Flags for opening the file */ + int filter; /* kqueue filter */ + int flags; /* kqueue flags */ +}; + + +/* + * Structure to pass around open file descriptors. + */ +struct Fildes { + int fd; + int kq; +}; + + +/* + * Set up a kqueue, open the file and insert the initial kevent. + */ +int bringup(struct Test_info *test, struct Fildes *fildes) +{ + int ret = 0; + struct kevent event; + + fildes->kq = kqueue(); + if (fildes->kq == -1) { + printf("%s: Failed to create kqueue: %s\n", test->name, + strerror(errno)); + return ret; + } + + + fildes->fd = open(test->path, test->open_flags); + + if (fildes->fd == -1) { + close(fildes->kq); + printf("%s: Failed to open file %s: %s\n", test->name, + test->path, strerror(errno)); + + return ret; + } + + EV_SET(&event, fildes->fd, test->filter, test->flags, 0, 0, NULL); + + ret = kevent(fildes->kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes->fd); + close(fildes->kq); + printf("%s: Failed to register event: %s\n", + test->name, strerror(errno)); + return ret; + } + + return 0; +} + + +/* + * Get a result from the kqueue and close the file descriptors. + */ +int get_result(struct Test_info *test, struct Fildes *fildes) +{ + int ret = 0; + struct kevent result; + ret = kevent(fildes->kq, NULL, 0, &result, 1, NULL); + if (ret == -1) { + close(fildes->fd); + close(fildes->kq); + printf("%s: Failed to retrieve result: %s\n", test->name, + strerror(errno)); + return ret; + } + + close(fildes->fd); + close(fildes->kq); + + if (ret > 0) { + if (result.flags & EV_ERROR) { + printf("%s: ", test->name); + printf("%s: Event indcated failure: %s\n", test->name, + strerror(result.data)); + return -1; + } else { + printf("%s: Test successful.\n", test->name); + return 0; + } + } + + return 0; +} + + +/* + * Test getting a kevent if a file can be written to. + */ +int test_write() +{ + int ret = 0; + struct Test_info test = { + "Write test", + "/dev/log", + O_WRONLY, + EVFILT_WRITE, + EV_ADD + }; + struct Fildes fildes; + ret = bringup(&test, &fildes); + if (ret) + return ret; + + return get_result(&test, &fildes); +} + + +/* + * Test getting a kevent if a file can be read. + */ +int test_read() +{ + int ret = 0; + struct Test_info test = { + "Read test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + ret = bringup(&test, &fildes); + if (ret) + return ret; + + return get_result(&test, &fildes); +} + + +/* + * Test deleting a queued kevent. + */ +int test_delete() +{ + int ret = 0; + struct kevent event; + struct Test_info test = { + "Cancel test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + ret = bringup(&test, &fildes); + if (ret) + return ret; + + /* Delete the event */ + EV_SET(&event, fildes.fd, test.filter, EV_DELETE, 0, 0, NULL); + ret = kevent(fildes.kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to delete event: %s\n", test.name, + strerror(errno)); + + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event, 1, &timeout); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result: %s\n", test.name, + strerror(errno)); + + return ret; + } + + /* + * Since we can always read /dev/rtc, wetting the results will only + * timeout if the event has been deleted sucessfuly. + */ + if (ret == 0) { + printf("%s: Test successful.\n", test.name); + return 0; + } else { + printf("%s: Event was not deleted: %s\n", test.name, + strerror(errno)); + + return -1; + } +} + + +/* + * Test repeating a non-oneshot event. + */ +int test_repeat() +{ + int ret = 0; + struct Test_info test = { + "Repeat test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + struct kevent event1, event2; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + ret = kevent(fildes.kq, NULL, 0, &event1, 1, NULL); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result 1: %s\n", test.name, + strerror(errno)); + + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event2, 1, NULL); + + close(fildes.fd); + close(fildes.kq); + + switch (ret) { + case 1: + printf("%s: Test successful.\n", test.name); + return 0; + case -1: + printf("%s: Failed to retrieve result 2: %s\n", + test.name, strerror(errno)); + break; + default: + printf("%s: Non-oneshot event was not repeated: %s\n", + test.name, strerror(errno)); + return -1; + } + + return ret; +} + + +/* + * Test queuing a oneshot event. + */ +int test_oneshot() +{ + int ret = 0; + struct Test_info test = { + "Oneshot test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD | EV_ONESHOT + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + struct kevent event1, event2; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + ret = kevent(fildes.kq, NULL, 0, &event1, 1, NULL); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result 1: %s\n", test.name, + strerror(errno)); + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event2, 1, &timeout); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result 2: %s\n", test.name, + strerror(errno)); + return ret; + } + + if (ret == 0) { + printf("%s: Test successful.\n", test.name); + return 0; + } else { + printf("%s: Oneshot event was repeated: %s\n", test.name, + strerror(errno)); + + return -1; + } +} + + +/* + * Test disabling a queued event. + */ +int test_disable() +{ + int ret = 0; + struct Test_info test = { + "Disable test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + struct kevent event; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + /* Disable the event */ + EV_SET(&event, fildes.fd, test.filter, EV_DISABLE, 0, 0, NULL); + ret = kevent(fildes.kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to disable event: %s\n", test.name, + strerror(errno)); + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event, 1, &timeout); + + close(fildes.fd); + close(fildes.kq); + + switch (ret) { + case 0: + printf("%s: Test successful.\n", test.name); + return 0; + case -1: + printf("%s: Failed to retrieve result: %s\n", test.name, + strerror(errno)); + return -1; + default: + printf("%s: Event was not disabled: %s\n", test.name, + strerror(errno)); + return -1; + } +} + + +/* + * Test (re-)enabling a disabled event. + */ +int test_enable() +{ + int ret = 0; + struct Test_info test = { + "Enable test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + struct kevent event; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + /* Disable the event */ + EV_SET(&event, fildes.fd, test.filter, EV_DISABLE, 0, 0, NULL); + ret = kevent(fildes.kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to disable event: %s\n", test.name, + strerror(errno)); + + return ret; + } + + ret = kevent(fildes.kq, NULL, 0, &event, 1, &timeout); + if (ret == -1) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to retrieve result 2: %s\n", test.name, + strerror(errno)); + return ret; + } + + if (ret != 0) { + printf("%s: Event was not disabled: %s\n", test.name, + strerror(errno)); + return -1; + } + + /* (Re-)Enable the event */ + EV_SET(&event, fildes.fd, test.filter, EV_ENABLE, 0, 0, NULL); + ret = kevent(fildes.kq, &event, 1, NULL, 0, NULL); + if (ret) { + close(fildes.fd); + close(fildes.kq); + printf("%s: Failed to enable event: %s\n", test.name, + strerror(errno)); + return ret; + } + + return get_result(&test, &fildes); +} + + +/* + * Test queuing a disabled event. + */ +int test_queue_disabled() +{ + int ret = 0; + struct Test_info test = { + "Queue disabled test", + "/dev/rtc", + O_RDONLY, + EVFILT_READ, + EV_ADD | EV_DISABLE + }; + struct Fildes fildes; + const struct timespec timeout = {.tv_sec = 0, .tv_nsec = 1000000}; + struct kevent event; + + ret = bringup(&test, &fildes); + if (ret) + return ret; + + ret = kevent(fildes.kq, NULL, 0, &event, 1, &timeout); + + close(fildes.fd); + close(fildes.kq); + + switch (ret) { + case 0: + printf("%s: Test successful.\n", test.name); + return 0; + case -1: + printf("%s: Failed to retrieve result: %s\n", test.name, + strerror(errno)); + return -1; + default: + printf("%s: Event was not disabled: %s\n", test.name, + strerror(errno)); + return -1; + } +} + + +int main(int argc, char **argv) +{ + int retval = 0; + + retval += test_write(); + retval += test_read(); + retval += test_delete(); + retval += test_repeat(); + retval += test_oneshot(); + retval += test_disable(); + retval += test_enable(); + retval += test_queue_disabled(); + + if (!retval) + printf("--- test succeeded ---\n"); + + return retval; +} diff --git a/repos/libports/src/test/libc_kqueue/target.mk b/repos/libports/src/test/libc_kqueue/target.mk new file mode 100644 index 0000000000..100980f875 --- /dev/null +++ b/repos/libports/src/test/libc_kqueue/target.mk @@ -0,0 +1,5 @@ +TARGET = test-libc_kqueue +SRC_C = kqueue.c +LIBS = posix + +CC_CXX_WARN_STRICT = diff --git a/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc b/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc index d432ba8bf5..1ed9c8054f 100644 --- a/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc +++ b/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc @@ -57,13 +57,13 @@ struct Window : Genode_egl_window Window(Genode::Env &env, int w, int h) : - env(env), mode { .area = Gui::Area(w, h) } + env(env), mode { .area = Gui::Area(w, h), .alpha = false } { width = w; height = h; type = WINDOW; - gui.buffer(mode, false); + gui.buffer(mode); mode_change(); } @@ -82,7 +82,7 @@ struct Window : Genode_egl_window void refresh() { - gui.framebuffer.refresh(0, 0, mode.area.w, mode.area.h); + gui.framebuffer.refresh({ { 0, 0 }, mode.area }); } }; diff --git a/repos/libports/src/test/pthread/main.cc b/repos/libports/src/test/pthread/main.cc index bf7a9e406c..a9f6e89c45 100644 --- a/repos/libports/src/test/pthread/main.cc +++ b/repos/libports/src/test/pthread/main.cc @@ -25,6 +25,7 @@ /* Genode includes */ #include <base/log.h> #include <base/sleep.h> +#include <cpu/atomic.h> struct Thread_args { @@ -536,7 +537,7 @@ struct Test_mutex_stress } /* stay in mutex for some time */ - for (unsigned volatile d = 0; d < 30000; ++d) ; + for (unsigned volatile d = 0; d < 30000; ) d = d + 3; if (MUTEX_TYPE == PTHREAD_MUTEX_RECURSIVE) { _unlock(); @@ -1099,7 +1100,7 @@ static bool key_destructor_func_called = false; static void test_tls_data() { - int test; + int test = 0; if (pthread_setspecific(key, &test) != 0) { Genode::error("pthread_setspecific() failed"); @@ -1193,6 +1194,156 @@ static void test_thread_local_destructor() } +/* test_pthread_once() counters */ +static int volatile once_init, once_round, once_round_complete; + +static int inc(int volatile *counter) +{ + int next = *counter + 1; + while (!Genode::cmpxchg(counter, next - 1, next)) + next++; + return next; +} + +static void init_once1() { inc(&once_init); } +static void init_once2() { inc(&once_init); } +static void init_once3() { inc(&once_init); } + +static void init_once_nested() +{ + pthread_once_t once_nested = PTHREAD_ONCE_INIT; + + pthread_once(&once_nested, init_once1); + + inc(&once_init); +} + +struct Once_thread +{ + enum { ROUNDS = 1'000 }; + + struct Arg + { + pthread_once_t *once; + void (*init_once)(void); + }; + + unsigned _tag; + + Cond &_cond; + Mutex<PTHREAD_MUTEX_NORMAL> &_mutex; + + Arg _once1, _once2, _once3; + + pthread_t _thread; + + static void * _entry_trampoline(void *arg) + { + Once_thread *t = (Once_thread *)arg; + t->_entry(); + return nullptr; + } + + void _entry() + { + for (int i = 1; i <= ROUNDS; ++i) { + pthread_mutex_lock(_mutex.mutex()); + while (once_round != i) + pthread_cond_wait(_cond.cond(), _mutex.mutex()); + pthread_mutex_unlock(_mutex.mutex()); + + pthread_once(_once1.once, _once1.init_once); + pthread_once(_once2.once, _once2.init_once); + pthread_once(_once3.once, _once3.init_once); + + inc(&once_round_complete); + } + } + + Once_thread(unsigned tag, Cond &cond, Mutex<PTHREAD_MUTEX_NORMAL> &mutex, + Arg once1, Arg once2, Arg once3) + : _tag(tag), _cond(cond), _mutex(mutex), _once1(once1), _once2(once2), _once3(once3) + { + if (pthread_create(&_thread, 0, _entry_trampoline, this) != 0) { + printf("Error: pthread_create() failed\n"); + exit(-1); + } + } + + void join() { pthread_join(_thread, nullptr); } +}; + + +static void check_pthread_once(int num_init) +{ + if (once_init == num_init) return; + + Genode::error("unxpected pthread_once initializer call count ", + once_init, "/", num_init); + exit(-1); +} + +static void test_pthread_once() +{ + printf("main thread: test pthread_once()\n"); + + pthread_once_t once1, once2, once3; + + /* test one thread and double-init prevention */ + once_init = 0; once1 = once2 = once3 = PTHREAD_ONCE_INIT; + pthread_once(&once1, init_once1); + pthread_once(&once1, init_once1); + check_pthread_once(1); + + /* test one thread with consecutive onces */ + once_init = 0; once1 = once2 = once3 = PTHREAD_ONCE_INIT; + pthread_once(&once1, init_once1); + pthread_once(&once2, init_once2); + pthread_once(&once3, init_once3); + check_pthread_once(3); + + /* test one thread and nested pthread_once() with different onces */ + once_init = 0; once1 = once2 = once3 = PTHREAD_ONCE_INIT; + pthread_once(&once1, init_once_nested); + check_pthread_once(2); + + Cond cond; + + Mutex<PTHREAD_MUTEX_NORMAL> mutex; + + enum { NUM_THREADS = 6 }; + Once_thread threads[NUM_THREADS] = { + { 1, cond, mutex, { &once1, init_once1 }, { &once2, init_once2 }, { &once3, init_once3 } }, + { 2, cond, mutex, { &once3, init_once3 }, { &once1, init_once1 }, { &once2, init_once2 } }, + { 3, cond, mutex, { &once2, init_once2 }, { &once3, init_once3 }, { &once1, init_once1 } }, + { 4, cond, mutex, { &once1, init_once1 }, { &once2, init_once2 }, { &once3, init_once3 } }, + { 5, cond, mutex, { &once3, init_once3 }, { &once1, init_once1 }, { &once2, init_once2 } }, + { 6, cond, mutex, { &once2, init_once2 }, { &once3, init_once3 }, { &once1, init_once1 } }, + }; + + for (int i = 1; i <= Once_thread::ROUNDS; ++i) { + pthread_mutex_lock(mutex.mutex()); + + once_round = i; once_init = 0; once_round_complete = 0; + once1 = once2 = once3 = PTHREAD_ONCE_INIT; + pthread_cond_broadcast(cond.cond()); + + pthread_mutex_unlock(mutex.mutex()); + + pthread_once(&once1, init_once1); + pthread_once(&once2, init_once2); + pthread_once(&once3, init_once3); + + while (once_round_complete != NUM_THREADS) + usleep(1000); + + check_pthread_once(3); + } + + for (Once_thread &t : threads) t.join(); +} + + int main(int argc, char **argv) { printf("--- pthread test ---\n"); @@ -1212,6 +1363,7 @@ int main(int argc, char **argv) test_cleanup(); test_tls(); test_thread_local_destructor(); + test_pthread_once(); printf("--- returning from main ---\n"); return 0; diff --git a/repos/os/include/capture_session/capture_session.h b/repos/os/include/capture_session/capture_session.h index dc1fe698ea..4313c88b9a 100644 --- a/repos/os/include/capture_session/capture_session.h +++ b/repos/os/include/capture_session/capture_session.h @@ -68,18 +68,28 @@ struct Capture::Session : Genode::Session */ virtual void screen_size_sigh(Signal_context_capability) = 0; + /** + * Register signal handler informed of new data to capture + * + * A wakeup signal is delivered only after a call of 'capture_stopped'. + */ + virtual void wakeup_sigh(Signal_context_capability) = 0; + + enum class Buffer_result { OK, OUT_OF_RAM, OUT_OF_CAPS }; + + struct Buffer_attr + { + Area px; /* buffer area in pixels */ + Area mm; /* physical size in millimeters */ + }; + /** * Define dimensions of the shared pixel buffer * * The 'size' controls the server-side allocation of the shared pixel - * buffer and may affect the screen size of the GUI server. The screen - * size is bounding box of the pixel buffers of all capture clients. - * - * \throw Out_of_ram session quota does not suffice for specified - * buffer dimensions - * \throw Out_of_caps + * buffer and may affect the screen size of the GUI server. */ - virtual void buffer(Area size) = 0; + virtual Buffer_result buffer(Buffer_attr) = 0; /** * Request dataspace of the shared pixel buffer defined via 'buffer' @@ -111,9 +121,24 @@ struct Capture::Session : Genode::Session * * \return geometry information about the content that changed since the * previous call of 'capture_at' + * + * A client should call 'capture_at' at intervals between 10 to 40 ms + * (25-100 FPS). Should no change happen for more than 50 ms, the client + * may stop the periodic capturing and call 'capture_stopped' once. As soon + * as new changes becomes available for capturing, a wakeup signal tells + * the client to resume the periodic capturing. + * + * The nitpicker GUI server reflects 'capture_at' calls as 'sync' signals + * to its GUI clients, which thereby enables applications to synchronize + * their output to the display's refresh rate. */ virtual Affected_rects capture_at(Point) = 0; + /** + * Schedule wakeup signal + */ + virtual void capture_stopped() = 0; + /********************* ** RPC declaration ** @@ -121,13 +146,14 @@ struct Capture::Session : Genode::Session GENODE_RPC(Rpc_screen_size, Area, screen_size); GENODE_RPC(Rpc_screen_size_sigh, void, screen_size_sigh, Signal_context_capability); - GENODE_RPC_THROW(Rpc_buffer, void, buffer, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), Area); + GENODE_RPC(Rpc_wakeup_sigh, void, wakeup_sigh, Signal_context_capability); + GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Buffer_attr); GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace); GENODE_RPC(Rpc_capture_at, Affected_rects, capture_at, Point); + GENODE_RPC(Rpc_capture_stopped, void, capture_stopped); - GENODE_RPC_INTERFACE(Rpc_screen_size, Rpc_screen_size_sigh, Rpc_buffer, - Rpc_dataspace, Rpc_capture_at); + GENODE_RPC_INTERFACE(Rpc_screen_size, Rpc_screen_size_sigh, Rpc_wakeup_sigh, + Rpc_buffer, Rpc_dataspace, Rpc_capture_at, Rpc_capture_stopped); }; #endif /* _INCLUDE__CAPTURE_SESSION__CAPTURE_SESSION_H_ */ diff --git a/repos/os/include/capture_session/client.h b/repos/os/include/capture_session/client.h deleted file mode 100644 index bf032d8d9f..0000000000 --- a/repos/os/include/capture_session/client.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * \brief Client-side capture session interface - * \author Norman Feske - * \date 2020-06-26 - */ - -/* - * Copyright (C) 2020 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _INCLUDE__CAPTURE_SESSION__CLIENT_H_ -#define _INCLUDE__CAPTURE_SESSION__CLIENT_H_ - -#include <capture_session/capture_session.h> -#include <base/rpc_client.h> - -namespace Capture { struct Session_client; } - - -struct Capture::Session_client : public Genode::Rpc_client<Session> -{ - /** - * Constructor - */ - Session_client(Capability<Session> session) : Rpc_client<Session>(session) { } - - Area screen_size() const override { return call<Rpc_screen_size>(); } - - void screen_size_sigh(Signal_context_capability sigh) override - { - call<Rpc_screen_size_sigh>(sigh); - } - - void buffer(Area size) override { call<Rpc_buffer>(size); } - - Dataspace_capability dataspace() override { return call<Rpc_dataspace>(); } - - Affected_rects capture_at(Point pos) override - { - return call<Rpc_capture_at>(pos); - } -}; - -#endif /* _INCLUDE__CAPTURE_SESSION__CLIENT_H_ */ diff --git a/repos/os/include/capture_session/connection.h b/repos/os/include/capture_session/connection.h index 35393a7737..f152057df0 100644 --- a/repos/os/include/capture_session/connection.h +++ b/repos/os/include/capture_session/connection.h @@ -14,7 +14,7 @@ #ifndef _INCLUDE__CAPTURE_SESSION__CONNECTION_H_ #define _INCLUDE__CAPTURE_SESSION__CONNECTION_H_ -#include <capture_session/client.h> +#include <capture_session/capture_session.h> #include <base/connection.h> #include <base/attached_dataspace.h> #include <os/texture.h> @@ -23,8 +23,7 @@ namespace Capture { class Connection; } -class Capture::Connection : public Genode::Connection<Session>, - public Session_client +class Capture::Connection : private Genode::Connection<Session> { private: @@ -32,19 +31,20 @@ class Capture::Connection : public Genode::Connection<Session>, public: + using Label = Genode::Session_label; + /** * Constructor */ Connection(Genode::Env &env, Label const &label = Label()) : Genode::Connection<Capture::Session>(env, label, - Ram_quota { 36*1024 }, Args()), - Session_client(cap()) + Ram_quota { 36*1024 }, Args()) { } - void buffer(Area size) override + void buffer(Session::Buffer_attr attr) { - size_t const needed = buffer_bytes(size); + size_t const needed = Session::buffer_bytes(attr.px); size_t const upgrade = needed > _session_quota ? needed - _session_quota : 0; @@ -53,10 +53,42 @@ class Capture::Connection : public Genode::Connection<Session>, _session_quota += upgrade; } - Session_client::buffer(size); + for (;;) { + using Result = Session::Buffer_result; + switch (cap().call<Session::Rpc_buffer>(attr)) { + case Result::OUT_OF_RAM: upgrade_ram(8*1024); break; + case Result::OUT_OF_CAPS: upgrade_caps(2); break; + case Result::OK: + return; + } + } } struct Screen; + + Area screen_size() const { return cap().call<Session::Rpc_screen_size>(); } + + void screen_size_sigh(Signal_context_capability sigh) + { + cap().call<Session::Rpc_screen_size_sigh>(sigh); + } + + void wakeup_sigh(Signal_context_capability sigh) + { + cap().call<Session::Rpc_wakeup_sigh>(sigh); + } + + Genode::Dataspace_capability dataspace() + { + return cap().call<Session::Rpc_dataspace>(); + } + + Session::Affected_rects capture_at(Point pos) + { + return cap().call<Session::Rpc_capture_at>(pos); + } + + void capture_stopped() { cap().call<Session::Rpc_capture_stopped>(); } }; @@ -64,29 +96,40 @@ class Capture::Connection::Screen { public: - Area const size; + struct Attr + { + Area px; /* buffer area in pixels */ + Area mm; /* physical size in millimeters */ + }; + + Attr const attr; private: Capture::Connection &_connection; - bool const _buffer_initialized = ( _connection.buffer(size), true ); + bool const _buffer_initialized = ( + _connection.buffer({ .px = attr.px, .mm = attr.mm }), true ); Attached_dataspace _ds; - Texture<Pixel> const _texture { _ds.local_addr<Pixel>(), nullptr, size }; + Texture<Pixel> const _texture { _ds.local_addr<Pixel>(), nullptr, attr.px }; public: - Screen(Capture::Connection &connection, Region_map &rm, Area size) + Screen(Capture::Connection &connection, Region_map &rm, Attr attr) : - size(size), _connection(connection), _ds(rm, _connection.dataspace()) + attr(attr), _connection(connection), _ds(rm, _connection.dataspace()) { } void with_texture(auto const &fn) const { fn(_texture); } - void apply_to_surface(Surface<Pixel> &surface) + Rect apply_to_surface(Surface<Pixel> &surface) { + Rect bounding_box { }; + + using Affected_rects = Session::Affected_rects; + Affected_rects const affected = _connection.capture_at(Capture::Point(0, 0)); with_texture([&] (Texture<Pixel> const &texture) { @@ -96,8 +139,13 @@ class Capture::Connection::Screen surface.clip(rect); Blit_painter::paint(surface, texture, Capture::Point(0, 0)); + + bounding_box = bounding_box.area.count() + ? Rect::compound(bounding_box, rect) + : rect; }); }); + return bounding_box; } }; diff --git a/repos/os/include/decorator/window.h b/repos/os/include/decorator/window.h index e5a54cc487..bc097c9de8 100644 --- a/repos/os/include/decorator/window.h +++ b/repos/os/include/decorator/window.h @@ -141,6 +141,8 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element _stacked = true; } + void forget_neighbor() { _neighbor.destruct(); } + bool back_most() const { return _stacked && !_neighbor.constructed(); diff --git a/repos/os/include/decorator/window_stack.h b/repos/os/include/decorator/window_stack.h index 518cecbfe2..e305a84d49 100644 --- a/repos/os/include/decorator/window_stack.h +++ b/repos/os/include/decorator/window_stack.h @@ -257,7 +257,7 @@ void Decorator::Window_stack::update_model(Genode::Xml_node root_node, reversed.remove(back_most); Window_base &window = *back_most->object(); stack_back_most_window(window); - window.stacking_neighbor(Gui::View_id()); + window.forget_neighbor(); Window_base *neighbor = &window; diff --git a/repos/os/include/framebuffer_session/client.h b/repos/os/include/framebuffer_session/client.h index 57bc389e19..b70b93ca3d 100644 --- a/repos/os/include/framebuffer_session/client.h +++ b/repos/os/include/framebuffer_session/client.h @@ -20,24 +20,46 @@ namespace Framebuffer { struct Session_client; } -struct Framebuffer::Session_client : Genode::Rpc_client<Session> +struct Framebuffer::Session_client : Rpc_client<Session> { - explicit Session_client(Session_capability session) - : Genode::Rpc_client<Session>(session) { } + explicit Session_client(Session_capability cap) : Rpc_client<Session>(cap) { } - Genode::Dataspace_capability dataspace() override { - return call<Rpc_dataspace>(); } + Dataspace_capability dataspace() override { return call<Rpc_dataspace>(); } Mode mode() const override { return call<Rpc_mode>(); } - void mode_sigh(Genode::Signal_context_capability sigh) override { - call<Rpc_mode_sigh>(sigh); } + void mode_sigh(Signal_context_capability sigh) override { call<Rpc_mode_sigh>(sigh); } - void sync_sigh(Genode::Signal_context_capability sigh) override { - call<Rpc_sync_sigh>(sigh); } + void sync_sigh(Signal_context_capability sigh) override { call<Rpc_sync_sigh>(sigh); } - void refresh(int x, int y, int w, int h) override { - call<Rpc_refresh>(x, y, w, h); } + void sync_source(Session_label const &source) override { call<Rpc_sync_source>(source); } + + void refresh(Rect rect) override { call<Rpc_refresh>(rect); } + + /** + * Flush specified pixel region + * + * \deprecated + * \noapi + */ + void refresh(int x, int y, int w, int h) + { + refresh(Rect { { x, y }, { unsigned(w), unsigned(h) } }); + } + + Blit_result blit(Blit_batch const &batch) override { return call<Rpc_blit>(batch); } + + /** + * Transfer a single pixel region within the framebuffer + */ + Blit_result blit(Rect from, Point to) + { + Blit_batch batch { }; + batch.transfer[0] = { from, to }; + return blit(batch); + } + + void panning(Point pos) override { call<Rpc_panning>(pos); } }; #endif /* _INCLUDE__FRAMEBUFFER_SESSION__CLIENT_H_ */ diff --git a/repos/os/include/framebuffer_session/connection.h b/repos/os/include/framebuffer_session/connection.h index 7d6ac22fb2..ab3ce94c6e 100644 --- a/repos/os/include/framebuffer_session/connection.h +++ b/repos/os/include/framebuffer_session/connection.h @@ -31,7 +31,7 @@ struct Framebuffer::Connection : Genode::Connection<Session>, Session_client * session, you should validate the actual frame-buffer attributes * by calling the 'info' method of the frame-buffer interface. */ - Connection(Genode::Env &env, Framebuffer::Mode mode) + Connection(Env &env, Framebuffer::Mode mode) : Genode::Connection<Session>(env, Label(), Ram_quota { 8*1024 }, Args("fb_width=", mode.area.w, ", " diff --git a/repos/os/include/framebuffer_session/framebuffer_session.h b/repos/os/include/framebuffer_session/framebuffer_session.h index 3f45ab9410..b3dde2ba86 100644 --- a/repos/os/include/framebuffer_session/framebuffer_session.h +++ b/repos/os/include/framebuffer_session/framebuffer_session.h @@ -19,30 +19,120 @@ #include <dataspace/capability.h> #include <session/session.h> #include <os/surface.h> +#include <os/pixel_rgb888.h> +#include <os/pixel_alpha8.h> namespace Framebuffer { - struct Mode; struct Session; struct Session_client; - using Area = Genode::Surface_base::Area; + using namespace Genode; + + using Area = Surface_base::Area; + using Point = Surface_base::Point; + using Rect = Surface_base::Rect; + + struct Mode + { + Area area; + bool alpha; + + void print(Output &out) const { Genode::print(out, area); } + + /* + * If using an alpha channel, the alpha buffer follows the pixel + * buffer. The alpha buffer is followed by an input-mask buffer. + * + * The input-mask buffer contains a byte value per texture pixel, + * which describes the policy of handling user input referring to the + * pixel. If set to zero, the input is passed through the view such + * that it can be handled by one of the subsequent views in the view + * stack. If set to one, the input is consumed by the view. + */ + + void with_pixel_surface(auto &ds, auto const &fn) const + { + Surface<Pixel_rgb888> surface { ds.bytes(), area }; + fn(surface); + } + + void with_alpha_bytes(auto &ds, auto const &fn) const + { + if (!alpha) + return; + + size_t const offset = area.count()*sizeof(Pixel_rgb888); + ds.bytes().with_skipped_bytes(offset, [&] (Byte_range_ptr const &bytes) { + fn(bytes); }); + } + + void with_alpha_surface(auto &ds, auto const &fn) const + { + with_alpha_bytes(ds, [&] (Byte_range_ptr const &bytes) { + Surface<Pixel_alpha8> surface { bytes, area }; + fn(surface); }); + } + + void with_input_bytes(auto &ds, auto const &fn) const + { + if (!alpha) + return; + + size_t const offset = area.count()*sizeof(Pixel_rgb888) + area.count(); + ds.bytes().with_skipped_bytes(offset, [&] (Byte_range_ptr const &bytes) { + fn(bytes); }); + } + + void with_input_surface(auto &ds, auto const &fn) const + { + with_input_bytes(ds, [&] (Byte_range_ptr const &bytes) { + Surface<Pixel_input8> surface { bytes, area }; + fn(surface); }); + } + + size_t num_bytes() const + { + size_t const bytes_per_pixel = + sizeof(Pixel_rgb888) + alpha*(sizeof(Pixel_alpha8) + sizeof(Pixel_input8)); + + return area.count()*bytes_per_pixel; + } + }; + + struct Transfer + { + Rect from; /* source rectangle */ + Point to; /* destination position */ + + /** + * Return true if transfer is applicable to 'mode' + * + * Pixels are transferred only if the source rectangle lies within + * the bounds of the framebuffer, and source does not overlap the + * destination. + */ + bool valid(Mode const &mode) const + { + Rect const fb { { }, mode.area }; + Rect const dest { to, from.area }; + + return from.area.valid() + && fb.contains(from.p1()) && fb.contains(from.p2()) + && fb.contains(dest.p1()) && fb.contains(dest.p2()) + && !Rect::intersect(from, dest).valid(); + } + }; + + struct Blit_batch + { + static constexpr unsigned N = 4; + + Transfer transfer[N]; + }; } -/** - * Framebuffer mode info as returned by 'Framebuffer::Session::mode()' - */ -struct Framebuffer::Mode -{ - Area area; - - Genode::size_t bytes_per_pixel() const { return 4; } - - void print(Genode::Output &out) const { Genode::print(out, area); } -}; - - struct Framebuffer::Session : Genode::Session { /** @@ -70,7 +160,7 @@ struct Framebuffer::Session : Genode::Session * have detached the previously requested dataspace from its local * address space. */ - virtual Genode::Dataspace_capability dataspace() = 0; + virtual Dataspace_capability dataspace() = 0; /** * Request display-mode properties of the framebuffer ready to be @@ -89,33 +179,66 @@ struct Framebuffer::Session : Genode::Session * method. However, from the client's perspective, the original mode * stays in effect until the it calls 'dataspace()' again. */ - virtual void mode_sigh(Genode::Signal_context_capability sigh) = 0; + virtual void mode_sigh(Signal_context_capability sigh) = 0; /** * Flush specified pixel region * - * \param x,y,w,h region to be updated on physical frame buffer + * \param rect region to be updated on physical frame buffer */ - virtual void refresh(int x, int y, int w, int h) = 0; + virtual void refresh(Rect rect) = 0; + + enum class Blit_result { OK, OVERLOADED }; + + /** + * Transfer pixel regions within the framebuffer + */ + virtual Blit_result blit(Blit_batch const &) = 0; + + /** + * Define panning position of the framebuffer + * + * The panning position is the point within the framebuffer that + * corresponds to the top-left corner of the output. It is designated + * for implementing buffer flipping of double-buffered output, and for + * scrolling. + */ + virtual void panning(Point pos) = 0; /** * Register signal handler for refresh synchronization */ - virtual void sync_sigh(Genode::Signal_context_capability) = 0; + virtual void sync_sigh(Signal_context_capability) = 0; + + /** + * Define the preferred source of sync signals + * + * In the presence of multiple capture clients at the GUI server, each + * client captures the GUI at independent refresh rates. Hence, there is + * no single source of sync signals but there can be multiple. From the + * application's perspective, the most adequate sync source may depend on + * the positions of the capture clients at the GUI server and the position + * of the application's view. By specifying a capture client's label as + * 'sync_sigh', the application can take an informed decision. + */ + virtual void sync_source(Session_label const &) = 0; /********************* ** RPC declaration ** *********************/ - GENODE_RPC(Rpc_dataspace, Genode::Dataspace_capability, dataspace); + GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace); GENODE_RPC(Rpc_mode, Mode, mode); - GENODE_RPC(Rpc_refresh, void, refresh, int, int, int, int); - GENODE_RPC(Rpc_mode_sigh, void, mode_sigh, Genode::Signal_context_capability); - GENODE_RPC(Rpc_sync_sigh, void, sync_sigh, Genode::Signal_context_capability); + GENODE_RPC(Rpc_refresh, void, refresh, Rect); + GENODE_RPC(Rpc_blit, Blit_result, blit, Blit_batch const &); + GENODE_RPC(Rpc_panning, void, panning, Point); + GENODE_RPC(Rpc_mode_sigh, void, mode_sigh, Signal_context_capability); + GENODE_RPC(Rpc_sync_sigh, void, sync_sigh, Signal_context_capability); + GENODE_RPC(Rpc_sync_source, void, sync_source, Session_label const &); GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_mode, Rpc_mode_sigh, Rpc_refresh, - Rpc_sync_sigh); + Rpc_blit, Rpc_panning, Rpc_sync_sigh, Rpc_sync_source); }; #endif /* _INCLUDE__FRAMEBUFFER_SESSION__FRAMEBUFFER_SESSION_H_ */ diff --git a/repos/os/include/gui_session/client.h b/repos/os/include/gui_session/client.h index 37da61b4bd..2228a8ef00 100644 --- a/repos/os/include/gui_session/client.h +++ b/repos/os/include/gui_session/client.h @@ -30,19 +30,22 @@ struct Gui::Session_client : Rpc_client<Session> Input::Session_capability input() override { return call<Rpc_input>(); } - View_result view(View_id id, View_attr const &attr) override { + Info_result info() override { + return call<Rpc_info>(); } + + [[nodiscard]] View_result view(View_id id, View_attr const &attr) override { return call<Rpc_view>(id, attr); } - Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override { + [[nodiscard]] Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override { return call<Rpc_child_view>(id, parent, attr); } void destroy_view(View_id view) override { call<Rpc_destroy_view>(view); } - Associate_result associate(View_id id, View_capability view) override { + [[nodiscard]] Associate_result associate(View_id id, View_capability view) override { return call<Rpc_associate>(id, view); } - View_capability_result view_capability(View_id id) override { + [[nodiscard]] View_capability_result view_capability(View_id id) override { return call<Rpc_view_capability>(id); } void release_view_id(View_id id) override { @@ -53,14 +56,8 @@ struct Gui::Session_client : Rpc_client<Session> void execute() override { call<Rpc_execute>(); } - Framebuffer::Mode mode() override { - return call<Rpc_mode>(); } - - void mode_sigh(Signal_context_capability sigh) override { - call<Rpc_mode_sigh>(sigh); } - - Buffer_result buffer(Framebuffer::Mode mode, bool alpha) override { - return call<Rpc_buffer>(mode, alpha); } + [[nodiscard]] Buffer_result buffer(Framebuffer::Mode mode) override { + return call<Rpc_buffer>(mode); } void focus(Gui::Session_capability session) override { call<Rpc_focus>(session); } diff --git a/repos/os/include/gui_session/connection.h b/repos/os/include/gui_session/connection.h index aa59a615b1..91743116e6 100644 --- a/repos/os/include/gui_session/connection.h +++ b/repos/os/include/gui_session/connection.h @@ -17,6 +17,7 @@ #include <gui_session/client.h> #include <framebuffer_session/client.h> #include <input_session/client.h> +#include <rom_session/client.h> #include <base/connection.h> namespace Gui { @@ -41,6 +42,54 @@ class Gui::Connection : private Genode::Connection<Session> Ram_quota _ram_quota { }; /* session quota donated for virtual frame buffer */ + /* + * Session quota at the construction time of the connection + * + * The 'Gui::Session::CAP_QUOTA' value is based the needs of the + * nitpicker GUI server. To accommodate the common case where a client + * is served by the wm, which in turn wraps a nitpicker session, extend + * the session quota according to the needs of the wm. + */ + static constexpr Ram_quota _RAM_QUOTA { 96*1024 }; + static constexpr Cap_quota _CAP_QUOTA { Session::CAP_QUOTA + 9 }; + + Constructible<Rom_session_client> _info_rom { }; + Constructible<Attached_dataspace> _info_ds { }; + + Rom_session_capability _info_rom_capability() + { + for (;;) { + using Error = Session::Info_error; + auto const result = _client.info(); + if (result == Error::OUT_OF_RAM) { upgrade_ram(8*1024); continue; } + if (result == Error::OUT_OF_CAPS) { upgrade_caps(2); continue; } + return result.convert<Rom_session_capability>( + [&] (Rom_session_capability cap) { return cap; }, + [&] (auto) /* handled above */ { return Rom_session_capability(); }); + } + } + + void _with_info_rom(auto const &fn) + { + if (!_info_ds.constructed()) + _info_rom.construct(_info_rom_capability()); + fn(*_info_rom); + } + + void _with_info_xml(auto const &fn) + { + _with_info_rom([&] (Rom_session_client &rom) { + if (!_info_ds.constructed() || rom.update() == false) + _info_ds.construct(_env.rm(), rom.dataspace()); + + try { + Xml_node xml(_info_ds->local_addr<char>(), _info_ds->size()); + fn(xml); } + catch (Xml_node::Invalid_syntax) { + warning("Gui::info has invalid XML syntax"); } + }); + } + public: View_ids view_ids { }; @@ -65,7 +114,8 @@ class Gui::Connection : private Genode::Connection<Session> */ Connection(Env &env, Session_label const &label = { }) : - Genode::Connection<Session>(env, label, Ram_quota { 36*1024 }, Args()), + Genode::Connection<Session>(env, label, _RAM_QUOTA, _CAP_QUOTA, + Affinity { }, Args { }), _env(env) { } @@ -142,9 +192,9 @@ class Gui::Connection : private Genode::Connection<Session> } } - void buffer(Framebuffer::Mode mode, bool use_alpha) + void buffer(Framebuffer::Mode mode) { - size_t const needed = Session_client::ram_quota(mode, use_alpha); + size_t const needed = Session_client::ram_quota(mode); size_t const upgrade = needed > _ram_quota.value ? needed - _ram_quota.value : 0u; if (upgrade > 0) { @@ -152,13 +202,12 @@ class Gui::Connection : private Genode::Connection<Session> _ram_quota.value += upgrade; } - for (bool retry = false; ; ) { + for (;;) { using Result = Session_client::Buffer_result; - auto const result = _client.buffer(mode, use_alpha); - if (result == Result::OUT_OF_RAM) { upgrade_ram(8*1024); retry = true; } - if (result == Result::OUT_OF_CAPS) { upgrade_caps(2); retry = true; } - if (!retry) - break; + auto const result = _client.buffer(mode); + if (result == Result::OUT_OF_RAM) { upgrade_ram(8*1024); continue; } + if (result == Result::OUT_OF_CAPS) { upgrade_caps(2); continue; } + break; } } @@ -188,14 +237,77 @@ class Gui::Connection : private Genode::Connection<Session> } /** - * Return physical screen mode + * Call 'fn' with mode information as 'Xml_node const &' argument */ - Framebuffer::Mode mode() { return _client.mode(); } + void with_info(auto const &fn) { _with_info_xml(fn); } + + Capability<Rom_session> info_rom_cap() + { + Capability<Rom_session> result { }; + _with_info_rom([&] (Rom_session_client &rom) { result = rom.rpc_cap(); }); + return result; + } + + using Panorama_result = Attempt<Gui::Rect, Gui::Undefined>; + + /** + * Return geometry of the total panorama + * + * The retured rectangle may be undefined for a client of the nitpicker + * GUI server in the absence of any capture client. + */ + Panorama_result panorama() + { + Gui::Rect result { }; + _with_info_xml([&] (Xml_node const &info) { + result = Rect::from_xml(info); }); + return result.valid() ? Panorama_result { result } + : Panorama_result { Undefined { } }; + } + + using Window_result = Attempt<Rect, Gui::Undefined>; + + /** + * Return suitable geometry of top-level view + * + * For nitpicker clients, the window is the bounding box of all capture + * clients. For window-manager clients, returned rectangle corresponds + * to the window size as defined by the layouter. + * + * The returned rectangle may be undefined when a client of the window + * manager has not defined a top-level view yet. Once a window is got + * closed, the returned rectangle is zero-sized. + */ + Window_result window() + { + Rect result { }; + bool closed = false; + _with_info_xml([&] (Xml_node const &info) { + Rect bb { }; /* bounding box of all captured rects */ + unsigned count = 0; + info.for_each_sub_node("capture", [&] (Xml_node const &capture) { + closed |= (capture.attribute_value("closed", false)); + bb = Rect::compound(bb, Rect::from_xml(capture)); + count++; + }); + result = (count == 1) ? bb : Rect::from_xml(info); + }); + if (closed) + return Rect { }; + + return result.valid() ? Window_result { result } + : Window_result { Undefined { } }; + } /** * Register signal handler to be notified about mode changes */ - void mode_sigh(Signal_context_capability sigh) { _client.mode_sigh(sigh); } + void info_sigh(Signal_context_capability sigh) + { + _with_info_rom([&] (Rom_session_client &rom) { rom.sigh(sigh); }); + if (sigh.valid()) + Signal_transmitter(sigh).submit(); + } void focus(Capability<Session> focused) { _client.focus(focused); } }; diff --git a/repos/os/include/gui_session/gui_session.h b/repos/os/include/gui_session/gui_session.h index 2e82d35582..e65042ca91 100644 --- a/repos/os/include/gui_session/gui_session.h +++ b/repos/os/include/gui_session/gui_session.h @@ -19,6 +19,7 @@ #include <os/surface.h> #include <framebuffer_session/capability.h> #include <input_session/capability.h> +#include <rom_session/rom_session.h> namespace Gui { @@ -44,6 +45,8 @@ namespace Gui { using Rect = Surface_base::Rect; using Point = Surface_base::Point; using Area = Surface_base::Area; + + struct Undefined { }; } @@ -171,6 +174,14 @@ struct Gui::Session : Genode::Session */ virtual Input::Session_capability input() = 0; + enum class Info_error { OUT_OF_RAM, OUT_OF_CAPS }; + using Info_result = Attempt<Capability<Rom_session>, Info_error>; + + /** + * Request ROM session containing the mode information + */ + virtual Info_result info() = 0; + struct View_attr { Title title; @@ -233,22 +244,12 @@ struct Gui::Session : Genode::Session */ virtual void execute() = 0; - /** - * Return physical screen mode - */ - virtual Framebuffer::Mode mode() = 0; - - /** - * Register signal handler to be notified about mode changes - */ - virtual void mode_sigh(Signal_context_capability) = 0; - enum class Buffer_result { OK, OUT_OF_RAM, OUT_OF_CAPS }; /** * Define dimensions of virtual framebuffer */ - virtual Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) = 0; + virtual Buffer_result buffer(Framebuffer::Mode mode) = 0; /** * Set focused session @@ -268,13 +269,13 @@ struct Gui::Session : Genode::Session /** * Return number of bytes needed for virtual framebuffer of specified size */ - static size_t ram_quota(Framebuffer::Mode mode, bool use_alpha) + static size_t ram_quota(Framebuffer::Mode mode) { /* * If alpha blending is used, each pixel requires an additional byte * for the alpha value and a byte holding the input mask. */ - return (mode.bytes_per_pixel() + 2*use_alpha)*mode.area.count(); + return (sizeof(Pixel_rgb888) + 2*mode.alpha)*mode.area.count(); } @@ -284,6 +285,7 @@ struct Gui::Session : Genode::Session GENODE_RPC(Rpc_framebuffer, Framebuffer::Session_capability, framebuffer); GENODE_RPC(Rpc_input, Input::Session_capability, input); + GENODE_RPC(Rpc_info, Info_result, info); GENODE_RPC(Rpc_view, View_result, view, View_id, View_attr const &); GENODE_RPC(Rpc_child_view, Child_view_result, child_view, View_id, View_id, View_attr const &); GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_id); @@ -293,16 +295,13 @@ struct Gui::Session : Genode::Session GENODE_RPC(Rpc_command_dataspace, Dataspace_capability, command_dataspace); GENODE_RPC(Rpc_execute, void, execute); GENODE_RPC(Rpc_background, int, background, View_capability); - GENODE_RPC(Rpc_mode, Framebuffer::Mode, mode); - GENODE_RPC(Rpc_mode_sigh, void, mode_sigh, Signal_context_capability); GENODE_RPC(Rpc_focus, void, focus, Capability<Session>); - GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Framebuffer::Mode, bool); + GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Framebuffer::Mode); - GENODE_RPC_INTERFACE(Rpc_framebuffer, Rpc_input, + GENODE_RPC_INTERFACE(Rpc_framebuffer, Rpc_input, Rpc_info, Rpc_view, Rpc_child_view, Rpc_destroy_view, Rpc_associate, Rpc_view_capability, Rpc_release_view_id, - Rpc_command_dataspace, Rpc_execute, Rpc_mode, - Rpc_mode_sigh, Rpc_buffer, Rpc_focus); + Rpc_command_dataspace, Rpc_execute, Rpc_buffer, Rpc_focus); }; #endif /* _INCLUDE__GUI_SESSION__GUI_SESSION_H_ */ diff --git a/repos/os/include/input/component.h b/repos/os/include/input/component.h index c606823e89..e21f802583 100644 --- a/repos/os/include/input/component.h +++ b/repos/os/include/input/component.h @@ -25,11 +25,21 @@ namespace Input { class Session_component; } -class Input::Session_component : public Genode::Rpc_object<Input::Session> +class Input::Session_component : public Rpc_object<Input::Session> { + public: + + struct Action : Interface + { + virtual void exclusive_input_requested(bool) = 0; + }; + private: - Genode::Attached_ram_dataspace _ds; + Entrypoint &_ep; + Action &_action; + + Attached_ram_dataspace _ds; Event_queue _event_queue { }; @@ -38,12 +48,18 @@ class Input::Session_component : public Genode::Rpc_object<Input::Session> /** * Constructor * - * \param ram allocator for the session buffer + * \param ram allocator for the shared-memory input buffer */ - Session_component(Genode::Env &env, Genode::Ram_allocator &ram) + Session_component(Entrypoint &ep, Ram_allocator &ram, + Region_map &rm, Action &action) : - _ds(ram, env.rm(), Event_queue::QUEUE_SIZE*sizeof(Input::Event)) - { } + _ep(ep), _action(action), + _ds(ram, rm, Event_queue::QUEUE_SIZE*sizeof(Input::Event)) + { + _ep.manage(*this); + } + + ~Session_component() { _ep.dissolve(*this); } /** * Return reference to event queue of the session @@ -58,7 +74,7 @@ class Input::Session_component : public Genode::Rpc_object<Input::Session> try { _event_queue.add(event); } catch (Input::Event_queue::Overflow) { - Genode::warning("input overflow - resetting queue"); + warning("input overflow - resetting queue"); _event_queue.reset(); } } @@ -68,7 +84,7 @@ class Input::Session_component : public Genode::Rpc_object<Input::Session> ** Input::Session interface ** ******************************/ - Genode::Dataspace_capability dataspace() override { return _ds.cap(); } + Dataspace_capability dataspace() override { return _ds.cap(); } bool pending() const override { return !_event_queue.empty(); } @@ -83,10 +99,15 @@ class Input::Session_component : public Genode::Rpc_object<Input::Session> return cnt; } - void sigh(Genode::Signal_context_capability sigh) override + void sigh(Signal_context_capability sigh) override { _event_queue.sigh(sigh); } + + void exclusive(bool enabled) override + { + _action.exclusive_input_requested(enabled); + } }; #endif /* _INCLUDE__INPUT__COMPONENT_H_ */ diff --git a/repos/os/include/input_session/client.h b/repos/os/include/input_session/client.h index 633bc98d3d..f24aa3e32c 100644 --- a/repos/os/include/input_session/client.h +++ b/repos/os/include/input_session/client.h @@ -22,26 +22,25 @@ namespace Input { struct Session_client; } -class Input::Session_client : public Genode::Rpc_client<Session> +class Input::Session_client : public Rpc_client<Session> { private: - Genode::Attached_dataspace _event_ds; + Attached_dataspace _event_ds; - Genode::size_t const _max_events = - _event_ds.size() / sizeof(Input::Event); + size_t const _max_events = _event_ds.size() / sizeof(Input::Event); friend class Input::Binding; public: - Session_client(Genode::Region_map &local_rm, Session_capability session) + Session_client(Region_map &local_rm, Session_capability session) : - Genode::Rpc_client<Session>(session), + Rpc_client<Session>(session), _event_ds(local_rm, call<Rpc_dataspace>()) { } - Genode::Dataspace_capability dataspace() override { + Dataspace_capability dataspace() override { return call<Rpc_dataspace>(); } bool pending() const override { @@ -50,9 +49,12 @@ class Input::Session_client : public Genode::Rpc_client<Session> int flush() override { return call<Rpc_flush>(); } - void sigh(Genode::Signal_context_capability sigh) override { + void sigh(Signal_context_capability sigh) override { call<Rpc_sigh>(sigh); } + void exclusive(bool enabled) override { + call<Rpc_exclusive>(enabled); } + /** * Flush and apply functor to pending events * @@ -61,10 +63,10 @@ class Input::Session_client : public Genode::Rpc_client<Session> */ void for_each_event(auto const &fn) { - Genode::size_t const n = Genode::min((Genode::size_t)call<Rpc_flush>(), _max_events); + size_t const n = min((size_t)call<Rpc_flush>(), _max_events); Event const *ev_buf = _event_ds.local_addr<const Event>(); - for (Genode::size_t i = 0; i < n; ++i) + for (size_t i = 0; i < n; ++i) fn(ev_buf[i]); } }; diff --git a/repos/os/include/input_session/input_session.h b/repos/os/include/input_session/input_session.h index 5532896bd0..d53ba4f9e3 100644 --- a/repos/os/include/input_session/input_session.h +++ b/repos/os/include/input_session/input_session.h @@ -19,7 +19,12 @@ #include <session/session.h> #include <base/signal.h> -namespace Input { struct Session; } +namespace Input { + + using namespace Genode; + + struct Session; +} struct Input::Session : Genode::Session @@ -41,7 +46,7 @@ struct Input::Session : Genode::Session /** * Return capability to event buffer dataspace */ - virtual Genode::Dataspace_capability dataspace() = 0; + virtual Dataspace_capability dataspace() = 0; /** * Request input state @@ -60,19 +65,26 @@ struct Input::Session : Genode::Session /** * Register signal handler to be notified on arrival of new input */ - virtual void sigh(Genode::Signal_context_capability) = 0; + virtual void sigh(Signal_context_capability) = 0; + + /** + * Express intent to receive relative pointer events exclusively + */ + virtual void exclusive(bool) = 0; /********************* ** RPC declaration ** *********************/ - GENODE_RPC(Rpc_dataspace, Genode::Dataspace_capability, dataspace); - GENODE_RPC(Rpc_pending, bool, pending); - GENODE_RPC(Rpc_flush, int, flush); - GENODE_RPC(Rpc_sigh, void, sigh, Genode::Signal_context_capability); + GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace); + GENODE_RPC(Rpc_pending, bool, pending); + GENODE_RPC(Rpc_flush, int, flush); + GENODE_RPC(Rpc_sigh, void, sigh, Signal_context_capability); + GENODE_RPC(Rpc_exclusive, void, exclusive, bool); - GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_pending, Rpc_flush, Rpc_sigh); + GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_pending, Rpc_flush, Rpc_sigh, + Rpc_exclusive); }; #endif /* _INCLUDE__INPUT_SESSION__INPUT_SESSION_H_ */ diff --git a/repos/os/include/os/pixel_alpha8.h b/repos/os/include/os/pixel_alpha8.h index f3e051b14c..4ba1718c0f 100644 --- a/repos/os/include/os/pixel_alpha8.h +++ b/repos/os/include/os/pixel_alpha8.h @@ -18,9 +18,11 @@ namespace Genode { - using Pixel_alpha8 = Genode::Pixel_rgba<uint8_t, Genode::Surface_base::ALPHA8, - 0, 0, 0, 0, 0, 0, 0xff, 0>; + using Pixel_alpha8 = Pixel_rgba<uint8_t, Surface_base::ALPHA8, + 0, 0, 0, 0, 0, 0, 0xff, 0>; + using Pixel_input8 = Pixel_rgba<uint8_t, Surface_base::INPUT8, + 0, 0, 0, 0, 0, 0, 0xff, 0>; /* * The second pixel parameter is ignored. It can be of any pixel type. diff --git a/repos/os/include/os/surface.h b/repos/os/include/os/surface.h index 881f32593c..7c8ceb6d7a 100644 --- a/repos/os/include/os/surface.h +++ b/repos/os/include/os/surface.h @@ -22,6 +22,8 @@ namespace Genode { class Surface_base; template <typename> class Surface; + + struct Surface_window { unsigned y, h; }; } @@ -46,7 +48,7 @@ class Genode::Surface_base : Interface using Point = Rect::Point; using Area = Rect::Area; - enum Pixel_format { UNKNOWN, RGB565, RGB888, ALPHA8 }; + enum Pixel_format { UNKNOWN, RGB565, RGB888, ALPHA8, INPUT8 }; struct Flusher : Interface { @@ -124,15 +126,49 @@ class Genode::Surface : public Surface_base PT *_addr; /* base address of pixel buffer */ + static Area _sanitized(Area area, size_t const num_bytes) + { + /* prevent division by zero */ + if (area.w == 0) + return { }; + + size_t const bytes_per_line = area.w*sizeof(PT); + + return { .w = area.w, + .h = unsigned(min(num_bytes/bytes_per_line, area.h)) }; + } + public: PT *addr() { return _addr; } - /** - * Constructor + /* + * \deprecated */ - Surface(PT *addr, Area size) - : Surface_base(size, PT::format()), _addr(addr) { } + Surface(PT *addr, Area size) : Surface_base(size, PT::format()), _addr(addr) { } + + Surface(Byte_range_ptr const &bytes, Area const area) + : + Surface_base(_sanitized(area, bytes.num_bytes), PT::format()), + _addr((PT *)bytes.start) + { } + + /** + * Call 'fn' with a sub-window surface as argument + * + * This method is useful for managing multiple surfaces within one + * larger surface, for example for organizing a back buffer and a front + * buffer within one virtual framebuffer. + */ + void with_window(Surface_window const win, auto const &fn) const + { + /* clip window coordinates against surface boundaries */ + Rect const rect = Rect::intersect({ { 0, 0 }, { 1, size().h } }, + { { 0, int(win.y) }, { 1, win.h } }); + + Surface surface { _addr + rect.y1()*size().w, { size().w, rect.h() } }; + fn(surface); + } }; #endif /* _INCLUDE__OS__SURFACE_H_ */ diff --git a/repos/os/include/util/dirty_rect.h b/repos/os/include/util/dirty_rect.h index 4c72935c94..c33af9b27f 100644 --- a/repos/os/include/util/dirty_rect.h +++ b/repos/os/include/util/dirty_rect.h @@ -136,6 +136,15 @@ class Genode::Dirty_rect rect = rect.valid() ? Rect::compound(rect, added) : added; } + + bool empty() const + { + for (unsigned i = 0; i < NUM_RECTS; i++) + if (_rects[i].area.count()) + return false; + + return true; + } }; #endif /* _INCLUDE__UTIL__DIRTY_RECT_H_ */ diff --git a/repos/os/recipes/api/capture_session/hash b/repos/os/recipes/api/capture_session/hash index fe090d4d6a..c6476d3c1d 100644 --- a/repos/os/recipes/api/capture_session/hash +++ b/repos/os/recipes/api/capture_session/hash @@ -1 +1 @@ -2024-05-28 ba263e0698a28074a83c02495747b5d072689a64 +2024-10-07 846414c9f32cb58ea96be01751d62c36a2e6c581 diff --git a/repos/os/recipes/api/event_session/hash b/repos/os/recipes/api/event_session/hash index ce7d8eae4b..03b89d9eb7 100644 --- a/repos/os/recipes/api/event_session/hash +++ b/repos/os/recipes/api/event_session/hash @@ -1 +1 @@ -2024-08-28 efc8cae4ad60f15c35191be401473f75927df3e7 +2024-10-07 7f32d92e111a6bbb1aba5f9ecb7c52ee68bdcf62 diff --git a/repos/os/recipes/api/framebuffer_session/hash b/repos/os/recipes/api/framebuffer_session/hash index b11528d168..4648443b32 100644 --- a/repos/os/recipes/api/framebuffer_session/hash +++ b/repos/os/recipes/api/framebuffer_session/hash @@ -1 +1 @@ -2024-08-28 2520ff6b0c289e79423e51d0a9094628cde1dea7 +2024-10-07 5df052ce4cd1c5d21e08f928cef91f6283d0cb27 diff --git a/repos/os/recipes/api/genode_c_api/hash b/repos/os/recipes/api/genode_c_api/hash index 11acf407bd..6c8583b408 100644 --- a/repos/os/recipes/api/genode_c_api/hash +++ b/repos/os/recipes/api/genode_c_api/hash @@ -1 +1 @@ -2024-08-28 209fd3a405bf7f8b81d2ab0431ca72ff5681e580 +2024-10-29 f03289b5e371461fbc31a14e004e4bee993d441d diff --git a/repos/os/recipes/api/gui_session/hash b/repos/os/recipes/api/gui_session/hash index 881969bbab..ffb3b9cf65 100644 --- a/repos/os/recipes/api/gui_session/hash +++ b/repos/os/recipes/api/gui_session/hash @@ -1 +1 @@ -2024-08-28 743930bf7e1e72fc1a800d624f32e2fc90af2def +2024-10-29 11e0d6f92de9e605c0d62c57f0ea97e99f3d6ca0 diff --git a/repos/os/recipes/api/input_session/hash b/repos/os/recipes/api/input_session/hash index ffd32ebdd3..4fb11529f3 100644 --- a/repos/os/recipes/api/input_session/hash +++ b/repos/os/recipes/api/input_session/hash @@ -1 +1 @@ -2024-08-28 aafe9f18aa692d8579d037680a4795a2cd2bb305 +2024-10-07 d86f6ad6bf2877aa0367b835d73a18faf257373c diff --git a/repos/os/recipes/api/os/hash b/repos/os/recipes/api/os/hash index ad167abbdc..da6423bda1 100644 --- a/repos/os/recipes/api/os/hash +++ b/repos/os/recipes/api/os/hash @@ -1 +1 @@ -2024-08-28 77fd0c06ea7ace45f14cd726323cfacbd76011de +2024-10-07 e1072a343816c9df02ffd24da0faf2608dd2e399 diff --git a/repos/os/recipes/pkg/black_hole/hash b/repos/os/recipes/pkg/black_hole/hash index 6ca7906920..4bd2fe18f0 100644 --- a/repos/os/recipes/pkg/black_hole/hash +++ b/repos/os/recipes/pkg/black_hole/hash @@ -1 +1 @@ -2024-08-28 c41e3dea50933b66bfaf6be475c6a2a064ab2ef9 +2024-10-07 9bd6c0588306788642646dedeca08d5e8c9bfed3 diff --git a/repos/os/recipes/pkg/chroot/hash b/repos/os/recipes/pkg/chroot/hash index 4246904813..8d4e8cf560 100644 --- a/repos/os/recipes/pkg/chroot/hash +++ b/repos/os/recipes/pkg/chroot/hash @@ -1 +1 @@ -2024-08-28 574169841518f1c0ff6f785aa260eeb9ff489782 +2024-10-07 4e0e5109687970456c9b1a634ae94b62aa30b6b9 diff --git a/repos/os/recipes/pkg/clipboard/hash b/repos/os/recipes/pkg/clipboard/hash index 78346bc17d..269fabcf21 100644 --- a/repos/os/recipes/pkg/clipboard/hash +++ b/repos/os/recipes/pkg/clipboard/hash @@ -1 +1 @@ -2024-08-28 b97e68aa7d023000231fcecdd7e2903263b451b3 +2024-10-07 05e6d7074a80668b8620852197724e2632a0e730 diff --git a/repos/os/recipes/pkg/cpu_balancer/hash b/repos/os/recipes/pkg/cpu_balancer/hash index bdbec8cce6..2a0eb56f56 100644 --- a/repos/os/recipes/pkg/cpu_balancer/hash +++ b/repos/os/recipes/pkg/cpu_balancer/hash @@ -1 +1 @@ -2024-08-28 6f5f124ce6e94e91f5fdda65909dfbfb64addf50 +2024-10-07 42320b4f949aa08268427a8577824bbd0c9dbb5e diff --git a/repos/os/recipes/pkg/cpu_balancer_config/hash b/repos/os/recipes/pkg/cpu_balancer_config/hash index 447fc455b4..b6762b2530 100644 --- a/repos/os/recipes/pkg/cpu_balancer_config/hash +++ b/repos/os/recipes/pkg/cpu_balancer_config/hash @@ -1 +1 @@ -2024-08-28 8c129d8c18d8e8d7a28acbafd0c1f60a5c9e8c3e +2024-10-29 2652b6da0140934036a8650886a0ee2eb1c390c1 diff --git a/repos/os/recipes/pkg/cpu_burner/hash b/repos/os/recipes/pkg/cpu_burner/hash index d86ed7258b..f5df2ecd0b 100644 --- a/repos/os/recipes/pkg/cpu_burner/hash +++ b/repos/os/recipes/pkg/cpu_burner/hash @@ -1 +1 @@ -2024-08-28 b16411d09f9c69ad831846dd8e9eb411c476a9e4 +2024-10-07 a655005b71e39b51e7804567516876ab3b64c6a2 diff --git a/repos/os/recipes/pkg/drivers_interactive-linux/hash b/repos/os/recipes/pkg/drivers_interactive-linux/hash index 3e370964fe..408a3780b3 100644 --- a/repos/os/recipes/pkg/drivers_interactive-linux/hash +++ b/repos/os/recipes/pkg/drivers_interactive-linux/hash @@ -1 +1 @@ -2024-08-28 bd4874ac5a7f21e15691d508ae4331bb74cc3049 +2024-10-07 fe75f05114178de80790976d679f54bb03284fc0 diff --git a/repos/os/recipes/pkg/drivers_interactive-pbxa9/hash b/repos/os/recipes/pkg/drivers_interactive-pbxa9/hash index ca8887b3ac..e93bf9c1c8 100644 --- a/repos/os/recipes/pkg/drivers_interactive-pbxa9/hash +++ b/repos/os/recipes/pkg/drivers_interactive-pbxa9/hash @@ -1 +1 @@ -2024-08-28 de1fa92ab2cef7fd463c99676f4f092cf043743e +2024-10-29 7fd87fef93b444b6ac145efeed6d5b43ecd6fef3 diff --git a/repos/os/recipes/pkg/drivers_interactive-pc/hash b/repos/os/recipes/pkg/drivers_interactive-pc/hash index 4d43ff09b5..127db235a5 100644 --- a/repos/os/recipes/pkg/drivers_interactive-pc/hash +++ b/repos/os/recipes/pkg/drivers_interactive-pc/hash @@ -1 +1 @@ -2024-08-28 109e3c8cc189664b63ba59c4ca0698235f268402 +2024-10-29 cbf5296ebe8b17933c7e450863f6e53d9db6f480 diff --git a/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v7a/hash b/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v7a/hash index e5ce27285a..d7ee7e13df 100644 --- a/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v7a/hash +++ b/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v7a/hash @@ -1 +1 @@ -2024-08-28 cafd9716b4fd61d6a795bfd377333147d3c35b10 +2024-10-29 c65742bf7954ff5f626a6e053242e13b332f0a5d diff --git a/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v8a/hash b/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v8a/hash index e5ce27285a..d7ee7e13df 100644 --- a/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v8a/hash +++ b/repos/os/recipes/pkg/drivers_interactive-virt_qemu_arm_v8a/hash @@ -1 +1 @@ -2024-08-28 cafd9716b4fd61d6a795bfd377333147d3c35b10 +2024-10-29 c65742bf7954ff5f626a6e053242e13b332f0a5d diff --git a/repos/os/recipes/pkg/drivers_nic-linux/hash b/repos/os/recipes/pkg/drivers_nic-linux/hash index 2438b34fd1..99fe172287 100644 --- a/repos/os/recipes/pkg/drivers_nic-linux/hash +++ b/repos/os/recipes/pkg/drivers_nic-linux/hash @@ -1 +1 @@ -2024-08-28 54e690478f563e83c392e55dd132ac7fb99f6ed2 +2024-10-07 8bb3dde85b14ea49e9ed7b67183cf306a48519e8 diff --git a/repos/os/recipes/pkg/drivers_nic-pbxa9/hash b/repos/os/recipes/pkg/drivers_nic-pbxa9/hash index b438845206..ebda0c04fc 100644 --- a/repos/os/recipes/pkg/drivers_nic-pbxa9/hash +++ b/repos/os/recipes/pkg/drivers_nic-pbxa9/hash @@ -1 +1 @@ -2024-08-28 d65a4113881a6c47c0d1b7096a393a62a93c8fef +2024-10-29 3519b448c5c8db6bd36b7e5ae75843654b4071cc diff --git a/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v7a/hash b/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v7a/hash index db7de4f307..35fc26c07f 100644 --- a/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v7a/hash +++ b/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v7a/hash @@ -1 +1 @@ -2024-08-28 205c036d7f12e793426d539b7359bad3f96c728b +2024-10-29 590ddae3de684b98a6092a55bdaeb1ca26491cfc diff --git a/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v8a/hash b/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v8a/hash index db7de4f307..35fc26c07f 100644 --- a/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v8a/hash +++ b/repos/os/recipes/pkg/drivers_nic-virt_qemu_arm_v8a/hash @@ -1 +1 @@ -2024-08-28 205c036d7f12e793426d539b7359bad3f96c728b +2024-10-29 590ddae3de684b98a6092a55bdaeb1ca26491cfc diff --git a/repos/os/recipes/pkg/dynamic_rom/hash b/repos/os/recipes/pkg/dynamic_rom/hash index d0c9d402b4..fce05cd4b5 100644 --- a/repos/os/recipes/pkg/dynamic_rom/hash +++ b/repos/os/recipes/pkg/dynamic_rom/hash @@ -1 +1 @@ -2024-08-28 a7ce460f1edb73e7ecc8aa92545b3971b571339e +2024-10-07 3e920a2d88fe80210b24d2101081b30d43ff2d08 diff --git a/repos/os/recipes/pkg/fs_report/hash b/repos/os/recipes/pkg/fs_report/hash index 1ada6b2f39..86e1ace4fc 100644 --- a/repos/os/recipes/pkg/fs_report/hash +++ b/repos/os/recipes/pkg/fs_report/hash @@ -1 +1 @@ -2024-08-28 49111736f6156f9abd2daa7066667d90d399f463 +2024-10-07 d6a6b04e221fd26d85735ba238a083e5d9dc3b1f diff --git a/repos/os/recipes/pkg/fs_rom/hash b/repos/os/recipes/pkg/fs_rom/hash index 66daadfc91..871f398e15 100644 --- a/repos/os/recipes/pkg/fs_rom/hash +++ b/repos/os/recipes/pkg/fs_rom/hash @@ -1 +1 @@ -2024-08-28 13078f911302683682fe15fbdcab79174f53845e +2024-10-07 1fcef49a3e5af3981473235b24ce3057953de9f2 diff --git a/repos/os/recipes/pkg/mixer/hash b/repos/os/recipes/pkg/mixer/hash index 9898fe2b77..f01dc9f102 100644 --- a/repos/os/recipes/pkg/mixer/hash +++ b/repos/os/recipes/pkg/mixer/hash @@ -1 +1 @@ -2024-08-28 c5d05408a5d9bd04048e71f6747bb045ba04154d +2024-10-07 8c67fb628dd89c804db27025ca342947df06b998 diff --git a/repos/os/recipes/pkg/nic_router-nat/hash b/repos/os/recipes/pkg/nic_router-nat/hash index b555b69ade..17adec7366 100644 --- a/repos/os/recipes/pkg/nic_router-nat/hash +++ b/repos/os/recipes/pkg/nic_router-nat/hash @@ -1 +1 @@ -2024-08-28 c53c80c66a5ae6a656049168cfe9269dc8f3305c +2024-10-29 1be93207edb60041f32314e88ef6eca76fa1d27e diff --git a/repos/os/recipes/pkg/nic_uplink/hash b/repos/os/recipes/pkg/nic_uplink/hash index ecf6e9cead..83f48a8fc2 100644 --- a/repos/os/recipes/pkg/nic_uplink/hash +++ b/repos/os/recipes/pkg/nic_uplink/hash @@ -1 +1 @@ -2024-08-28 4de53d351628ac0d8357ae131f2ac1a5e29c1c52 +2024-10-07 86e70710569d37abb00463f56913a7c51808f59b diff --git a/repos/os/recipes/pkg/nit_focus/hash b/repos/os/recipes/pkg/nit_focus/hash index ca6d3466b5..340832fdb8 100644 --- a/repos/os/recipes/pkg/nit_focus/hash +++ b/repos/os/recipes/pkg/nit_focus/hash @@ -1 +1 @@ -2024-08-28 4159f75b3dfa458441a9123c31caceeec870dbb1 +2024-10-07 38c4667b5001da0a9763cd23d50bca597c416340 diff --git a/repos/os/recipes/pkg/nitpicker/hash b/repos/os/recipes/pkg/nitpicker/hash index ef8205576e..b6ee41ef95 100644 --- a/repos/os/recipes/pkg/nitpicker/hash +++ b/repos/os/recipes/pkg/nitpicker/hash @@ -1 +1 @@ -2024-08-28 e5213ed6fe0f7e5886be8485dbce0b3735c2e8d3 +2024-11-04 a8b16b02840b8144ef442d780d2b6daa8aa3bd74 diff --git a/repos/os/recipes/pkg/part_block/hash b/repos/os/recipes/pkg/part_block/hash index fec8aec574..25062076fd 100644 --- a/repos/os/recipes/pkg/part_block/hash +++ b/repos/os/recipes/pkg/part_block/hash @@ -1 +1 @@ -2024-08-28 423e0d1e28d25cf62015b0f1ff8ab9b7cc1468b3 +2024-10-07 5057ee7cf05096956fc497d714903626553ad747 diff --git a/repos/os/recipes/pkg/ping/hash b/repos/os/recipes/pkg/ping/hash index f066c4bda4..f30053148c 100644 --- a/repos/os/recipes/pkg/ping/hash +++ b/repos/os/recipes/pkg/ping/hash @@ -1 +1 @@ -2024-08-28 7202d580bb7ef6e8aaaf43df2536765f8ae5a050 +2024-10-07 e209d28eaaa4820229c8b5954a427f140745cb2b diff --git a/repos/os/recipes/pkg/recall_fs/hash b/repos/os/recipes/pkg/recall_fs/hash index 2ea94753fc..65803ad4a3 100644 --- a/repos/os/recipes/pkg/recall_fs/hash +++ b/repos/os/recipes/pkg/recall_fs/hash @@ -1 +1 @@ -2024-08-28 ed8c24ef4bee8bd853e816347f3da18ce0ef7ba7 +2024-10-07 d852662ca5204d49850d3df357634326299c1f05 diff --git a/repos/os/recipes/pkg/record_play_mixer/hash b/repos/os/recipes/pkg/record_play_mixer/hash index 0ec3726376..4e60807711 100644 --- a/repos/os/recipes/pkg/record_play_mixer/hash +++ b/repos/os/recipes/pkg/record_play_mixer/hash @@ -1 +1 @@ -2024-08-28 b11e46e3cf255aff47e40ffec6d7f51af7ddf9fd +2024-10-07 36983b32ea843c2d64332dd385d4d0bbcda2fefa diff --git a/repos/os/recipes/pkg/record_rom/hash b/repos/os/recipes/pkg/record_rom/hash index b559ee71aa..874cd52df2 100644 --- a/repos/os/recipes/pkg/record_rom/hash +++ b/repos/os/recipes/pkg/record_rom/hash @@ -1 +1 @@ -2024-08-28 3714f312145c741e2f5425025fbb1b3dd94b357f +2024-10-07 19e7fb28ca85c993e62f7dacf2582e00e5946613 diff --git a/repos/os/recipes/pkg/report_rom/hash b/repos/os/recipes/pkg/report_rom/hash index 5c07f5263e..c3d79b1973 100644 --- a/repos/os/recipes/pkg/report_rom/hash +++ b/repos/os/recipes/pkg/report_rom/hash @@ -1 +1 @@ -2024-08-28 ae5367e47fc1ced31e2158b331fdf65cb0f33181 +2024-10-07 d0e59d7e43c34bd2f48c990f09f4a086f97a911a diff --git a/repos/os/recipes/pkg/rom_filter/hash b/repos/os/recipes/pkg/rom_filter/hash index 973f158981..2a09147da0 100644 --- a/repos/os/recipes/pkg/rom_filter/hash +++ b/repos/os/recipes/pkg/rom_filter/hash @@ -1 +1 @@ -2024-08-28 29f4002b075425f892404a7556d437485f4be670 +2024-10-07 5e42a6f4538aec3dcb609084dbc11f4ac876dc40 diff --git a/repos/os/recipes/pkg/rom_reporter/hash b/repos/os/recipes/pkg/rom_reporter/hash index 82b18496ba..467c2ddf19 100644 --- a/repos/os/recipes/pkg/rom_reporter/hash +++ b/repos/os/recipes/pkg/rom_reporter/hash @@ -1 +1 @@ -2024-08-28 7963fe27e4221b7bdf046e93276c010a1712b665 +2024-10-07 72de81a7b7b70c837fc7bae2b473b45e9d5112d7 diff --git a/repos/os/recipes/pkg/terminal_crosslink/hash b/repos/os/recipes/pkg/terminal_crosslink/hash index fefabb039d..369b031fd7 100644 --- a/repos/os/recipes/pkg/terminal_crosslink/hash +++ b/repos/os/recipes/pkg/terminal_crosslink/hash @@ -1 +1 @@ -2024-08-28 f50f4f35b082febd80be925adeef6436bb2ba1d8 +2024-10-07 5f5f251851bfb6c38ab37cf669ffe71e395f3d53 diff --git a/repos/os/recipes/pkg/test-audio_out/hash b/repos/os/recipes/pkg/test-audio_out/hash index 075504dad1..a50e1f82c2 100644 --- a/repos/os/recipes/pkg/test-audio_out/hash +++ b/repos/os/recipes/pkg/test-audio_out/hash @@ -1 +1 @@ -2024-08-28 cb7fdcc7e9bfbea1d0863e63bd4a8e6bd302fd56 +2024-10-07 dfa12739dfc8760c800b861a4f63c100c77e3663 diff --git a/repos/os/recipes/pkg/test-black_hole/hash b/repos/os/recipes/pkg/test-black_hole/hash index d5bc7096d9..67fd4378a7 100644 --- a/repos/os/recipes/pkg/test-black_hole/hash +++ b/repos/os/recipes/pkg/test-black_hole/hash @@ -1 +1 @@ -2024-08-28 15ab3da16f3a2751426cfd0ee039bf680ddd08e2 +2024-10-29 8e91425738a8481d245a29bb54686dbdb65bc5ed diff --git a/repos/os/recipes/pkg/test-capture/hash b/repos/os/recipes/pkg/test-capture/hash index a2c1e76aed..9d2c45288c 100644 --- a/repos/os/recipes/pkg/test-capture/hash +++ b/repos/os/recipes/pkg/test-capture/hash @@ -1 +1 @@ -2024-08-28 6ff1d504e233f04cc84a122d3eb9e06a3c6581e9 +2024-10-29 e2adce71309ad149e8b71fd2bdd690c44cc17195 diff --git a/repos/os/recipes/pkg/test-clipboard/hash b/repos/os/recipes/pkg/test-clipboard/hash index 180dff6683..72abfd0480 100644 --- a/repos/os/recipes/pkg/test-clipboard/hash +++ b/repos/os/recipes/pkg/test-clipboard/hash @@ -1 +1 @@ -2024-08-28 5c051f8ca01c7f62c96990e0d5202a7431e954a6 +2024-10-29 13274fb642fa993e780d5d5905607206eb09d006 diff --git a/repos/os/recipes/pkg/test-dynamic_config/hash b/repos/os/recipes/pkg/test-dynamic_config/hash index 76a3bef7b0..6cb5a288e4 100644 --- a/repos/os/recipes/pkg/test-dynamic_config/hash +++ b/repos/os/recipes/pkg/test-dynamic_config/hash @@ -1 +1 @@ -2024-08-28 842554dbf104a5b3a6a14afd897b9c3244266054 +2024-10-29 2d8d5792239b46ae2e27541fa2b957b525640671 diff --git a/repos/os/recipes/pkg/test-fault_detection/hash b/repos/os/recipes/pkg/test-fault_detection/hash index c4d13056b9..bf8fe5ada9 100644 --- a/repos/os/recipes/pkg/test-fault_detection/hash +++ b/repos/os/recipes/pkg/test-fault_detection/hash @@ -1 +1 @@ -2024-08-28 ee0974f68b3bb803e51f494eec941316eb71391b +2024-10-29 b42e27515ea5c91f3189e40d7ee90dd56e5c705b diff --git a/repos/os/recipes/pkg/test-fs_packet/hash b/repos/os/recipes/pkg/test-fs_packet/hash index 5a7fc0456a..d1c2c5fda7 100644 --- a/repos/os/recipes/pkg/test-fs_packet/hash +++ b/repos/os/recipes/pkg/test-fs_packet/hash @@ -1 +1 @@ -2024-08-28 251061004e6917ebcf1a6758de1e7f0f0fedb31e +2024-10-29 e691841c9e606e3e071b44949a75b2a20660bc4d diff --git a/repos/os/recipes/pkg/test-fs_report/hash b/repos/os/recipes/pkg/test-fs_report/hash index 1b731a875e..7499db3a38 100644 --- a/repos/os/recipes/pkg/test-fs_report/hash +++ b/repos/os/recipes/pkg/test-fs_report/hash @@ -1 +1 @@ -2024-08-28 0a6bdffbf892b1ad34c0bdf56aaa0e68a518ea7b +2024-11-04 b0bb30031044782763d2380769934d8be00f5eb7 diff --git a/repos/os/recipes/pkg/test-fs_rom_update/hash b/repos/os/recipes/pkg/test-fs_rom_update/hash index c823563123..ce969b9a36 100644 --- a/repos/os/recipes/pkg/test-fs_rom_update/hash +++ b/repos/os/recipes/pkg/test-fs_rom_update/hash @@ -1 +1 @@ -2024-08-28 d9d37961539259f27b6ec79e73dfb00b2e36c184 +2024-10-29 dfd94d4a9c635aa98eed4321a15841dd22c61f36 diff --git a/repos/os/recipes/pkg/test-fs_rom_update_fs/hash b/repos/os/recipes/pkg/test-fs_rom_update_fs/hash index c253704af2..4c614b7c97 100644 --- a/repos/os/recipes/pkg/test-fs_rom_update_fs/hash +++ b/repos/os/recipes/pkg/test-fs_rom_update_fs/hash @@ -1 +1 @@ -2024-08-28 e3c7f02a31c15ea1d69932c267d97487fc3ec179 +2024-10-29 c6562a3deaa49dbd8e5099d75faabb3f7cf0a7ee diff --git a/repos/os/recipes/pkg/test-fs_rom_update_ram/hash b/repos/os/recipes/pkg/test-fs_rom_update_ram/hash index e4664f19cb..49a5d8e571 100644 --- a/repos/os/recipes/pkg/test-fs_rom_update_ram/hash +++ b/repos/os/recipes/pkg/test-fs_rom_update_ram/hash @@ -1 +1 @@ -2024-08-28 4a13ad948a5caa7da0b8114e02dba7a6c7c2b105 +2024-10-29 fa840f100f29acf712af94aa679c15776a368dbe diff --git a/repos/os/recipes/pkg/test-init/hash b/repos/os/recipes/pkg/test-init/hash index 5d2054fdd9..ac6bcb96f8 100644 --- a/repos/os/recipes/pkg/test-init/hash +++ b/repos/os/recipes/pkg/test-init/hash @@ -1 +1 @@ -2024-08-28 0b2606f42a47c2c7f61a5bcdd10ea67e6b00a1a4 +2024-10-29 5e33957c26b7a95e91a376a04d4a546c0d467439 diff --git a/repos/os/recipes/pkg/test-init_loop/hash b/repos/os/recipes/pkg/test-init_loop/hash index c1ecdfe623..9907da64ad 100644 --- a/repos/os/recipes/pkg/test-init_loop/hash +++ b/repos/os/recipes/pkg/test-init_loop/hash @@ -1 +1 @@ -2024-08-28 1e90ae1676a0901ab5577d92adff5614f46d24ff +2024-10-29 0de05ed2ea1c24a1d6466a009bd08b6cccd43c5c diff --git a/repos/os/recipes/pkg/test-lx_block/hash b/repos/os/recipes/pkg/test-lx_block/hash index 3289795d3d..b1470af1fd 100644 --- a/repos/os/recipes/pkg/test-lx_block/hash +++ b/repos/os/recipes/pkg/test-lx_block/hash @@ -1 +1 @@ -2024-08-28 a3e201e0b27969eec7bb37eb4e47e84b41bb96c7 +2024-10-29 1b5f5d5dbe94e0500f7846072e2fe9ae4dca847b diff --git a/repos/os/recipes/pkg/test-nic_loopback/hash b/repos/os/recipes/pkg/test-nic_loopback/hash index 1765cd704d..4201726b72 100644 --- a/repos/os/recipes/pkg/test-nic_loopback/hash +++ b/repos/os/recipes/pkg/test-nic_loopback/hash @@ -1 +1 @@ -2024-08-28 6b2050d8f09e76e35d9400a842f6e335a0b4f25f +2024-10-29 065a5776da64ae848f7ea38e3e5da41810af12a7 diff --git a/repos/os/recipes/pkg/test-nic_perf/hash b/repos/os/recipes/pkg/test-nic_perf/hash index 0da517b1f5..8dc435e875 100644 --- a/repos/os/recipes/pkg/test-nic_perf/hash +++ b/repos/os/recipes/pkg/test-nic_perf/hash @@ -1 +1 @@ -2024-08-28 ae90325a552fc6a9f0b7e2052e58e3a16055aa5f +2024-10-29 26460394ed91ae4e5f7786545e707f3930a2e378 diff --git a/repos/os/recipes/pkg/test-nic_perf_router/hash b/repos/os/recipes/pkg/test-nic_perf_router/hash index bfb2b4bb81..d55f7c41c9 100644 --- a/repos/os/recipes/pkg/test-nic_perf_router/hash +++ b/repos/os/recipes/pkg/test-nic_perf_router/hash @@ -1 +1 @@ -2024-08-28 fce14cb27791ef5d6c7816b3ba5ce834deb68141 +2024-10-29 56036f5aed956c625c0bcf206f8812348a44e3d9 diff --git a/repos/os/recipes/pkg/test-part_block_ahdi/hash b/repos/os/recipes/pkg/test-part_block_ahdi/hash index 8484f8d5ec..765837c16f 100644 --- a/repos/os/recipes/pkg/test-part_block_ahdi/hash +++ b/repos/os/recipes/pkg/test-part_block_ahdi/hash @@ -1 +1 @@ -2024-08-28 6ce89e36bb7943b4249be6e68abbe0770c3cc111 +2024-10-29 9819a3c6ffd5eb190b32a0c866df88a665fa0e5e diff --git a/repos/os/recipes/pkg/test-part_block_disk/hash b/repos/os/recipes/pkg/test-part_block_disk/hash index 593a1a5da3..11a2416a24 100644 --- a/repos/os/recipes/pkg/test-part_block_disk/hash +++ b/repos/os/recipes/pkg/test-part_block_disk/hash @@ -1 +1 @@ -2024-08-28 5a1a961235741ed2207769c134d9991425b5d702 +2024-10-29 11fc947d3df1e8cbf0c0b9d0d474153d43245ada diff --git a/repos/os/recipes/pkg/test-part_block_gpt/hash b/repos/os/recipes/pkg/test-part_block_gpt/hash index df4bcca5b6..dec332cf93 100644 --- a/repos/os/recipes/pkg/test-part_block_gpt/hash +++ b/repos/os/recipes/pkg/test-part_block_gpt/hash @@ -1 +1 @@ -2024-08-28 dd0429546ec7fd239230674f5c68753900e7d7d3 +2024-10-29 97a712f0f7294f3e9c5e7e971c8951dcef58e585 diff --git a/repos/os/recipes/pkg/test-part_block_mbr/hash b/repos/os/recipes/pkg/test-part_block_mbr/hash index 3b9b506731..2dfe42ebfd 100644 --- a/repos/os/recipes/pkg/test-part_block_mbr/hash +++ b/repos/os/recipes/pkg/test-part_block_mbr/hash @@ -1 +1 @@ -2024-08-28 66fe19ccdd230143010a96a9c54f434c126560d9 +2024-10-29 1aad6ee4b529974246f7208e19d276235f17b49d diff --git a/repos/os/recipes/pkg/test-path/hash b/repos/os/recipes/pkg/test-path/hash index 862dd97f81..fba0caa292 100644 --- a/repos/os/recipes/pkg/test-path/hash +++ b/repos/os/recipes/pkg/test-path/hash @@ -1 +1 @@ -2024-08-28 5498469e18cf4dfdd5038adcde6eaeba6983e8d6 +2024-10-29 f749771d7e8e073125381650592f294e8e96d30a diff --git a/repos/os/recipes/pkg/test-ram_fs_chunk/hash b/repos/os/recipes/pkg/test-ram_fs_chunk/hash index fdf683fed3..26fd6919a0 100644 --- a/repos/os/recipes/pkg/test-ram_fs_chunk/hash +++ b/repos/os/recipes/pkg/test-ram_fs_chunk/hash @@ -1 +1 @@ -2024-08-28 93b2e25bc33bf1977e97f4db5594b0c3de7970bd +2024-10-29 390ae3c8dce0bb2bb0bcfe8b9c1f48e3a774a465 diff --git a/repos/os/recipes/pkg/test-read_only_rom/hash b/repos/os/recipes/pkg/test-read_only_rom/hash index 4db0e1cb0c..75ab567d7c 100644 --- a/repos/os/recipes/pkg/test-read_only_rom/hash +++ b/repos/os/recipes/pkg/test-read_only_rom/hash @@ -1 +1 @@ -2024-08-28 7b4312a61c7885d47b01b277e4105a8b00521c3a +2024-10-29 f8f81348c752b4f731757c83a81bbdc06157ddfa diff --git a/repos/os/recipes/pkg/test-report_rom/hash b/repos/os/recipes/pkg/test-report_rom/hash index 4ec8df9a91..52a493b7cf 100644 --- a/repos/os/recipes/pkg/test-report_rom/hash +++ b/repos/os/recipes/pkg/test-report_rom/hash @@ -1 +1 @@ -2024-08-28 4d6313bac482f836be5661382dea0fdfdd94881e +2024-10-29 80ca734e2b1b7636eb634c0f47f6a194b3206ea8 diff --git a/repos/os/recipes/pkg/test-resource_request/hash b/repos/os/recipes/pkg/test-resource_request/hash index bb39dab888..63c371958d 100644 --- a/repos/os/recipes/pkg/test-resource_request/hash +++ b/repos/os/recipes/pkg/test-resource_request/hash @@ -1 +1 @@ -2024-08-28 c37ce63b507e4d2dcd178a3702c021eb14f0fca3 +2024-10-29 eb6e572609e92e20d1c59561819997c293543b5d diff --git a/repos/os/recipes/pkg/test-resource_yield/hash b/repos/os/recipes/pkg/test-resource_yield/hash index 1d6d1cb260..f9fef8fd1e 100644 --- a/repos/os/recipes/pkg/test-resource_yield/hash +++ b/repos/os/recipes/pkg/test-resource_yield/hash @@ -1 +1 @@ -2024-08-28 b8ce62db44a3c559567eb00d843a77ba4f9cb2fa +2024-10-29 111c103af3b4a5797cf6ef95e347e9aa0a9cabd5 diff --git a/repos/os/recipes/pkg/test-rom_filter/hash b/repos/os/recipes/pkg/test-rom_filter/hash index 8b3a0a116f..c118768f10 100644 --- a/repos/os/recipes/pkg/test-rom_filter/hash +++ b/repos/os/recipes/pkg/test-rom_filter/hash @@ -1 +1 @@ -2024-08-28 178400ea34d3205bfe85326940c88a2b5e98dcbc +2024-10-29 f01d7e131c08eda711765b02a854c549f9720b3a diff --git a/repos/os/recipes/pkg/test-rtc/hash b/repos/os/recipes/pkg/test-rtc/hash index 87bd8be3ea..d3e582bf92 100644 --- a/repos/os/recipes/pkg/test-rtc/hash +++ b/repos/os/recipes/pkg/test-rtc/hash @@ -1 +1 @@ -2024-08-28 aa2942f41357f27d25222aee950c33e7cf2a8ea9 +2024-10-29 0b011339a81045003209eb4cc9df39c01c1da399 diff --git a/repos/os/recipes/pkg/test-sandbox/hash b/repos/os/recipes/pkg/test-sandbox/hash index a491787c8f..1c46a58e61 100644 --- a/repos/os/recipes/pkg/test-sandbox/hash +++ b/repos/os/recipes/pkg/test-sandbox/hash @@ -1 +1 @@ -2024-08-28 a3e3f9058e5434eda22d399c974f79ae081f5c3c +2024-10-29 91f342764a32d57adfba19ab335db7a8c187a628 diff --git a/repos/os/recipes/pkg/test-signal/hash b/repos/os/recipes/pkg/test-signal/hash index 2f4939df6f..b5416499d4 100644 --- a/repos/os/recipes/pkg/test-signal/hash +++ b/repos/os/recipes/pkg/test-signal/hash @@ -1 +1 @@ -2024-08-28 ba3c45f067b60dc46beb0a8c1d55c4b7e59b9919 +2024-10-29 7fb44e6027d60752777d81684298970674f59b9f diff --git a/repos/os/recipes/pkg/test-slab/hash b/repos/os/recipes/pkg/test-slab/hash index e9d97b2298..80e26b74e5 100644 --- a/repos/os/recipes/pkg/test-slab/hash +++ b/repos/os/recipes/pkg/test-slab/hash @@ -1 +1 @@ -2024-08-28 e1cf31b4c376d205af8b517258c2c219fe204129 +2024-10-29 c1031e87716faad42da3371cfbdf697a4ec2b97a diff --git a/repos/os/recipes/pkg/test-terminal_crosslink/hash b/repos/os/recipes/pkg/test-terminal_crosslink/hash index 708f5d84a0..149a50ec31 100644 --- a/repos/os/recipes/pkg/test-terminal_crosslink/hash +++ b/repos/os/recipes/pkg/test-terminal_crosslink/hash @@ -1 +1 @@ -2024-08-28 4422c86c1cc849fc6818bb1795b6845c35b1abc4 +2024-10-29 f6528ba9319e52936eeab8052d4442f3e8f81c07 diff --git a/repos/os/recipes/pkg/test-trace/hash b/repos/os/recipes/pkg/test-trace/hash index c4b25cd2c0..41f748a7e3 100644 --- a/repos/os/recipes/pkg/test-trace/hash +++ b/repos/os/recipes/pkg/test-trace/hash @@ -1 +1 @@ -2024-08-28 5a5402d0eb78610eb6809a7dbed567b7e0290d21 +2024-10-29 dc74d390b555d461e17910e3c29907e3c2bd684b diff --git a/repos/os/recipes/pkg/test-trace_buffer/hash b/repos/os/recipes/pkg/test-trace_buffer/hash index 849b99a860..a857e036fc 100644 --- a/repos/os/recipes/pkg/test-trace_buffer/hash +++ b/repos/os/recipes/pkg/test-trace_buffer/hash @@ -1 +1 @@ -2024-08-28 25892f30627ae46aa946fd417bc2793372dd4076 +2024-10-29 daaf414b7f42038fed4837271efe5678079a66e5 diff --git a/repos/os/recipes/pkg/test-trace_logger/hash b/repos/os/recipes/pkg/test-trace_logger/hash index 6e9e2ff3a1..bb356ca4a5 100644 --- a/repos/os/recipes/pkg/test-trace_logger/hash +++ b/repos/os/recipes/pkg/test-trace_logger/hash @@ -1 +1 @@ -2024-08-28 f1298cfe71193082724a00cade803279bbcdb173 +2024-10-29 51ef079e0e6dd473937cd77b31b333797f51185f diff --git a/repos/os/recipes/pkg/test-utf8/hash b/repos/os/recipes/pkg/test-utf8/hash index db9c50c2d2..435e23bb20 100644 --- a/repos/os/recipes/pkg/test-utf8/hash +++ b/repos/os/recipes/pkg/test-utf8/hash @@ -1 +1 @@ -2024-08-28 863444372f9a90b2716155cb6504e4c55dcfad71 +2024-10-29 6c8c70bb41d392498fc9a7b3fdd08596e51edcb5 diff --git a/repos/os/recipes/pkg/test-vfs_block/hash b/repos/os/recipes/pkg/test-vfs_block/hash index 6dcbe2dad0..60eacc0856 100644 --- a/repos/os/recipes/pkg/test-vfs_block/hash +++ b/repos/os/recipes/pkg/test-vfs_block/hash @@ -1 +1 @@ -2024-08-28 a9de0e9530bea26db56d29db03e4b20ecc1ca60a +2024-11-04 5423ed8ff627b236d0d27d88dab918ebea85584b diff --git a/repos/os/recipes/pkg/test-vfs_stress_fs/hash b/repos/os/recipes/pkg/test-vfs_stress_fs/hash index 8802c4c09c..3272537d93 100644 --- a/repos/os/recipes/pkg/test-vfs_stress_fs/hash +++ b/repos/os/recipes/pkg/test-vfs_stress_fs/hash @@ -1 +1 @@ -2024-08-28 77eb8d1bfe000cb018983e7dcd116e4a15ade031 +2024-10-29 759853c66f17e1e1dc0061948a957ddabc6c1b4c diff --git a/repos/os/recipes/pkg/test-vfs_stress_ram/hash b/repos/os/recipes/pkg/test-vfs_stress_ram/hash index 91649440f2..92d5763f49 100644 --- a/repos/os/recipes/pkg/test-vfs_stress_ram/hash +++ b/repos/os/recipes/pkg/test-vfs_stress_ram/hash @@ -1 +1 @@ -2024-08-28 f64cfc165893d5eb69fc1123cf7f134989db9b37 +2024-10-29 f4e3835332a91e30c0028c9e87236e3150e62432 diff --git a/repos/os/recipes/pkg/test-weak_ptr/hash b/repos/os/recipes/pkg/test-weak_ptr/hash index 64051135aa..62415f0d5f 100644 --- a/repos/os/recipes/pkg/test-weak_ptr/hash +++ b/repos/os/recipes/pkg/test-weak_ptr/hash @@ -1 +1 @@ -2024-08-28 c9e90f0aa074fed1a20d4a31a896646ffbfaf90d +2024-10-29 44a54527a8b2f8600572b88dbe579e249fdb3773 diff --git a/repos/os/recipes/pkg/top/hash b/repos/os/recipes/pkg/top/hash index 2bf65625b6..29b6cd6e8e 100644 --- a/repos/os/recipes/pkg/top/hash +++ b/repos/os/recipes/pkg/top/hash @@ -1 +1 @@ -2024-08-28 d7e0424e702d4a5590877758d9480b8bcac31b3a +2024-10-07 ae977373541c22027e0bd50173b82c35290a5b4f diff --git a/repos/os/recipes/pkg/trace_logger/hash b/repos/os/recipes/pkg/trace_logger/hash index d06e4e1697..d538980e94 100644 --- a/repos/os/recipes/pkg/trace_logger/hash +++ b/repos/os/recipes/pkg/trace_logger/hash @@ -1 +1 @@ -2024-08-28 00665e0359842337c2d74625235b5bc1337d196e +2024-10-07 a31b597e5b1693496e7e3de5c839a34ae55b6c26 diff --git a/repos/os/recipes/pkg/vfs/hash b/repos/os/recipes/pkg/vfs/hash index 85c5adc7ed..27f6e2623d 100644 --- a/repos/os/recipes/pkg/vfs/hash +++ b/repos/os/recipes/pkg/vfs/hash @@ -1 +1 @@ -2024-08-28 00d243d66ffc9dd572b68a15aacc9873070a9146 +2024-10-07 cf87501b6f0d4c4039301857ac1420aca223b985 diff --git a/repos/os/recipes/pkg/vfs_block/hash b/repos/os/recipes/pkg/vfs_block/hash index c7309569b7..d049fd4659 100644 --- a/repos/os/recipes/pkg/vfs_block/hash +++ b/repos/os/recipes/pkg/vfs_block/hash @@ -1 +1 @@ -2024-08-28 5bd7e196ae824cd85dfafb7c8392d9e864b5171f +2024-10-07 8d438302672fe733e1224903326417e6c627abe5 diff --git a/repos/os/recipes/pkg/waveform_player/hash b/repos/os/recipes/pkg/waveform_player/hash index d97f888f26..cd23dcee5a 100644 --- a/repos/os/recipes/pkg/waveform_player/hash +++ b/repos/os/recipes/pkg/waveform_player/hash @@ -1 +1 @@ -2024-08-28 eb0e8dafd06e991b175b474fd73781b08fd87d2d +2024-10-07 db42fd4da2522c5e13d22a6ab1b91a18fa01223a diff --git a/repos/os/recipes/src/acpi/hash b/repos/os/recipes/src/acpi/hash index a1ed2dae4a..2009d5a7d6 100644 --- a/repos/os/recipes/src/acpi/hash +++ b/repos/os/recipes/src/acpi/hash @@ -1 +1 @@ -2024-08-28 2fd2f87bbcf296e1e10159ece5ab700534e5039f +2024-10-07 a9b8f441fbece53df10deb116e93f2b5d68ba0e8 diff --git a/repos/os/recipes/src/ahci/hash b/repos/os/recipes/src/ahci/hash index 547452230d..2092e60977 100644 --- a/repos/os/recipes/src/ahci/hash +++ b/repos/os/recipes/src/ahci/hash @@ -1 +1 @@ -2024-08-28 3e23b7249f34258a15c095a4ad1542168b107a7d +2024-10-07 a8e6c92c950bdd495f2c3c5265f1fe4968278021 diff --git a/repos/os/recipes/src/black_hole/hash b/repos/os/recipes/src/black_hole/hash index 1ca68e550a..03c742c236 100644 --- a/repos/os/recipes/src/black_hole/hash +++ b/repos/os/recipes/src/black_hole/hash @@ -1 +1 @@ -2024-08-28 4962dc655cb9fa2908a5168c8a7934636f48e635 +2024-10-07 f55a6882d8167d53fef9ce61abf46172e3b76b4f diff --git a/repos/os/recipes/src/block_tester/hash b/repos/os/recipes/src/block_tester/hash index c590dcaf9d..132da5ceaf 100644 --- a/repos/os/recipes/src/block_tester/hash +++ b/repos/os/recipes/src/block_tester/hash @@ -1 +1 @@ -2024-08-28 7d29036c6589004365584f99d5df8b9ce0ba641d +2024-10-07 ab8abf8b48ff232d3627cfdca6ee0be7583509ac diff --git a/repos/os/recipes/src/boot_fb/hash b/repos/os/recipes/src/boot_fb/hash index 9e37f31477..1d0625b931 100644 --- a/repos/os/recipes/src/boot_fb/hash +++ b/repos/os/recipes/src/boot_fb/hash @@ -1 +1 @@ -2024-08-28 bb7ff929095525804b70526ad4748aefce6e3769 +2024-10-07 c5f62af009bc3d151a2713b031273e9375c61b2f diff --git a/repos/os/recipes/src/cached_fs_rom/hash b/repos/os/recipes/src/cached_fs_rom/hash index 8f9f285bbf..f82ebe93b5 100644 --- a/repos/os/recipes/src/cached_fs_rom/hash +++ b/repos/os/recipes/src/cached_fs_rom/hash @@ -1 +1 @@ -2024-08-28 1cdd09c43aeb4b1314397324d1a05596d17d21f6 +2024-10-07 ef5847075b1c7060641ba650814dd0c6c1d61a73 diff --git a/repos/os/recipes/src/chroot/hash b/repos/os/recipes/src/chroot/hash index b663da4b05..236dfe2f22 100644 --- a/repos/os/recipes/src/chroot/hash +++ b/repos/os/recipes/src/chroot/hash @@ -1 +1 @@ -2024-08-28 1f0221b00fbc210596d482975eca07648a682f55 +2024-10-07 52efc9328577945a974eefb621b587918f2777dd diff --git a/repos/os/recipes/src/clipboard/hash b/repos/os/recipes/src/clipboard/hash index f480235606..62e019fe8b 100644 --- a/repos/os/recipes/src/clipboard/hash +++ b/repos/os/recipes/src/clipboard/hash @@ -1 +1 @@ -2024-08-28 46762b9a50d16c87cdbef248f863a9dbd9ae9a11 +2024-10-07 e4f492f05895c4ca9c304f318951a7466aa78304 diff --git a/repos/os/recipes/src/cpu_balancer/hash b/repos/os/recipes/src/cpu_balancer/hash index 7b656ff72d..44f73a7e4a 100644 --- a/repos/os/recipes/src/cpu_balancer/hash +++ b/repos/os/recipes/src/cpu_balancer/hash @@ -1 +1 @@ -2024-08-28 48eb3f206877333f8e323af20cb9ec10ae614636 +2024-10-07 c601e2b3f7c5ccf6625c04690ec2373ce1d0dfe7 diff --git a/repos/os/recipes/src/cpu_burner/hash b/repos/os/recipes/src/cpu_burner/hash index e5d09ed594..da3b5faa75 100644 --- a/repos/os/recipes/src/cpu_burner/hash +++ b/repos/os/recipes/src/cpu_burner/hash @@ -1 +1 @@ -2024-08-28 ffe690a0456c4ed6258cb0f64399496aca8e433b +2024-10-07 c639a03bfc8168828cff6c04ecc7e3f80bcd792d diff --git a/repos/os/recipes/src/dummy/hash b/repos/os/recipes/src/dummy/hash index cfdca09606..28bd787547 100644 --- a/repos/os/recipes/src/dummy/hash +++ b/repos/os/recipes/src/dummy/hash @@ -1 +1 @@ -2024-08-28 6c4f877755d6be6b1b2e89ffb1de03e7adfc0a48 +2024-10-07 44ac262fcad189e49b64a66fba42c4060211fc98 diff --git a/repos/os/recipes/src/dummy_rtc/hash b/repos/os/recipes/src/dummy_rtc/hash index ca9a144c49..183d515344 100644 --- a/repos/os/recipes/src/dummy_rtc/hash +++ b/repos/os/recipes/src/dummy_rtc/hash @@ -1 +1 @@ -2024-08-28 dc2367f7e79053fb331b452f047518722cfac65b +2024-10-07 e2f4ceaa24d50674ee20eae32071ccbfec36cd82 diff --git a/repos/os/recipes/src/dynamic_rom/hash b/repos/os/recipes/src/dynamic_rom/hash index f07f6465bc..a01515dab5 100644 --- a/repos/os/recipes/src/dynamic_rom/hash +++ b/repos/os/recipes/src/dynamic_rom/hash @@ -1 +1 @@ -2024-08-28 37105dc54508d46fcdb1f9bb9aedddbb1cca9a6a +2024-10-07 6136a78c39d1c7eaeda9d4c289f53bdfe98e96b8 diff --git a/repos/os/recipes/src/event_filter/hash b/repos/os/recipes/src/event_filter/hash index 60df876575..3311ff8318 100644 --- a/repos/os/recipes/src/event_filter/hash +++ b/repos/os/recipes/src/event_filter/hash @@ -1 +1 @@ -2024-08-28 1e212e5ab3a5255c5d9c40922cde8098fe1bebc3 +2024-10-07 be30d1701e5ea7860821a04a17795787d9c0da39 diff --git a/repos/os/recipes/src/fb_sdl/hash b/repos/os/recipes/src/fb_sdl/hash index 68fd025ba5..e9aef01491 100644 --- a/repos/os/recipes/src/fb_sdl/hash +++ b/repos/os/recipes/src/fb_sdl/hash @@ -1 +1 @@ -2024-08-28 13a9c65bdc0ded9f6bd656d96027d0656bf60730 +2024-10-07 9301d1ef59b8db2e27ca32cf61da3fc9ac0f756e diff --git a/repos/os/recipes/src/fs_report/hash b/repos/os/recipes/src/fs_report/hash index ce0ba4dd4a..336b00a930 100644 --- a/repos/os/recipes/src/fs_report/hash +++ b/repos/os/recipes/src/fs_report/hash @@ -1 +1 @@ -2024-08-28 6b332d9e4052ddd45bf7bd17a447965dccf35974 +2024-10-07 dc2fe1f9b32e770dfd8541d523651adb1c08ba01 diff --git a/repos/os/recipes/src/fs_rom/hash b/repos/os/recipes/src/fs_rom/hash index 681c8e3509..3f5438431d 100644 --- a/repos/os/recipes/src/fs_rom/hash +++ b/repos/os/recipes/src/fs_rom/hash @@ -1 +1 @@ -2024-08-28 3133d7ce70162177b43d5408f9afc68e934f7c94 +2024-10-07 3cf13b9c1435c9210dd4c425ea4dd5f33d8601c6 diff --git a/repos/os/recipes/src/global_keys_handler/hash b/repos/os/recipes/src/global_keys_handler/hash index a3c2277183..16824a9edf 100644 --- a/repos/os/recipes/src/global_keys_handler/hash +++ b/repos/os/recipes/src/global_keys_handler/hash @@ -1 +1 @@ -2024-08-28 c6d9cbd45c65c29605185a1f440245d8c2881a69 +2024-10-29 cc70248e33e25e1f3308cb340885fa0619832593 diff --git a/repos/os/recipes/src/gui_fb/hash b/repos/os/recipes/src/gui_fb/hash index 005212b958..763f1fc92b 100644 --- a/repos/os/recipes/src/gui_fb/hash +++ b/repos/os/recipes/src/gui_fb/hash @@ -1 +1 @@ -2024-08-28 39675bf74414d875db6e7e08178efad70a173754 +2024-10-29 941ceea5830365b71c530cd31c3b178131d6aae5 diff --git a/repos/os/recipes/src/init/hash b/repos/os/recipes/src/init/hash index f9f4dfe48c..68854e91fa 100644 --- a/repos/os/recipes/src/init/hash +++ b/repos/os/recipes/src/init/hash @@ -1 +1 @@ -2024-08-28 dc258dc1b9b73a8bffa368c433c37978953b40e9 +2024-10-29 b5a6ed03b8b7ef998598d5d11e04e26546623a35 diff --git a/repos/os/recipes/src/intel_gpu/hash b/repos/os/recipes/src/intel_gpu/hash index 930fed0362..45445acec3 100644 --- a/repos/os/recipes/src/intel_gpu/hash +++ b/repos/os/recipes/src/intel_gpu/hash @@ -1 +1 @@ -2024-08-28 8d5d8b317b79ca58cd59eb1c5500d20d697042f0 +2024-10-29 c59da43f4c98ec7515e5696b370480ddd04ef3b5 diff --git a/repos/os/recipes/src/lan9118_nic/hash b/repos/os/recipes/src/lan9118_nic/hash index 21fc683bed..8309fabdf3 100644 --- a/repos/os/recipes/src/lan9118_nic/hash +++ b/repos/os/recipes/src/lan9118_nic/hash @@ -1 +1 @@ -2024-08-28 b2861fa78e8e8a48b0e1410d8dc276f4135a5dbb +2024-10-07 754a2f9509ef97f7e9e9625d2779797a0d12219a diff --git a/repos/os/recipes/src/linux_nic/hash b/repos/os/recipes/src/linux_nic/hash index de97546c78..4354755fce 100644 --- a/repos/os/recipes/src/linux_nic/hash +++ b/repos/os/recipes/src/linux_nic/hash @@ -1 +1 @@ -2024-08-28 9bf66a7a85d42c764ad4f106825b80653949dbe8 +2024-10-07 bab22fc260abf40afb360ed7755da22b0489a176 diff --git a/repos/os/recipes/src/linux_rtc/hash b/repos/os/recipes/src/linux_rtc/hash index cb7147d447..559c16a86c 100644 --- a/repos/os/recipes/src/linux_rtc/hash +++ b/repos/os/recipes/src/linux_rtc/hash @@ -1 +1 @@ -2024-08-28 b6644cc91883c0fe48673b740e72545c3d5c4062 +2024-10-07 558196f8d0a47cf28635a4664bc42b279feca070 diff --git a/repos/os/recipes/src/log_core/hash b/repos/os/recipes/src/log_core/hash index 3b2fb0ec42..ac73026aaf 100644 --- a/repos/os/recipes/src/log_core/hash +++ b/repos/os/recipes/src/log_core/hash @@ -1 +1 @@ -2024-08-28 cf0c839a7f1896eb6155bcf86ab162edaeab9e2e +2024-10-07 5673af6e2f9a9a38fcbcb687a96eef8ed8e6ec67 diff --git a/repos/os/recipes/src/log_terminal/hash b/repos/os/recipes/src/log_terminal/hash index 7cbdd16355..eb1642545a 100644 --- a/repos/os/recipes/src/log_terminal/hash +++ b/repos/os/recipes/src/log_terminal/hash @@ -1 +1 @@ -2024-08-28 615aefc66ab251f9eb45d076aad7ac2167491694 +2024-10-07 64bf185082b5b40dc205e0007e32c503a694eeeb diff --git a/repos/os/recipes/src/lx_block/hash b/repos/os/recipes/src/lx_block/hash index dc1515576c..f0e5172ad7 100644 --- a/repos/os/recipes/src/lx_block/hash +++ b/repos/os/recipes/src/lx_block/hash @@ -1 +1 @@ -2024-08-28 cf3cc85143826a2efeec9cff29797adc66405954 +2024-10-07 63a9a370cf6168858e345a318b13ef32df7b0d8f diff --git a/repos/os/recipes/src/lx_fs/hash b/repos/os/recipes/src/lx_fs/hash index 3ddd75e0cd..b6952be605 100644 --- a/repos/os/recipes/src/lx_fs/hash +++ b/repos/os/recipes/src/lx_fs/hash @@ -1 +1 @@ -2024-08-28 c4f4e9afe514699d9eb0575580909f9a00634a8f +2024-10-07 aab75e76b74ea4ae8280714c0b703dfcdac85df5 diff --git a/repos/os/recipes/src/mixer/hash b/repos/os/recipes/src/mixer/hash index 4af2158c6e..44ffa097da 100644 --- a/repos/os/recipes/src/mixer/hash +++ b/repos/os/recipes/src/mixer/hash @@ -1 +1 @@ -2024-08-28 f69f49e772c17708b9a2e19b141ee6ab04212296 +2024-10-07 3eaff8dddca22e7de96f64a879c1beb1467344fb diff --git a/repos/os/recipes/src/monitor/hash b/repos/os/recipes/src/monitor/hash index 2930e7cc29..1a489a5b5f 100644 --- a/repos/os/recipes/src/monitor/hash +++ b/repos/os/recipes/src/monitor/hash @@ -1 +1 @@ -2024-08-28 86ce5436f6c276ad11ea55528029b2a1459c0357 +2024-10-07 889ac1fe7177e67b859ad719042d7e357f7ef282 diff --git a/repos/os/recipes/src/nic_bridge/hash b/repos/os/recipes/src/nic_bridge/hash index 6ef529cd31..32685d25fd 100644 --- a/repos/os/recipes/src/nic_bridge/hash +++ b/repos/os/recipes/src/nic_bridge/hash @@ -1 +1 @@ -2024-08-28 c1743ba6b12dfb64cba5e87b22a9bf1ab4dfbbaa +2024-10-07 703b72db2aa822aea048569615c109745b4249e2 diff --git a/repos/os/recipes/src/nic_loopback/hash b/repos/os/recipes/src/nic_loopback/hash index ad2efeee92..cdad10e1df 100644 --- a/repos/os/recipes/src/nic_loopback/hash +++ b/repos/os/recipes/src/nic_loopback/hash @@ -1 +1 @@ -2024-08-28 154ce058d9f762645af1e1b5a263210f04710897 +2024-10-07 dc9d4c1649c96b6fafa9a7cd82221f8583937b08 diff --git a/repos/os/recipes/src/nic_perf/hash b/repos/os/recipes/src/nic_perf/hash index 74b62c0e40..01578dfb51 100644 --- a/repos/os/recipes/src/nic_perf/hash +++ b/repos/os/recipes/src/nic_perf/hash @@ -1 +1 @@ -2024-08-28 286b90d18f311c8fd7e0a391d21b29519e72a2a9 +2024-10-07 c15b521bdadc6305825790163faf621628b734bf diff --git a/repos/os/recipes/src/nic_router/hash b/repos/os/recipes/src/nic_router/hash index 2de584c011..03ca0197f5 100644 --- a/repos/os/recipes/src/nic_router/hash +++ b/repos/os/recipes/src/nic_router/hash @@ -1 +1 @@ -2024-08-28 70281fbc5484ea75e8c94bbaac99b6c8b775648e +2024-10-29 cc3d9f3a7833db33551a8880071106541ef73f32 diff --git a/repos/os/recipes/src/nic_uplink/hash b/repos/os/recipes/src/nic_uplink/hash index be0809ac2b..e0a97cb735 100644 --- a/repos/os/recipes/src/nic_uplink/hash +++ b/repos/os/recipes/src/nic_uplink/hash @@ -1 +1 @@ -2024-08-28 65b0200a2de1cff1cd9fb8ceb31e43b8f5e18570 +2024-10-07 b7828835156194fd7cec5c69710e65d43b6c1595 diff --git a/repos/os/recipes/src/nit_focus/hash b/repos/os/recipes/src/nit_focus/hash index b4d5137aa4..a5ed2d668c 100644 --- a/repos/os/recipes/src/nit_focus/hash +++ b/repos/os/recipes/src/nit_focus/hash @@ -1 +1 @@ -2024-08-28 8219e10ae0930bb718a096cab0ec9496ed253c79 +2024-10-07 9b8422a94f6b62432648f6c28db98ffa21ea270f diff --git a/repos/os/recipes/src/nitpicker/hash b/repos/os/recipes/src/nitpicker/hash index 552e6a1bcb..f7d9ea3b38 100644 --- a/repos/os/recipes/src/nitpicker/hash +++ b/repos/os/recipes/src/nitpicker/hash @@ -1 +1 @@ -2024-08-28 dadc09daf55a9f1e4fb15ef79ddd995d30428a06 +2024-11-04 e4fca38bd46e67b396ff7212a790e764e991a703 diff --git a/repos/os/recipes/src/nvme/hash b/repos/os/recipes/src/nvme/hash index 0db41540d1..f77ae27f5f 100644 --- a/repos/os/recipes/src/nvme/hash +++ b/repos/os/recipes/src/nvme/hash @@ -1 +1 @@ -2024-08-28 5e63e438d4f7dcc5174f5c344f865fc82a0c317f +2024-10-07 e14eeefe64a2cccbb4c1deb0e94eb8b81925516e diff --git a/repos/os/recipes/src/part_block/hash b/repos/os/recipes/src/part_block/hash index bc94f4a7e8..1f37c86c67 100644 --- a/repos/os/recipes/src/part_block/hash +++ b/repos/os/recipes/src/part_block/hash @@ -1 +1 @@ -2024-08-28 37c8ede3c26d8ad0e5ac590126b26feb0816a8a7 +2024-10-07 5239a95c88192072dfb809d13be52829f0d61c29 diff --git a/repos/os/recipes/src/pbxa9_drivers/hash b/repos/os/recipes/src/pbxa9_drivers/hash index 215da7f3af..64b302a318 100644 --- a/repos/os/recipes/src/pbxa9_drivers/hash +++ b/repos/os/recipes/src/pbxa9_drivers/hash @@ -1 +1 @@ -2024-08-28 b3511b56dcd1134f748024a9106318b479b579fd +2024-10-07 47037b1c747794f82196fa3bae1c45331d0d4f3c diff --git a/repos/os/recipes/src/pc_rtc/hash b/repos/os/recipes/src/pc_rtc/hash index 9e446e81e2..d669fd4f65 100644 --- a/repos/os/recipes/src/pc_rtc/hash +++ b/repos/os/recipes/src/pc_rtc/hash @@ -1 +1 @@ -2024-08-28 d0330367f25dd201e6e06aa83d273f0881321502 +2024-10-07 f37345766d9ed6711ec943c1bc32dbc55b49b593 diff --git a/repos/os/recipes/src/pci_decode/hash b/repos/os/recipes/src/pci_decode/hash index 14ad8a1ffa..10fed5e03d 100644 --- a/repos/os/recipes/src/pci_decode/hash +++ b/repos/os/recipes/src/pci_decode/hash @@ -1 +1 @@ -2024-08-28 6c2a4d25edf75e5c9199c08b99d0656fcb2f2982 +2024-10-07 c7f369b2bcabd2002537695c73196ddd7dd97716 diff --git a/repos/os/recipes/src/ping/hash b/repos/os/recipes/src/ping/hash index 761da312e4..5679eb9dd9 100644 --- a/repos/os/recipes/src/ping/hash +++ b/repos/os/recipes/src/ping/hash @@ -1 +1 @@ -2024-08-28 16b5573c7eea8dd9172ece805b44ef18d7505e26 +2024-10-07 b32d6ba3b391874d91439938ebd1277e9241b060 diff --git a/repos/os/recipes/src/platform/hash b/repos/os/recipes/src/platform/hash index fb87e05367..9ef304f526 100644 --- a/repos/os/recipes/src/platform/hash +++ b/repos/os/recipes/src/platform/hash @@ -1 +1 @@ -2024-08-28 67cf804d752327c4e4a097757b2ebf2e5b75f89f +2024-10-29 08805a90443577bc7ee9cc429c6f335f1a6f789d diff --git a/repos/os/recipes/src/ps2/hash b/repos/os/recipes/src/ps2/hash index 80c1bc2bda..5542d56d23 100644 --- a/repos/os/recipes/src/ps2/hash +++ b/repos/os/recipes/src/ps2/hash @@ -1 +1 @@ -2024-08-28 dfe678caeba22efb241f2af2a1d961848651aa76 +2024-10-07 41224d2215d5b65971b4db1ed68466d33282b225 diff --git a/repos/os/recipes/src/record_play_mixer/hash b/repos/os/recipes/src/record_play_mixer/hash index bec675f356..9e879e906e 100644 --- a/repos/os/recipes/src/record_play_mixer/hash +++ b/repos/os/recipes/src/record_play_mixer/hash @@ -1 +1 @@ -2024-08-28 eb2513f7433a89f334b054e0398f09ab6a8f507d +2024-10-07 bd10464243c3d6062fdffcf6efb85b3dd941e959 diff --git a/repos/os/recipes/src/record_rom/hash b/repos/os/recipes/src/record_rom/hash index d2982130f1..c20cfb80dc 100644 --- a/repos/os/recipes/src/record_rom/hash +++ b/repos/os/recipes/src/record_rom/hash @@ -1 +1 @@ -2024-08-28 90dcb7d4b3d74cd5fdbfd9476be9721eac6c5911 +2024-10-07 1bee2cdd168ae4ea3ce495694df4d05df074c0a4 diff --git a/repos/os/recipes/src/report_rom/hash b/repos/os/recipes/src/report_rom/hash index d56753b891..a68dbb61c3 100644 --- a/repos/os/recipes/src/report_rom/hash +++ b/repos/os/recipes/src/report_rom/hash @@ -1 +1 @@ -2024-08-28 0984d7cd3d0f1a00aa5d544fbb822e11cc77b1f6 +2024-10-07 a54358a88d31ee91a7f71cf8070dc231961246b9 diff --git a/repos/os/recipes/src/rom_filter/hash b/repos/os/recipes/src/rom_filter/hash index 035b4d0f17..bf246f033b 100644 --- a/repos/os/recipes/src/rom_filter/hash +++ b/repos/os/recipes/src/rom_filter/hash @@ -1 +1 @@ -2024-08-28 2fe10d71efd7382dfe1e7889723b95d99349884e +2024-10-07 ea90e157abd7c0cdde876f7b23564426aeeb65a0 diff --git a/repos/os/recipes/src/rom_logger/hash b/repos/os/recipes/src/rom_logger/hash index 48c76e38b9..e4bf992591 100644 --- a/repos/os/recipes/src/rom_logger/hash +++ b/repos/os/recipes/src/rom_logger/hash @@ -1 +1 @@ -2024-08-28 5a6f6b3bafa20cd506eef7b4847414d1872e5bcf +2024-10-07 3271fe363b6ab76d92e6deb8f39f10e5896661a8 diff --git a/repos/os/recipes/src/rom_reporter/hash b/repos/os/recipes/src/rom_reporter/hash index a6eb1136d1..36efc4fd0f 100644 --- a/repos/os/recipes/src/rom_reporter/hash +++ b/repos/os/recipes/src/rom_reporter/hash @@ -1 +1 @@ -2024-08-28 feddcd36ae165e2c28e37722b3da61c1fba5658c +2024-10-07 1e24742dcaeb10a9ac01c56b882eaa9982f19350 diff --git a/repos/os/recipes/src/rom_to_file/hash b/repos/os/recipes/src/rom_to_file/hash index e5f2c3371f..0ac3c10c96 100644 --- a/repos/os/recipes/src/rom_to_file/hash +++ b/repos/os/recipes/src/rom_to_file/hash @@ -1 +1 @@ -2024-08-28 a8f79b66f52389d62b83301c06ee8612d5d6d047 +2024-10-07 9f530dd60112e34fca2a0841f4fa38898f865fb2 diff --git a/repos/os/recipes/src/sandbox/hash b/repos/os/recipes/src/sandbox/hash index 806149b576..7053093cea 100644 --- a/repos/os/recipes/src/sandbox/hash +++ b/repos/os/recipes/src/sandbox/hash @@ -1 +1 @@ -2024-08-28 bc4953db26ba1dd6c69e7554e1df5f5127464c59 +2024-10-29 73730aafb90aabbad77e7ba49e8aaf487adfdb07 diff --git a/repos/os/recipes/src/sequence/hash b/repos/os/recipes/src/sequence/hash index 2e0c6ad0c9..c570a13e0c 100644 --- a/repos/os/recipes/src/sequence/hash +++ b/repos/os/recipes/src/sequence/hash @@ -1 +1 @@ -2024-08-28 2e988c647845e8b695147f1993c410b94e0d65ee +2024-10-07 68488bcc0aa655658f286044850d5ae1880079d1 diff --git a/repos/os/recipes/src/shim/hash b/repos/os/recipes/src/shim/hash index 9112c41ef3..ce3d59667a 100644 --- a/repos/os/recipes/src/shim/hash +++ b/repos/os/recipes/src/shim/hash @@ -1 +1 @@ -2024-08-28 e13c8a42dabbb213bb08098aa854cc375f994103 +2024-10-07 c46abb4c38ac48a2ef41cbb17c2d797d6910ecfa diff --git a/repos/os/recipes/src/terminal_crosslink/hash b/repos/os/recipes/src/terminal_crosslink/hash index 4afa31ae20..5085762bde 100644 --- a/repos/os/recipes/src/terminal_crosslink/hash +++ b/repos/os/recipes/src/terminal_crosslink/hash @@ -1 +1 @@ -2024-08-28 d70713dcfe6d291cc3a63656e2dbdd4741e52f35 +2024-10-07 7b6ae54d3f165799f8d3aec9c87aed7bd128f998 diff --git a/repos/os/recipes/src/terminal_log/hash b/repos/os/recipes/src/terminal_log/hash index e9fb7f29a8..e5b21975ad 100644 --- a/repos/os/recipes/src/terminal_log/hash +++ b/repos/os/recipes/src/terminal_log/hash @@ -1 +1 @@ -2024-08-28 f7f1b169fa7a4753ac3ec971ad3a2e467fd3762e +2024-10-07 6bb1ab695bdcbe0a8e8a0c3a744cef2ecd0ce5f5 diff --git a/repos/os/recipes/src/test-audio_out/hash b/repos/os/recipes/src/test-audio_out/hash index 53d6b35319..f23daf72c6 100644 --- a/repos/os/recipes/src/test-audio_out/hash +++ b/repos/os/recipes/src/test-audio_out/hash @@ -1 +1 @@ -2024-08-28 dcfc4cb84249b4226e3cffdb07fd9808a717c0db +2024-10-07 319654f5d9fd1c4321de441c510c1c0e9473f448 diff --git a/repos/os/recipes/src/test-black_hole/hash b/repos/os/recipes/src/test-black_hole/hash index d425b12ed9..97413468e6 100644 --- a/repos/os/recipes/src/test-black_hole/hash +++ b/repos/os/recipes/src/test-black_hole/hash @@ -1 +1 @@ -2024-08-28 d88a13621cdf0dba9fc7f1ce4c54f9cdfcad216b +2024-10-07 7c8dc98833299b0c55441563865fcf816f6a936d diff --git a/repos/os/recipes/src/test-bomb/hash b/repos/os/recipes/src/test-bomb/hash index 6170b0d095..434ca8674b 100644 --- a/repos/os/recipes/src/test-bomb/hash +++ b/repos/os/recipes/src/test-bomb/hash @@ -1 +1 @@ -2024-08-28 dbf9173b1648ce7d617d7cf6c7318715fd0bcc78 +2024-10-07 f7e50ad7c4be72ee0ef79f62898ed4f0cb349261 diff --git a/repos/os/recipes/src/test-capture/hash b/repos/os/recipes/src/test-capture/hash index 8bbfabbe86..434af5e430 100644 --- a/repos/os/recipes/src/test-capture/hash +++ b/repos/os/recipes/src/test-capture/hash @@ -1 +1 @@ -2024-08-28 e7a0de28a2648266ae28af34ef5a6f53665b6c2e +2024-10-29 55633a6951ceb535e235bb6da27f67a23be3ed5c diff --git a/repos/os/recipes/src/test-clipboard/hash b/repos/os/recipes/src/test-clipboard/hash index f75de7ea33..d8eb65b70f 100644 --- a/repos/os/recipes/src/test-clipboard/hash +++ b/repos/os/recipes/src/test-clipboard/hash @@ -1 +1 @@ -2024-08-28 a2d112feeabd4de21f1b8a7200401218f3424bd8 +2024-10-07 d8a4d58bba32e87876c96836722f7950db92ef63 diff --git a/repos/os/recipes/src/test-dynamic_config/hash b/repos/os/recipes/src/test-dynamic_config/hash index 69182bd92d..b7fee2f525 100644 --- a/repos/os/recipes/src/test-dynamic_config/hash +++ b/repos/os/recipes/src/test-dynamic_config/hash @@ -1 +1 @@ -2024-08-28 db654c9253ff8ad21fa7df99b7288ac00a786777 +2024-10-29 3cef74242f8fa72a2db8e12f8e0d4fcd9e83ebd5 diff --git a/repos/os/recipes/src/test-fault_detection/hash b/repos/os/recipes/src/test-fault_detection/hash index 5289218346..fd7d61149e 100644 --- a/repos/os/recipes/src/test-fault_detection/hash +++ b/repos/os/recipes/src/test-fault_detection/hash @@ -1 +1 @@ -2024-08-28 cfbd4a26d49960ea7e524b717d730b4ee50e98a5 +2024-10-29 3adb0cf80a0a953f870cbf3aaa29528d5e8ad909 diff --git a/repos/os/recipes/src/test-fs_packet/hash b/repos/os/recipes/src/test-fs_packet/hash index 225bc17936..fc64b57755 100644 --- a/repos/os/recipes/src/test-fs_packet/hash +++ b/repos/os/recipes/src/test-fs_packet/hash @@ -1 +1 @@ -2024-08-28 f9646b60feda933e42c81b68f53f5447eddb164f +2024-10-07 4d8a6973ccf6ad3212f833ac08a431b8cda11678 diff --git a/repos/os/recipes/src/test-fs_report/hash b/repos/os/recipes/src/test-fs_report/hash index 59e0d07690..ecfc36c2be 100644 --- a/repos/os/recipes/src/test-fs_report/hash +++ b/repos/os/recipes/src/test-fs_report/hash @@ -1 +1 @@ -2024-08-28 708df57adbc949e24ff02c724959eb6646d44f11 +2024-10-07 bb2377de93f26340c443c0c7934dfa5d01578762 diff --git a/repos/os/recipes/src/test-immutable_rom/hash b/repos/os/recipes/src/test-immutable_rom/hash index 1cb2e946c1..91d529b62e 100644 --- a/repos/os/recipes/src/test-immutable_rom/hash +++ b/repos/os/recipes/src/test-immutable_rom/hash @@ -1 +1 @@ -2024-08-28 7780569ec1dd23d51e1a2038b9a31d13b61d8573 +2024-10-07 cf8bf1e210b332b40b16ab3a7a7ac3365bbb573d diff --git a/repos/os/recipes/src/test-init/hash b/repos/os/recipes/src/test-init/hash index 4efdc065b5..460035b1f3 100644 --- a/repos/os/recipes/src/test-init/hash +++ b/repos/os/recipes/src/test-init/hash @@ -1 +1 @@ -2024-08-28 365a2cc80ad946930dd0db03bb3129d0d9d2ef6d +2024-10-07 c439cdbbe468eb92e19c5eddbc3c660df07fa935 diff --git a/repos/os/recipes/src/test-init_loop/hash b/repos/os/recipes/src/test-init_loop/hash index 32f7b85e11..8306411a50 100644 --- a/repos/os/recipes/src/test-init_loop/hash +++ b/repos/os/recipes/src/test-init_loop/hash @@ -1 +1 @@ -2024-08-28 0478334a0cc818ebb7cb723329b45195e60d73fb +2024-10-07 acc069827e72d1e3965469948f6292646f148b48 diff --git a/repos/os/recipes/src/test-nic_loopback/hash b/repos/os/recipes/src/test-nic_loopback/hash index d374cbb3c3..43b393e4b3 100644 --- a/repos/os/recipes/src/test-nic_loopback/hash +++ b/repos/os/recipes/src/test-nic_loopback/hash @@ -1 +1 @@ -2024-08-28 41f73f810cf5e5bd497c3bf90fce62be3e17842d +2024-10-07 1b03c323bfd3a3e21f8ca1924ad3a15db87121ad diff --git a/repos/os/recipes/src/test-path/hash b/repos/os/recipes/src/test-path/hash index 30f865dbba..45dae986df 100644 --- a/repos/os/recipes/src/test-path/hash +++ b/repos/os/recipes/src/test-path/hash @@ -1 +1 @@ -2024-08-28 33f071198958e69f82f7d2c589d7a95a41dcf052 +2024-10-07 b77358fb9a8b88f24be8f3a69e3b8fef8f4279d2 diff --git a/repos/os/recipes/src/test-ram_fs_chunk/hash b/repos/os/recipes/src/test-ram_fs_chunk/hash index 890ef57e19..3a97fd55ee 100644 --- a/repos/os/recipes/src/test-ram_fs_chunk/hash +++ b/repos/os/recipes/src/test-ram_fs_chunk/hash @@ -1 +1 @@ -2024-08-28 8950e35c0ab4fa91170cc7206f2205d76bf44328 +2024-10-07 c2d6bc3d6b6c5b22f1d100d4e2e9fb1430471000 diff --git a/repos/os/recipes/src/test-report_rom/hash b/repos/os/recipes/src/test-report_rom/hash index fdbaaee51c..6805758a88 100644 --- a/repos/os/recipes/src/test-report_rom/hash +++ b/repos/os/recipes/src/test-report_rom/hash @@ -1 +1 @@ -2024-08-28 105a58b2b55607cb930f589a90ec40ffb837ff02 +2024-10-07 2f4b386cd722e23323282a455147ca799206fc74 diff --git a/repos/os/recipes/src/test-resource_request/hash b/repos/os/recipes/src/test-resource_request/hash index 8a5812d6b5..197cc55ec8 100644 --- a/repos/os/recipes/src/test-resource_request/hash +++ b/repos/os/recipes/src/test-resource_request/hash @@ -1 +1 @@ -2024-08-28 7e4ae3f7c782ede9a0f9642f4968500f8f21adad +2024-10-07 7fd35cd4c0bef5451c1ec0fe3668f635c49c100d diff --git a/repos/os/recipes/src/test-resource_yield/hash b/repos/os/recipes/src/test-resource_yield/hash index 1e4e71e286..c8137ea27b 100644 --- a/repos/os/recipes/src/test-resource_yield/hash +++ b/repos/os/recipes/src/test-resource_yield/hash @@ -1 +1 @@ -2024-08-28 3f89fcc630fff1ab87357a582f2d62f3a9cbb3d9 +2024-10-07 9cc21fb58aba349ee79f8e42ad9b8b696b9c314d diff --git a/repos/os/recipes/src/test-rtc/hash b/repos/os/recipes/src/test-rtc/hash index b6160c4f39..92bb77faae 100644 --- a/repos/os/recipes/src/test-rtc/hash +++ b/repos/os/recipes/src/test-rtc/hash @@ -1 +1 @@ -2024-08-28 ea02423124ff7f6489147864f0b8886216d32c18 +2024-10-07 20924bffa6be5beb725602c56fa458ea4f9b81b8 diff --git a/repos/os/recipes/src/test-sandbox/hash b/repos/os/recipes/src/test-sandbox/hash index ee25a54c4d..dbcb0ba10d 100644 --- a/repos/os/recipes/src/test-sandbox/hash +++ b/repos/os/recipes/src/test-sandbox/hash @@ -1 +1 @@ -2024-08-28 5378c82f5d3026e66ab1d19d6941342066fcb6db +2024-10-07 9dffd4bcf8c3242918a8d2551929493284d53aa7 diff --git a/repos/os/recipes/src/test-signal/hash b/repos/os/recipes/src/test-signal/hash index 05311482ad..b6ea497595 100644 --- a/repos/os/recipes/src/test-signal/hash +++ b/repos/os/recipes/src/test-signal/hash @@ -1 +1 @@ -2024-08-28 7dcc54ae03b0782cb52a8c02e4543933bbfe9184 +2024-10-07 ca6192bd1e323477cae7a2951a58066c87d75709 diff --git a/repos/os/recipes/src/test-slab/hash b/repos/os/recipes/src/test-slab/hash index 9da408eee7..c9ed6f688c 100644 --- a/repos/os/recipes/src/test-slab/hash +++ b/repos/os/recipes/src/test-slab/hash @@ -1 +1 @@ -2024-08-28 5510fc2de1ba54933b8a51a5a9b58ba06cd536e2 +2024-10-07 1703eb749a1a9021b3e4c7580d9e23540755f45b diff --git a/repos/os/recipes/src/test-terminal_crosslink/hash b/repos/os/recipes/src/test-terminal_crosslink/hash index a2070eba9c..1e7c85ef23 100644 --- a/repos/os/recipes/src/test-terminal_crosslink/hash +++ b/repos/os/recipes/src/test-terminal_crosslink/hash @@ -1 +1 @@ -2024-08-28 9a8b89742dc6b7bef331438dd6ddfdabc9dc584d +2024-10-07 0c9b2eaef420f36f869a812bf60d2d71e75d279c diff --git a/repos/os/recipes/src/test-terminal_echo/hash b/repos/os/recipes/src/test-terminal_echo/hash index f8215c8410..a9634ced62 100644 --- a/repos/os/recipes/src/test-terminal_echo/hash +++ b/repos/os/recipes/src/test-terminal_echo/hash @@ -1 +1 @@ -2024-08-28 c4727d97f7e1950c28486f301c5bdaaf9fd00b49 +2024-10-07 b458510ef1d094faf20cb0f08b5dbf383414b818 diff --git a/repos/os/recipes/src/test-trace/hash b/repos/os/recipes/src/test-trace/hash index 19968b53c5..ead42b99f0 100644 --- a/repos/os/recipes/src/test-trace/hash +++ b/repos/os/recipes/src/test-trace/hash @@ -1 +1 @@ -2024-08-28 205189edc1d835aea19dc18396278ee8c4b189f1 +2024-10-07 8b201c46e688b4c37438e15898e46c384dd7924a diff --git a/repos/os/recipes/src/test-trace_buffer/hash b/repos/os/recipes/src/test-trace_buffer/hash index de3ebb17d3..027856d82d 100644 --- a/repos/os/recipes/src/test-trace_buffer/hash +++ b/repos/os/recipes/src/test-trace_buffer/hash @@ -1 +1 @@ -2024-08-28 138b99e002cd9d96f6591666055254f6de2b4aa8 +2024-10-07 b77ca6114b9924b95eede1d9d47aba9f3d384b00 diff --git a/repos/os/recipes/src/test-trace_logger/hash b/repos/os/recipes/src/test-trace_logger/hash index 6c09005d1b..b0d64dc2e0 100644 --- a/repos/os/recipes/src/test-trace_logger/hash +++ b/repos/os/recipes/src/test-trace_logger/hash @@ -1 +1 @@ -2024-08-28 611d656a5af50e8c075caee877ee23b3cc1eb075 +2024-10-07 469d5fd924ab1dc937fcf09839720dacd38689ed diff --git a/repos/os/recipes/src/test-utf8/hash b/repos/os/recipes/src/test-utf8/hash index 693afa466b..7f75fde273 100644 --- a/repos/os/recipes/src/test-utf8/hash +++ b/repos/os/recipes/src/test-utf8/hash @@ -1 +1 @@ -2024-08-28 5ceb66868a75cd9afe2d8084bcb15294483eada8 +2024-10-07 df1a1a34d5e6347eb94dc30e1af3c26b403e00f9 diff --git a/repos/os/recipes/src/test-vfs_capture/hash b/repos/os/recipes/src/test-vfs_capture/hash index 1b9426c7bc..70f092b3d8 100644 --- a/repos/os/recipes/src/test-vfs_capture/hash +++ b/repos/os/recipes/src/test-vfs_capture/hash @@ -1 +1 @@ -2024-08-28 5b7b47efe4e44d264f0a1d641654857682c9f77b +2024-10-29 71618f93ae7e3b0e1a96ab6ae3fa6369d77747d3 diff --git a/repos/os/recipes/src/test-vfs_stress/hash b/repos/os/recipes/src/test-vfs_stress/hash index 5f80f01b68..5418f15533 100644 --- a/repos/os/recipes/src/test-vfs_stress/hash +++ b/repos/os/recipes/src/test-vfs_stress/hash @@ -1 +1 @@ -2024-08-28 3084bca229034888a620b9332d4ceb95934fb024 +2024-10-07 69dfa130b9c8291e684f24581e0c5d418164edb9 diff --git a/repos/os/recipes/src/test-weak_ptr/hash b/repos/os/recipes/src/test-weak_ptr/hash index ecdce83f81..055e7416a3 100644 --- a/repos/os/recipes/src/test-weak_ptr/hash +++ b/repos/os/recipes/src/test-weak_ptr/hash @@ -1 +1 @@ -2024-08-28 14a7ccaa7b1310bf05751862171ec66cf880e63e +2024-10-07 4f862bdae95f9e0cf7095697980edf090666c9aa diff --git a/repos/os/recipes/src/top/hash b/repos/os/recipes/src/top/hash index 4cbec9a0f0..b63e6612e9 100644 --- a/repos/os/recipes/src/top/hash +++ b/repos/os/recipes/src/top/hash @@ -1 +1 @@ -2024-08-28 a8799e80657634344afe1f7e37ea6ae07ff8626c +2024-10-07 872c15a838e3a0bf338198d96cf467bd7d381988 diff --git a/repos/os/recipes/src/trace_logger/hash b/repos/os/recipes/src/trace_logger/hash index bbeaea2321..8fcc646fcd 100644 --- a/repos/os/recipes/src/trace_logger/hash +++ b/repos/os/recipes/src/trace_logger/hash @@ -1 +1 @@ -2024-08-28 af92c04a89ebf03c55961a3ffad40b7fcff173bd +2024-10-07 3f44a90a83316175d6db0302ec98f438234c88ba diff --git a/repos/os/recipes/src/trace_policy/hash b/repos/os/recipes/src/trace_policy/hash index 7cd9b0cbbf..22b4402559 100644 --- a/repos/os/recipes/src/trace_policy/hash +++ b/repos/os/recipes/src/trace_policy/hash @@ -1 +1 @@ -2024-08-28 446d90af0b814e1db57daaa742c81a31d3bcc52b +2024-10-07 3d2a2c9004491568621c7acf7775a196c26f3f2a diff --git a/repos/os/recipes/src/trace_subject_reporter/hash b/repos/os/recipes/src/trace_subject_reporter/hash index f45807c8fe..a7797b507e 100644 --- a/repos/os/recipes/src/trace_subject_reporter/hash +++ b/repos/os/recipes/src/trace_subject_reporter/hash @@ -1 +1 @@ -2024-08-28 d2acad6f8bcabe66c4ff4dc2e4e3db060d266bfe +2024-10-07 3ace05909b939ee880f27941a003411d5abaf6f0 diff --git a/repos/os/recipes/src/usb_block/hash b/repos/os/recipes/src/usb_block/hash index d0bc0228d3..f9a5b597ff 100644 --- a/repos/os/recipes/src/usb_block/hash +++ b/repos/os/recipes/src/usb_block/hash @@ -1 +1 @@ -2024-08-28 05b74e055bbb240f2e4d1d774cdd9822f0e142ee +2024-10-07 ea6cff533902f41658614bd56aaf738e63832cd8 diff --git a/repos/os/recipes/src/vfs/hash b/repos/os/recipes/src/vfs/hash index c1abe71776..0ba4127cbd 100644 --- a/repos/os/recipes/src/vfs/hash +++ b/repos/os/recipes/src/vfs/hash @@ -1 +1 @@ -2024-08-28 883fdeb460736948ca7ecace7a87f12b256b2d2b +2024-10-07 b2226e3e088fcdb1094c2778a1bcfa8a9d003f49 diff --git a/repos/os/recipes/src/vfs_block/hash b/repos/os/recipes/src/vfs_block/hash index af778d3cad..5e58fb0644 100644 --- a/repos/os/recipes/src/vfs_block/hash +++ b/repos/os/recipes/src/vfs_block/hash @@ -1 +1 @@ -2024-08-28 67575c5b8013628a808b10ec4eda364ec43bd63f +2024-10-07 fa16c07733a59c1debc1826dd5345fac3c037e3e diff --git a/repos/os/recipes/src/vfs_capture/hash b/repos/os/recipes/src/vfs_capture/hash index 24b7ff7d23..6e2e6d13fe 100644 --- a/repos/os/recipes/src/vfs_capture/hash +++ b/repos/os/recipes/src/vfs_capture/hash @@ -1 +1 @@ -2024-08-28 a47991d5b099ea566155be7715ccd584c2602134 +2024-10-07 ff22804167819f32ea8fca2ec13552b6810ceaa4 diff --git a/repos/os/recipes/src/vfs_tap/hash b/repos/os/recipes/src/vfs_tap/hash index ee224e12ab..8db9271df2 100644 --- a/repos/os/recipes/src/vfs_tap/hash +++ b/repos/os/recipes/src/vfs_tap/hash @@ -1 +1 @@ -2024-08-28 efb069bc92e6345e06cdef2307796bea2de20e2d +2024-10-07 179bf98b9f4e58f14c1265a7e61492cbc3b05775 diff --git a/repos/os/recipes/src/virt_qemu_drivers/hash b/repos/os/recipes/src/virt_qemu_drivers/hash index fe614c9ac1..a810341060 100644 --- a/repos/os/recipes/src/virt_qemu_drivers/hash +++ b/repos/os/recipes/src/virt_qemu_drivers/hash @@ -1 +1 @@ -2024-08-28 1bd387ae01057f8a2e691ccdd093ebb2aa5fd1f4 +2024-10-07 a305fab547038302e3ca46606558b04abd41f605 diff --git a/repos/os/recipes/src/virtdev_rom/hash b/repos/os/recipes/src/virtdev_rom/hash index 25e8c00b3f..2500789ec4 100644 --- a/repos/os/recipes/src/virtdev_rom/hash +++ b/repos/os/recipes/src/virtdev_rom/hash @@ -1 +1 @@ -2024-08-28 e87b6a429afdd7a91fea7d6328772c68334addc8 +2024-10-07 4e46c197f5e691543915877dda2659988ad0d517 diff --git a/repos/os/recipes/src/virtio_fb/hash b/repos/os/recipes/src/virtio_fb/hash index 60d115645d..e7c46fc226 100644 --- a/repos/os/recipes/src/virtio_fb/hash +++ b/repos/os/recipes/src/virtio_fb/hash @@ -1 +1 @@ -2024-08-28 ff1f478d3ec28456acb9cb7d24b8fef959971049 +2024-10-07 2bfa764896f0384867da65569e85551fb23af7f1 diff --git a/repos/os/recipes/src/virtio_input/hash b/repos/os/recipes/src/virtio_input/hash index 8a62380bed..002fd7bf3b 100644 --- a/repos/os/recipes/src/virtio_input/hash +++ b/repos/os/recipes/src/virtio_input/hash @@ -1 +1 @@ -2024-08-28 520998c1c17bce5fc956f25bb177b4fb15bad307 +2024-10-07 2ae023c27e6e2057e0765a595ea5e5877ed68b1e diff --git a/repos/os/recipes/src/virtio_nic/hash b/repos/os/recipes/src/virtio_nic/hash index a89a534f39..d6d0f4658e 100644 --- a/repos/os/recipes/src/virtio_nic/hash +++ b/repos/os/recipes/src/virtio_nic/hash @@ -1 +1 @@ -2024-08-28 6d1065aedf9477b2058d77e7b65ff0fac90cf586 +2024-10-07 09a0081792005fcc104a35927dc1ccbfa2f42f14 diff --git a/repos/os/recipes/src/vmm/hash b/repos/os/recipes/src/vmm/hash index c3e211df91..dd80f88d9c 100644 --- a/repos/os/recipes/src/vmm/hash +++ b/repos/os/recipes/src/vmm/hash @@ -1 +1 @@ -2024-08-28 43e940305d0578c3d74c927f07923ab9e5932d2b +2024-10-29 065877c006afdec6f5b6870c4d98168747be494e diff --git a/repos/os/recipes/src/waveform_player/hash b/repos/os/recipes/src/waveform_player/hash index 3b0e640464..fe5ac11065 100644 --- a/repos/os/recipes/src/waveform_player/hash +++ b/repos/os/recipes/src/waveform_player/hash @@ -1 +1 @@ -2024-08-28 161f756662fe55ee21eeecdea02a0a035bc975e3 +2024-10-07 a5fec7cfac7a6eaf46b98715f0937b405e77e1db diff --git a/repos/os/run/demo.run b/repos/os/run/demo.run index 2d4368dd5c..4c7514fd87 100644 --- a/repos/os/run/demo.run +++ b/repos/os/run/demo.run @@ -202,7 +202,7 @@ puts $launchpad_config_fd {<config> <launcher name="launchpad" ram_quota="6M" caps="1000"> <configfile name="launchpad.config" /> </launcher> - <launcher name="nitlog" ram_quota="1M" caps="100"/> + <launcher name="nitlog" ram_quota="1500K" caps="100"/> <launcher name="liquid_fb" ram_quota="9M" caps="100"> <config resize_handle="on" /> </launcher> diff --git a/repos/os/src/app/pci_decode/main.cc b/repos/os/src/app/pci_decode/main.cc index eb8d4156cd..59d1ecbb7d 100644 --- a/repos/os/src/app/pci_decode/main.cc +++ b/repos/os/src/app/pci_decode/main.cc @@ -228,26 +228,10 @@ bus_t Main::parse_pci_function(Bdf bdf, }); { - /* Apply GSI/MSI/MSI-X quirks based on vendor/device/class */ - using Cc = Config::Class_code_rev_id; - - bool const hdaudio = cfg.read<Cc::Class_code>() == 0x40300; + /* Apply GSI/MSI/MSI-X quirks based on vendor/device */ auto const vendor_id = cfg.read<Config::Vendor>(); auto const device_id = cfg.read<Config::Device>(); - if (hdaudio && vendor_id == 0x1022 /* AMD */) { - /** - * see dde_bsd driver dev/pci/azalia.c - * - * PCI_PRODUCT_AMD_17_HDA - * PCI_PRODUCT_AMD_17_1X_HDA - * PCI_PRODUCT_AMD_HUDSON2_HDA - */ - if (device_id == 0x1457 || device_id == 0x15e3 || - device_id == 0x780d) - msi = msi_x = false; - } - /* * Force use of GSI on given ath9k device as using MSI * does not work. diff --git a/repos/os/src/app/pointer/main.cc b/repos/os/src/app/pointer/main.cc index ec98137354..cfdc39cb7f 100644 --- a/repos/os/src/app/pointer/main.cc +++ b/repos/os/src/app/pointer/main.cc @@ -133,9 +133,7 @@ void Pointer::Main::_resize_gui_buffer_if_needed(Gui::Area pointer_size) if (pointer_size == _current_pointer_size) return; - Framebuffer::Mode const mode { .area = pointer_size }; - - _gui.buffer(mode, true /* use alpha */); + _gui.buffer({ .area = pointer_size, .alpha = true }); _pointer_ds = _gui.framebuffer.dataspace(); @@ -163,7 +161,7 @@ void Pointer::Main::_show_default_pointer() convert_default_pointer_data_to_pixels(ds.local_addr<Genode::Pixel_rgb888>(), pointer_size); - _gui.framebuffer.refresh(0, 0, pointer_size.w, pointer_size.h); + _gui.framebuffer.refresh({ { 0, 0 }, pointer_size }); Gui::Rect geometry(Gui::Point(0, 0), pointer_size); _gui.enqueue<Gui::Session::Command::Geometry>(_view.id(), geometry); @@ -224,7 +222,7 @@ void Pointer::Main::_show_shape_pointer(Shape_report &shape_report) Dither_painter::paint(alpha_surface, texture); } - _gui.framebuffer.refresh(0, 0, shape_size.w, shape_size.h); + _gui.framebuffer.refresh({ { 0, 0 }, shape_size }); Gui::Rect geometry(shape_hot, shape_size); _gui.enqueue<Gui::Session::Command::Geometry>(_view.id(), geometry); @@ -333,9 +331,9 @@ Pointer::Main::Main(Genode::Env &env) : _env(env) * pointer size to let the user know right from the start if the * RAM quota is too low. */ - Framebuffer::Mode const mode { .area = { Pointer::MAX_WIDTH, Pointer::MAX_HEIGHT } }; - _gui.buffer(mode, true /* use alpha */); + _gui.buffer({ .area = { Pointer::MAX_WIDTH, Pointer::MAX_HEIGHT }, + .alpha = true }); if (_shapes_enabled) { try { diff --git a/repos/os/src/app/status_bar/main.cc b/repos/os/src/app/status_bar/main.cc index ceefc3426d..141c6a2aad 100644 --- a/repos/os/src/app/status_bar/main.cc +++ b/repos/os/src/app/status_bar/main.cc @@ -44,18 +44,21 @@ struct Status_bar::Buffer Gui::Connection &_gui; - Framebuffer::Mode const _nit_mode { _gui.mode() }; + Gui::Area const _scr_area = _gui.panorama().convert<Gui::Area>( + [&] (Gui::Rect rect) { return rect.area; }, + [&] (Gui::Undefined) { return Gui::Area { 1, 1 }; }); /* * Dimension nitpicker buffer depending on nitpicker's screen size. * The status bar is as wide as nitpicker's screen and has a fixed * height. */ - Framebuffer::Mode const _mode { .area = { _nit_mode.area.w, HEIGHT } }; + Framebuffer::Mode const _mode { .area = { _scr_area.w, HEIGHT }, + .alpha = false }; Dataspace_capability _init_buffer() { - _gui.buffer(_mode, false); + _gui.buffer(_mode); return _gui.framebuffer.dataspace(); } @@ -157,7 +160,7 @@ void Status_bar::Buffer::draw(Domain_name const &domain_name, _draw_label(surface, view_rect.center(_label_size(domain_name, label)), domain_name, label, color); - _gui.framebuffer.refresh(0, 0, area.w, area.h); + _gui.framebuffer.refresh({ { 0, 0 }, area }); } @@ -197,7 +200,7 @@ struct Status_bar::Main { /* register signal handlers */ _focus_ds.sigh(_focus_handler); - _gui.mode_sigh(_mode_handler); + _gui.info_sigh(_mode_handler); /* import initial state */ _handle_mode(); diff --git a/repos/os/src/driver/framebuffer/boot/main.cc b/repos/os/src/driver/framebuffer/boot/main.cc index 02f3511e3b..d257fd39f8 100644 --- a/repos/os/src/driver/framebuffer/boot/main.cc +++ b/repos/os/src/driver/framebuffer/boot/main.cc @@ -87,8 +87,9 @@ struct Framebuffer::Main Capture::Connection _capture { _env }; - Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _info.size }; - + Capture::Connection::Screen _captured_screen { _capture, _env.rm(), { + .px = _info.size, + .mm = { } } }; Timer::Connection _timer { _env }; Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer }; diff --git a/repos/os/src/driver/framebuffer/pl11x/main.cc b/repos/os/src/driver/framebuffer/pl11x/main.cc index dd6bbfd349..54611e4ccb 100644 --- a/repos/os/src/driver/framebuffer/pl11x/main.cc +++ b/repos/os/src/driver/framebuffer/pl11x/main.cc @@ -59,7 +59,9 @@ struct Pl11x_driver::Main Capture::Connection _capture { _env }; - Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _size }; + Capture::Connection::Screen _captured_screen { _capture, _env.rm(), { + .px = _size, + .mm = { } } }; /* diff --git a/repos/os/src/driver/framebuffer/ram/main.cc b/repos/os/src/driver/framebuffer/ram/main.cc index 8d4d0c2425..38d099c2a9 100644 --- a/repos/os/src/driver/framebuffer/ram/main.cc +++ b/repos/os/src/driver/framebuffer/ram/main.cc @@ -65,8 +65,9 @@ class Main Capture::Area const _size { SCR_WIDTH, SCR_HEIGHT }; Capture::Connection _capture { _env }; - Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _size }; - + Capture::Connection::Screen _captured_screen { _capture, _env.rm(), { + .px = _size, + .mm = { } } }; Timer::Connection _timer { _env }; Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer }; diff --git a/repos/os/src/driver/framebuffer/sdl/main.cc b/repos/os/src/driver/framebuffer/sdl/main.cc index 7376dcf44e..d88cf5c8f6 100644 --- a/repos/os/src/driver/framebuffer/sdl/main.cc +++ b/repos/os/src/driver/framebuffer/sdl/main.cc @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2017 Genode Labs GmbH + * Copyright (C) 2006-2024 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -31,63 +31,100 @@ namespace Fb_sdl { class Main; + class Sdl; + using namespace Genode; -} - - -/* fatal exceptions */ -struct Sdl_init_failed : Genode::Exception { }; -struct Sdl_videodriver_not_supported : Genode::Exception { }; -struct Sdl_createwindow_failed : Genode::Exception { }; -struct Sdl_createrenderer_failed : Genode::Exception { }; -struct Sdl_creatergbsurface_failed : Genode::Exception { }; -struct Sdl_createtexture_failed : Genode::Exception { }; - - -struct Fb_sdl::Main -{ - Env &_env; - - Attached_rom_dataspace _config { _env, "config" }; - - Timer::Connection _timer { _env }; - Event::Connection _event { _env }; using Area = Capture::Area; - using Point = Capture::Area; + using Rect = Capture::Rect; using Pixel = Capture::Pixel; using Affected_rects = Capture::Session::Affected_rects; using Event_batch = Event::Session_client::Batch; - void _init_sdl() + static constexpr int USER_EVENT_CAPTURE_WAKEUP = 99; +} + + +/** + * Interplay with libSDL + */ +struct Fb_sdl::Sdl : Noncopyable +{ + Event::Connection &_event; + Capture::Connection &_capture; + Region_map &_rm; + + struct Ticks { Uint32 ms; }; + + struct Attr { - /* - * Initialize libSDL window - */ - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - error("SDL_Init failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_init_failed(); + Area initial_size; + + double fps; /* frames per second */ + unsigned idle; /* disable capturing after 'idle' frames of no progress */ + + static Attr from_xml(Xml_node const &node) + { + return { + .initial_size = { .w = node.attribute_value("width", 1024u), + .h = node.attribute_value("height", 768u) }, + .fps = node.attribute_value("fps", 60.0), + .idle = node.attribute_value("idle", 3U) + }; } - SDL_ShowCursor(0); + Ticks period() const + { + return { (fps > 0) ? unsigned(1000.0/fps) : 20u }; + } + }; + + Attr const _attr; + + /* fatal exceptions */ + struct Init_failed : Exception { }; + struct Createthread_failed : Exception { }; + struct Videodriver_not_supported : Exception { }; + struct Createwindow_failed : Exception { }; + struct Createrenderer_failed : Exception { }; + struct Creatergbsurface_failed : Exception { }; + struct Createtexture_failed : Exception { }; + + void _thread(); + + static int _entry(void *data_ptr) + { + ((Sdl *)data_ptr)->_thread(); + return 0; } - bool const _sdl_initialized = ( _init_sdl(), true ); + SDL_Thread &_init_thread() + { + SDL_Thread *ptr = SDL_CreateThread(_entry, "SDL", this); + if (ptr) + return *ptr; - struct Sdl_window + throw Createthread_failed(); + } + + SDL_Thread &_sdl_thread = _init_thread(); + + struct Window { Area const _initial_size; - SDL_Renderer &_sdl_renderer = _init_sdl_renderer(); + SDL_Renderer &renderer = _init_renderer(); - SDL_Renderer &_init_sdl_renderer() + SDL_Renderer &_init_renderer() { unsigned const window_flags = 0; - SDL_Window *window_ptr = SDL_CreateWindow("fb_sdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _initial_size.w, _initial_size.h, window_flags); + SDL_Window * const window_ptr = + SDL_CreateWindow("fb_sdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + _initial_size.w, _initial_size.h, window_flags); if (!window_ptr) { - error("SDL_CreateWindow failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_createwindow_failed(); + error("SDL_CreateWindow failed (", Cstring(SDL_GetError()), ")"); + throw Createwindow_failed(); } SDL_SetWindowResizable(window_ptr, SDL_TRUE); @@ -96,35 +133,30 @@ struct Fb_sdl::Main unsigned const renderer_flags = SDL_RENDERER_SOFTWARE; SDL_Renderer *renderer_ptr = SDL_CreateRenderer(window_ptr, index, renderer_flags); if (!renderer_ptr) { - error("SDL_CreateRenderer failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_createrenderer_failed(); + error("SDL_CreateRenderer failed (", Cstring(SDL_GetError()), ")"); + throw Createrenderer_failed(); } return *renderer_ptr; } - Sdl_window(Area size) : _initial_size(size) { } + Window(Area size) : _initial_size(size) { } - ~Sdl_window() + ~Window() { - SDL_DestroyRenderer(&_sdl_renderer); - } - - SDL_Renderer &renderer() - { - return _sdl_renderer; + SDL_DestroyRenderer(&renderer); } }; - struct Sdl_screen + struct Screen { Area const size; SDL_Renderer &renderer; - SDL_Surface &_sdl_surface = _init_sdl_surface(); - SDL_Texture &_sdl_texture = _init_sdl_texture(); + SDL_Surface &_surface = _init_surface(); + SDL_Texture &_texture = _init_texture(); - SDL_Surface &_init_sdl_surface() + SDL_Surface &_init_surface() { unsigned const flags = 0; unsigned const bpp = 32; @@ -133,127 +165,217 @@ struct Fb_sdl::Main unsigned const blue_mask = 0x000000FF; unsigned const alpha_mask = 0xFF000000; - SDL_Surface *surface_ptr = SDL_CreateRGBSurface(flags, size.w, size.h, bpp, red_mask, green_mask, blue_mask, alpha_mask); + SDL_Surface * const surface_ptr = + SDL_CreateRGBSurface(flags, size.w, size.h, bpp, + red_mask, green_mask, blue_mask, alpha_mask); if (!surface_ptr) { - error("SDL_CreateRGBSurface failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_creatergbsurface_failed(); + error("SDL_CreateRGBSurface failed (", Cstring(SDL_GetError()), ")"); + throw Creatergbsurface_failed(); } return *surface_ptr; } - SDL_Texture &_init_sdl_texture() + SDL_Texture &_init_texture() { - SDL_Texture *texture_ptr = SDL_CreateTexture(&renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, size.w, size.h); + SDL_Texture * const texture_ptr = + SDL_CreateTexture(&renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, size.w, size.h); if (!texture_ptr) { - error("SDL_CreateTexture failed (", Genode::Cstring(SDL_GetError()), ")"); - throw Sdl_createtexture_failed(); + error("SDL_CreateTexture failed (", Cstring(SDL_GetError()), ")"); + throw Createtexture_failed(); } return *texture_ptr; } - Sdl_screen(Area size, SDL_Renderer &renderer) : size(size), renderer(renderer) { } + Screen(Area size, SDL_Renderer &renderer) : size(size), renderer(renderer) { } - ~Sdl_screen() + ~Screen() { - SDL_FreeSurface(&_sdl_surface); - SDL_DestroyTexture(&_sdl_texture); + SDL_FreeSurface(&_surface); + SDL_DestroyTexture(&_texture); } - template <typename FN> - void with_surface(FN const &fn) + void with_surface(auto const &fn) { - Surface<Pixel> surface { (Pixel *)_sdl_surface.pixels, size }; + Surface<Pixel> surface { (Pixel *)_surface.pixels, size }; fn(surface); } - void flush() + void flush(Capture::Rect const bounding_box) { - SDL_UpdateTexture(&_sdl_texture, nullptr, _sdl_surface.pixels, _sdl_surface.pitch); - SDL_RenderClear(&renderer); - SDL_RenderCopy(&renderer, &_sdl_texture, nullptr, nullptr); + SDL_Rect const rect { .x = bounding_box.at.x, + .y = bounding_box.at.y, + .w = int(bounding_box.area.w), + .h = int(bounding_box.area.h) }; + + SDL_UpdateTexture(&_texture, nullptr, _surface.pixels, _surface.pitch); + SDL_RenderCopy(&renderer, &_texture, &rect, &rect); SDL_RenderPresent(&renderer); } + + void flush_all() { flush(Rect { { 0, 0 }, size }); } }; - Constructible<Sdl_window> _sdl_window { }; - Constructible<Sdl_screen> _sdl_screen { }; - - Capture::Connection _capture { _env }; + Constructible<Window> _window { }; + Constructible<Screen> _screen { }; Constructible<Capture::Connection::Screen> _captured_screen { }; - Signal_handler<Main> _timer_handler { - _env.ep(), *this, &Main::_handle_timer }; - int _mx = 0, _my = 0; - void _handle_sdl_event(Event_batch &, SDL_Event const &); - void _handle_sdl_events(); + unsigned _capture_woken_up = 0; - void _update_sdl_screen_from_capture() + struct Previous_frame { - Affected_rects const affected = _capture.capture_at(Capture::Point(0, 0)); + Ticks timestamp; + Ticks remaining; /* remaining ticks to next frame */ + unsigned idle; /* capture attempts without progress */ - _sdl_screen->with_surface([&] (Surface<Pixel> &surface) { + Ticks age() const { return { SDL_GetTicks() - timestamp.ms }; } + }; - _captured_screen->with_texture([&] (Texture<Pixel> const &texture) { + /* if constructed, the processing of a next frame is scheduled */ + Constructible<Previous_frame> _previous_frame { }; - affected.for_each_rect([&] (Capture::Rect const rect) { + void _schedule_next_frame() + { + _previous_frame.construct( + Previous_frame { .timestamp = { SDL_GetTicks() }, + .remaining = { _attr.period() }, + .idle = { } }); + } - surface.clip(rect); + void _handle_event(Event_batch &, SDL_Event const &); - Blit_painter::paint(surface, texture, Capture::Point(0, 0)); - }); - }); + bool _update_screen_from_capture() + { + bool progress = false; + _screen->with_surface([&] (Surface<Pixel> &surface) { + + Rect const bounding_box = _captured_screen->apply_to_surface(surface); + + progress = (bounding_box.area.count() > 0); + + if (progress) + _screen->flush(bounding_box); }); - - /* flush pixels in SDL window */ - _sdl_screen->flush(); + return progress; } - void _handle_timer() + void _resize(Area const size) { - _handle_sdl_events(); + _screen.construct(size, _window->renderer); - _update_sdl_screen_from_capture(); + using Attr = Capture::Connection::Screen::Attr; + _captured_screen.construct(_capture, _rm, Attr { + .px = size, + .mm = { } }); + + _update_screen_from_capture(); + _schedule_next_frame(); } - void _resize(Area size) - { - _sdl_screen.construct(size, _sdl_window->renderer()); - _captured_screen.construct(_capture, _env.rm(), size); - _update_sdl_screen_from_capture(); - } - - Main(Env &env) : _env(env) - { - Area size = Area(_config.xml().attribute_value("width", 1024U), - _config.xml().attribute_value("height", 768U)); - _sdl_window.construct(size); - _resize(size); - - _timer.sigh(_timer_handler); - _timer.trigger_periodic(100000000 / 5994); /* 59.94Hz */ - } + /* + * Construction executed by the main thread + */ + Sdl(Event::Connection &event, Capture::Connection &capture, Region_map &rm, + Attr const attr) + : + _event(event), _capture(capture), _rm(rm), _attr(attr) + { } }; -void Fb_sdl::Main::_handle_sdl_event(Event_batch &batch, SDL_Event const &event) +void Fb_sdl::Sdl::_thread() +{ + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + error("SDL_Init failed (", Cstring(SDL_GetError()), ")"); + throw Init_failed(); + } + + SDL_ShowCursor(0); + + _window.construct(_attr.initial_size); + _resize(_attr.initial_size); + + /* mainloop */ + for (;;) { + + if (_previous_frame.constructed()) + SDL_WaitEventTimeout(nullptr, _previous_frame->remaining.ms); + else + SDL_WaitEvent(nullptr); + + unsigned const orig_capture_woken_up = _capture_woken_up; + + _event.with_batch([&] (Event_batch &batch) { + SDL_Event event { }; + while (SDL_PollEvent(&event)) + _handle_event(batch, event); }); + + Ticks const period = _attr.period(); + + bool const woken_up = (_capture_woken_up != orig_capture_woken_up); + bool const frame_elapsed = _previous_frame.constructed() + && _previous_frame->age().ms >= period.ms; + + if (woken_up || frame_elapsed) { + + bool const progress = _update_screen_from_capture(); + bool const idle = !progress && !woken_up; + + if (idle) { + if (_previous_frame.constructed()) { + _previous_frame->idle++; + if (_previous_frame->idle > _attr.idle) { + _previous_frame.destruct(); + _capture.capture_stopped(); + } + } + } else { + _schedule_next_frame(); + } + + } else { + /* + * Events occurred in-between two frames. + * Update timeout for next call of 'SDL_WaitEventTimeout'. + */ + if (_previous_frame.constructed()) + _previous_frame->remaining = { + min(period.ms, period.ms - _previous_frame->age().ms) }; + } + } +} + + +void Fb_sdl::Sdl::_handle_event(Event_batch &batch, SDL_Event const &event) { using namespace Input; - if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) { + if (event.type == SDL_WINDOWEVENT) { - int w = event.window.data1; - int h = event.window.data2; - if (w < 0 || h < 0) { - warning("attempt to resize to negative size"); - return; + if (event.window.event == SDL_WINDOWEVENT_RESIZED) { + + int const w = event.window.data1, + h = event.window.data2; + + if (w <= 0 || h <= 0) { + warning("attempt to resize to invalid size"); + return; + } + _resize({ unsigned(w), unsigned(h) }); } - _resize(Area((unsigned)w, (unsigned)h)); + _screen->flush_all(); + return; + } + + if (event.type == SDL_USEREVENT) { + if (event.user.code == USER_EVENT_CAPTURE_WAKEUP) + _capture_woken_up++; return; } @@ -294,7 +416,6 @@ void Fb_sdl::Main::_handle_sdl_event(Event_batch &batch, SDL_Event const &event) } } - /* determine event type */ switch (event.type) { case SDL_KEYUP: @@ -323,16 +444,39 @@ void Fb_sdl::Main::_handle_sdl_event(Event_batch &batch, SDL_Event const &event) } -void Fb_sdl::Main::_handle_sdl_events() +struct Fb_sdl::Main { - SDL_Event event { }; + Env &_env; - _event.with_batch([&] (Event_batch &batch) { + Attached_rom_dataspace _config { _env, "config" }; - while (SDL_PollEvent(&event)) - _handle_sdl_event(batch, event); - }); -} + Event::Connection _event { _env }; + Capture::Connection _capture { _env }; + + void _handle_capture_wakeup() + { + SDL_Event ev { }; + ev.user = SDL_UserEvent { .type = SDL_USEREVENT, + .timestamp = SDL_GetTicks(), + .windowID = { }, + .code = USER_EVENT_CAPTURE_WAKEUP, + .data1 = { }, + .data2 = { } }; + + if (SDL_PushEvent(&ev) == 0) + warning("SDL_PushEvent failed (", Cstring(SDL_GetError()), ")"); + } + + Signal_handler<Main> _capture_wakeup_handler { + _env.ep(), *this, &Main::_handle_capture_wakeup }; + + Sdl _sdl { _event, _capture, _env.rm(), Sdl::Attr::from_xml(_config.xml()) }; + + Main(Env &env) : _env(env) + { + _capture.wakeup_sigh(_capture_wakeup_handler); + } +}; void Component::construct(Genode::Env &env) { static Fb_sdl::Main inst(env); } diff --git a/repos/os/src/driver/framebuffer/virtio/component.h b/repos/os/src/driver/framebuffer/virtio/component.h index 1ffd81c03b..1294c7daf2 100644 --- a/repos/os/src/driver/framebuffer/virtio/component.h +++ b/repos/os/src/driver/framebuffer/virtio/component.h @@ -355,7 +355,10 @@ class Virtio_fb::Driver throw Display_init_failed(); } - _captured_screen.construct(_capture, _env.rm(), _display_area); + using Attr = Capture::Connection::Screen::Attr; + _captured_screen.construct(_capture, _env.rm(), Attr { + .px = _display_area, + .mm = { } }); } void _shutdown_display() diff --git a/repos/os/src/driver/gpu/intel/platform_session.h b/repos/os/src/driver/gpu/intel/platform_session.h index 282fe3f1d3..a66ccd6d75 100644 --- a/repos/os/src/driver/gpu/intel/platform_session.h +++ b/repos/os/src/driver/gpu/intel/platform_session.h @@ -17,6 +17,7 @@ #include <region_map/client.h> #include <rm_session/connection.h> #include <platform_session/platform_session.h> +#include <os/dynamic_rom_session.h> #include <types.h> struct Irq_ack_handler @@ -171,7 +172,8 @@ class Platform::Device_component : public Rpc_object<Device_interface, }; -class Platform::Session_component : public Rpc_object<Session> +class Platform::Session_component : public Rpc_object<Session>, + private Dynamic_rom_session::Xml_producer { private: @@ -181,6 +183,8 @@ class Platform::Session_component : public Rpc_object<Session> Gpu_reset_handler & _reset_handler; Heap _heap { _env.ram(), _env.rm() }; Device_component _device_component; + Dynamic_rom_session _rom_session { _env.ep(), _env.ram(), + _env.rm(), *this }; bool _acquired { false }; /* @@ -213,6 +217,7 @@ class Platform::Session_component : public Rpc_object<Session> Dataspace_capability gmadr_ds_cap, Range gmadr_range) : + Dynamic_rom_session::Xml_producer("devices"), _env(env), _platform(platform), _hw_ready(hw_ready), @@ -282,10 +287,105 @@ class Platform::Session_component : public Rpc_object<Session> return ret; } - Rom_session_capability devices_rom() override { - return _platform.devices_rom(); } + Rom_session_capability devices_rom() override + { + _rom_session.update(); + + return _rom_session.cap(); + } bool handle_irq() { return _device_component.handle_irq(); } + + /******************************************* + ** Dynamic_rom_session::Xml_producer API ** + *******************************************/ + + void produce_xml(Xml_generator &xml) override + { + Rom_session_client rsc(_platform.devices_rom()); + Attached_dataspace rom(_env.rm(), rsc.dataspace()); + + if (!rom.size()) + return; + + Xml_node const rom_xml(rom.local_addr<char>()); + + copy_attributes(xml, rom_xml); + + rom_xml.for_each_sub_node("device", [&](auto const &dev) { + + bool intel_dev = false; + bool graphic_dev = false; + + dev.with_optional_sub_node("pci-config", [&] (Xml_node const &node) { + intel_dev = node.attribute_value("vendor_id", 0u) == 0x8086; + graphic_dev = node.attribute_value("class", 0u) == 0x30000; + }); + + if (!intel_dev) + return; + + if (!graphic_dev) { + copy_node(xml, dev); + return; + } + + xml.node("device", [&]() { + copy_attributes(xml, dev); + + dev.for_each_sub_node([&] (Xml_node const &node) { + if (!node.has_type("io_mem")) { + copy_node(xml, node); + return; + } + + auto const pci_bar = node.attribute_value("pci_bar", ~0U); + + xml.node("io_mem", [&]() { + node.for_each_attribute([&](auto const &attr){ + String<16> value { }; + attr.value(value); + + if (pci_bar == 2 && attr.has_type("size")) { + Range r = { }; + _device_component.io_mem(1, r); + + value = String<16>(Hex(r.size)); + } + + xml.attribute(attr.name().string(), + value.string()); + }); + }); + }); + }); + }); + } + + void copy_attributes(Xml_generator &xml, Xml_node const &from) + { + using Value = String<64>; + from.for_each_attribute([&] (Xml_attribute const &attr) { + Value value { }; + attr.value(value); + xml.attribute(attr.name().string(), value); + }); + } + + struct Xml_max_depth { unsigned value; }; + + void copy_node(Xml_generator &xml, Xml_node const &from, + Xml_max_depth max_depth = { 5 }) + { + if (!max_depth.value) + return; + + xml.node(from.type().string(), [&] { + copy_attributes(xml, from); + from.for_each_sub_node([&] (Xml_node const &sub_node) { + copy_node(xml, sub_node, { max_depth.value - 1 }); }); + }); + } }; diff --git a/repos/os/src/driver/platform/common.h b/repos/os/src/driver/platform/common.h index 411cce8b90..0f0216faf7 100644 --- a/repos/os/src/driver/platform/common.h +++ b/repos/os/src/driver/platform/common.h @@ -68,6 +68,9 @@ class Driver::Common : Device_reporter, Io_mmu_devices & io_mmu_devices() { return _io_mmu_devices; } + Xml_node platform_info() { + return _platform_info.xml(); } + void announce_service(); void handle_config(Xml_node config); void acquire_io_mmu_devices(); diff --git a/repos/os/src/lib/genode_c_api/usb.cc b/repos/os/src/lib/genode_c_api/usb.cc index d09963995c..3645f88a9a 100644 --- a/repos/os/src/lib/genode_c_api/usb.cc +++ b/repos/os/src/lib/genode_c_api/usb.cc @@ -112,6 +112,15 @@ struct Reg_list fn(e->_object); } } + + void apply(auto const &condition, auto const & fn) + { + for (Element *e = _elements.first(); e; e = e->next()) + if (condition(e->_object)) { + fn(e->_object); + return; + } + } }; @@ -907,8 +916,11 @@ Device_component::_handle_request(Constructible<Packet_descriptor> &cpd, granted = true; break; case P::SET_INTERFACE: - _interfaces.for_each([&] (Interface_component & ic) { - if (ic._iface_idx == cpd->index) granted = true; }); + _interfaces.apply( + [&] (Interface_component & ic) { + return ic._iface_idx == cpd->index; + }, + [&] (Interface_component &) { granted = true; }); if (granted) break; [[fallthrough]]; default: granted = _controls; @@ -947,8 +959,10 @@ void Device_component::release_interface(Interface_capability cap) if (!cap.valid()) return; - _interfaces.for_each([&] (Interface_component & ic) { - if (cap.local_name() == ic.cap().local_name()) + _interfaces.apply( + [&] (Interface_component & ic) { + return cap.local_name() == ic.cap().local_name(); }, + [&] (Interface_component & ic) { destroy(_heap, &ic); }); } @@ -958,8 +972,10 @@ bool Device_component::request(genode_usb_req_callback_t const callback, { bool ret = false; - _interfaces.for_each([&] (Interface_component & ic) { - if (ic.request(callback, opaque_data)) ret = true; }); + _interfaces.apply( + [&] (Interface_component & ic) { + return ic.request(callback, opaque_data); }, + [&] (Interface_component &) { ret = true; }); return ret ? ret : Base::request(callback, opaque_data); } @@ -1003,10 +1019,11 @@ Device_component::handle_response(genode_usb_request_handle_t handle, [&] (Packet_error) {}); if (!ret) - _interfaces.for_each([&] (Interface_component & ic) { - if (ret) return; - if (ic.handle_response(handle, value, actual_sizes)) ret = true; - }); + _interfaces.apply( + [&] (Interface_component & ic) { + return ic.handle_response(handle, value, actual_sizes); }, + [&] (Interface_component &) { + ret = true; }); return ret; } @@ -1143,12 +1160,13 @@ void Session_component::_release(Device_component &dc) genode_usb_device::Label name = dc._device_label; destroy(_heap, &dc); - _devices.for_each([&] (genode_usb_device & device) { - if (device.label() != name) - return; - _sessions.for_each([&] (Session_component &sc) { - if (sc._matches(device)) sc.update_devices_rom(); }); - _root.report(); + _devices.apply( + [&] (genode_usb_device & device) { + return device.label() == name; }, + [&] (genode_usb_device & device) { + _sessions.for_each([&] (Session_component &sc) { + if (sc._matches(device)) sc.update_devices_rom(); }); + _root.report(); }); } @@ -1157,22 +1175,24 @@ void Session_component::set_interface(genode_usb_device::Label label, uint16_t num, uint16_t alt) { bool changed = false; - _devices.for_each([&] (genode_usb_device & d) { - if (d.label() != label) - return; - d.configs.for_each([&] (genode_usb_configuration & c) { - if (!c.active) - return; - c.interfaces.for_each([&] (genode_usb_interface & i) { - if (i.desc.number != num) - return; - - if (i.active != (i.desc.alt_settings == alt)) { - i.active = (i.desc.alt_settings == alt); - changed = true; - } + _devices.apply( + [&] (genode_usb_device & d) { + return d.label() == label; }, + [&] (genode_usb_device & d) { + d.configs.apply( + [&] (genode_usb_configuration & c) { + return c.active; }, + [&] (genode_usb_configuration & c) { + c.interfaces.apply( + [&] (genode_usb_interface & i) { + return i.desc.number == num; }, + [&] (genode_usb_interface & i) { + if (i.active != (i.desc.alt_settings == alt)) { + i.active = (i.desc.alt_settings == alt); + changed = true; + } + }); }); - }); }); if (changed) { @@ -1186,15 +1206,17 @@ void Session_component::set_configuration(genode_usb_device::Label label, uint16_t num) { bool changed = false; - _devices.for_each([&] (genode_usb_device & d) { - if (d.label() != label) - return; - d.configs.for_each([&] (genode_usb_configuration & c) { - if (c.active != (c.desc.config_value == num)) { - c.active = (c.desc.config_value == num); - changed = true; - } - }); + _devices.apply( + [&] (genode_usb_device & d) { + return d.label() == label; }, + [&] (genode_usb_device & d) { + d.configs.apply( + [&] (genode_usb_configuration & c) { + return c.active != (c.desc.config_value == num); }, + [&] (genode_usb_configuration & c) { + c.active = (c.desc.config_value == num); + changed = true; + }); }); if (changed) { @@ -1211,18 +1233,19 @@ bool Session_component::matches(genode_usb_device::Label label, uint8_t iface) * all interfaces are allowed, otherwise check for the iface number */ bool ret = false; - _devices.for_each([&] (genode_usb_device const & d) { - if (d.label() != label) - return; - _device_policy(d, [&] (Xml_node dev_node) { - if (!dev_node.has_sub_node("interface")) - ret = true; - else - dev_node.for_each_sub_node("interface", [&] (Xml_node & node) { - if (node.attribute_value<uint8_t>("number", 255) == iface) - ret = true; - }); - }); + _devices.apply( + [&] (genode_usb_device const & d) { + return d.label() == label; }, + [&] (genode_usb_device const & d) { + _device_policy(d, [&] (Xml_node dev_node) { + if (!dev_node.has_sub_node("interface")) + ret = true; + else + dev_node.for_each_sub_node("interface", [&] (Xml_node & node) { + if (node.attribute_value<uint8_t>("number", 255) == iface) + ret = true; + }); + }); }); return ret; } @@ -1232,17 +1255,21 @@ template <typename FN> void Session_component::for_each_ep(genode_usb_device::Label label, uint8_t iface_idx, FN const & fn) { - _devices.for_each([&] (genode_usb_device const & d) { - if (d.label() != label) - return; - d.configs.for_each([&] (genode_usb_configuration const & cfg) { - if (!cfg.active) - return; - cfg.interfaces.for_each([&] (genode_usb_interface const & iface) { - if (iface.desc.number == iface_idx) - iface.endpoints.for_each(fn); + _devices.apply( + [&] (genode_usb_device const & d) { + return d.label() == label; }, + [&] (genode_usb_device & d) { + d.configs.apply( + [&] (genode_usb_configuration const & cfg) { + return cfg.active; }, + [&] (genode_usb_configuration & cfg) { + cfg.interfaces.apply( + [&] (genode_usb_interface const & iface) { + return iface.desc.number == iface_idx; }, + [&] (genode_usb_interface const & iface) { + iface.endpoints.for_each(fn); + }); }); - }); }); } @@ -1255,11 +1282,12 @@ void Session_component::announce_device(genode_usb_device const & device) void Session_component::discontinue_device(genode_usb_device const & device) { - _device_sessions.for_each([&] (Device_component & dc) { - if (dc._device_label != device.label()) - return; - dc.disconnect(); - update_devices_rom(); + _device_sessions.apply( + [&] (Device_component & dc) { + return dc._device_label == device.label(); }, + [&] (Device_component & dc) { + dc.disconnect(); + update_devices_rom(); }); } @@ -1267,13 +1295,14 @@ void Session_component::discontinue_device(genode_usb_device const & device) void Session_component::update_policy() { _device_sessions.for_each([&] (Device_component & dc) { - _devices.for_each([&] (genode_usb_device const & device) { - if (device.label() != dc._device_label) - return; - if (!_matches(device)) { - dc.disconnect(); - _release_fn(device.bus, device.dev); - } + _devices.apply( + [&] (genode_usb_device const & device) { + return device.label() == dc._device_label; }, + [&] (genode_usb_device const & device) { + if (!_matches(device)) { + dc.disconnect(); + _release_fn(device.bus, device.dev); + } }); }); update_devices_rom(); @@ -1298,8 +1327,11 @@ bool Session_component::acquired(genode_usb_device const &dev) return false; bool ret = false; - _device_sessions.for_each([&] (Device_component & dc) { - if (dc._device_label == dev.label()) ret = dc.connected(); }); + _device_sessions.apply( + [&] (Device_component & dc) { + return dc._device_label == dev.label(); }, + [&] (Device_component & dc) { + ret = dc.connected(); }); return ret; } @@ -1309,10 +1341,11 @@ bool Session_component::request(genode_usb_device const &dev, void *opaque_data) { bool ret = false; - _device_sessions.for_each([&] (Device_component & dc) { - if (dc._device_label == dev.label()) - if (dc.request(callback, opaque_data)) ret = true; - }); + _device_sessions.apply( + [&] (Device_component & dc) { + return dc._device_label == dev.label(); }, + [&] (Device_component & dc) { + if (dc.request(callback, opaque_data)) ret = true; }); return ret; } @@ -1323,8 +1356,10 @@ Session_component::handle_response(genode_usb_request_handle_t handle, uint32_t *actual_sizes) { bool handled = false; - _device_sessions.for_each([&] (Device_component & dc) { - if (!handled) handled = dc.handle_response(handle, v, actual_sizes); }); + _device_sessions.apply( + [&] (Device_component & dc) { + return dc.handle_response(handle, v, actual_sizes); }, + [&] (Device_component &) { handled = true; }); return handled; } @@ -1341,23 +1376,27 @@ Device_capability Session_component::acquire_device(Device_name const &name) Device_capability cap; bool found = false; - _devices.for_each([&] (genode_usb_device & device) { - if (device.label() != name || !_matches(device)) - return; + _devices.apply( + [&] (genode_usb_device & device) { + return device.label() == name && _matches(device); }, - found = true; - _sessions.for_each([&] (Session_component &sc) { - if (sc.acquired(device)) found = false; }); + [&] (genode_usb_device & device) { + found = true; + _sessions.apply( + [&] (Session_component &sc) { + return sc.acquired(device); }, + [&] (Session_component &) { + found = false; }); - if (!found) { - warning("USB device ", name, - "already acquired by another session"); - } + if (!found) { + warning("USB device ", name, + "already acquired by another session"); + } - cap = _acquire(device.label(), true); - _sessions.for_each([&] (Session_component &sc) { - if (sc._matches(device)) sc.update_devices_rom(); }); - _root.report(); + cap = _acquire(device.label(), true); + _sessions.for_each([&] (Session_component &sc) { + if (sc._matches(device)) sc.update_devices_rom(); }); + _root.report(); }); if (!found) @@ -1371,21 +1410,25 @@ Device_capability Session_component::acquire_device(Device_name const &name) Device_capability Session_component::acquire_single_device() { Device_capability cap; - _devices.for_each([&] (genode_usb_device & device) { - if (cap.valid() || !_matches(device)) - return; + _devices.apply( + [&] (genode_usb_device & device) { + return !cap.valid() && _matches(device); }, + [&] (genode_usb_device & device) { - bool acquired = false; - _sessions.for_each([&] (Session_component &sc) { - if (sc.acquired(device)) acquired = true; }); + bool acquired = false; + _sessions.apply( + [&] (Session_component &sc) { + return sc.acquired(device); }, + [&] (Session_component &) { + acquired = true; }); - if (acquired) - return; + if (acquired) + return; - cap = _acquire(device.label(), true); - _sessions.for_each([&] (Session_component &sc) { - if (sc._matches(device)) sc.update_devices_rom(); }); - _root.report(); + cap = _acquire(device.label(), true); + _sessions.for_each([&] (Session_component &sc) { + if (sc._matches(device)) sc.update_devices_rom(); }); + _root.report(); }); return cap; } @@ -1396,8 +1439,10 @@ void Session_component::release_device(Device_capability cap) if (!cap.valid()) return; - _device_sessions.for_each([&] (Device_component & dc) { - if (cap.local_name() == dc.cap().local_name()) + _device_sessions.apply( + [&] (Device_component & dc) { + return cap.local_name() == dc.cap().local_name(); }, + [&] (Device_component & dc) { _release(dc); }); } @@ -1409,8 +1454,10 @@ void Session_component::produce_xml(Xml_generator &xml) return; bool acquired_by_other_session = false; - _sessions.for_each([&] (Session_component &sc) { - if (sc.acquired(device) && &sc != this) + _sessions.apply( + [&] (Session_component &sc) { + return sc.acquired(device) && &sc != this; }, + [&] (Session_component &) { acquired_by_other_session = true; }); if (acquired_by_other_session) @@ -1458,8 +1505,10 @@ Session_component::~Session_component() { _state = IN_DESTRUCTION; _device_sessions.for_each([&] (Device_component & dc) { - _devices.for_each([&] (genode_usb_device & device) { - if (device.label() == dc._device_label) + _devices.apply( + [&] (genode_usb_device & device) { + return device.label() == dc._device_label; }, + [&] (genode_usb_device & device) { _release_fn(device.bus, device.dev); }); _release(dc); @@ -1472,18 +1521,13 @@ Session_component * ::Root::_create_session(const char * args, { Session_component * sc = nullptr; try { - Session_label const label { session_label_from_args(args) }; - Session_policy const policy { label, _config.xml() }; + Session_label const label { session_label_from_args(args) }; sc = new (md_alloc()) Session_component(_env, *this, _sessions, _devices, _config, _sigh_cap, _alloc_fn, _free_fn, _release_fn, label, session_resources_from_args(args), session_diag_from_args(args)); - } catch (Session_policy::No_policy_defined) { - error("Invalid session request, no matching policy for ", - "'", label_from_args(args).string(), "'"); - throw Service_denied(); } catch (...) { if (sc) { Genode::destroy(md_alloc(), sc); } throw; @@ -1507,8 +1551,11 @@ void ::Root::report() _device_reporter->generate([&] (Reporter::Xml_generator &xml) { _devices.for_each([&] (genode_usb_device & d) { bool acquired = false; - _sessions.for_each([&] (Session_component &sc) { - if (sc.acquired(d)) acquired = true; }); + _sessions.apply( + [&] (Session_component &sc) { + return sc.acquired(d); }, + [&] (Session_component &) { + acquired = true; }); d.generate(xml, acquired); }); }); @@ -1627,23 +1674,23 @@ void ::Root::announce_device(genode_usb_bus_num_t bus, void ::Root::discontinue_device(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev) { - _devices.for_each([&] (genode_usb_device & device) - { - if (device.bus != bus || device.dev != dev) - return; + _devices.apply( + [&] (genode_usb_device & device) { + return device.bus == bus && device.dev == dev; }, - _sessions.for_each([&] (Session_component & sc) { - sc.discontinue_device(device); }); + [&] (genode_usb_device & device) { + _sessions.for_each([&] (Session_component & sc) { + sc.discontinue_device(device); }); - device.configs.for_each([&] (genode_usb_configuration & cfg) { - cfg.interfaces.for_each([&] (genode_usb_interface & iface) { - iface.endpoints.for_each([&] (genode_usb_endpoint & endp) { - Genode::destroy(_heap, &endp); }); - Genode::destroy(_heap, &iface); + device.configs.for_each([&] (genode_usb_configuration & cfg) { + cfg.interfaces.for_each([&] (genode_usb_interface & iface) { + iface.endpoints.for_each([&] (genode_usb_endpoint & endp) { + Genode::destroy(_heap, &endp); }); + Genode::destroy(_heap, &iface); + }); + Genode::destroy(_heap, &cfg); }); - Genode::destroy(_heap, &cfg); - }); - Genode::destroy(_heap, &device); + Genode::destroy(_heap, &device); }); report(); } @@ -1652,10 +1699,15 @@ void ::Root::discontinue_device(genode_usb_bus_num_t bus, bool ::Root::acquired(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev) { bool ret = false; - _devices.for_each([&] (genode_usb_device & device) { - if (device.bus == bus && device.dev == dev) - _sessions.for_each([&] (Session_component & sc) { - if (sc.acquired(device)) ret = true; }); + _devices.apply( + [&] (genode_usb_device & device) { + return device.bus == bus && device.dev == dev; }, + [&] (genode_usb_device & device) { + _sessions.apply( + [&] (Session_component & sc) { + return sc.acquired(device); }, + [&] (Session_component &) { + ret = true; }); }); return ret; } @@ -1667,13 +1719,15 @@ bool ::Root::request(genode_usb_bus_num_t bus, void *opaque_data) { bool ret = false; - _devices.for_each([&] (genode_usb_device & device) - { - if (device.bus != bus || device.dev != dev) - return; + _devices.apply( + [&] (genode_usb_device & device) { + return device.bus == bus && device.dev == dev; }, - _sessions.for_each([&] (Session_component & sc) { - if (sc.request(device, callback, opaque_data)) ret = true; }); + [&] (genode_usb_device & device) { + _sessions.apply( + [&] (Session_component & sc) { + return sc.request(device, callback, opaque_data); }, + [&] (Session_component &) { ret = true; }); }); return ret; } @@ -1683,10 +1737,10 @@ void ::Root::handle_response(genode_usb_request_handle_t id, genode_usb_request_ret_t ret, uint32_t *actual_sizes) { - bool handled = false; - _sessions.for_each([&] (Session_component & sc) { - if (!handled) handled = sc.handle_response(id, ret, actual_sizes); - }); + _sessions.apply( + [&] (Session_component & sc) { + return sc.handle_response(id, ret, actual_sizes); }, + [&] (Session_component &) { }); } diff --git a/repos/os/src/lib/sandbox/server.cc b/repos/os/src/lib/sandbox/server.cc index c8e7a36136..c557d237be 100644 --- a/repos/os/src/lib/sandbox/server.cc +++ b/repos/os/src/lib/sandbox/server.cc @@ -316,11 +316,12 @@ void Sandbox::Server::_handle_upgrade_session_request(Xml_node request, { _client_id_space.apply<Session_state>(id, [&] (Session_state &session) { + if (session.phase == Session_state::UPGRADE_REQUESTED) + return; + Ram_quota const ram_quota { request.attribute_value("ram_quota", 0UL) }; Cap_quota const cap_quota { request.attribute_value("cap_quota", 0UL) }; - session.phase = Session_state::UPGRADE_REQUESTED; - try { Ram_transfer::Remote_account env_ram_account(_env.pd(), _env.pd_session_cap()); Cap_transfer::Remote_account env_cap_account(_env.pd(), _env.pd_session_cap()); @@ -338,6 +339,7 @@ void Sandbox::Server::_handle_upgrade_session_request(Xml_node request, return; } + session.phase = Session_state::UPGRADE_REQUESTED; session.increase_donated_quota(ram_quota, cap_quota); session.service().initiate_request(session); session.service().wakeup(); diff --git a/repos/os/src/lib/vfs/capture/plugin.cc b/repos/os/src/lib/vfs/capture/plugin.cc index f4bb061438..abe27cf2bd 100644 --- a/repos/os/src/lib/vfs/capture/plugin.cc +++ b/repos/os/src/lib/vfs/capture/plugin.cc @@ -121,7 +121,7 @@ class Vfs_capture::Data_file_system : public Single_file_system } catch (Genode::Service_denied) { return OPEN_ERR_UNACCESSIBLE; } - _capture->buffer(_capture_area); + _capture->buffer({ .px = _capture_area, .mm = { } }); _capture_ds.construct(_env.rm(), _capture->dataspace()); } diff --git a/repos/os/src/server/black_hole/capture.h b/repos/os/src/server/black_hole/capture.h index 601c9f6333..7e8e7e5b92 100644 --- a/repos/os/src/server/black_hole/capture.h +++ b/repos/os/src/server/black_hole/capture.h @@ -67,14 +67,21 @@ class Capture::Session_component : public Session_object<Capture::Session> void screen_size_sigh(Signal_context_capability) override { } - void buffer(Area size) override + void wakeup_sigh(Signal_context_capability) override { } + + Buffer_result buffer(Buffer_attr attr) override { - if (size.count() == 0) { + if (attr.px.count() == 0) { _buffer.destruct(); - return; + return Buffer_result::OK; } - _buffer.construct(_ram, _env.rm(), buffer_bytes(size)); + try { + _buffer.construct(_ram, _env.rm(), buffer_bytes(attr.px)); + } + catch (Out_of_ram) { return Buffer_result::OUT_OF_RAM; } + catch (Out_of_caps) { return Buffer_result::OUT_OF_CAPS; } + return Buffer_result::OK; } Dataspace_capability dataspace() override @@ -89,6 +96,8 @@ class Capture::Session_component : public Session_object<Capture::Session> { return Affected_rects(); } + + void capture_stopped() override { } }; diff --git a/repos/os/src/server/gui_fb/main.cc b/repos/os/src/server/gui_fb/main.cc index db02a179cb..6f0565f66e 100644 --- a/repos/os/src/server/gui_fb/main.cc +++ b/repos/os/src/server/gui_fb/main.cc @@ -20,18 +20,18 @@ #include <base/attached_rom_dataspace.h> #include <base/component.h> -namespace Nit_fb { +namespace Gui_fb { + using namespace Genode; + + struct View_updater; struct Main; - using Genode::Static_root; - using Genode::Signal_handler; - using Genode::Xml_node; - using Genode::size_t; + using Point = Gui::Point; + using Area = Gui::Area; + using Rect = Gui::Rect; - using Point = Genode::Surface_base::Point; - using Area = Genode::Surface_base::Area; - using Rect = Genode::Surface_base::Rect; + static ::Input::Event translate_event(::Input::Event, Point, Area); } @@ -42,16 +42,14 @@ namespace Nit_fb { /** * Translate input event */ -static Input::Event translate_event(Input::Event ev, - Nit_fb::Point const input_origin, - Nit_fb::Area const boundary) +static Input::Event Gui_fb::translate_event(Input::Event ev, + Point const input_origin, + Area const boundary) { - using Nit_fb::Point; - /* function to clamp point to bounday */ auto clamp = [boundary] (Point p) { - return Point(Genode::min((int)boundary.w - 1, Genode::max(0, p.x)), - Genode::min((int)boundary.h - 1, Genode::max(0, p.y))); }; + return Point(min((int)boundary.w - 1, max(0, p.x)), + min((int)boundary.h - 1, max(0, p.y))); }; /* function to translate point to 'input_origin' */ auto translate = [input_origin] (Point p) { return p - input_origin; }; @@ -70,7 +68,7 @@ static Input::Event translate_event(Input::Event ev, } -struct View_updater : Genode::Interface +struct Gui_fb::View_updater : Genode::Interface { virtual void update_view() = 0; }; @@ -80,18 +78,23 @@ struct View_updater : Genode::Interface ** Virtualized framebuffer ** *****************************/ -namespace Framebuffer { struct Session_component; } +namespace Framebuffer { + + using namespace Gui_fb; + + struct Session_component; +} struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> { - Genode::Pd_session const &_pd; + Pd_session const &_pd; Gui::Connection &_gui; - Genode::Signal_context_capability _mode_sigh { }; + Signal_context_capability _mode_sigh { }; - Genode::Signal_context_capability _sync_sigh { }; + Signal_context_capability _sync_sigh { }; View_updater &_view_updater; @@ -101,7 +104,7 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> */ Framebuffer::Mode _next_mode; - using size_t = Genode::size_t; + bool _mode_sigh_pending = false; /* * Number of bytes used for backing the current virtual framebuffer at @@ -123,18 +126,25 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> { /* calculation in bytes */ size_t const used = _buffer_num_bytes, - needed = Gui::Session::ram_quota(mode, false), + needed = Gui::Session::ram_quota(mode), usable = _pd.avail_ram().value, preserved = 64*1024; return used + usable > needed + preserved; } + void _update_view() + { + if (_dataspace_is_new) { + _view_updater.update_view(); + _dataspace_is_new = false; + } + } /** * Constructor */ - Session_component(Genode::Pd_session const &pd, + Session_component(Pd_session const &pd, Gui::Connection &gui, View_updater &view_updater, Framebuffer::Mode initial_mode) @@ -149,17 +159,19 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> if (Gui::Area(_next_mode.area.w, _next_mode.area.h) == size) return; - Framebuffer::Mode const mode { .area = size }; + Framebuffer::Mode const mode { .area = size, .alpha = false }; if (!_ram_suffices_for_mode(mode)) { - Genode::warning("insufficient RAM for mode ", mode); + warning("insufficient RAM for mode ", mode); return; } _next_mode = mode; if (_mode_sigh.valid()) - Genode::Signal_transmitter(_mode_sigh).submit(); + Signal_transmitter(_mode_sigh).submit(); + else + _mode_sigh_pending = true; } Gui::Area size() const @@ -172,13 +184,12 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> ** Framebuffer::Session interface ** ************************************/ - Genode::Dataspace_capability dataspace() override + Dataspace_capability dataspace() override { - _gui.buffer(_active_mode, false); + _gui.buffer(_active_mode); _buffer_num_bytes = - Genode::max(_buffer_num_bytes, - Gui::Session::ram_quota(_active_mode, false)); + max(_buffer_num_bytes, Gui::Session::ram_quota(_active_mode)); /* * We defer the update of the view until the client calls refresh the @@ -196,22 +207,36 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> return _active_mode; } - void mode_sigh(Genode::Signal_context_capability sigh) override + void mode_sigh(Signal_context_capability sigh) override { _mode_sigh = sigh; - } - void refresh(int x, int y, int w, int h) override - { - if (_dataspace_is_new) { - _view_updater.update_view(); - _dataspace_is_new = false; + /* notify mode change that happened just before 'mode_sigh' */ + if (_mode_sigh.valid() && _mode_sigh_pending) { + Signal_transmitter(_mode_sigh).submit(); + _mode_sigh_pending = false; } - - _gui.framebuffer.refresh(x, y, w, h); } - void sync_sigh(Genode::Signal_context_capability sigh) override + void refresh(Rect rect) override + { + _update_view(); + _gui.framebuffer.refresh(rect); + } + + Blit_result blit(Blit_batch const &batch) override + { + _update_view(); + return _gui.framebuffer.blit(batch); + } + + void panning(Point pos) override + { + _update_view(); + _gui.framebuffer.panning(pos); + } + + void sync_sigh(Signal_context_capability sigh) override { /* * Keep a component-local copy of the signal capability. Otherwise, @@ -223,6 +248,8 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> _gui.framebuffer.sync_sigh(sigh); } + + void sync_source(Session_label const &) override { } }; @@ -230,21 +257,30 @@ struct Framebuffer::Session_component : Genode::Rpc_object<Framebuffer::Session> ** Main program ** ******************/ -struct Nit_fb::Main : View_updater +struct Gui_fb::Main : View_updater, Input::Session_component::Action { - Genode::Env &env; + Env &_env; - Genode::Attached_rom_dataspace config_rom { env, "config" }; + Attached_rom_dataspace _config_rom { _env, "config" }; - Gui::Connection gui { env }; + Gui::Connection _gui { _env }; - Point position { 0, 0 }; + Point _position { 0, 0 }; - unsigned refresh_rate = 0; + unsigned _refresh_rate = 0; - Gui::Top_level_view const view { gui }; + Gui::Top_level_view const _view { _gui }; - Genode::Attached_dataspace input_ds { env.rm(), gui.input.dataspace() }; + Attached_dataspace _input_ds { _env.rm(), _gui.input.dataspace() }; + + Gui::Rect _gui_window() + { + return _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return _gui.panorama().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 1, 1 } }; }); }); + } struct Initial_size { @@ -253,47 +289,95 @@ struct Nit_fb::Main : View_updater bool set { false }; - Initial_size(Genode::Xml_node config) + Initial_size(Xml_node config) : _width (config.attribute_value("initial_width", 0L)), _height(config.attribute_value("initial_height", 0L)) { } - unsigned width(Framebuffer::Mode const &mode) const + unsigned width(Gui::Area const &gui_area) const { if (_width > 0) return (unsigned)_width; - if (_width < 0) return (unsigned)(mode.area.w + _width); - return mode.area.w; + if (_width < 0) return (unsigned)(gui_area.w + _width); + return gui_area.w; } - unsigned height(Framebuffer::Mode const &mode) const + unsigned height(Gui::Area const &gui_area) const { if (_height > 0) return (unsigned)_height; - if (_height < 0) return (unsigned)(mode.area.h + _height); - return mode.area.h; + if (_height < 0) return (unsigned)(gui_area.h + _height); + return gui_area.h; } bool valid() const { return _width != 0 && _height != 0; } - } _initial_size { config_rom.xml() }; + } _initial_size { _config_rom.xml() }; Framebuffer::Mode _initial_mode() { - return Framebuffer::Mode { .area = { _initial_size.width (gui.mode()), - _initial_size.height(gui.mode()) } }; + Gui::Area const gui_area = _gui_window().area; + return { + .area = { _initial_size.width (gui_area), + _initial_size.height(gui_area) }, + .alpha = false + }; } /* * Input and framebuffer sessions provided to our client */ - Input::Session_component input_session { env, env.ram() }; - Framebuffer::Session_component fb_session { env.pd(), gui, *this, _initial_mode() }; + Input::Session_component _input_session { _env.ep(), _env.ram(), _env.rm(), *this }; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool enabled) override + { + _gui.input.exclusive(enabled); + } + + Framebuffer::Session_component _fb_session { _env.pd(), _gui, *this, _initial_mode() }; + + struct Input_root : Static_root<Input::Session> + { + Main &_main; + + Input_root(Main &main) + : + Static_root<Input::Session>(main._input_session.cap()), + _main(main) + { } + + void close(Capability<Session>) override + { + _main._input_session.sigh(Signal_context_capability()); + } + }; + + Input_root _input_root { *this }; /* * Attach root interfaces to the entry point */ - Static_root<Input::Session> input_root { env.ep().manage(input_session) }; - Static_root<Framebuffer::Session> fb_root { env.ep().manage(fb_session) }; + + struct Fb_root : Static_root<Framebuffer::Session> + { + Main &_main; + + Fb_root(Main &main) + : + Static_root<Framebuffer::Session>(main._env.ep().manage(main._fb_session)), + _main(main) + { } + + void close(Capability<Session>) override + { + _main._fb_session.sync_sigh(Signal_context_capability()); + _main._fb_session.mode_sigh(Signal_context_capability()); + } + }; + + Fb_root _fb_root { *this }; /** * View_updater interface @@ -301,28 +385,28 @@ struct Nit_fb::Main : View_updater void update_view() override { using Command = Gui::Session::Command; - gui.enqueue<Command::Geometry>(view.id(), Rect(position, fb_session.size())); - gui.enqueue<Command::Front>(view.id()); - gui.execute(); + _gui.enqueue<Command::Geometry>(_view.id(), Rect(_position, _fb_session.size())); + _gui.enqueue<Command::Front>(_view.id()); + _gui.execute(); } /** * Return screen-coordinate origin, depening on the config and screen mode */ - static Point _coordinate_origin(Framebuffer::Mode mode, Xml_node config) + static Point _coordinate_origin(Gui::Area gui_area, Xml_node config) { char const * const attr = "origin"; if (!config.has_attribute(attr)) return Point(0, 0); - using Value = Genode::String<32>; + using Value = String<32>; Value const value = config.attribute_value(attr, Value()); if (value == "top_left") return Point(0, 0); - if (value == "top_right") return Point(mode.area.w, 0); - if (value == "bottom_left") return Point(0, mode.area.h); - if (value == "bottom_right") return Point(mode.area.w, mode.area.h); + if (value == "top_right") return Point(gui_area.w, 0); + if (value == "bottom_left") return Point(0, gui_area.h); + if (value == "bottom_right") return Point(gui_area.w, gui_area.h); warning("unsupported ", attr, " attribute value '", value, "'"); return Point(0, 0); @@ -330,30 +414,27 @@ struct Nit_fb::Main : View_updater void _update_size() { - Xml_node const config = config_rom.xml(); + Xml_node const config = _config_rom.xml(); - Framebuffer::Mode const gui_mode = gui.mode(); + Gui::Area const gui_area = _gui_window().area; - position = _coordinate_origin(gui_mode, config) + Point::from_xml(config); + _position = _coordinate_origin(gui_area, config) + Point::from_xml(config); bool const attr = config.has_attribute("width") || config.has_attribute("height"); if (_initial_size.valid() && attr) { - Genode::warning("setting both inital and normal attributes not " - " supported, ignore initial size"); + warning("setting both inital and normal attributes not " + " supported, ignore initial size"); /* force initial to disable check below */ _initial_size.set = true; } - unsigned const gui_width = gui_mode.area.w; - unsigned const gui_height = gui_mode.area.h; - - long width = config.attribute_value("width", (long)gui_mode.area.w), - height = config.attribute_value("height", (long)gui_mode.area.h); + long width = config.attribute_value("width", long(gui_area.w)), + height = config.attribute_value("height", long(gui_area.h)); if (!_initial_size.set && _initial_size.valid()) { - width = _initial_size.width (gui_mode); - height = _initial_size.height(gui_mode); + width = _initial_size.width (gui_area); + height = _initial_size.height(gui_area); _initial_size.set = true; } else { @@ -362,43 +443,40 @@ struct Nit_fb::Main : View_updater * If configured width / height values are negative, the effective * width / height is deduced from the screen size. */ - if (width < 0) width = gui_width + width; - if (height < 0) height = gui_height + height; + if (width < 0) width = gui_area.w + width; + if (height < 0) height = gui_area.h + height; } - fb_session.size(Area((unsigned)width, (unsigned)height)); + _fb_session.size(Area((unsigned)width, (unsigned)height)); } - void handle_config_update() + void _handle_config_update() { - config_rom.update(); + _config_rom.update(); _update_size(); update_view(); } - Signal_handler<Main> config_update_handler = - { env.ep(), *this, &Main::handle_config_update }; + Signal_handler<Main> _config_update_handler = + { _env.ep(), *this, &Main::_handle_config_update }; - void handle_mode_update() + void _handle_mode_update() { _update_size(); } + + Signal_handler<Main> _mode_update_handler = + { _env.ep(), *this, &Main::_handle_mode_update }; + + void _handle_input() { - _update_size(); - } + Input::Event const * const events = _input_ds.local_addr<Input::Event>(); - Signal_handler<Main> mode_update_handler = - { env.ep(), *this, &Main::handle_mode_update }; - - void handle_input() - { - Input::Event const * const events = input_ds.local_addr<Input::Event>(); - - unsigned const num = gui.input.flush(); + unsigned const num = _gui.input.flush(); bool update = false; for (unsigned i = 0; i < num; i++) { update |= events[i].focus_enter(); - input_session.submit(translate_event(events[i], position, fb_session.size())); + _input_session.submit(translate_event(events[i], _position, _fb_session.size())); } /* get to front if we got input focus */ @@ -406,36 +484,35 @@ struct Nit_fb::Main : View_updater update_view(); } - Signal_handler<Main> input_handler = - { env.ep(), *this, &Main::handle_input }; + Signal_handler<Main> _input_handler { _env.ep(), *this, &Main::_handle_input }; /** * Constructor */ - Main(Genode::Env &env) : env(env) + Main(Env &env) : _env(env) { - input_session.event_queue().enabled(true); + _input_session.event_queue().enabled(true); /* * Announce services */ - env.parent().announce(env.ep().manage(fb_root)); - env.parent().announce(env.ep().manage(input_root)); + _env.parent().announce(_env.ep().manage(_fb_root)); + _env.parent().announce(_env.ep().manage(_input_root)); /* * Apply initial configuration */ - handle_config_update(); + _handle_config_update(); /* * Register signal handlers */ - config_rom.sigh(config_update_handler); - gui.mode_sigh(mode_update_handler); - gui.input.sigh(input_handler); + _config_rom.sigh(_config_update_handler); + _gui.info_sigh(_mode_update_handler); + _gui.input.sigh(_input_handler); } }; -void Component::construct(Genode::Env &env) { static Nit_fb::Main inst(env); } +void Component::construct(Genode::Env &env) { static Gui_fb::Main inst(env); } diff --git a/repos/os/src/server/nic_router/domain.h b/repos/os/src/server/nic_router/domain.h index 1067d6c9e9..7bc4be1baa 100644 --- a/repos/os/src/server/nic_router/domain.h +++ b/repos/os/src/server/nic_router/domain.h @@ -232,7 +232,7 @@ class Net::Domain : public List<Domain>::Element, dhcp_server_fn(*_dhcp_server_ptr); } - void with_dhcp_server(auto const &fn) { with_dhcp_server(fn, []{}); } + void with_optional_dhcp_server(auto const &fn) { with_dhcp_server(fn, []{}); } /********* ** log ** diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index ce58bc84f3..7247865402 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -1734,7 +1734,7 @@ void Interface::_continue_handle_eth(Packet_descriptor const &pkt) void Interface::_destroy_dhcp_allocation(Dhcp_allocation &allocation, Domain &local_domain) { - local_domain.with_dhcp_server([&] (Dhcp_server &srv) { + local_domain.with_optional_dhcp_server([&] (Dhcp_server &srv) { srv.free_ip(allocation.ip()); }); destroy(_alloc, &allocation); } @@ -2035,6 +2035,18 @@ void Interface::_update_dhcp_allocations(Domain &old_domain, Domain &new_domain) { bool dhcp_clients_outdated { false }; + + auto dismiss_all_fn = [&] () { + dhcp_clients_outdated = true; + while (Dhcp_allocation *allocation = _dhcp_allocations.first()) { + if (_config_ptr->verbose()) + log("[", new_domain, "] dismiss DHCP allocation: ", + *allocation, " (other/no DHCP server)"); + _dhcp_allocations.remove(*allocation); + _destroy_dhcp_allocation(*allocation, old_domain); + } + }; + old_domain.with_dhcp_server([&] (Dhcp_server &old_dhcp_srv) { new_domain.with_dhcp_server([&] (Dhcp_server &new_dhcp_srv) { if (old_dhcp_srv.config_equal_to_that_of(new_dhcp_srv)) { @@ -2054,18 +2066,16 @@ void Interface::_update_dhcp_allocations(Domain &old_domain, }); } else { /* dismiss all DHCP allocations */ - dhcp_clients_outdated = true; - while (Dhcp_allocation *allocation = _dhcp_allocations.first()) { - if (_config_ptr->verbose()) - log("[", new_domain, "] dismiss DHCP allocation: ", - *allocation, " (other/no DHCP server)"); - _dhcp_allocations.remove(*allocation); - _destroy_dhcp_allocation(*allocation, old_domain); - } + dismiss_all_fn(); } - if (dhcp_clients_outdated) - _reset_and_refetch_domain_ready_state(); - });}); + }, + /* no DHCP server on new domain */ + [&] () { dismiss_all_fn(); }); }, + /* no DHCP server on old domain */ + [&] () { dismiss_all_fn(); }); + + if (dhcp_clients_outdated) + _reset_and_refetch_domain_ready_state(); } diff --git a/repos/os/src/server/nitpicker/README b/repos/os/src/server/nitpicker/README index d9cb871626..9d40acf086 100644 --- a/repos/os/src/server/nitpicker/README +++ b/repos/os/src/server/nitpicker/README @@ -242,6 +242,49 @@ The 'keystate' attribute enables the reporting of the currently pressed keys. The 'clicked' attribute enables the reporting of the last clicked-on unfocused client. This report is useful for a focus-managing component to implement a focus-on-click policy. +The 'panorama' attribute enables the reporting of the panorama of displays +described below. + + +Multi-monitor support +~~~~~~~~~~~~~~~~~~~~~ + +Display drivers obtain pixel data from the nitpicker GUI server using +nitpicker's capture service. For each connected monitor, the driver creates a +distinct capture session labeled after the name of the connector. Therefore, +from nitpicker's perspective, each monitor corresponds to one capture client. +Each capture client can have a different size, which corresponds to the +respective display resolution. Together, all capture clients span a panorama, +which is the bounding box of all capture clients. Each capture client shows a +part of the panorama. + +By default, when configuring nitpicker with an empty '<capture/>' node, the +top-left corner of each capture client corresponds to the coordinate origin +(0, 0) of the panorama. Hence, each client obtains a mirror of the panorama. +This default policy can be overridden by explicit rules as follows: + +! <capture> +! <policy label="intel_fb -> eDP-1" width_mm="160" height_mm="90" /> +! <policy label="intel_fb -> HDMI-A-1" xpos="1024" ypos="0" +! width="1280" height="800"/> +! <default-policy/> +! </capture> + +The policy for the 'eDP-1' connector merely overrides the physical dimensions +of the display as reported by the driver. This is useful in situations where +the display's EDID information are incorrect. Apart from that tweak, the +client obtains the default part of the panorama at the coordinate origin. + +The policy for the HDMI-A-1 connector dictates an explicit placement within +the panorama. So a data projector connected via HDMI shows a mere window of +the panorama where the top-left corner corresponds to the panorama position +(1024, 0). The client won't observe any pixels outside the specified window. +It is possible to specify only a subset of attributes. E.g., by only +specifying the 'xpos', the width and height remain unconstrained. + +The default policy tells nitpicker to regard any other capture client as a +mirror of the panorama's coordinate origin. If absent, a client with no +policy, won't obtain any picture. Cascaded usage scenarios diff --git a/repos/os/src/server/nitpicker/buffer.h b/repos/os/src/server/nitpicker/buffer.h index e6c0d4bf33..e00f976a78 100644 --- a/repos/os/src/server/nitpicker/buffer.h +++ b/repos/os/src/server/nitpicker/buffer.h @@ -25,33 +25,22 @@ namespace Nitpicker { class Buffer; } -class Nitpicker::Buffer +struct Nitpicker::Buffer : private Attached_ram_dataspace { - private: + /** + * Constructor - allocate and map dataspace for virtual frame buffer + * + * \throw Out_of_ram + * \throw Out_of_caps + * \throw Region_map::Region_conflict + */ + Buffer(Ram_allocator &ram, Region_map &rm, size_t num_bytes) + : + Attached_ram_dataspace(ram, rm, num_bytes) + { } - Area _size; - Attached_ram_dataspace _ram_ds; - - public: - - /** - * Constructor - allocate and map dataspace for virtual frame buffer - * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Region_map::Region_conflict - */ - Buffer(Ram_allocator &ram, Region_map &rm, Area size, size_t bytes) - : - _size(size), _ram_ds(ram, rm, bytes) - { } - - /** - * Accessors - */ - Ram_dataspace_capability ds_cap() const { return _ram_ds.cap(); } - Area size() const { return _size; } - void *local_addr() const { return _ram_ds.local_addr<void>(); } + using Attached_ram_dataspace::bytes; + using Attached_ram_dataspace::cap; }; @@ -61,11 +50,15 @@ namespace Nitpicker { struct Buffer_provider; } /** * Interface for triggering the re-allocation of a virtual framebuffer * - * Used by 'Framebuffer::Session_component', * implemented by 'Gui_session' + * Used by 'Framebuffer::Session_component', implemented by 'Gui_session' */ struct Nitpicker::Buffer_provider : Interface { - virtual Dataspace_capability realloc_buffer(Framebuffer::Mode mode, bool use_alpha) = 0; + virtual Dataspace_capability realloc_buffer(Framebuffer::Mode) = 0; + + virtual void blit(Rect from, Point to) = 0; + + virtual void panning(Point) = 0; }; #endif /* _BUFFER_H_ */ diff --git a/repos/os/src/server/nitpicker/capture_session.h b/repos/os/src/server/nitpicker/capture_session.h index 66490249c6..b591506358 100644 --- a/repos/os/src/server/nitpicker/capture_session.h +++ b/repos/os/src/server/nitpicker/capture_session.h @@ -32,6 +32,58 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> * present capture buffers. */ virtual void capture_buffer_size_changed() = 0; + + virtual void capture_requested(Label const &) = 0; + }; + + struct Policy + { + template <typename T> + struct Attr + { + bool _defined { }; + T _value { }; + + Attr() { } + + Attr(T value) : _defined(true), _value(value) { } + + Attr(Xml_node const node, auto const &attr) + { + if (node.has_attribute(attr)) { + _value = node.attribute_value(attr, T { }); + _defined = true; + } + } + + /** + * Return defined attribute value, or default value + */ + T or_default(T def) const { return _defined ? _value : def; } + }; + + Attr<int> x, y; /* placement within panorama */ + Attr<unsigned> w, h; /* capture contraints */ + Attr<unsigned> w_mm, h_mm; /* physical size overrides */ + + static Policy from_xml(Xml_node const &policy) + { + return { .x = { policy, "xpos" }, + .y = { policy, "ypos" }, + .w = { policy, "width" }, + .h = { policy, "height" }, + .w_mm = { policy, "width_mm" }, + .h_mm = { policy, "height_mm" } }; + } + + static Policy unconstrained() { return { }; } + + static Policy blocked() + { + Policy result { }; + result.w = 0, result.h = 0; + return result; + } }; private: @@ -44,16 +96,44 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> View_stack const &_view_stack; - Area _buffer_size { }; + Policy _policy = Policy::blocked(); + + bool _policy_changed = false; + + Buffer_attr _buffer_attr { }; Constructible<Attached_ram_dataspace> _buffer { }; Signal_context_capability _screen_size_sigh { }; + Signal_context_capability _wakeup_sigh { }; + + bool _stopped = false; + using Dirty_rect = Genode::Dirty_rect<Rect, Affected_rects::NUM_RECTS>; Dirty_rect _dirty_rect { }; + void _wakeup_if_needed() + { + if (_stopped && !_dirty_rect.empty() && _wakeup_sigh.valid()) { + Signal_transmitter(_wakeup_sigh).submit(); + _stopped = false; + } + } + + Point _anchor_point() const + { + return { .x = _policy.x.or_default(0), + .y = _policy.y.or_default(0) }; + } + + Area _area_bounds() const + { + return { .w = _policy.w.or_default(_buffer_attr.px.w), + .h = _policy.h.or_default(_buffer_attr.px.h) }; + } + public: Capture_session(Env &env, @@ -69,7 +149,7 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> _handler(handler), _view_stack(view_stack) { - _dirty_rect.mark_as_dirty(Rect(Point(0, 0), view_stack.size())); + _dirty_rect.mark_as_dirty(view_stack.bounding_box()); } ~Capture_session() { } @@ -79,48 +159,93 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> ** Interface used by 'Nitpicker::Main' ** *****************************************/ - Area buffer_size() const { return _buffer_size; } + /** + * Geometry within the panorama, depending on policy and client buffer + */ + Rect bounding_box() const { return { _anchor_point(), _area_bounds() }; } void mark_as_damaged(Rect rect) { - _dirty_rect.mark_as_dirty(rect); + _dirty_rect.mark_as_dirty(Rect::intersect(rect, bounding_box())); } + void process_damage() { _wakeup_if_needed(); } + void screen_size_changed() { if (_screen_size_sigh.valid()) Signal_transmitter(_screen_size_sigh).submit(); } + void apply_policy(Policy const &policy) + { + _policy = policy; + _policy_changed = true; + } + + void gen_capture_attr(Xml_generator &xml, Rect const domain_panorama) const + { + xml.attribute("name", label()); + + gen_attr(xml, Rect::intersect(domain_panorama, bounding_box())); + + unsigned const w_mm = _policy.w_mm.or_default(_buffer_attr.mm.w), + h_mm = _policy.h_mm.or_default(_buffer_attr.mm.h); + + if (w_mm) xml.attribute("width_mm", w_mm); + if (h_mm) xml.attribute("height_mm", h_mm); + } + /******************************* ** Capture session interface ** *******************************/ - Area screen_size() const override { return _view_stack.size(); } + Area screen_size() const override + { + Rect const panorama = _view_stack.bounding_box(); + Rect const policy { _anchor_point(), + { .w = _policy.w.or_default(panorama.w()), + .h = _policy.h.or_default(panorama.h()) } }; + + return Rect::intersect(panorama, policy).area; + } void screen_size_sigh(Signal_context_capability sigh) override { _screen_size_sigh = sigh; } - void buffer(Area size) override + void wakeup_sigh(Signal_context_capability sigh) override { - _buffer_size = Area { }; + _wakeup_sigh = sigh; + _wakeup_if_needed(); + } - if (size.count() == 0) { + Buffer_result buffer(Buffer_attr const attr) override + { + Buffer_result result = Buffer_result::OK; + + _buffer_attr = { }; + + if (!attr.px.valid()) { _buffer.destruct(); - return; + return result; } try { - _buffer.construct(_ram, _env.rm(), buffer_bytes(size)); - _buffer_size = size; - _handler.capture_buffer_size_changed(); - } catch (...) { - _handler.capture_buffer_size_changed(); - throw; + _buffer.construct(_ram, _env.rm(), buffer_bytes(attr.px)); + _buffer_attr = attr; } + catch (Out_of_ram) { result = Buffer_result::OUT_OF_RAM; } + catch (Out_of_caps) { result = Buffer_result::OUT_OF_CAPS; } + + _handler.capture_buffer_size_changed(); + + /* report complete buffer as dirty on next call of 'capture_at' */ + mark_as_damaged({ _anchor_point(), attr.px }); + + return result; } Dataspace_capability dataspace() override @@ -131,16 +256,27 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> return Dataspace_capability(); } - Affected_rects capture_at(Point pos) override + Affected_rects capture_at(Point const pos) override { + _handler.capture_requested(label()); + if (!_buffer.constructed()) return Affected_rects { }; - using Pixel = Pixel_rgb888; + Point const anchor = _anchor_point() + pos; - Canvas<Pixel> canvas = { _buffer->local_addr<Pixel>(), pos, _buffer_size }; + Canvas<Pixel_rgb888> canvas { _buffer->local_addr<Pixel_rgb888>(), + anchor, _buffer_attr.px }; - Rect const buffer_rect(Point(0, 0), _buffer_size); + if (_policy_changed) { + canvas.draw_box({ anchor, canvas.size() }, Color::rgb(0, 0, 0)); + _dirty_rect.mark_as_dirty({ anchor, canvas.size() }); + _policy_changed = false; + } + + canvas.clip(Rect::intersect(bounding_box(), _view_stack.bounding_box())); + + Rect const buffer_rect { { }, _buffer_attr.px }; Affected_rects affected { }; unsigned i = 0; @@ -149,7 +285,7 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> _view_stack.draw(canvas, rect); if (i < Affected_rects::NUM_RECTS) { - Rect const translated(rect.p1() - pos, rect.area); + Rect const translated(rect.p1() - anchor, rect.area); Rect const clipped = Rect::intersect(translated, buffer_rect); affected.rects[i++] = clipped; } @@ -157,6 +293,14 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session> return affected; } + + void capture_stopped() override + { + _stopped = true; + + /* dirty pixels may be pending */ + _wakeup_if_needed(); + } }; #endif /* _CAPTURE_SESSION_H_ */ diff --git a/repos/os/src/server/nitpicker/chunky_texture.h b/repos/os/src/server/nitpicker/chunky_texture.h index 6b39d4c274..04427c8a61 100644 --- a/repos/os/src/server/nitpicker/chunky_texture.h +++ b/repos/os/src/server/nitpicker/chunky_texture.h @@ -14,6 +14,9 @@ #ifndef _CHUNKY_TEXTURE_H_ #define _CHUNKY_TEXTURE_H_ +/* Genode includes */ +#include <blit/painter.h> + /* local includes */ #include <buffer.h> @@ -21,53 +24,80 @@ namespace Nitpicker { template <typename> class Chunky_texture; } template <typename PT> -class Nitpicker::Chunky_texture : public Buffer, public Texture<PT> +class Nitpicker::Chunky_texture : Buffer, public Texture<PT> { private: + Framebuffer::Mode const _mode; + /** * Return base address of alpha channel or 0 if no alpha channel exists */ - unsigned char *_alpha_base(Area size, bool use_alpha) + static uint8_t *_alpha_base(Buffer &buffer, Framebuffer::Mode mode) { - if (!use_alpha) return 0; + uint8_t *result = nullptr; + mode.with_alpha_bytes(buffer, [&] (Byte_range_ptr const &bytes) { + result = (uint8_t *)bytes.start; }); + return result; + } - /* alpha values come right after the pixel values */ - return (unsigned char *)local_addr() + calc_num_bytes(size, false); + void _with_alpha_texture(auto const &fn) const + { + Buffer const &buffer = *this; + _mode.with_alpha_bytes(buffer, [&] (Byte_range_ptr const &bytes) { + Texture<Pixel_alpha8> texture { (Pixel_alpha8 *)bytes.start, nullptr, _mode.area }; + fn(texture); }); + } + + void _with_input_texture(auto const &fn) const + { + Buffer const &buffer = *this; + _mode.with_input_bytes(buffer, [&] (Byte_range_ptr const &bytes) { + Texture<Pixel_input8> texture { (Pixel_input8 *)bytes.start, nullptr, _mode.area }; + fn(texture); }); + } + + template <typename T> + void _blit_channel(Surface<T> &surface, Texture<T> const &texture, + Rect const from, Point const to) + { + surface.clip({ to, from.area }); + Blit_painter::paint(surface, texture, to - from.p1()); } public: - /** - * Constructor - */ - Chunky_texture(Ram_allocator &ram, Region_map &rm, Area size, bool use_alpha) - : - Buffer(ram, rm, size, calc_num_bytes(size, use_alpha)), - Texture<PT>((PT *)local_addr(), - _alpha_base(size, use_alpha), size) { } + using Buffer::cap; - static size_t calc_num_bytes(Area size, bool use_alpha) + Chunky_texture(Ram_allocator &ram, Region_map &rm, Framebuffer::Mode mode) + : + Buffer(ram, rm, mode.num_bytes()), + Texture<PT>((PT *)Buffer::bytes().start, _alpha_base(*this, mode), mode.area), + _mode(mode) + { } + + void with_input_mask(auto const &fn) const { - /* - * If using an alpha channel, the alpha buffer follows the - * pixel buffer. The alpha buffer is followed by an input - * mask buffer. Hence, we have to account one byte per - * alpha value and one byte for the input mask value. - */ - size_t bytes_per_pixel = sizeof(PT) + (use_alpha ? 2 : 0); - return bytes_per_pixel*size.count(); + Buffer const &buffer = *this; + _mode.with_input_bytes(buffer, [&] (Byte_range_ptr const &bytes) { + Const_byte_range_ptr const_bytes { bytes.start, bytes.num_bytes }; + fn(const_bytes); }); } - unsigned char const *input_mask_buffer() const + void blit(Rect from, Point to) { - if (!Texture<PT>::alpha()) return 0; + Buffer &buffer = *this; - Area const size = Texture<PT>::size(); + _mode.with_pixel_surface(buffer, [&] (Surface<Pixel_rgb888> &surface) { + _blit_channel(surface, *this, from, to); }); - /* input-mask values come right after the alpha values */ - return (unsigned char const *)local_addr() + calc_num_bytes(size, false) - + size.count(); + _mode.with_alpha_surface(buffer, [&] (Surface<Pixel_alpha8> &surface) { + _with_alpha_texture([&] (Texture<Pixel_alpha8> &texture) { + _blit_channel(surface, texture, from, to); }); }); + + _mode.with_input_surface(buffer, [&] (Surface<Pixel_input8> &surface) { + _with_input_texture([&] (Texture<Pixel_input8> &texture) { + _blit_channel(surface, texture, from, to); }); }); } }; diff --git a/repos/os/src/server/nitpicker/domain_registry.h b/repos/os/src/server/nitpicker/domain_registry.h index 3d20ce40cf..5f68a580a7 100644 --- a/repos/os/src/server/nitpicker/domain_registry.h +++ b/repos/os/src/server/nitpicker/domain_registry.h @@ -64,17 +64,16 @@ class Nitpicker::Domain_registry _origin(origin), _layer(layer), _offset(offset), _area(area) { } - Point _corner(Area const screen_area) const + Point _corner(Rect const rect) const { switch (_origin) { - case Origin::POINTER: return Point(0, 0); - case Origin::TOP_LEFT: return Point(0, 0); - case Origin::TOP_RIGHT: return Point(screen_area.w, 0); - case Origin::BOTTOM_LEFT: return Point(0, screen_area.h); - case Origin::BOTTOM_RIGHT: return Point(screen_area.w, - screen_area.h); + case Origin::POINTER: return { 0, 0 }; + case Origin::TOP_LEFT: return { rect.x1(), rect.y1() }; + case Origin::TOP_RIGHT: return { rect.x2(), rect.y1() }; + case Origin::BOTTOM_LEFT: return { rect.x1(), rect.y2() }; + case Origin::BOTTOM_RIGHT: return { rect.x2(), rect.y2() }; } - return Point(0, 0); + return { 0, 0 }; } public: @@ -95,22 +94,22 @@ class Nitpicker::Domain_registry bool focus_transient() const { return _focus == Focus::TRANSIENT; } bool origin_pointer() const { return _origin == Origin::POINTER; } - Point phys_pos(Point pos, Area screen_area) const + Point phys_pos(Point pos, Rect panorama) const { - return pos + _corner(screen_area) + _offset; + return pos + _corner(panorama) + _offset; } - Area screen_area(Area phys_screen_area) const + Rect screen_rect(Rect const panorama) const { - int const w = _area.x > 0 - ? _area.x - : max(0, (int)phys_screen_area.w + _area.x); + /* align value to zero or to limit, depending on its sign */ + auto aligned = [&] (unsigned limit, int v) + { + return unsigned((v > 0) ? v : max(0, int(limit) + v)); + }; - int const h = _area.y > 0 - ? _area.y - : max(0, (int)phys_screen_area.h + _area.y); - - return Area(w, h); + return { .at = _offset + panorama.at, + .area = { .w = aligned(panorama.w(), _area.x), + .h = aligned(panorama.h(), _area.y) } }; } }; diff --git a/repos/os/src/server/nitpicker/framebuffer_session.h b/repos/os/src/server/nitpicker/framebuffer_session.h index bc6a0e6ec8..72628a13ff 100644 --- a/repos/os/src/server/nitpicker/framebuffer_session.h +++ b/repos/os/src/server/nitpicker/framebuffer_session.h @@ -38,27 +38,33 @@ class Framebuffer::Session_component : public Rpc_object<Session> Session_component(Session_component const &); Session_component &operator = (Session_component const &); + Entrypoint &_ep; View_stack &_view_stack; Nitpicker::Gui_session &_session; Buffer_provider &_buffer_provider; Signal_context_capability _mode_sigh { }; Signal_context_capability _sync_sigh { }; Framebuffer::Mode _mode { }; - bool _alpha = false; public: /** * Constructor */ - Session_component(View_stack &view_stack, + Session_component(Entrypoint &ep, + View_stack &view_stack, Nitpicker::Gui_session &session, Buffer_provider &buffer_provider) : + _ep(ep), _view_stack(view_stack), _session(session), _buffer_provider(buffer_provider) - { } + { + _ep.manage(*this); + } + + ~Session_component() { _ep.dissolve(*this); } /** * Change virtual framebuffer mode @@ -71,10 +77,9 @@ class Framebuffer::Session_component : public Rpc_object<Session> * client calls 'dataspace' the next time, the new mode becomes * effective. */ - void notify_mode_change(Framebuffer::Mode mode, bool alpha) + void notify_mode_change(Framebuffer::Mode mode) { - _mode = mode; - _alpha = alpha; + _mode = mode; if (_mode_sigh.valid()) Signal_transmitter(_mode_sigh).submit(); @@ -93,7 +98,7 @@ class Framebuffer::Session_component : public Rpc_object<Session> Dataspace_capability dataspace() override { - return _buffer_provider.realloc_buffer(_mode, _alpha); + return _buffer_provider.realloc_buffer(_mode); } Mode mode() const override { return _mode; } @@ -108,7 +113,13 @@ class Framebuffer::Session_component : public Rpc_object<Session> _sync_sigh = sigh; } - void refresh(int x, int y, int w, int h) override; + void sync_source(Session_label const &) override { } + + void refresh(Rect) override; + + Blit_result blit(Blit_batch const &) override; + + void panning(Point) override; }; #endif /* _FRAMEBUFFER_SESSION_COMPONENT_H_ */ diff --git a/repos/os/src/server/nitpicker/gui_session.cc b/repos/os/src/server/nitpicker/gui_session.cc index 5b1bd1ce69..6516e1c0bd 100644 --- a/repos/os/src/server/nitpicker/gui_session.cc +++ b/repos/os/src/server/nitpicker/gui_session.cc @@ -64,7 +64,7 @@ void Gui_session::_execute_command(Command const &command) /* transpose position of top-level views by vertical session offset */ if (view.top_level()) - pos = _phys_pos(pos, _view_stack.size()); + pos = _phys_pos(pos, _view_stack.bounding_box()); _view_stack.geometry(view, Rect(pos, args.rect.area)); }); @@ -155,7 +155,10 @@ void Gui_session::_destroy_view(View &view) _view_stack.default_background(_builtin_background); _view_stack.remove_view(view); - _env.ep().dissolve(view); + if (view.cap().valid()) { + _env.ep().dissolve(view); + replenish(Cap_quota { 1 }); + } _view_list.remove(&view); destroy(_view_alloc, &view); } @@ -172,7 +175,7 @@ void Gui_session::submit_input_event(Input::Event e) { using namespace Input; - Point const origin_offset = _phys_pos(Point(0, 0), _view_stack.size()); + Point const origin_offset = _phys_pos({ 0, 0 }, _view_stack.bounding_box()); /* * Transpose absolute coordinates by session-specific vertical offset. @@ -194,7 +197,6 @@ void Gui_session::_adopt_new_view(View &view) view.apply_origin_policy(_pointer_origin); _view_list.insert(&view); - _env.ep().manage(view); } @@ -342,8 +344,17 @@ Gui_session::associate(View_id id, View_capability view_cap) Gui_session::View_capability_result Gui_session::view_capability(View_id id) { return _with_view(id, - [&] (View &view) { return view.cap(); }, - [&] /* view does not exist */ { return View_capability(); }); + [&] (View &view) -> View_capability_result + { + if (!view.cap().valid()) { + if (!try_withdraw(Cap_quota { 1 })) + return View_capability_error::OUT_OF_CAPS; + + _env.ep().manage(view); + } + return view.cap(); + }, + [&] () -> View_capability_result { return View_capability(); }); } @@ -364,30 +375,17 @@ void Gui_session::execute() } -Framebuffer::Mode Gui_session::mode() -{ - Area const screen = screen_area(_view_stack.size()); - - /* - * Return at least a size of 1x1 to spare the clients the need to handle - * the special case of 0x0, which can happen at boot time before the - * framebuffer driver is running. - */ - return { .area = { max(screen.w, 1u), max(screen.h, 1u) } }; -} - - -Gui_session::Buffer_result Gui_session::buffer(Framebuffer::Mode mode, bool use_alpha) +Gui_session::Buffer_result Gui_session::buffer(Framebuffer::Mode mode) { /* check if the session quota suffices for the specified mode */ - if (_buffer_size + _ram_quota_guard().avail().value < ram_quota(mode, use_alpha)) + if (_buffer_size + _ram_quota_guard().avail().value < ram_quota(mode)) return Buffer_result::OUT_OF_RAM; /* buffer re-allocation may consume new dataspace capability if buffer is new */ if (_cap_quota_guard().avail().value < 1) - throw Buffer_result::OUT_OF_CAPS; + return Buffer_result::OUT_OF_CAPS; - _framebuffer_session_component.notify_mode_change(mode, use_alpha); + _framebuffer_session_component.notify_mode_change(mode); return Buffer_result::OK; } @@ -407,9 +405,9 @@ void Gui_session::focus(Capability<Gui::Session> session_cap) } -Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode, bool use_alpha) +Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode) { - Ram_quota const next_buffer_size { Chunky_texture<Pixel>::calc_num_bytes(mode.area, use_alpha) }; + Ram_quota const next_buffer_size { mode.num_bytes() }; Ram_quota const orig_buffer_size { _buffer_size }; /* @@ -428,15 +426,13 @@ Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode, bool us } _buffer_size = 0; - _uses_alpha = false; - _input_mask = nullptr; Ram_quota const temporary_ram_upgrade = _texture.valid() ? next_buffer_size : Ram_quota{0}; _ram_quota_guard().upgrade(temporary_ram_upgrade); - if (!_texture.try_construct_next(_env.ram(), _env.rm(), mode.area, use_alpha)) { + if (!_texture.try_construct_next(_env.ram(), _env.rm(), mode)) { _texture.release_current(); replenish(orig_buffer_size); _ram_quota_guard().try_downgrade(temporary_ram_upgrade); @@ -459,8 +455,16 @@ Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode, bool us } _buffer_size = next_buffer_size.value; - _uses_alpha = use_alpha; - _input_mask = _texture.input_mask_buffer(); return _texture.dataspace(); } + + +void Gui_session::produce_xml(Xml_generator &xml) +{ + Rect const domain_panorama = + _domain ? _domain->screen_rect(_view_stack.bounding_box()) + : Rect { }; + + _action.gen_capture_info(xml, domain_panorama); +} diff --git a/repos/os/src/server/nitpicker/gui_session.h b/repos/os/src/server/nitpicker/gui_session.h index 1235b51475..a1e2caa09c 100644 --- a/repos/os/src/server/nitpicker/gui_session.h +++ b/repos/os/src/server/nitpicker/gui_session.h @@ -20,8 +20,7 @@ #include <base/heap.h> #include <os/session_policy.h> #include <os/reporter.h> -#include <os/pixel_rgb888.h> -#include <blit/painter.h> +#include <os/dynamic_rom_session.h> #include <gui_session/gui_session.h> /* local includes */ @@ -44,8 +43,22 @@ namespace Nitpicker { class Nitpicker::Gui_session : public Session_object<Gui::Session>, public View_owner, public Buffer_provider, - private Session_list::Element + private Session_list::Element, + private Dynamic_rom_session::Xml_producer, + private Input::Session_component::Action { + public: + + struct Action : Interface + { + /* + * \param rect domain-specific panorama rectangle + */ + virtual void gen_capture_info(Xml_generator &xml, Rect rect) const = 0; + + virtual void exclusive_input_changed() = 0; + }; + private: struct View_ref : Gui::View_ref @@ -87,7 +100,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, Gui_session(Gui_session const &); Gui_session &operator = (Gui_session const &); - Env &_env; + Env &_env; + Action &_action; Constrained_ram_allocator _ram; @@ -96,19 +110,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, Domain_registry::Entry const *_domain = nullptr; View *_background = nullptr; - /* - * The input mask buffer containing a byte value per texture pixel, - * which describes the policy of handling user input referring to the - * pixel. If set to zero, the input is passed through the view such - * that it can be handled by one of the subsequent views in the view - * stack. If set to one, the input is consumed by the view. If - * 'input_mask' is a null pointer, user input is unconditionally - * consumed by the view. - */ - unsigned char const *_input_mask = nullptr; - - bool _uses_alpha = false; - bool _visible = true; + bool _visible = true; Sliced_heap _session_alloc; @@ -117,14 +119,14 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, bool const _input_session_accounted = ( withdraw(Ram_quota{Input::Session_component::ev_ds_size()}), true ); - Input::Session_component _input_session_component { _env }; + Input::Session_component _input_session_component { _env, *this }; View_stack &_view_stack; Focus_updater &_focus_updater; Hover_updater &_hover_updater; - Signal_context_capability _mode_sigh { }; + Constructible<Dynamic_rom_session> _info_rom { }; View &_pointer_origin; @@ -132,13 +134,20 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, List<Session_view_list_elem> _view_list { }; - Tslab<View, 4000> _view_alloc { &_session_alloc }; + /* + * Slab allocator that includes an initial block as member + */ + template <size_t BLOCK_SIZE> + struct Initial_slab_block { uint8_t buf[BLOCK_SIZE]; }; + template <typename T, size_t BLOCK_SIZE> + struct Slab : private Initial_slab_block<BLOCK_SIZE>, Tslab<T, BLOCK_SIZE> + { + Slab(Allocator &block_alloc) + : Tslab<T, BLOCK_SIZE>(block_alloc, Initial_slab_block<BLOCK_SIZE>::buf) { }; + }; - Tslab<View_ref, 4000> _view_ref_alloc { &_session_alloc }; - - /* capabilities for sub sessions */ - Framebuffer::Session_capability _framebuffer_session_cap; - Input::Session_capability _input_session_cap; + Slab<View, 4000> _view_alloc { _session_alloc }; + Slab<View_ref, 4000> _view_ref_alloc { _session_alloc }; bool const _provides_default_bg; @@ -160,14 +169,14 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, Gui_session *_forwarded_focus = nullptr; /** - * Calculate session-local coordinate to physical screen position + * Calculate session-local coordinate to position within panorama * - * \param pos coordinate in session-local coordinate system - * \param screen_area session-local screen size + * \param pos coordinate in session-local coordinate system + * \param rect geometry within panorama */ - Point _phys_pos(Point pos, Area screen_area) const + Point _phys_pos(Point pos, Rect panorama) const { - return _domain ? _domain->phys_pos(pos, screen_area) : Point(0, 0); + return _domain ? _domain->phys_pos(pos, panorama) : Point(0, 0); } void _execute_command(Command const &); @@ -190,9 +199,28 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, [&] /* ID does not exist */ { return missing_fn(); }); } + /** + * Dynamic_rom_session::Xml_producer interface + */ + void produce_xml(Xml_generator &) override; + + bool _exclusive_input_requested = false; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_requested(bool const requested) override + { + bool const orig = _exclusive_input_requested; + _exclusive_input_requested = requested; + if (orig != requested) + _action.exclusive_input_changed(); + } + public: Gui_session(Env &env, + Action &action, Resources const &resources, Label const &label, Diag const &diag, @@ -205,25 +233,21 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, Reporter &focus_reporter) : Session_object(env.ep(), resources, label, diag), - _env(env), + Xml_producer("panorama"), + _env(env), _action(action), _ram(env.ram(), _ram_quota_guard(), _cap_quota_guard()), _session_alloc(_ram, env.rm()), - _framebuffer_session_component(view_stack, *this, *this), + _framebuffer_session_component(env.ep(), view_stack, *this, *this), _view_stack(view_stack), _focus_updater(focus_updater), _hover_updater(hover_updater), _pointer_origin(pointer_origin), _builtin_background(builtin_background), - _framebuffer_session_cap(_env.ep().manage(_framebuffer_session_component)), - _input_session_cap(_env.ep().manage(_input_session_component)), _provides_default_bg(provides_default_bg), _focus_reporter(focus_reporter) { } ~Gui_session() { - _env.ep().dissolve(_framebuffer_session_component); - _env.ep().dissolve(_input_session_component); - while (_view_ids.apply_any<View_ref>([&] (View_ref &view_ref) { destroy(_view_ref_alloc, &view_ref); })); @@ -284,7 +308,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, View const *background() const override { return _background; } - bool uses_alpha() const override { return _texture.valid() && _uses_alpha; } + bool uses_alpha() const override { return _texture.alpha(); } unsigned layer() const override { return _domain ? _domain->layer() : ~0U; } @@ -293,20 +317,28 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, /** * Return input mask value at specified buffer position */ - unsigned char input_mask_at(Point p) const override + bool input_mask_at(Point const p) const override { - if (!_input_mask || !_texture.valid()) return 0; + bool result = false; + _texture.with_input_mask([&] (Const_byte_range_ptr const &bytes) { - /* check boundaries */ - if ((unsigned)p.x >= _texture.size().w - || (unsigned)p.y >= _texture.size().h) - return 0; + unsigned const x = p.x % _texture.size().w, + y = p.y % _texture.size().h; - return _input_mask[p.y*_texture.size().w + p.x]; + size_t const offset = y*_texture.size().w + x; + if (offset < bytes.num_bytes) + result = bytes.start[offset]; + }); + return result; } void submit_input_event(Input::Event e) override; + bool exclusive_input_requested() const override + { + return _exclusive_input_requested; + } + void report(Xml_generator &xml) const override { xml.attribute("label", _label); @@ -328,16 +360,6 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, */ void visible(bool visible) { _visible = visible; } - /** - * Return session-local screen area - * - * \param phys_pos size of physical screen - */ - Area screen_area(Area phys_area) const - { - return _domain ? _domain->screen_area(phys_area) : Area(0, 0); - } - void reset_domain() { _domain = nullptr; } /** @@ -355,8 +377,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, */ void notify_mode_change() { - if (_mode_sigh.valid()) - Signal_transmitter(_mode_sigh).submit(); + if (_info_rom.constructed()) + _info_rom->trigger_update(); } /** @@ -373,16 +395,42 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, _forwarded_focus = nullptr; } + Point panning() const { return _texture.panning; } + /*************************** ** GUI session interface ** ***************************/ Framebuffer::Session_capability framebuffer() override { - return _framebuffer_session_cap; } + return _framebuffer_session_component.cap(); } Input::Session_capability input() override { - return _input_session_cap; } + return _input_session_component.cap(); } + + Info_result info() override + { + if (!_info_rom.constructed()) { + Cap_quota const needed_caps { 2 }; + if (!try_withdraw(needed_caps)) + return Info_error::OUT_OF_CAPS; + + bool out_of_caps = false, out_of_ram = false; + try { + Dynamic_rom_session::Content_producer &rom_producer = *this; + _info_rom.construct(_env.ep(), _ram, _env.rm(), rom_producer); + } + catch (Out_of_ram) { out_of_ram = true; } + catch (Out_of_caps) { out_of_caps = true; } + + if (out_of_ram || out_of_ram) { + replenish(needed_caps); + if (out_of_ram) return Info_error::OUT_OF_RAM; + if (out_of_caps) return Info_error::OUT_OF_CAPS; + } + } + return _info_rom->cap(); + } View_result view(View_id, View_attr const &attr) override; @@ -400,11 +448,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, void execute() override; - Framebuffer::Mode mode() override; - - void mode_sigh(Signal_context_capability sigh) override { _mode_sigh = sigh; } - - Buffer_result buffer(Framebuffer::Mode, bool) override; + Buffer_result buffer(Framebuffer::Mode) override; void focus(Capability<Gui::Session>) override; @@ -413,7 +457,11 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>, ** Buffer_provider interface ** *******************************/ - Dataspace_capability realloc_buffer(Framebuffer::Mode mode, bool use_alpha) override; + Dataspace_capability realloc_buffer(Framebuffer::Mode mode) override; + + void blit(Rect from, Point to) override { _texture.blit(from, to); } + + void panning(Point pos) override { _texture.panning = pos; } }; #endif /* _GUI_SESSION_H_ */ diff --git a/repos/os/src/server/nitpicker/input_session.h b/repos/os/src/server/nitpicker/input_session.h index 02712db8d0..796d06686d 100644 --- a/repos/os/src/server/nitpicker/input_session.h +++ b/repos/os/src/server/nitpicker/input_session.h @@ -32,6 +32,11 @@ class Input::Session_component : public Rpc_object<Session> { public: + struct Action : Interface + { + virtual void exclusive_input_requested(bool) = 0; + }; + enum { MAX_EVENTS = 200 }; static size_t ev_ds_size() { @@ -39,6 +44,9 @@ class Input::Session_component : public Rpc_object<Session> private: + Entrypoint &_ep; + Action &_action; + /* * Exported event buffer dataspace */ @@ -56,10 +64,15 @@ class Input::Session_component : public Rpc_object<Session> public: - Session_component(Env &env) + Session_component(Env &env, Action &action) : + _ep(env.ep()), _action(action), _ev_ram_ds(env.ram(), env.rm(), ev_ds_size()) - { } + { + _ep.manage(*this); + } + + ~Session_component() { _ep.dissolve(*this); } /** * Wake up client @@ -107,6 +120,11 @@ class Input::Session_component : public Rpc_object<Session> } void sigh(Signal_context_capability sigh) override { _sigh = sigh; } + + void exclusive(bool requested) override + { + _action.exclusive_input_requested(requested); + } }; #endif /* _INPUT_SESSION_COMPONENT_H_ */ diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index 36f099d7b7..12e862158d 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -54,14 +54,33 @@ extern char _binary_default_tff_start[]; ** Framebuffer::Session_component ** ************************************/ -void Framebuffer::Session_component::refresh(int x, int y, int w, int h) +void Framebuffer::Session_component::refresh(Rect rect) { - Rect const rect(Point(x, y), Area(w, h)); - _view_stack.mark_session_views_as_dirty(_session, rect); } +Framebuffer::Session::Blit_result +Framebuffer::Session_component::blit(Blit_batch const &batch) +{ + for (Transfer const &transfer : batch.transfer) { + if (transfer.valid(_mode)) { + _buffer_provider.blit(transfer.from, transfer.to); + Rect const to_rect { transfer.to, transfer.from.area }; + _view_stack.mark_session_views_as_dirty(_session, to_rect); + } + } + return Blit_result::OK; +} + + +void Framebuffer::Session_component::panning(Point pos) +{ + _buffer_provider.panning(pos); + _view_stack.mark_session_views_as_dirty(_session, { { 0, 0 }, _mode.area }); +} + + /*************************************** ** Implementation of the GUI service ** ***************************************/ @@ -71,6 +90,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> private: Env &_env; + Gui_session::Action &_action; Attached_rom_dataspace const &_config; Session_list &_session_list; Domain_registry const &_domain_registry; @@ -91,9 +111,16 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> bool const provides_default_bg = (label == "backdrop"); + Genode::Session::Resources resources = session_resources_from_args(args); + + /* account caps for input and framebuffer RPC objects */ + if (resources.cap_quota.value < 2) + throw Insufficient_cap_quota(); + resources.cap_quota.value -= 2; + Gui_session *session = new (md_alloc()) - Gui_session(_env, - session_resources_from_args(args), label, + Gui_session(_env, _action, + resources, label, session_diag_from_args(args), _view_stack, _focus_updater, _hover_updater, _pointer_origin, _builtin_background, provides_default_bg, @@ -144,6 +171,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> * Constructor */ Gui_root(Env &env, + Gui_session::Action &action, Attached_rom_dataspace const &config, Session_list &session_list, Domain_registry const &domain_registry, @@ -158,7 +186,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> Hover_updater &hover_updater) : Root_component<Gui_session>(&env.ep().rpc_ep(), &md_alloc), - _env(env), _config(config), _session_list(session_list), + _env(env), _action(action), _config(config), _session_list(session_list), _domain_registry(domain_registry), _global_keys(global_keys), _view_stack(view_stack), _user_state(user_state), _pointer_origin(pointer_origin), @@ -175,27 +203,38 @@ class Nitpicker::Gui_root : public Root_component<Gui_session> class Nitpicker::Capture_root : public Root_component<Capture_session> { + public: + + struct Action : Interface + { + virtual void capture_client_appeared_or_disappeared() = 0; + }; + private: using Sessions = Registry<Registered<Capture_session>>; Env &_env; + Action &_action; Sessions _sessions { }; View_stack const &_view_stack; Capture_session::Handler &_handler; - Area _fallback_bounding_box { 0, 0 }; + Rect _fallback_bounding_box { }; protected: Capture_session *_create_session(const char *args) override { - return new (md_alloc()) + Capture_session &session = *new (md_alloc()) Registered<Capture_session>(_sessions, _env, session_resources_from_args(args), session_label_from_args(args), session_diag_from_args(args), _handler, _view_stack); + + _action.capture_client_appeared_or_disappeared(); + return &session; } void _upgrade_session(Capture_session *s, const char *args) override @@ -211,12 +250,11 @@ class Nitpicker::Capture_root : public Root_component<Capture_session> * mode switches when the only capture client temporarily * disappears (driver restart). */ - _fallback_bounding_box = session->buffer_size(); + _fallback_bounding_box = session->bounding_box(); Genode::destroy(md_alloc(), session); - /* shrink screen according to the remaining output back ends */ - _handler.capture_buffer_size_changed(); + _action.capture_client_appeared_or_disappeared(); } public: @@ -225,26 +263,77 @@ class Nitpicker::Capture_root : public Root_component<Capture_session> * Constructor */ Capture_root(Env &env, + Action &action, Allocator &md_alloc, View_stack const &view_stack, Capture_session::Handler &handler) : Root_component<Capture_session>(&env.ep().rpc_ep(), &md_alloc), - _env(env), _view_stack(view_stack), _handler(handler) + _env(env), _action(action), _view_stack(view_stack), _handler(handler) { } - /** - * Determine the size of the bounding box of all capture pixel buffers - */ - Area bounding_box() const + void apply_config(Xml_node const &config) { - Area result = { 0, 0 }; - bool any_session_present = false; - _sessions.for_each([&] (Capture_session const &session) { - any_session_present = true; - result = max_area(result, session.buffer_size()); }); + using Policy = Capture_session::Policy; - return any_session_present ? result : _fallback_bounding_box; + if (config.num_sub_nodes() == 0) { + + /* if no policies are defined, mirror with no constraints */ + _sessions.for_each([&] (Capture_session &session) { + session.apply_policy(Policy::unconstrained()); }); + + } else { + + /* apply constraits per session */ + _sessions.for_each([&] (Capture_session &session) { + with_matching_policy(session.label(), config, + [&] (Xml_node const &policy) { + session.apply_policy(Policy::from_xml(policy)); + }, + [&] { session.apply_policy(Policy::blocked()); }); }); + } + + _sessions.for_each([&] (Capture_session &session) { + session.screen_size_changed(); }); + } + + /** + * Determine the bounding box of all capture clients + */ + Rect bounding_box() const + { + Rect bb { }; + _sessions.for_each([&] (Capture_session const &session) { + bb = Rect::compound(bb, session.bounding_box()); }); + + return bb.valid() ? bb : _fallback_bounding_box; + } + + /** + * Return true if specified position is suited as pointer position + */ + bool visible(Pointer const pointer) const + { + bool result = false; + pointer.with_result( + [&] (Point const p) { + _sessions.for_each([&] (Capture_session const &session) { + if (!result && session.bounding_box().contains(p)) + result = true; }); }, + [&] (Nowhere) { }); + return result; + } + + /** + * Return position suitable for the initial pointer position + */ + Pointer any_visible_pointer_position() const + { + Pointer result = Nowhere { }; + _sessions.for_each([&] (Capture_session const &session) { + if (session.bounding_box().valid()) + result = session.bounding_box().center({ 1, 1 }); }); + return result; } /** @@ -262,24 +351,17 @@ class Nitpicker::Capture_root : public Root_component<Capture_session> session.mark_as_damaged(rect); }); } - void report_displays(Xml_generator &xml) const + void process_damage() { - bool any_session_present = false; - _sessions.for_each([&] (Capture_session const &) { - any_session_present = true; }); + _sessions.for_each([&] (Capture_session &session) { + session.process_damage(); }); + } - if (!any_session_present) - return; - - Area const size = bounding_box(); - - if (size.count() == 0) - return; - - xml.node("display", [&] () { - xml.attribute("width", size.w); - xml.attribute("height", size.h); - }); + void report_panorama(Xml_generator &xml, Rect const domain_panorama) const + { + gen_attr(xml, domain_panorama); + _sessions.for_each([&] (Capture_session const &capture) { + xml.node("capture", [&] { capture.gen_capture_attr(xml, domain_panorama); }); }); } }; @@ -335,63 +417,133 @@ class Nitpicker::Event_root : public Root_component<Event_session> struct Nitpicker::Main : Focus_updater, Hover_updater, View_stack::Damage, Capture_session::Handler, - Event_session::Handler + Event_session::Handler, + Capture_root::Action, + User_state::Action, + Gui_session::Action + { Env &_env; Timer::Connection _timer { _env }; - Signal_handler<Main> _timer_handler = { _env.ep(), *this, &Main::_handle_period }; + struct Ticks { uint64_t ms; }; - unsigned long _timer_period_ms = 10; + Ticks _now() { return { .ms = _timer.curr_time().trunc_to_plain_ms().value }; } - Constructible<Framebuffer::Connection> _framebuffer { }; - - struct Input_connection + struct Input_connection : Noncopyable { - Input::Connection connection; + Env &_env; + Main &_main; - Attached_dataspace ev_ds; + Input::Connection _connection { _env }; - Input_connection(Env &env) - : connection(env), ev_ds(env.rm(), connection.dataspace()) { } + Attached_dataspace _ev_ds { _env.rm(), _connection.dataspace() }; + + void _handle() + { + size_t const max_events = _ev_ds.size() / sizeof(Input::Event); + + User_state::Input_batch const batch { + .events = _ev_ds.local_addr<Input::Event>(), + .count = min(max_events, (size_t)_connection.flush()) }; + + _main.handle_input_events(batch); + } + + Signal_handler<Input_connection> _handler { + _env.ep(), *this, &Input_connection::_handle }; + + Input_connection(Env &env, Main &main) : _env(env), _main(main) + { + _connection.sigh(_handler); + } + + ~Input_connection() + { + _connection.sigh(Signal_context_capability()); + } }; Constructible<Input_connection> _input { }; using PT = Pixel_rgb888; /* physical pixel type */ - /* - * Initialize framebuffer - * - * The framebuffer is encapsulated in a volatile object to allow its - * reconstruction at runtime as a response to resolution changes. + /** + * Framebuffer connection used when operating in 'request_framebuffer' mode */ struct Framebuffer_screen { - Framebuffer::Session &framebuffer; + Env &_env; + Main &_main; - Framebuffer::Mode const mode = framebuffer.mode(); + Framebuffer::Connection _fb { _env, { } }; - Attached_dataspace fb_ds; + Framebuffer::Mode const _mode = _fb.mode(); - Canvas<PT> screen = { fb_ds.local_addr<PT>(), Point(0, 0), mode.area }; + Attached_dataspace _fb_ds { _env.rm(), _fb.dataspace() }; - Area size = screen.size(); + Canvas<PT> _screen { _fb_ds.local_addr<PT>(), Point(0, 0), _mode.area }; + + Rect const _rect { { 0, 0 }, _screen.size() }; using Dirty_rect = Genode::Dirty_rect<Rect, 3>; - Dirty_rect dirty_rect { }; + Dirty_rect _dirty_rect { }; - /** - * Constructor - */ - Framebuffer_screen(Region_map &rm, Framebuffer::Session &fb) - : - framebuffer(fb), fb_ds(rm, framebuffer.dataspace()) + Ticks _previous_sync { }; + + Signal_handler<Framebuffer_screen> _sync_handler { + _env.ep(), *this, &Framebuffer_screen::_handle_sync }; + + void _handle_sync() { - dirty_rect.mark_as_dirty(Rect(Point(0, 0), size)); + /* call 'Dirty_rect::flush' on a copy to preserve the state */ + Dirty_rect dirty_rect = _dirty_rect; + dirty_rect.flush([&] (Rect const &rect) { + _main._view_stack.draw(_screen, rect); }); + + bool const any_pixels_refreshed = !_dirty_rect.empty(); + + /* flush pixels to the framebuffer, reset dirty_rect */ + _dirty_rect.flush([&] (Rect const &rect) { + _fb.refresh(rect); }); + + /* deliver framebuffer synchronization events */ + for (Gui_session *s = _main._session_list.first(); s; s = s->next()) + s->submit_sync(); + + if (any_pixels_refreshed) + _previous_sync = _main._now(); } + + Framebuffer_screen(Env &env, Main &main) : _env(env), _main(main) + { + _fb.mode_sigh(_main._fb_screen_mode_handler); + _fb.sync_sigh(_sync_handler); + mark_as_dirty(_rect); + } + + ~Framebuffer_screen() + { + _fb.mode_sigh(Signal_context_capability()); + _fb.sync_sigh(Signal_context_capability()); + } + + void mark_as_dirty(Rect rect) + { + _dirty_rect.mark_as_dirty(rect); + } + + void process_damage() + { + if (_main._now().ms - _previous_sync.ms > 40) + _handle_sync(); + } + + bool visible(Point p) const { return _rect.contains(p); } + + Point anywhere() const { return _rect.center({ 1, 1 }); }; }; bool _request_framebuffer = false; @@ -399,10 +551,33 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, Constructible<Framebuffer_screen> _fb_screen { }; - void _handle_fb_mode(); - void _report_displays(); + bool _visible_at_fb_screen(Pointer pointer) const + { + return pointer.convert<bool>( + [&] (Point p) { return _fb_screen.constructed() && _fb_screen->visible(p); }, + [&] (Nowhere) { return false; }); + } - Signal_handler<Main> _fb_mode_handler = { _env.ep(), *this, &Main::_handle_fb_mode }; + Pointer _anywhere_at_fb_screen() const + { + return _fb_screen.constructed() ? Pointer { _fb_screen->anywhere() } + : Pointer { Nowhere { } }; + } + + Signal_handler<Main> _fb_screen_mode_handler { + _env.ep(), *this, &Main::_reconstruct_fb_screen }; + + void _reconstruct_fb_screen() + { + _fb_screen.destruct(); + + if (_request_framebuffer) + _fb_screen.construct(_env, *this); + + capture_buffer_size_changed(); + } + + void _report_panorama(); /* * User-input policy @@ -426,7 +601,7 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, Focus _focus { }; View_stack _view_stack { _focus, _font, *this }; - User_state _user_state { _focus, _global_keys, _view_stack }; + User_state _user_state { *this, _focus, _global_keys, _view_stack }; View_owner _global_view_owner { }; @@ -447,18 +622,26 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, Reporter _focus_reporter = { _env, "focus" }; Reporter _keystate_reporter = { _env, "keystate" }; Reporter _clicked_reporter = { _env, "clicked" }; - Reporter _displays_reporter = { _env, "displays" }; + Reporter _panorama_reporter = { _env, "panorama" }; Attached_rom_dataspace _config_rom { _env, "config" }; Constructible<Attached_rom_dataspace> _focus_rom { }; - Gui_root _gui_root { _env, _config_rom, _session_list, *_domain_registry, + Gui_root _gui_root { _env, *this, _config_rom, _session_list, *_domain_registry, _global_keys, _view_stack, _user_state, _pointer_origin, _builtin_background, _sliced_heap, _focus_reporter, *this, *this }; - Capture_root _capture_root { _env, _sliced_heap, _view_stack, *this }; + /** + * Gui_session::Action interface + */ + void gen_capture_info(Xml_generator &xml, Rect const domain_panorama) const override + { + _capture_root.report_panorama(xml, domain_panorama); + } + + Capture_root _capture_root { _env, *this, _sliced_heap, _view_stack, *this }; Event_root _event_root { _env, _sliced_heap, *this }; @@ -466,26 +649,39 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, { if (_hover_reporter.enabled()) { Reporter::Xml_generator xml(_hover_reporter, [&] () { - _user_state.report_hovered_view_owner(xml, false); }); + _user_state.report_hovered_view_owner(xml, false); + _user_state.report_pointer_position(xml); + }); } } + Signal_handler<Main> _damage_handler { _env.ep(), *this, &Main::_handle_damage }; + + void _handle_damage() + { + if (_fb_screen.constructed()) + _fb_screen->process_damage(); + + _capture_root.process_damage(); + } + /** * View_stack::Damage interface */ void mark_as_damaged(Rect rect) override { - if (_fb_screen.constructed()) { - _fb_screen->dirty_rect.mark_as_dirty(rect); - } + if (_fb_screen.constructed()) + _fb_screen->mark_as_dirty(rect); _capture_root.mark_as_damaged(rect); + + _damage_handler.local_submit(); } void _update_input_connection() { - bool const output_present = (_view_stack.size().count() > 0); - _input.conditional(_request_input && output_present, _env); + bool const output_present = (_view_stack.bounding_box().valid()); + _input.conditional(_request_input && output_present, _env, *this); } /** @@ -498,18 +694,21 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, * present output back ends. */ - Area new_size { 0, 0 }; + Rect new_bb { }; if (_fb_screen.constructed()) - new_size = max_area(new_size, _fb_screen->size); + new_bb = Rect::compound(new_bb, Rect { _fb_screen->_rect }); - new_size = max_area(new_size, _capture_root.bounding_box()); + new_bb = Rect::compound(new_bb, _capture_root.bounding_box()); - bool const size_changed = (new_size != _view_stack.size()); + bool const size_changed = (new_bb != _view_stack.bounding_box()); if (size_changed) { - _view_stack.size(new_size); - _user_state.sanitize_pointer_position(); + _view_stack.bounding_box(new_bb); + + if (!_user_state.pointer().ok()) + _user_state.pointer(_capture_root.any_visible_pointer_position()); + _update_pointer_position(); _capture_root.screen_size_changed(); @@ -521,10 +720,68 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, s->notify_mode_change(); } - _report_displays(); + _report_panorama(); _update_input_connection(); } + /** + * Capture_session::Handler interface + */ + void capture_requested(Capture_session::Label const &) override + { + /* deliver video-sync events */ + for (Gui_session *s = _session_list.first(); s; s = s->next()) + s->submit_sync(); + } + + Pointer _any_visible_pointer_position() + { + Pointer const captured_pos = _capture_root.any_visible_pointer_position(); + + return captured_pos.ok() ? captured_pos : _anywhere_at_fb_screen(); + } + + bool _visible(Pointer const p) const + { + return _capture_root.visible(p) || _visible_at_fb_screen(p); + } + + /** + * User_state::Action interface + */ + Pointer sanitized_pointer_position(Pointer const orig_pos, Point pos) override + { + auto for_each_value = [] (int const from, int const to, auto const &fn) + { + int const step = (from < to) ? 1 : -1; + for (int i = from; i != to; i += step) + fn(i); + }; + + if (_visible(pos)) + return pos; + + /* move pointer along screen edge */ + if (orig_pos.ok()) { + Point best = orig_pos.convert<Point>( + [&] (Point p) { return p; }, + [&] (Nowhere) { return Point { }; }); + + /* panorama change may have made area around the pointer invisible */ + if (!_visible(best)) + return _any_visible_pointer_position(); + + auto try_better = [&] (Point p) { if (_visible(p)) best = p; }; + + for_each_value(best.x, pos.x, [&] (int x) { try_better({ x, best.y }); }); + for_each_value(best.y, pos.y, [&] (int y) { try_better({ best.x, y }); }); + + return best; + } + + return _any_visible_pointer_position(); + } + /** * Focus_updater interface * @@ -551,15 +808,41 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, * manually to turn the initial configuration into effect. */ void _handle_config(); + void _apply_capture_config(); - Signal_handler<Main> _config_handler = { _env.ep(), *this, &Main::_handle_config }; + Signal_handler<Main> _config_handler { _env.ep(), *this, &Main::_handle_config }; + + /** + * Capture_root::Action interface + */ + void capture_client_appeared_or_disappeared() override + { + _apply_capture_config(); + capture_buffer_size_changed(); + } + + bool _exclusive_input = false; + + /** + * Input::Session_component::Action interface + */ + void exclusive_input_changed() override + { + if (_user_state.exclusive_input() != _exclusive_input) { + _exclusive_input = _user_state.exclusive_input(); + + /* toggle pointer visibility */ + _update_pointer_position(); + _view_stack.update_all_views(); + } + } /** * Signal handler for externally triggered focus changes */ void _handle_focus(); - Signal_handler<Main> _focus_handler = { _env.ep(), *this, &Main::_handle_focus }; + Signal_handler<Main> _focus_handler { _env.ep(), *this, &Main::_handle_focus }; /** * Event_session::Handler interface @@ -578,45 +861,28 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, void _update_motion_and_focus_activity_reports(); /** - * Signal handler periodically invoked for the reception of user input and redraw + * Track when the user was active the last time */ - void _handle_period(); - - Signal_handler<Main> _input_period = { _env.ep(), *this, &Main::_handle_period }; + Ticks _last_button_activity { }, + _last_motion_activity { }; /** - * Counter that is incremented periodically + * Number of milliseconds since the last user interaction, after which + * we regard the user as inactive */ - unsigned _period_cnt = 0; - - /** - * Period counter when the user was active the last time - */ - unsigned _last_button_activity_period = 0, - _last_motion_activity_period = 0; - - /** - * Number of periods after the last user activity when we regard the user - * as becoming inactive - */ - unsigned const _activity_threshold = 50; - - /** - * True if the user has recently interacted with buttons or keys - * - * This state is reported as part of focus reports to allow the clipboard - * to dynamically adjust its information-flow policy to the user activity. - */ - bool _button_activity = false; - - /** - * True if the user recently moved the pointer - */ - bool _motion_activity = false; + Ticks const _activity_threshold { .ms = 500 }; void _update_pointer_position() { - _view_stack.geometry(_pointer_origin, Rect(_user_state.pointer_pos(), Area{})); + /* move pointer out of the way while a client receives exclusive input */ + if (_user_state.exclusive_input()) { + _view_stack.geometry(_pointer_origin, Rect { { -1000*1000, 0 }, { } }); + return; + } + _user_state.pointer().with_result( + [&] (Point p) { + _view_stack.geometry(_pointer_origin, Rect(p, Area{})); }, + [&] (Nowhere) { }); } Main(Env &env) : _env(env) @@ -629,9 +895,7 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, _config_rom.sigh(_config_handler); _handle_config(); - _timer.sigh(_timer_handler); - - _handle_fb_mode(); + _reconstruct_fb_screen(); _env.parent().announce(_env.ep().manage(_gui_root)); @@ -641,32 +905,22 @@ struct Nitpicker::Main : Focus_updater, Hover_updater, if (_config_rom.xml().has_sub_node("event")) _env.parent().announce(_env.ep().manage(_event_root)); - /* - * Detect initial motion activity such that the first hover report - * contains the boot-time activity of the user in the very first - * report. - */ - _handle_period(); + _update_motion_and_focus_activity_reports(); - _report_displays(); + _report_panorama(); } }; void Nitpicker::Main::handle_input_events(User_state::Input_batch batch) { + Ticks const now = _now(); + User_state::Handle_input_result const result = _user_state.handle_input_events(batch); - if (result.button_activity) { - _last_button_activity_period = _period_cnt; - _button_activity = true; - } - - if (result.motion_activity) { - _last_motion_activity_period = _period_cnt; - _motion_activity = true; - } + if (result.button_activity) _last_button_activity = now; + if (result.motion_activity) _last_motion_activity = now; /* * Report information about currently pressed keys whenever the key state @@ -703,74 +957,39 @@ void Nitpicker::Main::handle_input_events(User_state::Input_batch batch) /* update pointer position */ if (result.motion_activity) _update_pointer_position(); + + _update_motion_and_focus_activity_reports(); } void Nitpicker::Main::_update_motion_and_focus_activity_reports() { - /* flag user as inactive after activity threshold is reached */ - if (_period_cnt == _last_button_activity_period + _activity_threshold) - _button_activity = false; + Ticks const now = _now(); - if (_period_cnt == _last_motion_activity_period + _activity_threshold) - _motion_activity = false; + bool const button_activity = (now.ms - _last_button_activity.ms < _activity_threshold.ms); + bool const motion_activity = (now.ms - _last_motion_activity.ms < _activity_threshold.ms); bool const hover_changed = (_reported_hover_count != _hover_count); - if (hover_changed || (_reported_motion_activity != _motion_activity)) { - Reporter::Xml_generator xml(_hover_reporter, [&] () { - _user_state.report_hovered_view_owner(xml, _motion_activity); }); + if (hover_changed || (_reported_motion_activity != motion_activity)) { + Reporter::Xml_generator xml(_hover_reporter, [&] { + _user_state.report_hovered_view_owner(xml, motion_activity); + _user_state.report_pointer_position(xml); + }); } bool const focus_changed = (_reported_focus_count != _focus_count); - if (focus_changed || (_reported_button_activity != _button_activity)) { - Reporter::Xml_generator xml(_focus_reporter, [&] () { - _user_state.report_focused_view_owner(xml, _button_activity); }); + if (focus_changed || (_reported_button_activity != button_activity)) { + Reporter::Xml_generator xml(_focus_reporter, [&] { + _user_state.report_focused_view_owner(xml, button_activity); }); } - _reported_motion_activity = _motion_activity; - _reported_button_activity = _button_activity; + _reported_motion_activity = motion_activity; + _reported_button_activity = button_activity; _reported_hover_count = _hover_count; _reported_focus_count = _focus_count; } -void Nitpicker::Main::_handle_period() -{ - _period_cnt++; - - /* handle batch of pending events */ - if (_input.constructed()) { - - size_t const max_events = _input->ev_ds.size() / sizeof(Input::Event); - - User_state::Input_batch const batch { - .events = _input->ev_ds.local_addr<Input::Event>(), - .count = min(max_events, (size_t)_input->connection.flush()) }; - - handle_input_events(batch); - } - - _update_motion_and_focus_activity_reports(); - - /* perform redraw */ - if (_framebuffer.constructed() && _fb_screen.constructed()) { - /* call 'Dirty_rect::flush' on a copy to preserve the state */ - Dirty_rect dirty_rect = _fb_screen->dirty_rect; - dirty_rect.flush([&] (Rect const &rect) { - _view_stack.draw(_fb_screen->screen, rect); }); - - /* flush pixels to the framebuffer, reset dirty_rect */ - _fb_screen->dirty_rect.flush([&] (Rect const &rect) { - _framebuffer->refresh(rect.x1(), rect.y1(), - rect.w(), rect.h()); }); - } - - /* deliver framebuffer synchronization events */ - for (Gui_session *s = _session_list.first(); s; s = s->next()) - s->submit_sync(); -} - - /** * Helper function for 'handle_config' */ @@ -809,6 +1028,15 @@ void Nitpicker::Main::_handle_focus() } +void Nitpicker::Main::_apply_capture_config() +{ + /* propagate capture policies */ + _config_rom.xml().with_optional_sub_node("capture", + [&] (Xml_node const &capture) { + _capture_root.apply_config(capture); }); +} + + void Nitpicker::Main::_handle_config() { _config_rom.update(); @@ -830,7 +1058,9 @@ void Nitpicker::Main::_handle_config() configure_reporter(config, _focus_reporter); configure_reporter(config, _keystate_reporter); configure_reporter(config, _clicked_reporter); - configure_reporter(config, _displays_reporter); + configure_reporter(config, _panorama_reporter); + + capture_client_appeared_or_disappeared(); /* update domain registry and session policies */ for (Gui_session *s = _session_list.first(); s; s = s->next()) @@ -873,13 +1103,14 @@ void Nitpicker::Main::_handle_config() /* update focus report since the domain colors might have changed */ Reporter::Xml_generator xml(_focus_reporter, [&] () { - _user_state.report_focused_view_owner(xml, _button_activity); }); + bool const button_activity = (_now().ms - _last_button_activity.ms < _activity_threshold.ms); + _user_state.report_focused_view_owner(xml, button_activity); }); /* update framebuffer output back end */ bool const request_framebuffer = config.attribute_value("request_framebuffer", false); if (request_framebuffer != _request_framebuffer) { _request_framebuffer = request_framebuffer; - _handle_fb_mode(); + _reconstruct_fb_screen(); } /* @@ -893,50 +1124,20 @@ void Nitpicker::Main::_handle_config() } -void Nitpicker::Main::_report_displays() +void Nitpicker::Main::_report_panorama() { - if (!_displays_reporter.enabled()) + if (!_panorama_reporter.enabled()) return; - Reporter::Xml_generator xml(_displays_reporter, [&] () { - if (_fb_screen.constructed()) { - xml.node("display", [&] () { - xml.attribute("width", _fb_screen->size.w); - xml.attribute("height", _fb_screen->size.h); - }); - } + Reporter::Xml_generator xml(_panorama_reporter, [&] () { + if (_fb_screen.constructed()) + xml.node("panorama", [&] { gen_attr(xml, _fb_screen->_rect); }); - _capture_root.report_displays(xml); + _capture_root.report_panorama(xml, _view_stack.bounding_box()); }); } -void Nitpicker::Main::_handle_fb_mode() -{ - if (_request_framebuffer && !_framebuffer.constructed()) { - _framebuffer.construct(_env, Framebuffer::Mode{}); - _framebuffer->mode_sigh(_fb_mode_handler); - _framebuffer->sync_sigh(_timer_handler); - _timer.trigger_periodic(0); - } - - /* reconstruct '_fb_screen' with updated mode */ - if (_request_framebuffer && _framebuffer.constructed()) - _fb_screen.construct(_env.rm(), *_framebuffer); - - if (!_request_framebuffer && _fb_screen.constructed()) - _fb_screen.destruct(); - - if (!_request_framebuffer && _framebuffer.constructed()) - _framebuffer.destruct(); - - if (!_request_framebuffer) - _timer.trigger_periodic(_timer_period_ms*1000); - - capture_buffer_size_changed(); -} - - void Component::construct(Genode::Env &env) { static Nitpicker::Main nitpicker(env); diff --git a/repos/os/src/server/nitpicker/resizeable_texture.h b/repos/os/src/server/nitpicker/resizeable_texture.h index f5b7436cbf..6f8c4a097e 100644 --- a/repos/os/src/server/nitpicker/resizeable_texture.h +++ b/repos/os/src/server/nitpicker/resizeable_texture.h @@ -14,10 +14,6 @@ #ifndef _RESIZEABLE_TEXTURE_H_ #define _RESIZEABLE_TEXTURE_H_ -/* Genode includes */ -#include <blit/painter.h> -#include <os/pixel_alpha8.h> - /* local includes */ #include <chunky_texture.h> @@ -31,17 +27,18 @@ class Nitpicker::Resizeable_texture unsigned _current = 0; - using Constructible_texture = Constructible<Chunky_texture<PT>>; + Constructible<Chunky_texture<PT>> _textures[2] { }; - struct Element : Constructible_texture + static void _with_texture(auto &obj, auto const &fn) { - Element() : Constructible_texture() { } - }; - - Element _textures[2]; + if (obj.valid()) + fn(*obj._textures[obj._current]); + } public: + Point panning { 0, 0 }; + bool valid() const { return _textures[_current].constructed(); } Area size() const @@ -50,14 +47,15 @@ class Nitpicker::Resizeable_texture : Area { }; } + bool alpha() const { return valid() && _textures[_current]->alpha(); } + void release_current() { _textures[_current].destruct(); } - bool try_construct_next(Ram_allocator &ram, Region_map &rm, - Area size, bool use_alpha) + bool try_construct_next(Ram_allocator &ram, Region_map &rm, Framebuffer::Mode mode) { try { unsigned const next = !_current; - _textures[next].construct(ram, rm, size, use_alpha); + _textures[next].construct(ram, rm, mode); return true; } catch (...) { } return false; @@ -102,22 +100,24 @@ class Nitpicker::Resizeable_texture _current = next; } - template <typename FN> - void with_texture(FN const &fn) const - { - if (valid()) - fn(*_textures[_current]); - } + void with_texture(auto const &fn) const { _with_texture(*this, fn); } + void with_texture(auto const &fn) { _with_texture(*this, fn); } Dataspace_capability dataspace() { - return valid() ? _textures[_current]->ds_cap() : Ram_dataspace_capability(); + return valid() ? _textures[_current]->cap() : Ram_dataspace_capability(); } - unsigned char const *input_mask_buffer() const + void with_input_mask(auto const &fn) const { - return valid() ? _textures[_current]->input_mask_buffer() - : nullptr; + if (valid()) + _textures[_current]->with_input_mask(fn); + } + + void blit(Rect from, Point to) + { + with_texture([&] (Chunky_texture<PT> &texture) { + texture.blit(from, to); }); } }; diff --git a/repos/os/src/server/nitpicker/types.h b/repos/os/src/server/nitpicker/types.h index c23723a6fd..2350eace1a 100644 --- a/repos/os/src/server/nitpicker/types.h +++ b/repos/os/src/server/nitpicker/types.h @@ -16,9 +16,9 @@ /* Genode includes */ #include <util/xml_node.h> +#include <util/xml_generator.h> #include <util/color.h> #include <base/allocator.h> -#include <os/pixel_rgb888.h> #include <gui_session/gui_session.h> namespace Nitpicker { @@ -40,6 +40,23 @@ namespace Nitpicker { { return Area(max(a1.w, a2.w), max(a1.h, a2.h)); } + + struct Nowhere { }; + + using Pointer = Attempt<Point, Nowhere>; + + static inline void gen_attr(Xml_generator &xml, Point const point) + { + if (point.x) xml.attribute("xpos", point.x); + if (point.y) xml.attribute("ypos", point.y); + } + + static inline void gen_attr(Xml_generator &xml, Rect const rect) + { + gen_attr(xml, rect.at); + if (rect.w()) xml.attribute("width", rect.w()); + if (rect.h()) xml.attribute("height", rect.h()); + } } #endif /* _TYPES_H_ */ diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc index e36e0c01d2..6a7360e7fd 100644 --- a/repos/os/src/server/nitpicker/user_state.cc +++ b/repos/os/src/server/nitpicker/user_state.cc @@ -93,24 +93,27 @@ void User_state::_handle_input_event(Input::Event ev) _last_seq_number.construct(seq); }); /* transparently convert relative into absolute motion event */ - ev.handle_relative_motion([&] (int x, int y) { - - int const ox = _pointer_pos.x, - oy = _pointer_pos.y; - - int const ax = max(0, min((int)_view_stack.size().w - 1, ox + x)), - ay = max(0, min((int)_view_stack.size().h - 1, oy + y)); - - ev = Absolute_motion{ax, ay}; - }); + if (!exclusive_input()) + ev.handle_relative_motion([&] (int x, int y) { + _pointer.with_result( + [&] (Point orig_pos) { + Point const p = orig_pos + Point { x, y }; + ev = Absolute_motion { p.x, p.y }; }, + [&] (Nowhere) { }); }); /* respond to motion events by updating the pointer position */ ev.handle_absolute_motion([&] (int x, int y) { - _pointer_pos = Point(x, y); }); + _try_move_pointer({ x, y }); + + /* enforce sanitized position (prevent move to invisible areas) */ + _pointer.with_result( + [&] (Point p) { ev = Absolute_motion { p.x, p.y }; }, + [&] (Nowhere) { ev = { }; }); + }); /* let pointer position correspond to most recent touch position */ ev.handle_touch([&] (Input::Touch_id, float x, float y) { - _pointer_pos = Point((int)x, (int)y); }); + _try_move_pointer({ int(x), int(y) }); }); /* track key states, drop double press/release events */ { @@ -188,9 +191,11 @@ void User_state::_handle_input_event(Input::Event ev) _focused->submit_input_event(Focus_leave()); if (_hovered) { - _hovered->submit_input_event(Absolute_motion{_pointer_pos.x, - _pointer_pos.y}); - _hovered->submit_input_event(Focus_enter()); + _pointer.with_result( + [&] (Point p) { + _hovered->submit_input_event(Absolute_motion{p.x, p.y}); + _hovered->submit_input_event(Focus_enter()); }, + [&] (Nowhere) { }); } if (_hovered->has_transient_focusable_domain()) { @@ -244,27 +249,33 @@ void User_state::_handle_input_event(Input::Event ev) /* * Deliver event to session */ - bool const forward_to_session = (ev.absolute_motion() || ev.wheel() || - ev.touch() || ev.touch_release() || - ev.seq_number()); + bool const forward_to_session = ev.absolute_motion() || ev.relative_motion() + || ev.touch() || ev.touch_release() + || ev.wheel() || ev.seq_number(); if (forward_to_session) { - if (_key_cnt == 0) { + View_owner *receiver = _input_receiver; - if (_hovered) { + if (_key_cnt == 0 && _hovered) { + if (ev.absolute_motion()) + receiver = nullptr; + /* + * Unless the domain of the pointed session is configured to + * always receive hover events, we deliver motion events only + * to the focused domain. + */ + if (_hovered->hover_always() || _hovered->has_same_domain(_focused)) + receiver = _hovered; + } - /* - * Unless the domain of the pointed session is configured to - * always receive hover events, we deliver motion events only - * to the focused domain. - */ - if (_hovered->hover_always() - || _hovered->has_same_domain(_focused)) - _hovered->submit_input_event(ev); - } + /* + * Route relative motion (exclusive input) to the focused client + */ + if (ev.relative_motion() && _focused) + receiver = _focused; - } else if (_input_receiver) - _input_receiver->submit_input_event(ev); + if (receiver) + receiver->submit_input_event(ev); } /* @@ -276,7 +287,7 @@ void User_state::_handle_input_event(Input::Event ev) if (!_input_receiver) return; - if (!_mouse_button(key) + if (!_mouse_button(key) || _global_key_sequence || (_hovered && (_hovered->has_focusable_domain() || _hovered->has_same_domain(_focused)))) @@ -311,7 +322,7 @@ void User_state::_handle_input_event(Input::Event ev) User_state::Handle_input_result User_state::handle_input_events(Input_batch batch) { - Point const old_pointer_pos = _pointer_pos; + Pointer const old_pointer = _pointer; View_owner * const old_hovered = _hovered; View_owner const * const old_focused = _focused; View_owner const * const old_input_receiver = _input_receiver; @@ -389,13 +400,23 @@ User_state::handle_input_events(Input_batch batch) _last_clicked_redeliver = false; } + auto pointer_changed = [&] + { + return old_pointer.convert<bool>( + [&] (Point const old) { + return _pointer.convert<bool>( + [&] (Point const p) { return p != old; }, + [&] (Nowhere) { return true; }); }, + [&] (Nowhere) { return _pointer.ok(); }); + }; + return { .hover_changed = _hovered != old_hovered, .focus_changed = (_focused != old_focused) || (_input_receiver != old_input_receiver), .key_state_affected = key_state_affected, .button_activity = button_activity, - .motion_activity = (_pointer_pos != old_pointer_pos) || touch_occurred, + .motion_activity = pointer_changed() || touch_occurred, .key_pressed = _key_pressed(), .last_clicked_changed = last_clicked_changed }; @@ -411,8 +432,8 @@ void User_state::report_keystate(Xml_generator &xml) const void User_state::report_pointer_position(Xml_generator &xml) const { - xml.attribute("xpos", _pointer_pos.x); - xml.attribute("ypos", _pointer_pos.y); + _pointer.with_result([&] (Point p) { gen_attr(xml, p); }, + [&] (Nowhere) { }); } @@ -486,9 +507,12 @@ User_state::Update_hover_result User_state::update_hover() return { .hover_changed = false }; View_owner * const old_hovered = _hovered; - View const * const pointed_view = _view_stack.find_view(_pointer_pos); - _hovered = pointed_view ? &pointed_view->owner() : nullptr; + _hovered = _pointer.convert<View_owner *>( + [&] (Point const p) { + View const * const pointed_view = _view_stack.find_view(p); + return pointed_view ? &pointed_view->owner() : nullptr; }, + [&] (Nowhere) { return nullptr; }); /* * Deliver a leave event if pointed-to session changed, notify newly @@ -499,8 +523,10 @@ User_state::Update_hover_result User_state::update_hover() old_hovered->submit_input_event(Hover_leave()); if (_hovered) - _hovered->submit_input_event(Absolute_motion{_pointer_pos.x, - _pointer_pos.y}); + _pointer.with_result( + [&] (Point p) { + _hovered->submit_input_event(Absolute_motion{p.x, p.y}); }, + [&] (Nowhere) { }); } return { .hover_changed = (_hovered != old_hovered) }; diff --git a/repos/os/src/server/nitpicker/user_state.h b/repos/os/src/server/nitpicker/user_state.h index 821017f027..7a852d4f07 100644 --- a/repos/os/src/server/nitpicker/user_state.h +++ b/repos/os/src/server/nitpicker/user_state.h @@ -29,6 +29,19 @@ namespace Nitpicker { class User_state; } class Nitpicker::User_state { + public: + + struct Action : Interface + { + /** + * Return the pointer position when attempting to move to 'pos' + * + * This policy hook enables the restriction of pointer movements + * to those areas that are captured. + */ + virtual Pointer sanitized_pointer_position(Pointer orig, Point pos) = 0; + }; + private: /* @@ -65,6 +78,8 @@ class Nitpicker::User_state */ bool _focus_via_click = true; + Action &_action; + /** * Input-focus information propagated to the view stack */ @@ -80,16 +95,10 @@ class Nitpicker::User_state */ View_stack &_view_stack; - /** - * True once the initial screen size becomes known and used as the - * initial (centered) pointer position. - */ - bool _initial_pointer_position_defined = false; - /* * Current pointer position */ - Point _pointer_pos { }; + Pointer _pointer = Nowhere { }; /* * Currently pointed-at view owner @@ -199,6 +208,11 @@ class Nitpicker::User_state } } + void _try_move_pointer(Point next) + { + _pointer = _action.sanitized_pointer_position(_pointer, next); + } + public: /** @@ -207,29 +221,16 @@ class Nitpicker::User_state * \param focus exported focus information, to be consumed by the * view stack to tailor its view drawing operations */ - User_state(Focus &focus, Global_keys &global_keys, View_stack &view_stack) + User_state(Action &action, Focus &focus, Global_keys &global_keys, + View_stack &view_stack) : - _focus(focus), _global_keys(global_keys), _view_stack(view_stack) + _action(action), _focus(focus), _global_keys(global_keys), + _view_stack(view_stack) { } - /** - * Called whenever the view-stack size has changed - */ - void sanitize_pointer_position() - { - Area const screen_size = _view_stack.size(); + void pointer(Pointer p) { _pointer = p; } - /* center pointer initially */ - if (!_initial_pointer_position_defined) { - _pointer_pos = Point(screen_size.w/2, screen_size.h/2); - _initial_pointer_position_defined = true; - } - - /* ensure that pointer remains within screen boundaries */ - if (screen_size.count() > 0) - _pointer_pos = Point(min((int)screen_size.w - 1, _pointer_pos.x), - min((int)screen_size.h - 1, _pointer_pos.y)); - } + Pointer pointer() const { return _pointer; } /**************************************** @@ -251,6 +252,12 @@ class Nitpicker::User_state Handle_input_result handle_input_events(Input_batch); + bool exclusive_input() const + { + return (_focused && _focused->exclusive_input_requested()) + || (_input_receiver && _input_receiver->exclusive_input_requested()); + } + /** * Discard all references to specified view owner */ @@ -272,8 +279,6 @@ class Nitpicker::User_state void report_focused_view_owner(Xml_generator &, bool button_active) const; void report_last_clicked_view_owner(Xml_generator &) const; - Point pointer_pos() { return _pointer_pos; } - /** * Enable/disable direct focus changes by clicking on a client */ diff --git a/repos/os/src/server/nitpicker/view.cc b/repos/os/src/server/nitpicker/view.cc index 1a580886cd..694a73e406 100644 --- a/repos/os/src/server/nitpicker/view.cc +++ b/repos/os/src/server/nitpicker/view.cc @@ -11,8 +11,6 @@ * under the terms of the GNU Affero General Public License version 3. */ -#include <os/pixel_rgb888.h> - #include <nitpicker_gfx/texture_painter.h> #include <nitpicker_gfx/box_painter.h> @@ -126,9 +124,32 @@ void Nitpicker::View::draw(Canvas_base &canvas, Font const &font, Focus const &f owner_color.g >> 1, owner_color.b >> 1); + auto for_each_tile_pos = [&] (auto const &fn) + { + int const view_w = view_rect.w(), + view_h = view_rect.h(); + + int const texture_w = int(_texture.size().w), + texture_h = int(_texture.size().h); + + if (!texture_w || !texture_h) + return; + + int off_x = (_buffer_off.x - _texture.panning.x) % texture_w; + int off_y = (_buffer_off.y - _texture.panning.y) % texture_h; + + if (off_x > 0) off_x -= texture_w; + if (off_y > 0) off_y -= texture_h; + + for (int y = off_y; y < view_h; y += texture_h) + for (int x = off_x; x < view_w; x += texture_w) + fn(Point { x, y }); + }; + _texture.with_texture([&] (Texture_base const &texture) { - canvas.draw_texture(_buffer_off + view_rect.p1(), texture, op, - mix_color, allow_alpha); }); + for_each_tile_pos([&] (Point const pos) { + canvas.draw_texture(view_rect.p1() + pos, texture, op, + mix_color, allow_alpha); }); }); if (!_texture.valid()) canvas.draw_box(view_rect, Color::black()); @@ -163,7 +184,7 @@ bool Nitpicker::View::input_response_at(Point const p) const /* if view uses an alpha channel, check the input mask */ if (_owner.content_client() && _owner.uses_alpha()) - return _owner.input_mask_at(p - view_rect.p1() - _buffer_off); + return _owner.input_mask_at(p - view_rect.p1() - _buffer_off + _texture.panning); return true; } diff --git a/repos/os/src/server/nitpicker/view_owner.h b/repos/os/src/server/nitpicker/view_owner.h index 81b57609bc..6252dfe00c 100644 --- a/repos/os/src/server/nitpicker/view_owner.h +++ b/repos/os/src/server/nitpicker/view_owner.h @@ -82,10 +82,12 @@ struct Nitpicker::View_owner : Interface /** * Return input-mask value at given position */ - virtual unsigned char input_mask_at(Point) const { return 0; } + virtual bool input_mask_at(Point) const { return false; } virtual void submit_input_event(Input::Event) { } + virtual bool exclusive_input_requested() const { return false; } + /** * Produce report with the owner's information */ diff --git a/repos/os/src/server/nitpicker/view_stack.cc b/repos/os/src/server/nitpicker/view_stack.cc index d76235655c..5012f9be34 100644 --- a/repos/os/src/server/nitpicker/view_stack.cc +++ b/repos/os/src/server/nitpicker/view_stack.cc @@ -145,7 +145,7 @@ void View_stack::_place_labels(Rect rect) Rect old = view->label_rect(), best; /* calculate best visible label position */ - Rect rect = Rect::intersect(Rect(Point(), _size), view_rect); + Rect rect = Rect::intersect(_bounding_box, view_rect); if (start) _optimize_label_rec(start, view, rect, &best); /* @@ -239,13 +239,13 @@ void View_stack::geometry(View &view, Rect const rect) * views. The 'refresh_view' function takes care to constrain the * refresh to the actual view geometry. */ - refresh_view(view, Rect(Point(), _size)); + refresh_view(view, _bounding_box); /* change geometry */ view.geometry(Rect(rect)); /* refresh new view geometry */ - refresh_view(view, Rect(Point(), _size)); + refresh_view(view, _bounding_box); Rect const compound = Rect::compound(old_outline, _outline(view)); @@ -259,7 +259,7 @@ void View_stack::buffer_offset(View &view, Point const buffer_off) { view.buffer_off(buffer_off); - refresh_view(view, Rect(Point(), _size)); + refresh_view(view, _bounding_box); } diff --git a/repos/os/src/server/nitpicker/view_stack.h b/repos/os/src/server/nitpicker/view_stack.h index bc3567ca68..510846bc12 100644 --- a/repos/os/src/server/nitpicker/view_stack.h +++ b/repos/os/src/server/nitpicker/view_stack.h @@ -32,7 +32,7 @@ class Nitpicker::View_stack private: - Area _size { }; + Rect _bounding_box { }; Focus &_focus; Font const &_font; List<View_stack_elem> _views { }; @@ -99,11 +99,11 @@ class Nitpicker::View_stack /** * Return size */ - Area size() const { return _size; } + Rect bounding_box() const { return _bounding_box; } - void size(Area size) + void bounding_box(Rect rect) { - _size = size; + _bounding_box = rect; update_all_views(); } @@ -128,10 +128,8 @@ class Nitpicker::View_stack */ void update_all_views() { - Rect const whole_screen(Point(), _size); - - _place_labels(whole_screen); - _damage.mark_as_damaged(whole_screen); + _place_labels(_bounding_box); + _damage.mark_as_damaged(_bounding_box); } /** @@ -151,7 +149,8 @@ class Nitpicker::View_stack * Determine view portion that displays the buffer portion * specified by 'rect'. */ - Point const offset = view->abs_position() + view->buffer_off(); + Point const offset = view->abs_position() + view->buffer_off() + - session.panning(); Rect const r = Rect::intersect(Rect::compound(rect.p1() + offset, rect.p2() + offset), view->abs_geometry()); diff --git a/repos/os/src/server/vmm/virtio_gpu.cc b/repos/os/src/server/vmm/virtio_gpu.cc index 9214e119ca..81f2025b17 100644 --- a/repos/os/src/server/vmm/virtio_gpu.cc +++ b/repos/os/src/server/vmm/virtio_gpu.cc @@ -43,15 +43,15 @@ void Vmm::Virtio_gpu_queue::notify(Virtio_gpu_device & dev) void Vmm::Virtio_gpu_control_request::_get_display_info() { - Framebuffer::Mode mode = _device.resize(); + Gui::Area const mode = _device.resize(); Display_info_response dir { _desc_range(1) }; memset((void*)dir.base(), 0, Display_info_response::SIZE); dir.write<Control_header::Type>(Control_header::Type::OK_DISPLAY_INFO); dir.write<Display_info_response::X>(0); dir.write<Display_info_response::Y>(0); - dir.write<Display_info_response::Width>(mode.area.w); - dir.write<Display_info_response::Height>(mode.area.h); + dir.write<Display_info_response::Width>(mode.w); + dir.write<Display_info_response::Height>(mode.h); dir.write<Display_info_response::Enabled>(1); dir.write<Display_info_response::Flags>(0); } @@ -195,9 +195,9 @@ void Vmm::Virtio_gpu_control_request::_resource_flush() uint32_t x = rf.read<Resource_flush::X>(); uint32_t y = rf.read<Resource_flush::Y>(); uint32_t w = min(rf.read<Resource_flush::Width>(), - _device._fb_mode.area.w - x); + _device._gui_win.area.w - x); uint32_t h = min(rf.read<Resource_flush::Height>(), - _device._fb_mode.area.h - y); + _device._gui_win.area.h - y); enum { BYTES_PER_PIXEL = Virtio_gpu_device::BYTES_PER_PIXEL }; @@ -218,12 +218,12 @@ void Vmm::Virtio_gpu_control_request::_resource_flush() (res.area.w * y + x) * BYTES_PER_PIXEL); void * dst = (void*)((addr_t)_device._fb_ds->local_addr<void>() + - (_device._fb_mode.area.w * y + x) * BYTES_PER_PIXEL); + (_device._gui_win.area.w * y + x) * BYTES_PER_PIXEL); uint32_t line_src = res.area.w * BYTES_PER_PIXEL; - uint32_t line_dst = _device._fb_mode.area.w * BYTES_PER_PIXEL; + uint32_t line_dst = _device._gui_win.area.w * BYTES_PER_PIXEL; blit(src, line_src, dst, line_dst, w*BYTES_PER_PIXEL, h); - _device._gui.framebuffer.refresh(x, y, w, h); + _device._gui.framebuffer.refresh({ { int(x), int(y) }, { w, h } }); }); } diff --git a/repos/os/src/server/vmm/virtio_gpu.h b/repos/os/src/server/vmm/virtio_gpu.h index 59633d77bd..c5db7da971 100644 --- a/repos/os/src/server/vmm/virtio_gpu.h +++ b/repos/os/src/server/vmm/virtio_gpu.h @@ -296,8 +296,16 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2> Gui::Connection & _gui; Cpu::Signal_handler<Virtio_gpu_device> _handler; Constructible<Attached_dataspace> _fb_ds { }; - Framebuffer::Mode _fb_mode { _gui.mode() }; - Gui::Top_level_view _view { _gui, { { }, _fb_mode.area } }; + + Gui::Rect _request_gui_window() + { + return _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 640, 480 } }; }); + } + + Gui::Rect _gui_win = _request_gui_window(); + Gui::Top_level_view _view { _gui, _gui_win }; using Area = Genode::Area<>; using Rect = Genode::Rect<>; @@ -446,7 +454,7 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2> _env(env), _heap(heap), _ram_ds(ram_ds), _gui(gui), _handler(cpu, env.ep(), *this, &Virtio_gpu_device::_mode_change) { - _gui.mode_sigh(_handler); + _gui.info_sigh(_handler); } void buffer_notification() @@ -454,21 +462,21 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2> _buffer_notification(); } - Framebuffer::Mode resize() + Gui::Area resize() { _fb_ds.destruct(); - _fb_mode = _gui.mode(); - _gui.buffer(_fb_mode, false); + _gui_win = _request_gui_window(); + _gui.buffer({ .area = _gui_win.area, .alpha = false }); - if (_fb_mode.area.count() > 0) + if (_gui_win.valid()) _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); using Command = Gui::Session::Command; - _gui.enqueue<Command::Geometry>(_view.id(), Rect(Point(0, 0), _fb_mode.area)); + _gui.enqueue<Command::Geometry>(_view.id(), _gui_win); _gui.enqueue<Command::Front>(_view.id()); _gui.execute(); - return _gui.mode(); + return _gui_win.area; } }; diff --git a/repos/os/src/test/black_hole/main.cc b/repos/os/src/test/black_hole/main.cc index 7aff1e7afb..1a14e083ec 100644 --- a/repos/os/src/test/black_hole/main.cc +++ b/repos/os/src/test/black_hole/main.cc @@ -261,7 +261,9 @@ class Black_hole_test::Capture_test Capture::Area _screen_size { 1, 1 }; Capture::Pixel _pixels[1]; Surface<Capture::Pixel> _surface { _pixels, _screen_size }; - Capture::Connection::Screen _screen { _connection, _env.rm(), _screen_size }; + Capture::Connection::Screen _screen { _connection, _env.rm(), + { .px = _screen_size, + .mm = { } } }; bool _finished { false }; public: diff --git a/repos/os/src/test/capture/main.cc b/repos/os/src/test/capture/main.cc index 915e248168..bb847c4728 100644 --- a/repos/os/src/test/capture/main.cc +++ b/repos/os/src/test/capture/main.cc @@ -66,7 +66,7 @@ struct Test::Main } } - bool _gui_buffer_init = ( _validate_mode(), _gui.buffer(_mode, false), true ); + bool _gui_buffer_init = ( _validate_mode(), _gui.buffer(_mode), true ); Attached_dataspace _fb_ds { _env.rm(), _gui.framebuffer.dataspace() }; @@ -75,7 +75,7 @@ struct Test::Main Output(Env &env, Allocator &alloc, Xml_node const &config) : _env(env), _alloc(alloc), - _mode({ .area = _area_from_xml(config, Area { }) }) + _mode({ .area = _area_from_xml(config, Area { }), .alpha = false }) { auto view_rect = [&] (Xml_node node) { @@ -113,7 +113,7 @@ struct Test::Main Capture::Connection _capture { _env, "" }; - bool _capture_buffer_init = ( _capture.buffer(_area), true ); + bool _capture_buffer_init = ( _capture.buffer({ .px = _area, .mm = { }}), true ); Attached_dataspace _capture_ds { _env.rm(), _capture.dataspace() }; @@ -164,9 +164,7 @@ struct Test::Main }); affected.for_each_rect([&] (Gui::Rect const rect) { - _output->_gui.framebuffer.refresh(rect.x1(), rect.y1(), - rect.w(), rect.h()); - }); + _output->_gui.framebuffer.refresh(rect); }); }); }); diff --git a/repos/os/src/test/fb_bench/main.cc b/repos/os/src/test/fb_bench/main.cc index 96dfe86e8c..85eea4e704 100644 --- a/repos/os/src/test/fb_bench/main.cc +++ b/repos/os/src/test/fb_bench/main.cc @@ -31,8 +31,8 @@ struct Test Timer::Connection timer { env }; Heap heap { env.ram(), env.rm() }; Framebuffer::Connection fb { env, Framebuffer::Mode { } }; - Attached_dataspace fb_ds { env.rm(), fb.dataspace() }; Framebuffer::Mode const fb_mode { fb.mode() }; + Attached_dataspace fb_ds { env.rm(), fb.dataspace() }; char *buf[2]; Test(Env &env, int id, char const *brief) : env(env), id(id) @@ -107,7 +107,7 @@ struct Blit_test : Test { unsigned kib = 0; uint64_t const start_ms = timer.elapsed_ms(); - unsigned const w = (unsigned)(fb_mode.area.w * fb_mode.bytes_per_pixel()); + unsigned const w = unsigned(fb_mode.area.w * sizeof(Pixel_rgb888)); unsigned const h = fb_mode.area.h; for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) { blit(buf[i % 2], w, fb_ds.local_addr<char>(), w, w, h); @@ -125,7 +125,7 @@ struct Unaligned_blit_test : Test { unsigned kib = 0; uint64_t const start_ms = timer.elapsed_ms(); - unsigned const w = (unsigned)(fb_mode.area.w * fb_mode.bytes_per_pixel()); + unsigned const w = unsigned(fb_mode.area.w * sizeof(Pixel_rgb888)); unsigned const h = fb_mode.area.h; for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) { blit(buf[i % 2] + 2, w, fb_ds.local_addr<char>() + 2, w, w - 2, h); diff --git a/repos/os/src/test/framebuffer/main.cc b/repos/os/src/test/framebuffer/main.cc index f924dd5585..9539906ecb 100644 --- a/repos/os/src/test/framebuffer/main.cc +++ b/repos/os/src/test/framebuffer/main.cc @@ -19,6 +19,7 @@ #include <base/log.h> #include <os/static_root.h> #include <capture_session/capture_session.h> +#include <timer_session/connection.h> #include <base/attached_ram_dataspace.h> #include <util/reconstructible.h> @@ -53,15 +54,38 @@ struct Test::Capture_session : Rpc_object<Capture::Session> State _state = STRIPES; - unsigned long _sync_cnt = 0; - - enum { FRAME_CNT = 200 }; - void _draw(); - void _draw_frame(Pixel *, Pixel, Area); - Capture_session(Env &env) : _env(env) { } + bool _dirty = false; /* true if there is data not yet delivered */ + bool _capture_stopped = false; + + Signal_context_capability _wakeup_sigh { }; + + void _wakeup_if_needed() + { + if (_capture_stopped && _dirty && _wakeup_sigh.valid()) { + Signal_transmitter(_wakeup_sigh).submit(); + _capture_stopped = false; + } + } + + Timer::Connection _timer { _env }; + + Signal_handler<Capture_session> _timer_handler { + _env.ep(), *this, &Capture_session::_handle_timer }; + + void _handle_timer() + { + _dirty = true; + _wakeup_if_needed(); + } + + Capture_session(Env &env) : _env(env) + { + _timer.sigh(_timer_handler); + _timer.trigger_periodic(1000*1000); + } /******************************** @@ -72,11 +96,22 @@ struct Test::Capture_session : Rpc_object<Capture::Session> void screen_size_sigh(Signal_context_capability) override { } - void buffer(Area size) override + void wakeup_sigh(Signal_context_capability sigh) override { _wakeup_sigh = sigh; } + + Buffer_result buffer(Buffer_attr attr) override { - _ds.construct(_env.ram(), _env.rm(), buffer_bytes(size)); - _size = size; + try { + _ds.construct(_env.ram(), _env.rm(), buffer_bytes(attr.px)); + } + catch (Out_of_ram) { return Buffer_result::OUT_OF_RAM; } + catch (Out_of_caps) { return Buffer_result::OUT_OF_CAPS; } + + _size = attr.px; + + log("screen dimension: ", _size); + _draw(); + return Buffer_result::OK; } Dataspace_capability dataspace() override @@ -87,14 +122,15 @@ struct Test::Capture_session : Rpc_object<Capture::Session> Affected_rects capture_at(Point) override { Affected_rects affected { }; - - if (_sync_cnt++ % FRAME_CNT == 0) { + if (_dirty) { _draw(); - affected.rects[0] = Rect(Point(0, 0), _size); + affected.rects[0] = Rect { { }, _size }; + _dirty = false; } - return affected; } + + void capture_stopped() override { _capture_stopped = true; } }; @@ -128,6 +164,11 @@ void Test::Capture_session::_draw_frame(Pixel *p, Pixel c, Area area) /* left and right */ for (unsigned i = 0; i < h; ++i) p[i*w] = p[i*w + w - 1] = c; + + /* 15px marker for (0,0) */ + for (unsigned i = 0; i < 15; i++) + for (unsigned j = 0; j < 15; j++) + p[i*w + j] = c; } diff --git a/repos/os/src/test/nitpicker/main.cc b/repos/os/src/test/nitpicker/main.cc index 49156c8234..d3696ad954 100644 --- a/repos/os/src/test/nitpicker/main.cc +++ b/repos/os/src/test/nitpicker/main.cc @@ -236,11 +236,11 @@ Test::Main::Main(Genode::Env &env) : _env(env) Gui::Area const size { 256, 256 }; - Framebuffer::Mode const mode { .area = size }; + Framebuffer::Mode const mode { .area = size, .alpha = _config.alpha }; log("screen is ", mode); - _gui.buffer(mode, _config.alpha); + _gui.buffer(mode); _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); @@ -265,6 +265,8 @@ Test::Main::Main(Genode::Env &env) : _env(env) } } + _gui.framebuffer.refresh({ { 0, 0 }, size }); + _view_stack.construct(View_stack::Input_mask_ptr { .size = size, .ptr = input_mask }); diff --git a/repos/os/src/test/vfs_capture/main.cc b/repos/os/src/test/vfs_capture/main.cc index 43b15f7b01..ba3c017be5 100644 --- a/repos/os/src/test/vfs_capture/main.cc +++ b/repos/os/src/test/vfs_capture/main.cc @@ -70,7 +70,7 @@ struct Test::Main } } - bool _gui_buffer_init = ( _validate_mode(), _gui.buffer(_mode, false), true ); + bool _gui_buffer_init = ( _validate_mode(), _gui.buffer(_mode), true ); Attached_dataspace _fb_ds { _env.rm(), _gui.framebuffer.dataspace() }; @@ -79,7 +79,7 @@ struct Test::Main Output(Env &env, Allocator &alloc, Xml_node const &config) : _env(env), _alloc(alloc), - _mode({ .area = _area_from_xml(config, Area { }) }) + _mode({ .area = _area_from_xml(config, Area { }), .alpha = false }) { auto view_rect = [&] (Xml_node node) { @@ -179,9 +179,7 @@ struct Test::Main }); affected.for_each_rect([&] (Gui::Rect const rect) { - _output->_gui.framebuffer.refresh(rect.x1(), rect.y1(), - rect.w(), rect.h()); - }); + _output->_gui.framebuffer.refresh(rect); }); }); }); diff --git a/repos/os/src/test/vmm_x86/component.cc b/repos/os/src/test/vmm_x86/component.cc index c7cfe8c938..3710a75e1e 100644 --- a/repos/os/src/test/vmm_x86/component.cc +++ b/repos/os/src/test/vmm_x86/component.cc @@ -120,8 +120,10 @@ class Vmm::Vcpu void force_fpu_state_transfer(Vcpu_state & state) { /* force FPU-state transfer on next entry */ - state.fpu.charge([] (Vcpu_state::Fpu::State &) { - /* don't change state */ }); + state.fpu.charge([] (Vcpu_state::Fpu::State &state) { + /* don't change state */ + return sizeof(state); + }); } /* diff --git a/repos/pc/recipes/api/pc_linux/hash b/repos/pc/recipes/api/pc_linux/hash index 756a60bdd7..692281f96a 100644 --- a/repos/pc/recipes/api/pc_linux/hash +++ b/repos/pc/recipes/api/pc_linux/hash @@ -1 +1 @@ -2024-08-28 c35413dcbed20d55bcf3c4dd978a902089a532b9 +2024-10-29 42f394837d2a6d7b6a823b0e4676a6826f8b7c04 diff --git a/repos/pc/recipes/pkg/pc_nic/hash b/repos/pc/recipes/pkg/pc_nic/hash index f9969510e5..4841ef111a 100644 --- a/repos/pc/recipes/pkg/pc_nic/hash +++ b/repos/pc/recipes/pkg/pc_nic/hash @@ -1 +1 @@ -2024-08-28 b2a6bcf47cecaf90bcb08adb24e5de947dbad327 +2024-10-29 23616e6a75361bda36011ba9f2f6ce421465b84c diff --git a/repos/pc/recipes/pkg/pc_wifi/hash b/repos/pc/recipes/pkg/pc_wifi/hash index 864a54a200..cffb507755 100644 --- a/repos/pc/recipes/pkg/pc_wifi/hash +++ b/repos/pc/recipes/pkg/pc_wifi/hash @@ -1 +1 @@ -2024-08-28 663bb485f69895a0d59cfeb3907174d8a2a19d15 +2024-10-29 896e55dc6b7a70a99221cf6a253b0fee0b26be47 diff --git a/repos/pc/recipes/pkg/test_usb_host-pc/hash b/repos/pc/recipes/pkg/test_usb_host-pc/hash index bfdb2aa062..ca2f277c2b 100644 --- a/repos/pc/recipes/pkg/test_usb_host-pc/hash +++ b/repos/pc/recipes/pkg/test_usb_host-pc/hash @@ -1 +1 @@ -2024-08-28 268075437cc4a10b44dd0528f7eb0b7a57d9c956 +2024-10-29 ae889c865c683161658e0a226a7d4756d9bb9e90 diff --git a/repos/pc/recipes/raw/pc_wifi_firmware/hash b/repos/pc/recipes/raw/pc_wifi_firmware/hash index f9b6eb1884..1bc15e2a94 100644 --- a/repos/pc/recipes/raw/pc_wifi_firmware/hash +++ b/repos/pc/recipes/raw/pc_wifi_firmware/hash @@ -1 +1 @@ -2024-08-28 aa43b665f2d6704235f72ae43490bb4d5b9a066e +2024-10-29 64855e51d95c59c2934c7ff62d3a95c27334c43b diff --git a/repos/pc/recipes/src/pc_intel_fb/hash b/repos/pc/recipes/src/pc_intel_fb/hash index 5dc15cd732..542d6e6f8e 100644 --- a/repos/pc/recipes/src/pc_intel_fb/hash +++ b/repos/pc/recipes/src/pc_intel_fb/hash @@ -1 +1 @@ -2024-08-28 82da7198675b5adce9804848eec840552d002678 +2024-10-29 72d62051ab1ebedde2ea45435deadb76a31763de diff --git a/repos/pc/recipes/src/pc_nic/hash b/repos/pc/recipes/src/pc_nic/hash index b9100acc86..ef1538f055 100644 --- a/repos/pc/recipes/src/pc_nic/hash +++ b/repos/pc/recipes/src/pc_nic/hash @@ -1 +1 @@ -2024-08-28 7cf329fbf078f1e99757867160caf3f5c1c84eea +2024-10-29 c7aeacce12092ccd2140c39974972c444049ad97 diff --git a/repos/pc/recipes/src/pc_platform/hash b/repos/pc/recipes/src/pc_platform/hash index 1fd7397f8a..719e6ca79b 100644 --- a/repos/pc/recipes/src/pc_platform/hash +++ b/repos/pc/recipes/src/pc_platform/hash @@ -1 +1 @@ -2024-08-28 43c56f099802141a7cefa3fc5f643c6e6375e645 +2024-10-29 e3680a9cb739a577f8498a6f7aea758f18ad4866 diff --git a/repos/pc/recipes/src/pc_usb_host/hash b/repos/pc/recipes/src/pc_usb_host/hash index 105dc061de..e65c0482b6 100644 --- a/repos/pc/recipes/src/pc_usb_host/hash +++ b/repos/pc/recipes/src/pc_usb_host/hash @@ -1 +1 @@ -2024-08-28 6a457bbf43cd27a863aa0e341d9e161b4d3139bf +2024-10-29 e2d68d948d4d12b872716523c292c0fde127adf6 diff --git a/repos/pc/recipes/src/pc_wifi/hash b/repos/pc/recipes/src/pc_wifi/hash index dd7e6643f1..9db65c02db 100644 --- a/repos/pc/recipes/src/pc_wifi/hash +++ b/repos/pc/recipes/src/pc_wifi/hash @@ -1 +1 @@ -2024-08-28 debac2bfadd4661a848aa4c444f770f45b1a5038 +2024-10-29 b574e37e8945ce789670ad7ca5b91e9d23c68c0d diff --git a/repos/pc/run/intel_fb.run b/repos/pc/run/intel_fb.run index 8c4e860298..c4395e087f 100644 --- a/repos/pc/run/intel_fb.run +++ b/repos/pc/run/intel_fb.run @@ -26,10 +26,6 @@ if {$use_fb_controller} { set apply_on_hotplug "yes" } -if {$use_usb} { - import_from_depot [depot_user]/src/pc_usb_host -} - import_from_depot [depot_user]/src/fs_rom \ [depot_user]/src/vfs \ [depot_user]/src/vfs_import \ @@ -44,6 +40,7 @@ set build_components { test/framebuffer } +append_if $use_usb build_components { driver/usb_host } append_if $use_gpu build_components { driver/gpu/intel } append_if $use_top build_components { app/top } @@ -71,7 +68,12 @@ append config { </default-route> <default caps="100"/> - <start name="report_rom" caps="100"> + <start name="timer"> + <resource name="RAM" quantum="1M"/> + <provides><service name="Timer"/></provides> + </start> + + <start name="report_rom" caps="100" priority="-1"> <resource name="RAM" quantum="2M"/> <provides> <service name="ROM" /> @@ -90,7 +92,7 @@ append config { </route> </start> - <start name="acpi" caps="250"> + <start name="acpi" caps="250" priority="-1"> <resource name="RAM" quantum="6M"/> <route> <service name="IO_MEM"> <parent/> </service> @@ -103,7 +105,7 @@ append config { </route> </start> - <start name="pci_decode" caps="350"> + <start name="pci_decode" caps="350" priority="-1"> <resource name="RAM" quantum="2M"/> <route> <service name="Report"> @@ -119,7 +121,7 @@ append config { </route> </start> - <start name="platform" caps="100" managing_system="yes"> + <start name="platform" caps="100" managing_system="yes" priority="-1"> <resource name="RAM" quantum="2M"/> <provides> <service name="Platform"/> </provides> <route> @@ -146,14 +148,20 @@ append config { <pci class="USB"/> </policy> </config> - </start> + </start>} - <start name="timer"> - <resource name="RAM" quantum="1M"/> - <provides><service name="Timer"/></provides> - </start> +append_if $use_top config { + <start name="top" priority="-1"> + <resource name="RAM" quantum="2M"/> + <config period_ms="40000"/> + <route> + <service name="TRACE"> <parent label=""/> </service> + <any-service> <parent/> <any-child/> </any-service> + </route> + </start>} - <start name="init_dynamic" caps="10000"> +append config { + <start name="init_dynamic" caps="10000" priority="-2"> <binary name="init"/> <resource name="RAM" quantum="1000M"/> <route> @@ -184,16 +192,6 @@ append config { <default caps="100"/> <report init_ram="yes" child_ram="yes" delay_ms="10000"/>} -append_if $use_top config { - <start name="top"> - <resource name="RAM" quantum="2M"/> - <config period_ms="40000"/> - <route> - <service name="TRACE"> <parent label=""/> </service> - <any-service> <parent/> <any-child/> </any-service> - </route> - </start>} - append config { <start name="report_rom" priority="-1"> <resource name="RAM" quantum="2M"/> @@ -222,6 +220,13 @@ append config { <inline name="fb.config"> <config ld_verbose="yes" apply_on_hotplug="} $apply_on_hotplug {"> <report connectors="yes"/> + <merge name="mirror"> + <!-- all connectors in merge node gets mirrored --> +<!-- + <connector name="DP-1"/> + <connector name="HDMI-A-1"/> +--> + </merge> </config> </inline> </import> @@ -269,7 +274,7 @@ append_if $use_gpu config { append config { <start name="intel_fb" caps="1000"> <binary name="pc_intel_fb"/> - <resource name="RAM" quantum="90M"/> + <resource name="RAM" quantum="128M"/> <route>} append_if $use_gpu config { @@ -279,6 +284,18 @@ append config { <service name="ROM" label="config"> <child name="config_rom" label="fb.config"/> </service> <service name="Report"> <child name="report_rom"/> </service> + + <service name="Capture" label="eDP-1"> <child name="test-framebuffer-eDP-1"/> </service> + <service name="Capture" label="HDMI-A-1"> <child name="test-framebuffer-HDMI-A-1"/> </service> + <service name="Capture" label="HDMI-A-2"> <child name="test-framebuffer-HDMI-A-2"/> </service> + <service name="Capture" label="HDMI-A-3"> <child name="test-framebuffer-HDMI-A-3"/> </service> + <service name="Capture" label="DP-1"> <child name="test-framebuffer-DP-1"/> </service> + <service name="Capture" label="DP-2"> <child name="test-framebuffer-DP-2"/> </service> + <service name="Capture" label="DP-3"> <child name="test-framebuffer-DP-3"/> </service> + <service name="Capture" label="DP-4"> <child name="test-framebuffer-DP-4"/> </service> + <service name="Capture" label="VGA-1"> <child name="test-framebuffer-VGA-1"/> </service> + <service name="Capture" label="mirror"> <child name="test-framebuffer-mirror"/> </service> + <any-service> <parent/> <any-child /> </any-service> </route> </start>} @@ -312,7 +329,62 @@ append_if $use_fb_controller config { </start>} append config { - <start name="test-framebuffer" priority="-1"> + <start name="test-framebuffer-eDP-1" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-HDMI-A-1" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-HDMI-A-2" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-HDMI-A-3" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-DP-1" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-DP-2" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-DP-3" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-DP-4" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-VGA-1" priority="-1"> + <binary name="test-framebuffer"/> + <resource name="RAM" quantum="10M"/> + <provides> <service name="Capture"/> </provides> + <config/> + </start> + <start name="test-framebuffer-mirror" priority="-1"> + <binary name="test-framebuffer"/> <resource name="RAM" quantum="10M"/> <provides> <service name="Capture"/> </provides> <config/> diff --git a/repos/pc/run/pc_wifi.run b/repos/pc/run/pc_wifi.run index 64be6b23bd..2ada3eaa53 100644 --- a/repos/pc/run/pc_wifi.run +++ b/repos/pc/run/pc_wifi.run @@ -5,68 +5,7 @@ # set debug_driver false -# -# Configure wireless lan -# - -proc wifi_ssid { } { - return $::env(GENODE_WIFI_SSID) -} - -proc wifi_psk { } { - return $::env(GENODE_WIFI_PSK) -} - -proc wifi_wpa { } { - if {![info exists ::env(GENODE_WIFI_WPA)]} { - return WPA2 - } - return $::env(GENODE_WIFI_WPA) -} - -# -# wifi-driver config generator (supporting a network list) -# -# You may script your tests with this function in the dynamic_rom config below. -# The syntax for the networks parameter is -# -# { ssid protection passphrase explicit_scan } -# -# Example dynamic_rom config: -# -# {<inline description="auto-connect both networks"> -# } [wifi_config 30 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk no"]] { -# </inline> -# <inline description="aquto-connect both, but net2 explicitly"> -# } [wifi_config 30 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk yes"]] { -# </inline>} - -set wifi_verbose false -set wifi_verbose_state false - -proc wifi_config { connected_scan_interval scan_interval rfkill networks } { - global wifi_verbose - global wifi_verbose_state - - set config "<wifi_config" - append config " verbose=\"$wifi_verbose\"" - append config " verbose_state=\"$wifi_verbose_state\"" - append config " connected_scan_interval=\"$connected_scan_interval\"" - append config " scan_interval=\"$scan_interval\"" - append config " rfkill=\"$rfkill\"" - append config ">\n" - foreach n $networks { - append config " <network" - append config " ssid=\"[lindex $n 0]\"" - append config " protection=\"[lindex $n 1]\"" - append config " passphrase=\"[lindex $n 2]\"" - append config " explicit_scan=\"[lindex $n 3]\"" - append config "/>\n" - } - append config "</wifi_config>\n" - - return $config -} +source ${genode_dir}/repos/dde_linux/run/wifi_config.inc # # Restrict platforms @@ -236,19 +175,19 @@ append config { <config verbose="yes"> <rom name="wifi_config"> <inline description="disconnect"> -} [wifi_config 30 5 no {}] { +} [wifi_config 5 10 no {}] { </inline> <sleep milliseconds="15000"/> <inline description="connect"> -} [wifi_config 30 5 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] yes"]] { +} [wifi_config 5 10 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] no"]] { </inline> <sleep milliseconds="60000"/> <inline description="rfkill block"> -} [wifi_config 30 5 yes [list "[wifi_ssid] [wifi_wpa] [wifi_psk] yes"]] { +} [wifi_config 5 10 yes [list "[wifi_ssid] [wifi_wpa] [wifi_psk] no"]] { </inline> <sleep milliseconds="30000"/> <inline description="rfkill unblock"> -} [wifi_config 30 5 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] yes"]] { +} [wifi_config 5 10 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] no"]] { </inline> <sleep milliseconds="30000"/> </rom> @@ -327,7 +266,7 @@ install_config $config # boot-module assembly # if {$debug_driver} { -exec rm bin/wifi.lib.so +catch {exec rm bin/wifi.lib.so} exec echo dummy > bin/wifi.lib.so } diff --git a/repos/pc/sculpt/deploy/goa_testbed b/repos/pc/sculpt/deploy/goa_testbed index 6362efb151..9d21432006 100644 --- a/repos/pc/sculpt/deploy/goa_testbed +++ b/repos/pc/sculpt/deploy/goa_testbed @@ -60,13 +60,13 @@ </route> </start> - <start name="fs_rom" priority="-2" pkg="jschlatow/pkg/fs_rom/2024-04-11"> + <start name="fs_rom" priority="-2" pkg="jschlatow/pkg/fs_rom/2024-10-07"> <route> <service name="File_system"> <parent label="report"/> </service> </route> </start> - <start name="system_info" pkg="jschlatow/pkg/system_info/2024-04-22" priority="-2"> + <start name="system_info" pkg="jschlatow/pkg/system_info/2024-10-09" priority="-2"> <route> <service name="Gui"> <parent label="backdrop"/> </service> <service name="Rtc"> <child name="system_clock"/> </service> @@ -89,15 +89,15 @@ </config> </start> - <start name="goa_testbed" pkg="jschlatow/pkg/goa_testbed/2024-07-15" priority="-2"> + <start name="goa_testbed" pkg="jschlatow/pkg/goa_testbed/2024-10-11" priority="-2"> <route> <service name="TRACE"> <parent/> </service> <service name="VM"> <parent/> </service> <service name="Gpu"> <child name="intel_gpu"/> </service> <service name="Gui"> <child name="wm"/> </service> <service name="Rtc"> <child name="system_clock"/> </service> - <service name="Audio_in"> <child name="black_hole"/> </service> - <service name="Audio_out"> <child name="black_hole"/> </service> + <service name="Play"> <child name="black_hole"/> </service> + <service name="Record"> <child name="black_hole"/> </service> <service name="Usb"> <child name="black_hole"/> </service> <service name="Event"> <child name="black_hole"/> </service> <service name="Capture"> <child name="black_hole"/> </service> @@ -105,7 +105,7 @@ <service name="Nic" label_prefix="telnet"> <child name="nic_router" label="telnet"/> </service> <service name="Nic" label_prefix="http"> <child name="nic_router" label="http"/> </service> <service name="Nic" label_prefix="gdb"> <child name="nic_router" label="gdb"/> </service> - <service name="Nic"> <!-- for test scenario --> <child name="nic_router"/> </service> + <service name="Nic"> <!-- for test scenario --> <child name="nic_router"/> </service> <service name="Report" label="clipboard"> <child name="wm"/> </service> <service name="Report" label="shape"> <child name="wm"/> </service> <service name="ROM" label="clipboard"> <child name="wm"/> </service> diff --git a/repos/pc/src/driver/framebuffer/intel/pc/README b/repos/pc/src/driver/framebuffer/intel/pc/README index e40a311dec..5c7d49827a 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/README +++ b/repos/pc/src/driver/framebuffer/intel/pc/README @@ -3,62 +3,22 @@ This driver is for Intel i915 compatible graphic cards. Default behaviour ~~~~~~~~~~~~~~~~~ -When no configuration is provided to the driver, it will switch on all devices -connected to the graphics card. It will use the highest resolution as -provided by the BIOS or EDID information from the display devices for each -connector. The virtual resolution delivered to the client is the maximum in -width and height of the active connectors. +When no configuration is provided to the driver, it will enable all connectors +with attached displays and allocate for each display a discrete framebuffer. +It will use the highest resolution as provided by the BIOS or EDID information. +For each connector a separate Capture connection will be requested labeled +according to the connector name. When newly connected displays are detected +by the driver, the new connectors are enabled and another Capture session +labeled according to the connector will be requested. -When newly connected devices are detected by the hardware, the new connectors -are enabled, probed, and again the highest resolution across all active -connectors will be chosen. By default, the current config of the driver will -be re-read and re-applied. This behaviour can be disabled by +By default, on hotplug of a display, the current config of the driver will be +re-parsed and re-applied. This behaviour can be disabled by ! <config apply_on_hotplug="no"/> Configuration ~~~~~~~~~~~~~ -Each of the connectors can be configured explicitly in terms of resolution and -whether it should be enabled or not. This looks like the following: - -! <config> -! <connector name="eDP-1" width="1920" height="1080" hz="60" brightness="75" enabled="true"/> -! <connector name="DP-1" mode_id="2" enabled="true"/> -! </config> - -The resolution can be configured exactly by the reported mode_id or by -the width/height/hz attributes. In the latter case the driver will take the -first matching mode out of multiple matching modes potentially. - -When the configuration changes during runtime, the driver will adapt to it. In -this case, it will also change the current virtual resolution to the maximum of -the configured resolutions in width and height, and it will inform its client -about the change in resolution. - -The brightness value is in percent and takes effect only if supported by -the hardware. - -The maximal physical resolution can be enforced by: - -! <config max_width="2560" max_height="1440"> -! </config> - -The virtual resolution can be enforced by: - -! <config force_width="1024" force_height="768"> -! </config> - -The amount of memory used by the driver for the accounting of its available -buffer space is set by: - -! <config max_framebuffer_memory="64M"> -! </config> - -The default and minimal value is '64M' and suffices for resolutions of at -least '3840x2160'. How much actual memory is used depends on the configured -resolution. - To present all available connectors and their possible resolutions to the user, the driver is able to deliver a corresponding report, which can be enabled in the configuration as follows: @@ -71,14 +31,14 @@ The exported report has the following format: ! <connectors> ! <connector name="eDP-1" connected="true" brightness="50" width_mm="290" height_mm="170"> -! <mode width="1920" height="1080" hz="60" mode_id="1" preferred="true" used="true" width_mm="288" height_mm="165"/> +! <mode width="1920" height="1080" hz="60" id="1" preferred="true" used="true" width_mm="288" height_mm="165"/> ! ... ! </connector> ! <connector name="DP-1" connected="true" width_mm="280" height_mm="160"> -! <mode width="1920" height="1200" hz="60" mode_id="1" preferred="true" width_mm="280" height_mm="160"/> -! <mode width="1920" height="1080" hz="60" mode_id="2" used="true" width_mm="278" height_mm="158"/> -! <mode width="1280" height="1024" hz="60" mode_id="3"/> -! <mode width="1024" height="768" hz="60" mode_id="4"/> +! <mode width="1920" height="1200" hz="60" id="1" preferred="true" width_mm="280" height_mm="160"/> +! <mode width="1920" height="1080" hz="60" id="2" used="true" width_mm="278" height_mm="158"/> +! <mode width="1280" height="1024" hz="60" id="3"/> +! <mode width="1024" height="768" hz="60" id="4"/> ! ... ! </connector> ! <connector name="HDMI-A-1" connected="false"/> @@ -89,5 +49,79 @@ in millimeter per connector and if available, also per mode. The values can be used as input to DPI calculations. The currently used mode of the connector is tagged in the report explicitly. -The brightness attribute is reported only if the hardware supports it. +Each of the connectors can be configured a specific mode and +whether it should be enabled or not. This looks like the following: +! <config> +! <connector name="eDP-1" enabled="true" width="1920" height="1080" hz="60" brightness="75"/> +! <connector name="DP-1" enabled="true" mode="2"/> +! </config> + +The resolution can be configured exactly by setting the 'mode' attribute +to one of the 'id' values of the reported modes or by setting the +width/height/hz attributes. In the latter case the driver will take the first +matching mode out of multiple matching modes potentially. + +The brightness value is in percent and takes effect only if supported by +the hardware. + +The maximal physical resolution across all connectors can be restricted by: + +! <config max_width="2560" max_height="1440"> +! </config> + +Note: All larger modes still will be reported, but are marked as unusable + by an additional attribute 'usable' set to false. + +The amount of memory used by the driver for the accounting of its available +buffer space is set by: + +! <config max_framebuffer_memory="64M"> +! </config> + +The default and minimal value is '64M' and suffices for resolutions of at +least '3840x2160'. How much actual memory is used depends on the configured +resolution. + + +Non-discrete usage of connectors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Mirrored usage of connectors can be achieved by moving those connectors into +a sub node called 'merge' of the configuration. For all those connectors, +exactly one and the same framebuffer will be used internally by the driver. +The driver will allocate the framebuffer large enough to accommodate all +non-discrete connectors. If some of the modes of the connectors are smaller, +than only a subset of the content will be visible on those displays. + +! <connectors> +! +! <connector name="eDP-1" ...> <!-- discrete, not mirrored --> +! ... +! </connector> +! <connector name="DP-1" ...> <!.. discrete, not mirrored --> +! ... +! </connector> +! +! <merge name="mirror"> +! <connector name="HDMI-A-1" ...> +! ... +! </connector> +! <connector name="VGA--1" ...> +! ... +! </connector> +! </merge> +! </connectors> + +Note: If connectors are configured as non-discrete, they will also be + reported inside a separate 'merge' node. + +Additionally, the virtual resolution for non-discrete connectors may be +restricted via: + +! <merge name="mirror" width="1024" height="768"> +! ... +! </merge> + +Thereby, the driver will open a Genode capture session to the +GUI multiplexer with this limited dimension. diff --git a/repos/pc/src/driver/framebuffer/intel/pc/fb.c b/repos/pc/src/driver/framebuffer/intel/pc/fb.c deleted file mode 100644 index 240021045e..0000000000 --- a/repos/pc/src/driver/framebuffer/intel/pc/fb.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * \brief Linux kernel framebuffer device support - * \author Stefan Kalkowski - * \date 2021-05-03 - */ - -/* - * Copyright (C) 2021-2023 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/fb.h> -#include <lx_emul/fb.h> - - -int register_framebuffer(struct fb_info * fb_info) -{ - lx_emul_framebuffer_ready(fb_info->screen_base, fb_info->screen_size, - fb_info->var.xres_virtual, fb_info->var.yres_virtual, - fb_info->fix.line_length / - (fb_info->var.bits_per_pixel / 8), fb_info->var.yres); - return 0; -} diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_emul.c b/repos/pc/src/driver/framebuffer/intel/pc/lx_emul.c index 5262c6b112..5100e551bf 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_emul.c +++ b/repos/pc/src/driver/framebuffer/intel/pc/lx_emul.c @@ -105,9 +105,6 @@ int intel_root_gt_init_early(struct drm_i915_private * i915) intel_uc_init_early(>->uc); - /* disable panel self refresh (required for FUJITSU S937/S938) */ - i915->params.enable_psr = 0; - /* * Tells driver that IOMMU, e.g. VT-d, is on, so that scratch page * workaround is applied by Intel display driver: diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_emul/fb.h b/repos/pc/src/driver/framebuffer/intel/pc/lx_emul/fb.h deleted file mode 100644 index 438c52bc41..0000000000 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_emul/fb.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * \brief Lx_emul support to register Linux kernel framebuffer - * \author Stefan Kalkowski - * \date 2021-05-17 - */ - -/* - * Copyright (C) 2021 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#ifndef _LX_EMUL__FB_H_ -#define _LX_EMUL__FB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -void lx_emul_framebuffer_ready(void * base, unsigned long size, - unsigned xres, unsigned yres, - unsigned virtual_width, unsigned virtual_height); - -#ifdef __cplusplus -} -#endif - -#endif /* _LX_EMUL__FB_H_ */ diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h b/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h index 2ae68b1228..47d5676846 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h +++ b/repos/pc/src/driver/framebuffer/intel/pc/lx_i915.h @@ -29,18 +29,33 @@ struct genode_mode { unsigned preferred; unsigned inuse; unsigned id; + char mirror; char name[32]; }; -void lx_emul_i915_report(void * genode_xml); +int lx_emul_i915_blit(unsigned const connector_id, char const may_sleep); +void lx_emul_i915_wakeup(unsigned connector_id); +void lx_emul_i915_report_discrete(void * genode_xml); +void lx_emul_i915_report_non_discrete(void * genode_xml); void lx_emul_i915_hotplug_connector(void); + void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, char const *name, char connected, + char modes, unsigned brightness, unsigned width_mm, unsigned height_mm); void lx_emul_i915_iterate_modes(void *lx_data, void * genode_data); void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *); void lx_emul_i915_connector_config(char * name, struct genode_mode *); int lx_emul_i915_config_done_and_block(void); +void lx_emul_i915_framebuffer_ready(unsigned connector_id, + char const * const connector_name, + void * base, + unsigned long size, + unsigned xres, unsigned yres, + unsigned virtual_width, + unsigned virtual_height, + unsigned mm_width, + unsigned mm_height); #endif /* _LX_I915_H_ */ diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c b/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c index 3d6b3b81bd..75ec819a0d 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c +++ b/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c @@ -28,13 +28,19 @@ enum { MAX_BRIGHTNESS = 100, INVALID_BRIGHTNESS = MAX_BRIGHTNESS + 1 }; - struct task_struct * lx_user_task = NULL; -static struct drm_client_dev * dev_client = NULL; + struct task_struct * lx_user_task = NULL; +static struct task_struct * lx_update_task = NULL; +static struct drm_client_dev * dev_client = NULL; + + +enum { CONNECTOR_ID_MIRROR = 15 }; +static bool mirrored [16] = { }; static int user_register_fb(struct drm_client_dev const * const dev, struct fb_info * const info, - struct drm_mode_fb_cmd2 const * const dumb_fb); + struct drm_mode_fb_cmd2 const * const dumb_fb, + unsigned width_mm, unsigned height_mm); static int user_attach_fb_to_crtc(struct drm_client_dev * const dev, @@ -84,32 +90,32 @@ static inline bool fb_smaller_mode(struct fb_info const * const info, /* - * Heuristic to calculate max resolution across all connectors + * Heuristic to calculate mixed resolution across all mirrored connectors */ -static void preferred_mode(struct drm_device const * const dev, - struct drm_display_mode * const prefer, - struct drm_display_mode * const min_mode) +static void mirror_heuristic(struct drm_device const * const dev, + struct drm_display_mode * const virtual, + struct drm_display_mode * const compound, + struct drm_display_mode * const min_mode) { struct drm_connector *connector = NULL; struct drm_display_mode *mode = NULL; - unsigned connector_usable = 0; - struct drm_display_mode max_enforcement = { }; struct drm_connector_list_iter conn_iter; /* read Genode's config per connector */ drm_connector_list_iter_begin(dev, &conn_iter); drm_client_for_each_connector_iter(connector, &conn_iter) { struct drm_display_mode smallest = { .hdisplay = ~0, .vdisplay = ~0 }; - struct genode_mode conf_mode = { .enabled = 1 }; + struct drm_display_mode usable = { }; + struct genode_mode conf_mode = { }; unsigned mode_id = 0; /* check for connector configuration on Genode side */ lx_emul_i915_connector_config(connector->name, &conf_mode); - if (!conf_mode.enabled) + if (!conf_mode.enabled || !conf_mode.mirror) continue; - /* look for smallest possible mode or if a specific mode is forced */ + /* look for smallest possible mode or if a specific mode is specified */ list_for_each_entry(mode, &connector->modes, head) { mode_id ++; @@ -121,21 +127,22 @@ static void preferred_mode(struct drm_device const * const dev, smallest.vdisplay = mode->vdisplay; } - if (!conf_mode.id) - continue; + /* maximal resolution enforcement */ + if (conf_mode.max_width && conf_mode.max_height) { + if (conf_smaller_max_mode(&conf_mode, mode)) + continue; + } - if (!mode || conf_mode.id != mode_id) - continue; + if (!usable.hdisplay && !usable.vdisplay) + usable = *mode; - conf_mode.width = mode->hdisplay; - conf_mode.height = mode->vdisplay; - - break; + if (conf_mode.id == mode_id) { + conf_mode.width = mode->hdisplay; + conf_mode.height = mode->vdisplay; + break; + } } - if (mode_id) - connector_usable ++; - /* * If at least on mode is available, store smallest mode if it * is larger than min_mode of other connectors @@ -144,6 +151,7 @@ static void preferred_mode(struct drm_device const * const dev, *min_mode = smallest; if (conf_mode.force_width && conf_mode.force_height) { + /* * Even so the force_* mode is selected, a configured mode for * a connector is considered, effectively the framebuffer content @@ -155,24 +163,23 @@ static void preferred_mode(struct drm_device const * const dev, } /* enforce the force mode */ - conf_mode.width = conf_mode.force_width; - conf_mode.height = conf_mode.force_height; + virtual->hdisplay = conf_mode.force_width; + virtual->vdisplay = conf_mode.force_height; } - /* maximal resolution enforcement */ - if (conf_mode.max_width && conf_mode.max_height) { - max_enforcement.hdisplay = conf_mode.max_width; - max_enforcement.vdisplay = conf_mode.max_height; - if (conf_smaller_max_mode(&conf_mode, prefer)) - continue; - } - - if (!conf_mode.width || !conf_mode.height) - continue; - - if (conf_larger_mode(&conf_mode, prefer)) { - prefer->hdisplay = conf_mode.width; - prefer->vdisplay = conf_mode.height; + /* compound calculation */ + if (conf_mode.width && conf_mode.height) { + if (conf_mode.width > compound->hdisplay) + compound->hdisplay = conf_mode.width; + if (conf_mode.height > compound->vdisplay) + compound->vdisplay = conf_mode.height; + } else { + if (usable.hdisplay && usable.vdisplay) { + if (usable.hdisplay > compound->hdisplay) + compound->hdisplay = usable.hdisplay; + if (usable.vdisplay > compound->vdisplay) + compound->vdisplay = usable.vdisplay; + } } } drm_connector_list_iter_end(&conn_iter); @@ -181,36 +188,9 @@ static void preferred_mode(struct drm_device const * const dev, if (!min_mode->hdisplay || !min_mode->vdisplay) return; - /* we got a preferred resolution */ - if (prefer->hdisplay && prefer->vdisplay) - return; - - /* if too large or nothing configured by Genode's config */ - drm_connector_list_iter_begin(dev, &conn_iter); - drm_client_for_each_connector_iter(connector, &conn_iter) { - list_for_each_entry(mode, &connector->modes, head) { - if (!mode) - continue; - - if (mode_larger(min_mode, mode)) - continue; - - if (max_enforcement.hdisplay && max_enforcement.vdisplay) { - if (mode_larger(mode, &max_enforcement)) - continue; - } - - if (mode_larger(mode, prefer)) { - prefer->hdisplay = mode->hdisplay; - prefer->vdisplay = mode->vdisplay; - } - } - } - drm_connector_list_iter_end(&conn_iter); - - /* handle the "never should happen case" gracefully */ - if (!prefer->hdisplay || !prefer->vdisplay) - *prefer = *min_mode; + /* if no mirrored connectors are enabled, compound is the minimal mode */ + if (!compound->hdisplay || !compound->vdisplay) + *compound = *min_mode; } @@ -248,74 +228,376 @@ static unsigned get_brightness(struct drm_connector * const connector, return ret * MAX_BRIGHTNESS / panel->backlight.device->props.max_brightness; } -static struct drm_mode_fb_cmd2 dumb_fb = {}; + +static struct drm_mode_fb_cmd2 *mirror_fb_cmd; + + +static struct drm_framebuffer * lookup_framebuffer(struct drm_crtc *crtc, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_atomic_state *state; + struct drm_plane_state *plane; + struct drm_crtc_state *crtc_state; + + state = drm_atomic_state_alloc(crtc->dev); + if (!state) + return NULL; + + state->acquire_ctx = ctx; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + drm_atomic_state_put(state); + return NULL; + } + + plane = drm_atomic_get_plane_state(state, crtc->primary); + + drm_atomic_state_put(state); + + return plane ? plane->fb : NULL; +} + + +enum { MAX_FBS = 8 }; + + +/* own data structure for tracking dumb buffers, e.g. GEM handles, flags, vma */ +struct gem_dumb { + struct drm_mode_create_dumb fb_dumb; + struct drm_mode_fb_cmd2 fb_cmd; + struct i915_vma * vma; + unsigned long flags; +}; + + +/* allocator and lookup helper for our own meta data */ +static bool _meta_data(struct drm_client_dev const * const dev, + struct drm_framebuffer const * const fb, + struct drm_mode_create_dumb ** fb_dumb, /* out */ + struct drm_mode_fb_cmd2 ** fb_cmd, /* out */ + struct gem_dumb ** gem_dumb) /* out */ +{ + static struct gem_dumb gem_dumb_list [MAX_FBS] = { }; + + struct gem_dumb * free_slot = NULL; + + if (!dev) + return false; + + for (unsigned i = 0; i < MAX_FBS; i++) { + struct gem_dumb * slot = &gem_dumb_list[i]; + struct drm_framebuffer * cmp = NULL; + + if (!slot->fb_cmd.fb_id) { + if (!free_slot) + free_slot = slot; + + continue; + } + + if (!fb) + continue; + + cmp = drm_framebuffer_lookup(dev->dev, dev->file, + slot->fb_cmd.fb_id); + + if (cmp) + drm_framebuffer_put(cmp); + + /* lookup case */ + if (cmp == fb) { + if (fb_dumb) *fb_dumb = &slot->fb_dumb; + if (fb_cmd) *fb_cmd = &slot->fb_cmd; + if (gem_dumb) *gem_dumb = slot; + return true; + } + } + + /* allocate case */ + if (free_slot) { + if (fb_dumb) *fb_dumb = &free_slot->fb_dumb; + if (fb_cmd) *fb_cmd = &free_slot->fb_cmd; + if (gem_dumb) *gem_dumb = free_slot; + } + + return !!free_slot; +} + + +static bool dumb_meta(struct drm_client_dev const * const dev, + struct drm_framebuffer const * const fb, + struct drm_mode_create_dumb ** fb_dumb, /* out */ + struct drm_mode_fb_cmd2 ** fb_cmd) /* out */ +{ + return _meta_data(dev, fb, fb_dumb, fb_cmd, NULL); +} + + +static bool dumb_gem(struct drm_client_dev const * const dev, + struct drm_framebuffer const * const fb, + struct gem_dumb ** gem_dumb) /* out */ +{ + return _meta_data(dev, fb, NULL, NULL, gem_dumb); +} + + +static void destroy_fb(struct drm_client_dev * const dev, + struct drm_mode_create_dumb * const gem_dumb, + struct drm_mode_fb_cmd2 * const dumb_fb) +{ + int result = drm_mode_rmfb(dev->dev, dumb_fb->fb_id, dev->file); + + if (result) { + drm_err(dev->dev, "%s: failed to remove framebuffer %d\n", + __func__, result); + } + + result = drm_mode_destroy_dumb(dev->dev, gem_dumb->handle, dev->file); + + if (result) { + drm_err(dev->dev, "%s: failed to destroy framebuffer %d\n", + __func__, result); + } + + /* frees the entry in _meta_data allocator */ + memset(gem_dumb, 0, sizeof(*gem_dumb)); + memset(dumb_fb, 0, sizeof(*dumb_fb)); +} + + +static int kernel_register_fb(struct fb_info const * const fb_info, + unsigned const width_mm, + unsigned const height_mm) +{ + lx_emul_i915_framebuffer_ready(fb_info->node, + fb_info->par, + fb_info->screen_base, + fb_info->screen_size, + fb_info->var.xres_virtual, + fb_info->var.yres_virtual, + fb_info->fix.line_length / + (fb_info->var.bits_per_pixel / 8), + fb_info->var.yres, + width_mm, height_mm); + + return 0; +} + + +struct drm_mode_fb_cmd2 fb_of_screen(struct drm_client_dev * const dev, + struct genode_mode const * const conf_mode, + struct fb_info * const fb_info, + struct drm_mode_fb_cmd2 const * const dumb_fb_mirror, + struct drm_display_mode const * const mode, + struct drm_framebuffer * fb, + struct drm_connector const * const connector) +{ + int err = -EINVAL; + struct drm_mode_create_dumb *gem_dumb = NULL; + struct drm_mode_fb_cmd2 *fb_cmd = NULL; + struct drm_framebuffer *fb_mirror = drm_framebuffer_lookup(dev->dev, + dev->file, + dumb_fb_mirror->fb_id); + + /* during hotplug the mirrored fb is used for non mirrored connectors temporarily */ + if (fb && !conf_mode->mirror && fb == fb_mirror) { + fb = NULL; + } + + if (!dumb_meta(dev, fb, &gem_dumb, &fb_cmd) || !gem_dumb || !fb_cmd) { + struct drm_mode_fb_cmd2 invalid = { }; + printk("could not create dumb buffer\n"); + return invalid; + } + + /* notify genode side about switch from connector specific fb to mirror fb */ + if (fb && conf_mode->mirror && fb != fb_mirror) { + struct fb_info info = {}; + + info.var.bits_per_pixel = 32; + info.node = connector->index; + info.par = connector->name; + + kernel_register_fb(&info, mode->width_mm, mode->height_mm); + + destroy_fb(dev, gem_dumb, fb_cmd); + } + + if (fb_mirror) + drm_framebuffer_put(fb_mirror); + + fb_info->node = connector->index; + + if (!conf_mode->enabled) { + struct drm_mode_fb_cmd2 invalid = { }; + return invalid; + } + + if (conf_mode->mirror) + return *dumb_fb_mirror; + + err = check_resize_fb(dev, gem_dumb, fb_cmd, + mode->hdisplay, mode->vdisplay); + + if (err) { + printk("setting up framebuffer of %ux%u failed - error=%d\n", + mode->hdisplay, mode->vdisplay, err); + return *dumb_fb_mirror; + } + + fb_info->var.xres = mode->hdisplay; + fb_info->var.yres = mode->vdisplay; + fb_info->var.xres_virtual = mode->hdisplay; + fb_info->var.yres_virtual = mode->vdisplay; + + return *fb_cmd; +} + + +static void close_unused_captures(struct drm_client_dev * const dev) +{ + /* report disconnected connectors to close capture connections */ + struct drm_connector_list_iter conn_iter; + struct drm_connector *connector = NULL; + bool mirror_in_use = false; + + drm_connector_list_iter_begin(dev->dev, &conn_iter); + drm_client_for_each_connector_iter(connector, &conn_iter) { + bool unused = connector->status != connector_status_connected; + + if (!unused) { + unused = !connector->state || !connector->state->crtc; + + if (!unused) { + struct drm_modeset_acquire_ctx ctx; + void * fb = NULL; + int err = -1; + + DRM_MODESET_LOCK_ALL_BEGIN(dev->dev, ctx, + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, + err); + + fb = lookup_framebuffer(connector->state->crtc, &ctx); + + DRM_MODESET_LOCK_ALL_END(dev->dev, ctx, err); + + unused = !fb; + } + } + + if (unused) { + struct fb_info fb_info = {}; + + if (connector->index < sizeof(mirrored) / sizeof(*mirrored)) + mirrored[connector->index] = false; + + fb_info.par = connector->name; + fb_info.var.bits_per_pixel = 32; + fb_info.node = connector->index; + + kernel_register_fb(&fb_info, 0, 0); + } + } + drm_connector_list_iter_end(&conn_iter); + + for (unsigned i = 0; i < sizeof(mirrored) / sizeof(mirrored[0]); i++) { + if (!mirrored[i]) + continue; + + mirror_in_use = true; + break; + } + + if (!mirror_in_use) { + struct fb_info fb_info = {}; + + fb_info.par = "mirror_capture"; + fb_info.var.bits_per_pixel = 32; + fb_info.node = CONNECTOR_ID_MIRROR; + + kernel_register_fb(&fb_info, 0, 0); + } +} + static bool reconfigure(struct drm_client_dev * const dev) { - static struct drm_mode_create_dumb gem_dumb = {}; + static struct drm_mode_create_dumb *gem_mirror = NULL; - struct drm_display_mode mode_preferred = {}; - struct drm_display_mode mode_minimum = {}; - struct drm_display_mode framebuffer = {}; - struct drm_mode_modeinfo user_mode = {}; - struct drm_display_mode *mode = NULL; - struct drm_mode_set *mode_set = NULL; - struct fb_info report_fb_info = {}; - bool report_fb = false; - bool retry = false; + struct drm_display_mode mirror_force = {}; + struct drm_display_mode mirror_compound = {}; + struct drm_display_mode mirror_minimum = {}; + struct drm_display_mode mirror_fb = {}; + struct drm_mode_modeinfo user_mode = {}; + struct drm_display_mode * mode = NULL; + struct drm_mode_set * mode_set = NULL; + struct fb_info info = {}; + bool retry = false; + struct { + struct fb_info info; + unsigned width_mm; + unsigned height_mm; + bool report; + } mirror = { { }, 0, 0, false }; - if (!dev || !dev->dev) + if (!gem_mirror) { + /* request storage for gem_mirror and mirror_fb_cmd */ + dumb_meta(dev, NULL, &gem_mirror, &mirror_fb_cmd); + } + + if (!dev || !dev->dev || !gem_mirror || !mirror_fb_cmd) return false; - preferred_mode(dev->dev, &mode_preferred, &mode_minimum); + mirror_heuristic(dev->dev, &mirror_force, &mirror_compound, + &mirror_minimum); - if (!mode_minimum.hdisplay || !mode_minimum.vdisplay) { + if (!mirror_minimum.hdisplay || !mirror_minimum.vdisplay) { /* no valid modes on any connector on early boot */ - if (!dumb_fb.fb_id) + if (!mirror_fb_cmd->fb_id) return false; /* valid connectors but all are disabled by config */ - mode_minimum.hdisplay = dumb_fb.width; - mode_minimum.vdisplay = dumb_fb.height; - mode_preferred = mode_minimum; + mirror_minimum.hdisplay = mirror_fb_cmd->width; + mirror_minimum.vdisplay = mirror_fb_cmd->height; + mirror_compound = mirror_minimum; } - if (mode_larger(&mode_preferred, &mode_minimum)) - framebuffer = mode_preferred; + if (mode_larger(&mirror_compound, &mirror_minimum)) + mirror_fb = mirror_compound; else - framebuffer = mode_minimum; + mirror_fb = mirror_minimum; { int const err = check_resize_fb(dev, - &gem_dumb, - &dumb_fb, - framebuffer.hdisplay, - framebuffer.vdisplay); + gem_mirror, + mirror_fb_cmd, + mirror_fb.hdisplay, + mirror_fb.vdisplay); if (err) { - printk("setting up framebuffer of %ux%u failed - error=%d\n", - framebuffer.hdisplay, framebuffer.vdisplay, err); + printk("setting up mirrored framebuffer of %ux%u failed - error=%d\n", + mirror_fb.hdisplay, mirror_fb.vdisplay, err); return true; } } /* without fb handle created by check_resize_fb we can't proceed */ - if (!dumb_fb.fb_id) + if (!mirror_fb_cmd->fb_id) return retry; - /* prepare fb info for register_framebuffer() evaluated by Genode side */ - report_fb_info.var.xres = framebuffer.hdisplay; - report_fb_info.var.yres = framebuffer.vdisplay; - report_fb_info.var.xres_virtual = mode_preferred.hdisplay; - report_fb_info.var.yres_virtual = mode_preferred.vdisplay; + /* prepare fb info for kernel_register_fb() evaluated by Genode side */ + info.var.xres = mirror_fb.hdisplay; + info.var.yres = mirror_fb.vdisplay; + info.var.xres_virtual = mirror_force.hdisplay ? : mirror_compound.hdisplay; + info.var.yres_virtual = mirror_force.vdisplay ? : mirror_compound.vdisplay; drm_client_for_each_modeset(mode_set, dev) { - struct drm_display_mode *mode_match = NULL; - unsigned mode_id = 0; - struct drm_connector *connector = NULL; - - struct genode_mode conf_mode = { }; + struct drm_display_mode * mode_match = NULL; + unsigned mode_id = 0; + struct drm_connector * connector = NULL; + struct genode_mode conf_mode = {}; if (!mode_set->connectors || !*mode_set->connectors) continue; @@ -335,8 +617,8 @@ static bool reconfigure(struct drm_client_dev * const dev) if (!mode) continue; - /* allocated framebuffer smaller than mode can't be used */ - if (fb_smaller_mode(&report_fb_info, mode)) + /* allocated mirrored framebufer smaller than mode can't be used */ + if (conf_mode.mirror && fb_smaller_mode(&info, mode)) continue; /* use mode id if configured and matches exactly */ @@ -345,13 +627,13 @@ static bool reconfigure(struct drm_client_dev * const dev) continue; mode_match = mode; + break; } /* if invalid, mode is configured in second loop below */ - if (conf_mode.width == 0 || conf_mode.height == 0) { + if (conf_mode.width == 0 || conf_mode.height == 0) break; - } /* no exact match by mode id -> try matching by size */ if ((mode->hdisplay != conf_mode.width) || @@ -370,22 +652,42 @@ static bool reconfigure(struct drm_client_dev * const dev) mode_match = mode; } + /* track whether connector is used mirrored or discrete */ + if (connector->index < sizeof(mirrored) / sizeof(*mirrored)) + mirrored[connector->index] = conf_mode.enabled && conf_mode.mirror; + /* apply new mode */ mode_id = 0; list_for_each_entry(mode, &connector->modes, head) { - int err = -1; - bool no_match = false; + struct fb_info fb_info = info; + int err = -1; + bool no_match = false; + struct drm_mode_fb_cmd2 fb_cmd = *mirror_fb_cmd; mode_id ++; if (!mode) continue; + /* use first mode for non mirrored connector in case of no match */ + if (!mode_match && !conf_mode.mirror) { + + struct drm_display_mode max = { .hdisplay = conf_mode.max_width, + .vdisplay = conf_mode.max_height }; + + if (conf_mode.max_width && conf_mode.max_height) { + if (conf_larger_mode(&conf_mode, &max)) + continue; + } + + mode_match = mode; + } + /* no matching mode ? */ if (!mode_match) { /* fb smaller than mode is denied by drm_mode_setcrtc */ - if (fb_smaller_mode(&report_fb_info, mode)) + if (conf_mode.enabled && fb_smaller_mode(&fb_info, mode)) continue; /* use first smaller mode */ @@ -398,19 +700,34 @@ static bool reconfigure(struct drm_client_dev * const dev) if (mode_match != mode) continue; - /* convert kernel internal mode to user mode expectecd via ioctl */ + /* Genode side prefer to have a name for the connector */ + fb_info.par = connector->name; + + { + struct drm_modeset_acquire_ctx ctx; + struct drm_framebuffer *fb = NULL; + + DRM_MODESET_LOCK_ALL_BEGIN(dev->dev, ctx, + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, + err); + + fb = lookup_framebuffer(mode_set->crtc, &ctx); + + DRM_MODESET_LOCK_ALL_END(dev->dev, ctx, err); + + /* check for mirrored fb or specific one for connector */ + fb_cmd = fb_of_screen(dev, &conf_mode, &fb_info, mirror_fb_cmd, + mode, fb, connector); + } + + /* convert kernel internal mode to user mode expected via ioctl */ drm_mode_convert_to_umode(&user_mode, mode); /* assign fb & connector to crtc with specified mode */ err = user_attach_fb_to_crtc(dev, connector, mode_set->crtc, - &user_mode, dumb_fb.fb_id, + &user_mode, fb_cmd.fb_id, conf_mode.enabled); - if (err) - retry = true; - else - report_fb = true; - /* set brightness */ if (!err && conf_mode.enabled && conf_mode.brightness <= MAX_BRIGHTNESS) { drm_modeset_lock(&dev->dev->mode_config.connection_mutex, NULL); @@ -419,15 +736,28 @@ static bool reconfigure(struct drm_client_dev * const dev) drm_modeset_unlock(&dev->dev->mode_config.connection_mutex); } + if (!retry) + retry = !!err; + + if (!err && conf_mode.enabled && conf_mode.mirror && !mirror.report) { + /* use fb_info of first mirrored screen */ + mirror.report = true; + mirror.width_mm = 0; + mirror.height_mm = 0; + mirror.info = fb_info; + mirror.info.node = CONNECTOR_ID_MIRROR; + } + /* diagnostics */ - printk("%10s: %s name='%9s' id=%u%s mode=%4ux%4u@%u%s fb=%4ux%4u%s", + printk("%10s: %s name='%9s' id=%u%s%s mode=%4ux%4u@%u%s fb=%4ux%4u%s", connector->name ? connector->name : "unnamed", conf_mode.enabled ? " enable" : "disable", mode->name ? mode->name : "noname", - mode_id, mode_id < 10 ? " " : "", mode->hdisplay, - mode->vdisplay, drm_mode_vrefresh(mode), + mode_id, mode_id < 10 ? " " : "", + conf_mode.mirror ? " mirror " : " discrete", + mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode), drm_mode_vrefresh(mode) < 100 ? " ": "", - framebuffer.hdisplay, framebuffer.vdisplay, + fb_info.var.xres, fb_info.var.yres, (err || no_match) ? "" : "\n"); if (no_match) @@ -437,12 +767,24 @@ static bool reconfigure(struct drm_client_dev * const dev) if (err) printk(" - failed, error=%d\n", err); + if (!err && !conf_mode.mirror && conf_mode.enabled) { + unsigned width_mm = mode->width_mm ? : connector->display_info.width_mm; + unsigned height_mm = mode->height_mm ? : connector->display_info.height_mm; + + user_register_fb(dev, &fb_info, &fb_cmd, width_mm, height_mm); + } + break; } } - if (report_fb) - user_register_fb(dev, &report_fb_info, &dumb_fb); + if (mirror.report) { + mirror.info.par = "mirror_capture"; + user_register_fb(dev, &mirror.info, mirror_fb_cmd, mirror.width_mm, + mirror.height_mm); + } + + close_unused_captures(dev); return retry; } @@ -473,26 +815,208 @@ static int configure_connectors(void * data) } -void lx_user_init(void) +static void mark_framebuffer_dirty(struct drm_framebuffer * const fb) { - int pid = kernel_thread(configure_connectors, NULL, "lx_user", - CLONE_FS | CLONE_FILES); - lx_user_task = find_task_by_pid_ns(pid, NULL);; + struct drm_clip_rect *clips = NULL; + struct drm_mode_fb_dirty_cmd r = { }; + + unsigned flags = 0; + int num_clips = 0; + int ret = 0; + + if (!dev_client) + return; + + if (!fb || !fb->funcs || !fb->funcs->dirty) + return; + + ret = fb->funcs->dirty(fb, dev_client->file, flags, r.color, clips, + num_clips); + + if (ret) + printk("%s failed %d\n", __func__, ret); } -void lx_emul_i915_report(void * genode_data) +/* track per connector (16 max) the empty capture attempts before stopping */ +enum { CAPTURE_RATE_MS = 10, ATTEMPTS_BEFORE_STOP = 7 }; +static unsigned unchanged[16] = { }; + + +void lx_emul_i915_wakeup(unsigned const connector_id) +{ + bool const valid_id = connector_id < sizeof(unchanged) / sizeof(*unchanged); + + if (!valid_id) { + printk("%s: connector id invalid %d\n", __func__, connector_id); + return; + } + + unchanged[connector_id] = 0; + + /* wake potential sleeping update task */ + lx_emul_task_unblock(lx_update_task); +} + + +static int update_content(void *) +{ + while (true) { + struct drm_connector_list_iter conn_iter; + struct drm_connector *connector = NULL; + struct drm_device const *dev = dev_client->dev; + bool block_task = true; + bool mirror_run = false; + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_client_for_each_connector_iter(connector, &conn_iter) { + + struct drm_modeset_acquire_ctx ctx; + struct drm_framebuffer *fb = NULL; + + int err = -1; + bool may_sleep = false; + unsigned index = connector->index; + + if (connector->status != connector_status_connected) + continue; + + if (connector->index >= sizeof(unchanged) / sizeof(*unchanged)) { + printk("%s: connector id invalid %d\n", __func__, index); + index = CONNECTOR_ID_MIRROR; /* should never happen case */ + } + + if (mirrored[index] && mirror_run) + continue; + + if (mirrored[index]) { + mirror_run = true; + index = CONNECTOR_ID_MIRROR; + } + + unchanged[index] ++; + + may_sleep = unchanged[index] >= ATTEMPTS_BEFORE_STOP; + + if (!lx_emul_i915_blit(index, may_sleep)) { + if (!may_sleep) + block_task = false; + + continue; + } + + block_task = false; + + unchanged[index] = 0; + + if (!connector->state || !connector->state->crtc) + continue; + + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, + err); + + fb = lookup_framebuffer(connector->state->crtc, &ctx); + + DRM_MODESET_LOCK_ALL_END(dev, ctx, err); + + if (fb) + mark_framebuffer_dirty(fb); + } + drm_connector_list_iter_end(&conn_iter); + + if (block_task) + lx_emul_task_schedule(true /* block task */); + else + /* schedule_timeout(jiffes) or hrtimer or msleep */ + msleep(CAPTURE_RATE_MS); + } + + return 0; +} + + +void lx_user_init(void) +{ + int pid = kernel_thread(configure_connectors, NULL, "lx_user", + CLONE_FS | CLONE_FILES); + int pid2 = kernel_thread(update_content, NULL, "lx_update", + CLONE_FS | CLONE_FILES); + + lx_user_task = find_task_by_pid_ns(pid , NULL); + lx_update_task = find_task_by_pid_ns(pid2, NULL); +} + + +static bool mirrored_fb(struct drm_client_dev * client, + struct drm_crtc const * const crtc) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_framebuffer const * fb = NULL; + struct drm_framebuffer const * fb_mirror = NULL; + int result = -1; + + if (mirror_fb_cmd && mirror_fb_cmd->fb_id) + fb_mirror = drm_framebuffer_lookup(client->dev, client->file, + mirror_fb_cmd->fb_id); + + if (!fb_mirror || !crtc) + return false; + + if (fb_mirror) + drm_framebuffer_put(fb_mirror); + + DRM_MODESET_LOCK_ALL_BEGIN(client->dev, ctx, + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, + result); + + fb = lookup_framebuffer(crtc, &ctx); + + DRM_MODESET_LOCK_ALL_END(client->dev, ctx, result); + + return fb && fb_mirror == fb; +} + + +static void _report_connectors(void * genode_data, bool const discrete) { struct drm_connector_list_iter conn_iter; struct drm_device const *dev = dev_client->dev; struct drm_connector *connector = NULL; + struct drm_display_mode *mode = NULL; + bool has_modes = false; drm_connector_list_iter_begin(dev, &conn_iter); drm_client_for_each_connector_iter(connector, &conn_iter) { + + bool mirror = connector->state && connector->state->crtc && + mirrored_fb(dev_client, connector->state->crtc); + + if (!mirror && (!connector->state || !connector->state->crtc)) { + struct genode_mode conf_mode = { }; + + /* check for connector configuration on Genode side */ + lx_emul_i915_connector_config(connector->name, &conf_mode); + + mirror = conf_mode.mirror; + } + + if ((discrete && mirror) || (!discrete && !mirror)) + continue; + + list_for_each_entry(mode, &connector->modes, head) { + + if (!mode) + continue; + + has_modes = true; + } + lx_emul_i915_report_connector(connector, genode_data, connector->name, - connector->status != connector_status_disconnected, + connector->status == connector_status_connected, + has_modes, get_brightness(connector, INVALID_BRIGHTNESS), connector->display_info.width_mm, connector->display_info.height_mm); @@ -501,6 +1025,18 @@ void lx_emul_i915_report(void * genode_data) } +void lx_emul_i915_report_discrete(void * genode_data) +{ + _report_connectors(genode_data, true /* discrete */); +} + + +void lx_emul_i915_report_non_discrete(void * genode_data) +{ + _report_connectors(genode_data, false /* non discrete */); +} + + void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data) { struct drm_connector *connector = lx_data; @@ -535,6 +1071,8 @@ void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data) bool const inuse = connector->state && connector->state->crtc && connector->state->crtc->state && drm_mode_equal(&connector->state->crtc->state->mode, mode); + bool const mirror = connector->state && connector->state->crtc && + mirrored_fb(dev_client, connector->state->crtc); struct genode_mode conf_mode = { .width = mode->hdisplay, @@ -544,6 +1082,7 @@ void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data) .preferred = mode->type & (DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DEFAULT), .inuse = inuse, + .mirror = mirror, .hz = drm_mode_vrefresh(mode), .id = mode_id, .enabled = !max_mode || @@ -575,12 +1114,13 @@ void i915_switcheroo_unregister(struct drm_i915_private *i915) static int fb_client_hotplug(struct drm_client_dev *client) { - struct drm_mode_set *modeset = NULL; - struct drm_framebuffer *fb = NULL; - int result = -EINVAL; + struct drm_mode_set *modeset = NULL; + struct drm_framebuffer *fb_mirror = NULL; + int result = -EINVAL; - if (dumb_fb.fb_id) - fb = drm_framebuffer_lookup(client->dev, client->file, dumb_fb.fb_id); + if (mirror_fb_cmd && mirror_fb_cmd->fb_id) + fb_mirror = drm_framebuffer_lookup(client->dev, client->file, + mirror_fb_cmd->fb_id); /* * Triggers set up of display pipelines for connectors and @@ -594,23 +1134,83 @@ static int fb_client_hotplug(struct drm_client_dev *client) } /* - * (Re-)assign framebuffer to modeset (lost due to modeset_probe) and - * commit the change. + * (Re-)assign mirrored framebuffer to modeset (lost due to modeset_probe) + * and commit the change. */ - if (fb) { + if (fb_mirror) { + struct drm_framebuffer * free_fbs[MAX_FBS] = { }; + struct drm_modeset_acquire_ctx ctx; + + bool mode_too_large = false; + unsigned fb_count = 0; + + DRM_MODESET_LOCK_ALL_BEGIN(client->dev, ctx, + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, + result); mutex_lock(&client->modeset_mutex); drm_client_for_each_modeset(modeset, client) { - if (!modeset || !modeset->num_connectors) + struct drm_connector *connector = NULL; + struct drm_framebuffer *fb = NULL; + + if (!modeset) continue; - modeset->fb = fb; + if (modeset->crtc) + fb = lookup_framebuffer(modeset->crtc, &ctx); + + if (!mode_too_large && fb && modeset->mode && + (modeset->mode->hdisplay > fb->width || + modeset->mode->vdisplay > fb->height)) + mode_too_large = true; + + if (!modeset->num_connectors || !modeset->connectors || !*modeset->connectors) { + + struct drm_mode_fb_cmd2 *fb_cmd = NULL; + struct drm_mode_create_dumb *fb_dumb = NULL; + + if (!fb || fb == fb_mirror) + continue; + + if (!dumb_meta(client, fb, &fb_dumb, &fb_cmd) || !fb_dumb || !fb_cmd) + continue; + + if (fb_count >= MAX_FBS) { + printk("leaking framebuffer memory\n"); + continue; + } + + free_fbs[fb_count++] = fb; + + continue; + } + + /* set connector */ + connector = *modeset->connectors; + + modeset->fb = fb ? fb : fb_mirror; } mutex_unlock(&client->modeset_mutex); + DRM_MODESET_LOCK_ALL_END(client->dev, ctx, result); + + for (unsigned i = 0; i < fb_count; i++) { + struct drm_mode_fb_cmd2 *fb_cmd = NULL; + struct drm_mode_create_dumb *fb_dumb = NULL; + + if (!free_fbs[i]) + continue; + + if (!dumb_meta(client, free_fbs[i], &fb_dumb, &fb_cmd) || !fb_dumb || !fb_cmd) + continue; + + destroy_fb(client, fb_dumb, fb_cmd); + + free_fbs[i] = NULL; + } /* triggers disablement of encoders attached to disconnected ports */ result = drm_client_modeset_commit(client); - if (result) { + if (result && !(mode_too_large && result == -ENOSPC)) { printk("%s: error on modeset commit %d%s\n", __func__, result, (result == -ENOSPC) ? " - ENOSPC" : " - unknown error"); } @@ -619,8 +1219,8 @@ static int fb_client_hotplug(struct drm_client_dev *client) /* notify Genode side */ lx_emul_i915_hotplug_connector(); - if (fb) - drm_framebuffer_put(fb); + if (fb_mirror) + drm_framebuffer_put(fb_mirror); return 0; } @@ -701,15 +1301,16 @@ int user_attach_fb_to_crtc(struct drm_client_dev * const dev, static int user_register_fb(struct drm_client_dev const * const dev, struct fb_info * const info, - struct drm_mode_fb_cmd2 const * const dumb_fb) + struct drm_mode_fb_cmd2 const * const dumb_fb, + unsigned const width_mm, + unsigned const height_mm) { intel_wakeref_t wakeref; int result = -EINVAL; struct i915_gtt_view const view = { .type = I915_GTT_VIEW_NORMAL }; - static struct i915_vma *vma = NULL; - static unsigned long flags = 0; void __iomem *vaddr = NULL; + struct gem_dumb *gem_dumb = NULL; struct drm_i915_private *dev_priv = to_i915(dev->dev); struct drm_framebuffer *fb = drm_framebuffer_lookup(dev->dev, dev->file, @@ -720,49 +1321,61 @@ static int user_register_fb(struct drm_client_dev const * const dev, return -ENODEV; } - wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - - if (vma) { - intel_unpin_fb_vma(vma, flags); - - vma = NULL; - flags = 0; + if (!dumb_gem(dev, fb, &gem_dumb) || !gem_dumb) { + printk("%s:%u error looking up fb and vma\n", __func__, __LINE__); + return -ENODEV; } + if (gem_dumb->vma) { + intel_unpin_fb_vma(gem_dumb->vma, gem_dumb->flags); + + gem_dumb->vma = NULL; + gem_dumb->flags = 0; + } + + wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); + /* Pin the GGTT vma for our access via info->screen_base. * This also validates that any existing fb inherited from the * BIOS is suitable for own access. */ - vma = intel_pin_and_fence_fb_obj(fb, false /* phys_cursor */, - &view, false /* use fences */, - &flags); + gem_dumb->vma = intel_pin_and_fence_fb_obj(fb, false /* phys_cursor */, + &view, false /* use fences */, + &gem_dumb->flags); - if (IS_ERR(vma)) { + if (IS_ERR(gem_dumb->vma)) { intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - result = PTR_ERR(vma); - printk("%s:%u error setting vma %d\n", __func__, __LINE__, result); + result = PTR_ERR(gem_dumb->vma); + + printk("%s:%u error setting vma %d\n", __func__, __LINE__, result); + + gem_dumb->vma = NULL; return result; } - vaddr = i915_vma_pin_iomap(vma); + vaddr = i915_vma_pin_iomap(gem_dumb->vma); if (IS_ERR(vaddr)) { intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); result = PTR_ERR(vaddr); printk("%s:%u error pin iomap %d\n", __func__, __LINE__, result); + + intel_unpin_fb_vma(gem_dumb->vma, gem_dumb->flags); + gem_dumb->vma = NULL; + return result; } - /* fill framebuffer info for register_framebuffer */ + /* fill framebuffer info for kernel_register_fb */ info->screen_base = vaddr; - info->screen_size = vma->size; + info->screen_size = gem_dumb->vma->size; info->fix.line_length = fb->pitches[0]; info->var.bits_per_pixel = drm_format_info_bpp(fb->format, 0); intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - register_framebuffer(info); + kernel_register_fb(info, width_mm, height_mm); if (fb) drm_framebuffer_put(fb); @@ -787,20 +1400,7 @@ static int check_resize_fb(struct drm_client_dev * const dev, if (gem_dumb->width && gem_dumb->height && (gem_dumb->width < width || gem_dumb->height < height)) { - result = drm_mode_rmfb(dev->dev, dumb_fb->fb_id, dev->file); - if (result) { - drm_err(dev->dev, "%s: failed to remove framebufer %d\n", - __func__, result); - } - - result = drm_mode_destroy_dumb(dev->dev, gem_dumb->handle, dev->file); - if (result) { - drm_err(dev->dev, "%s: failed to destroy framebuffer %d\n", - __func__, result); - } - - memset(gem_dumb, 0, sizeof(*gem_dumb)); - memset(dumb_fb, 0, sizeof(*dumb_fb)); + destroy_fb(dev, gem_dumb, dumb_fb); } /* allocate dumb framebuffer, on success a GEM object handle is returned */ diff --git a/repos/pc/src/driver/framebuffer/intel/pc/main.cc b/repos/pc/src/driver/framebuffer/intel/pc/main.cc index d480048568..61461e96ff 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/main.cc +++ b/repos/pc/src/driver/framebuffer/intel/pc/main.cc @@ -13,7 +13,6 @@ #include <base/attached_rom_dataspace.h> #include <base/component.h> -#include <timer_session/connection.h> #include <capture_session/connection.h> #include <os/pixel_rgb888.h> #include <os/reporter.h> @@ -21,7 +20,6 @@ /* emulation includes */ #include <lx_emul/init.h> -#include <lx_emul/fb.h> #include <lx_emul/task.h> #include <lx_kit/env.h> #include <lx_kit/init.h> @@ -46,15 +44,13 @@ struct Framebuffer::Driver using Attached_rom_system = Constructible<Attached_rom_dataspace>; Env &env; - Timer::Connection timer { env }; + Heap heap { env.ram(), env.rm() }; Attached_rom_dataspace config { env, "config" }; Attached_rom_system system { }; Expanding_reporter reporter { env, "connectors", "connectors" }; Signal_handler<Driver> config_handler { env.ep(), *this, &Driver::config_update }; - Signal_handler<Driver> timer_handler { env.ep(), *this, - &Driver::handle_timer }; Signal_handler<Driver> scheduler_handler { env.ep(), *this, &Driver::handle_scheduler }; Signal_handler<Driver> system_handler { env.ep(), *this, @@ -64,61 +60,108 @@ struct Framebuffer::Driver bool new_config_rom { false }; bool disable_all { false }; bool disable_report_once { false }; + bool merge_label_changed { false }; - class Fb - { - private: + Capture::Connection::Label merge_label { "mirror" }; - Capture::Connection _capture; - Capture::Area const _size; - Capture::Area const _size_phys; - Capture::Connection::Screen _captured_screen; - void * _base; + struct Connector { + using Space = Id_space<Connector>; + using Id = Space::Id; - /* - * Non_copyable - */ - Fb(const Fb&); - Fb & operator=(const Fb&); + Space::Element id_element; + Signal_handler<Connector> capture_wakeup; - public: + addr_t base { }; + Capture::Area size { }; + Capture::Area size_phys { }; + Capture::Area size_mm { }; - void paint() - { - using Pixel = Capture::Pixel; - Surface<Pixel> surface((Pixel*)_base, _size_phys); - _captured_screen.apply_to_surface(surface); - } + Constructible<Capture::Connection> capture { }; + Constructible<Capture::Connection::Screen> screen { }; - Fb(Env & env, void * base, Capture::Area size, - Capture::Area size_phys) - : - _capture(env), - _size(size), - _size_phys(size_phys), - _captured_screen(_capture, env.rm(), _size), - _base(base) {} + Connector(Env &env, Space &space, Id id) + : + id_element(*this, space, id), + capture_wakeup(env.ep(), *this, &Connector::wakeup_handler) + { } - bool same_setup(void * base, Capture::Area &size, - Capture::Area &size_phys) - { - return ((base == _base) && (size == _size) && - (size_phys == _size_phys)); - } + void wakeup_handler() + { + lx_emul_i915_wakeup(unsigned(id_element.id().value)); + Lx_kit::env().scheduler.execute(); + } }; - Constructible<Fb> fb {}; + Connector::Space ids { }; + + bool capture(Connector::Space &ids, Connector::Id const &id, bool const may_stop) + { + using Pixel = Capture::Pixel; + + bool dirty = false; + + ids.apply<Connector>(id, [&](Connector &connector) { + + if (!connector.capture.constructed() || + !connector.screen.constructed()) + return; + + Surface<Pixel> surface((Pixel*)connector.base, connector.size_phys); + + auto box = connector.screen->apply_to_surface(surface); + + if (box.valid()) + dirty = true; + + if (!dirty && may_stop) + connector.capture->capture_stopped(); + + }, [&](){ /* unknown connector id */ }); + + return dirty; + } + + bool update(Connector &conn, + addr_t const base, + Capture::Area const &size, + Capture::Area const &size_phys, + Capture::Area const &mm, + auto const &label, + bool const force_change) + { + bool same = (base == conn.base) && + (size == conn.size) && + (size_phys == conn.size_phys) && + (mm == conn.size_mm) && + !force_change; + + if (same) + return same; + + conn.base = base; + conn.size = size; + conn.size_phys = size_phys; + conn.size_mm = mm; + + if (conn.size.valid()) { + Capture::Connection::Screen::Attr attr = { .px = conn.size, .mm = conn.size_mm }; + conn.capture.construct(env, label); + conn.screen .construct(*conn.capture, env.rm(), attr); + + conn.capture->wakeup_sigh(conn.capture_wakeup); + } else { + conn.screen .destruct(); + conn.capture.destruct(); + } + + return same; + } void config_update(); void system_update(); void generate_report(); void lookup_config(char const *, struct genode_mode &mode); - void handle_timer() - { - if (fb.constructed()) { fb->paint(); } - } - void handle_scheduler() { Lx_kit::env().scheduler.execute(); @@ -157,9 +200,6 @@ struct Framebuffer::Driver log("--- Intel framebuffer driver started ---"); lx_emul_start_kernel(nullptr); - - timer.sigh(timer_handler); - timer.trigger_periodic(20*1000); } bool apply_config_on_hotplug() const @@ -172,8 +212,7 @@ struct Framebuffer::Driver return apply_config; } - template <typename T> - void with_max_enforcement(T const &fn) const + void with_max_enforcement(auto const &fn) const { unsigned max_width = config.xml().attribute_value("max_width", 0u); unsigned max_height = config.xml().attribute_value("max_height",0u); @@ -182,11 +221,10 @@ struct Framebuffer::Driver fn(max_width, max_height); } - template <typename T> - void with_force(T const &fn) const + void with_force(auto const &node, auto const &fn) const { - unsigned force_width = config.xml().attribute_value("force_width", 0u); - unsigned force_height = config.xml().attribute_value("force_height", 0u); + unsigned force_width = node.attribute_value("width", 0u); + unsigned force_height = node.attribute_value("height", 0u); if (force_width && force_height) fn(force_width, force_height); @@ -241,6 +279,15 @@ void Framebuffer::Driver::config_update() if (!config.valid() || !lx_user_task) return; + config.xml().with_optional_sub_node("merge", [&](auto const &node) { + auto const merge_label_before = merge_label; + + if (node.has_attribute("name")) + merge_label = node.attribute_value("name", String<160>(merge_label)); + + merge_label_changed = merge_label_before != merge_label; + }); + if (config.xml().attribute_value("system", false)) { system.construct(Lx_kit::env().env, "system"); system->sigh(system_handler); @@ -304,12 +351,19 @@ void Framebuffer::Driver::generate_report() xml.attribute("max_height", height); }); - with_force([&](unsigned width, unsigned height) { - xml.attribute("force_width", width); - xml.attribute("force_height", height); - }); + lx_emul_i915_report_discrete(&xml); - lx_emul_i915_report(&xml); + xml.node("merge", [&] () { + xml.attribute("name", merge_label); + node.with_optional_sub_node("merge", [&](auto const &merge) { + with_force(merge, [&](unsigned width, unsigned height) { + xml.attribute("width", width); + xml.attribute("height", height); + }); + }); + + lx_emul_i915_report_non_discrete(&xml); + }); }); }); @@ -320,41 +374,66 @@ void Framebuffer::Driver::generate_report() void Framebuffer::Driver::lookup_config(char const * const name, struct genode_mode &mode) { + bool mirror_node = false; + /* default settings, possibly overridden by explicit configuration below */ mode.enabled = !disable_all; - mode.brightness = 70 /* percent */; + mode.brightness = 70; /* percent */ + mode.mirror = true; - if (!config.valid() || disable_all) + if (!config.valid()) return; - /* iterate independently of force* ever to get brightness and hz */ - config.xml().for_each_sub_node("connector", [&] (Xml_node &node) { + with_max_enforcement([&](unsigned const width, unsigned const height) { + mode.max_width = width; + mode.max_height = height; + }); + + if (disable_all) + return; + + auto for_each_node = [&](auto const &node, bool const mirror){ using Name = String<32>; Name const con_policy = node.attribute_value("name", Name()); if (con_policy != name) return; + mode.mirror = mirror; mode.enabled = node.attribute_value("enabled", true); + if (!mode.enabled) return; + mode.width = node.attribute_value("width" , 0U); + mode.height = node.attribute_value("height" , 0U); + mode.hz = node.attribute_value("hz" , 0U); + mode.id = node.attribute_value("mode" , 0U); mode.brightness = node.attribute_value("brightness", unsigned(MAX_BRIGHTNESS + 1)); + }; - mode.width = node.attribute_value("width", 0U); - mode.height = node.attribute_value("height", 0U); - mode.hz = node.attribute_value("hz", 0U); - mode.id = node.attribute_value("mode_id", 0U); + /* lookup config of discrete connectors */ + config.xml().for_each_sub_node("connector", [&] (Xml_node const &conn) { + for_each_node(conn, false); }); - with_force([&](unsigned const width, unsigned const height) { - mode.force_width = width; - mode.force_height = height; - }); + /* lookup config of mirrored connectors */ + config.xml().for_each_sub_node("merge", [&] (Xml_node const &merge) { + if (mirror_node) { + error("only one mirror node supported"); + return; + } - with_max_enforcement([&](unsigned const width, unsigned const height) { - mode.max_width = width; - mode.max_height = height; + merge.for_each_sub_node("connector", [&] (Xml_node const &conn) { + for_each_node(conn, true); + }); + + with_force(merge, [&](unsigned const width, unsigned const height) { + mode.force_width = width; + mode.force_height = height; + }); + + mirror_node = true; }); } @@ -366,41 +445,81 @@ unsigned long long driver_max_framebuffer_memory(void) } -/** - * Can be called already as side-effect of `lx_emul_start_kernel`, - * that's why the Driver object needs to be constructed already here. - */ -extern "C" void lx_emul_framebuffer_ready(void * base, unsigned long, - unsigned xres, unsigned yres, - unsigned phys_width, - unsigned phys_height) +void lx_emul_i915_framebuffer_ready(unsigned const connector_id, + char const * const conn_name, + void * const base, + unsigned long, + unsigned const xres, + unsigned const yres, + unsigned const phys_width, + unsigned const phys_height, + unsigned const mm_width, + unsigned const mm_height) { auto &env = Lx_kit::env().env; auto &drv = driver(env); - auto &fb = drv.fb; - Capture::Area area(xres, yres); - Capture::Area area_phys(phys_width, phys_height); + using namespace Genode; - if (fb.constructed()) { - if (fb->same_setup(base, area, area_phys)) + typedef Framebuffer::Driver::Connector Connector; + + auto const id = Connector::Id { connector_id }; + + /* allocate new id for new connector */ + drv.ids.apply<Connector>(id, [&](Connector &) { /* known id */ }, [&](){ + /* ignore unused connector - don't need a object for it */ + if (!base) return; - fb.destruct(); - } + new (drv.heap) Connector (env, drv.ids, id); + }); - /* clear artefacts */ - if (area != area_phys) - Genode::memset(base, 0, area_phys.count() * 4); + drv.ids.apply<Connector>(id, [&](Connector &conn) { - fb.construct(env, base, area, area_phys); + Capture::Area const area (xres, yres); + Capture::Area const area_phys(phys_width, phys_height); - Genode::log("framebuffer reconstructed - virtual=", xres, "x", yres, - " physical=", phys_width, "x", phys_height); + bool const merge = Capture::Connection::Label(conn_name) == "mirror_capture"; + + auto const label = !conn_name + ? Capture::Connection::Label(conn.id_element) + : merge ? drv.merge_label + : Capture::Connection::Label(conn_name); + + bool const same = drv.update(conn, Genode::addr_t(base), area, + area_phys, { mm_width, mm_height}, label, + merge && drv.merge_label_changed); + + if (merge) + drv.merge_label_changed = false; + + if (same) { + lx_emul_i915_wakeup(unsigned(id.value)); + return; + } + + /* clear artefacts */ + if (base && (area != area_phys)) + Genode::memset(base, 0, area_phys.count() * 4); + + String<12> space { }; + for (auto i = label.length(); i < space.capacity() - 1; i++) { + space = String<12>(" ", space); + } + + if (conn.size.valid()) { + log(space, label, ": capture ", xres, "x", yres, " with " + " framebuffer ", phys_width, "x", phys_height); + + lx_emul_i915_wakeup(unsigned(id.value)); + } else + log(space, label, ": capture closed "); + + }, [](){ /* unknown id */ }); } -extern "C" void lx_emul_i915_hotplug_connector() +void lx_emul_i915_hotplug_connector() { Genode::Env &env = Lx_kit::env().env; driver(env).generate_report(); @@ -409,6 +528,7 @@ extern "C" void lx_emul_i915_hotplug_connector() void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, char const *name, char const connected, + char const modes_available, unsigned brightness, unsigned width_mm, unsigned height_mm) { @@ -416,8 +536,8 @@ void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, xml.node("connector", [&] () { + xml.attribute("connected", connected && modes_available); xml.attribute("name", name); - xml.attribute("connected", !!connected); if (width_mm) xml.attribute("width_mm" , width_mm); if (height_mm) @@ -441,17 +561,17 @@ void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *mode) xml.node("mode", [&] () { - xml.attribute("width", mode->width); - xml.attribute("height", mode->height); - xml.attribute("hz", mode->hz); - xml.attribute("mode_id", mode->id); - xml.attribute("mode_name", mode->name); + xml.attribute("width", mode->width); + xml.attribute("height", mode->height); + xml.attribute("hz", mode->hz); + xml.attribute("id", mode->id); + xml.attribute("name", mode->name); if (mode->width_mm) xml.attribute("width_mm", mode->width_mm); if (mode->height_mm) xml.attribute("height_mm", mode->height_mm); if (!mode->enabled) - xml.attribute("unavailable", true); + xml.attribute("usable", false); if (mode->preferred) xml.attribute("preferred", true); if (mode->inuse) @@ -460,6 +580,16 @@ void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *mode) } +int lx_emul_i915_blit(unsigned const connector_id, char const may_stop) +{ + auto &drv = driver(Lx_kit::env().env); + + auto const id = Framebuffer::Driver::Connector::Id { connector_id }; + + return drv.capture(drv.ids, id, may_stop); +} + + void lx_emul_i915_connector_config(char * name, struct genode_mode * mode) { if (!mode || !name) diff --git a/repos/pc/src/driver/framebuffer/intel/pc/target.inc b/repos/pc/src/driver/framebuffer/intel/pc/target.inc index 93004a960f..d69ff94f46 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/target.inc +++ b/repos/pc/src/driver/framebuffer/intel/pc/target.inc @@ -15,7 +15,6 @@ SRC_C += dummies.c SRC_C += pci.c SRC_C += lx_emul.c SRC_C += $(notdir $(wildcard $(REL_PRG_DIR)/generated_dummies.c)) -SRC_C += fb.c SRC_C += lx_user.c SRC_C += gem.c SRC_C += lx_emul/common_dummies.c diff --git a/repos/pc/src/driver/nic/pc/lx_user.c b/repos/pc/src/driver/nic/pc/lx_user.c index 5ecfaa43a6..3dbbe4f846 100644 --- a/repos/pc/src/driver/nic/pc/lx_user.c +++ b/repos/pc/src/driver/nic/pc/lx_user.c @@ -11,214 +11,17 @@ * version 2. */ -#include <linux/kthread.h> -#include <linux/netdevice.h> #include <lx_user/init.h> -#include <genode_c_api/uplink.h> -#include <genode_c_api/mac_address_reporter.h> - - -static struct genode_uplink *dev_genode_uplink(struct net_device *dev) -{ - return (struct genode_uplink *)dev->ifalias; -} - - -struct genode_uplink_rx_context -{ - struct net_device *dev; -}; - - -struct genode_uplink_tx_packet_context -{ - struct sk_buff *skb; -}; - - -static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx, - char *dst, unsigned long dst_len) -{ - struct sk_buff * const skb = ctx->skb; - - skb_push(skb, ETH_HLEN); - - if (dst_len < skb->len) { - printk("uplink_tx_packet_content: packet exceeds uplink packet size\n"); - memset(dst, 0, dst_len); - return 0; - } - - skb_copy_from_linear_data(skb, dst, skb->len); - - /* clear unused part of the destination buffer */ - memset(dst + skb->len, 0, dst_len - skb->len); - - return skb->len; -} - - -static rx_handler_result_t handle_rx(struct sk_buff **pskb) -{ - struct sk_buff *skb = *pskb; - struct net_device *dev = skb->dev; - struct genode_uplink_tx_packet_context ctx = { .skb = skb }; - struct genode_uplink *uplink = dev_genode_uplink(dev); - - if (!uplink) - return RX_HANDLER_PASS; - - { - bool progress = genode_uplink_tx_packet(uplink, - uplink_tx_packet_content, - &ctx); - if (!progress) - printk("handle_rx: uplink saturated, dropping packet\n"); - } - - kfree_skb(skb); - return RX_HANDLER_CONSUMED; -} - - -/** - * Create Genode uplink for given net device - * - * The uplink is registered at the dev->ifalias pointer. - */ -static void handle_create_uplink(struct net_device *dev) -{ - struct genode_uplink_args args; - - if (dev_genode_uplink(dev)) - return; - - if (!netif_carrier_ok(dev)) - return; - - printk("create uplink for net device %s\n", &dev->name[0]); - - memset(&args, 0, sizeof(args)); - - if (dev->addr_len != sizeof(args.mac_address)) { - printk("error: net device has unexpected addr_len %u\n", dev->addr_len); - return; - } - - { - unsigned i; - for (i = 0; i < dev->addr_len; i++) - args.mac_address[i] = dev->dev_addr[i]; - } - - args.label = &dev->name[0]; - - dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args); -} - - -static void handle_destroy_uplink(struct net_device *dev) -{ - struct genode_uplink *uplink = dev_genode_uplink(dev); - - if (!uplink) - return; - - if (netif_carrier_ok(dev)) - return; - - genode_uplink_destroy(uplink); - - dev->ifalias = NULL; -} - - -static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx, - char const *ptr, unsigned long len) -{ - struct sk_buff *skb = alloc_skb(len, GFP_KERNEL); - - if (!skb) { - printk("alloc_skb failed\n"); - return GENODE_UPLINK_RX_RETRY; - } - - skb_copy_to_linear_data(skb, ptr, len); - skb_put(skb, len); - skb->dev = ctx->dev; - - if (dev_queue_xmit(skb) < 0) { - printk("lx_user: failed to xmit packet\n"); - return GENODE_UPLINK_RX_REJECTED; - } - - return GENODE_UPLINK_RX_ACCEPTED; -} - - -static int user_task_function(void *arg) -{ - for (;;) { - - struct net_device *dev; - - for_each_netdev(&init_net, dev) { - struct genode_mac_address dev_addr; - - /* enable link sensing, repeated calls are handled by testing IFF_UP */ - dev_open(dev, 0); - - memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr)); - genode_mac_address_register(dev->name, dev_addr); - - /* install rx handler once */ - if (!netdev_is_rx_handler_busy(dev)) - netdev_rx_handler_register(dev, handle_rx, NULL); - - /* respond to cable plug/unplug */ - handle_create_uplink(dev); - handle_destroy_uplink(dev); - - /* transmit packets received from the uplink session */ - if (netif_carrier_ok(dev)) { - - struct genode_uplink_rx_context ctx = { .dev = dev }; - - while (genode_uplink_rx(dev_genode_uplink(dev), - uplink_rx_one_packet, - &ctx)); - } - }; - - /* block until lx_emul_task_unblock */ - lx_emul_task_schedule(true); - } - return 0; -} - - -struct task_struct *user_task_struct_ptr; /* used by 'Main' for lx_emul_task_unblock */ +#include <lx_emul/nic.h> void lx_user_init(void) { - pid_t pid; - - pid = kernel_thread(user_task_function, NULL, "user_task", CLONE_FS | CLONE_FILES); - - user_task_struct_ptr = find_task_by_pid_ns(pid, NULL); + lx_emul_nic_init(); } -#include <linux/rtnetlink.h> - -/* - * Called whenever the link state changes - */ -void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags, - u32 portid, const struct nlmsghdr *nlh) +void lx_user_handle_io(void) { - /* trigger handle_create_uplink / handle_destroy_uplink */ - if (user_task_struct_ptr) - lx_emul_task_unblock(user_task_struct_ptr); + lx_emul_nic_handle_io(); } diff --git a/repos/pc/src/driver/nic/pc/main.cc b/repos/pc/src/driver/nic/pc/main.cc index f81f6e0dda..22d57541e5 100644 --- a/repos/pc/src/driver/nic/pc/main.cc +++ b/repos/pc/src/driver/nic/pc/main.cc @@ -16,7 +16,7 @@ #include <lx_kit/init.h> #include <lx_kit/env.h> #include <lx_emul/init.h> -#include <lx_emul/task.h> +#include <lx_user/io.h> #include <genode_c_api/uplink.h> #include <genode_c_api/mac_address_reporter.h> @@ -26,8 +26,6 @@ namespace Pc { } -extern task_struct *user_task_struct_ptr; - struct Pc::Main { Env &_env; @@ -52,11 +50,8 @@ struct Pc::Main void _handle_signal() { - if (user_task_struct_ptr) - lx_emul_task_unblock(user_task_struct_ptr); - + lx_user_handle_io(); Lx_kit::env().scheduler.execute(); - genode_uplink_notify_peers(); } diff --git a/repos/pc/src/driver/nic/pc/rtnetlink.c b/repos/pc/src/driver/nic/pc/rtnetlink.c index 78c956d90d..9dac867eae 100644 --- a/repos/pc/src/driver/nic/pc/rtnetlink.c +++ b/repos/pc/src/driver/nic/pc/rtnetlink.c @@ -12,6 +12,7 @@ */ #include <lx_emul.h> +#include <lx_emul/nic.h> #include <net/rtnetlink.h> #include <linux/mutex.h> @@ -56,3 +57,13 @@ void rtnl_unlock(void) { netdev_run_todo(); } + + +/* + * Called whenever the link state changes + */ +void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags, + u32 portid, const struct nlmsghdr *nlh) +{ + lx_emul_nic_handle_io(); +} diff --git a/repos/pc/src/driver/nic/pc/target.inc b/repos/pc/src/driver/nic/pc/target.inc index 3fd76b75d6..94761b45c6 100644 --- a/repos/pc/src/driver/nic/pc/target.inc +++ b/repos/pc/src/driver/nic/pc/target.inc @@ -7,6 +7,7 @@ SRC_CC += main.cc SRC_C += dummies.c SRC_C += lx_emul.c SRC_C += lx_emul/common_dummies.c +SRC_C += lx_emul/nic.c SRC_C += lx_user.c SRC_C += rtnetlink.c diff --git a/repos/pc/src/lib/pc_wifi/dummies.c b/repos/pc/src/lib/pc_wifi/dummies.c index bcc7e7fbc7..2631ab74de 100644 --- a/repos/pc/src/lib/pc_wifi/dummies.c +++ b/repos/pc/src/lib/pc_wifi/dummies.c @@ -774,3 +774,12 @@ struct thermal_zone_device * thermal_zone_device_register_with_trips(const char lx_emul_trace(__func__); return ERR_PTR(-EINVAL); } + + +#include <linux/ratelimit_types.h> + +int ___ratelimit(struct ratelimit_state * rs,const char * func) +{ + lx_emul_trace(__func__); + return 0; +} diff --git a/repos/pc/src/lib/pc_wifi/generated_dummies.c b/repos/pc/src/lib/pc_wifi/generated_dummies.c index 801d9b7e18..3dcc9709ba 100644 --- a/repos/pc/src/lib/pc_wifi/generated_dummies.c +++ b/repos/pc/src/lib/pc_wifi/generated_dummies.c @@ -7,14 +7,6 @@ #include <lx_emul.h> -#include <linux/ratelimit_types.h> - -int ___ratelimit(struct ratelimit_state * rs,const char * func) -{ - lx_emul_trace_and_stop(__func__); -} - - #include <linux/cpumask.h> struct cpumask __cpu_active_mask; diff --git a/repos/ports/ports/netperf.hash b/repos/ports/ports/netperf.hash index b3f3bf65a0..7326120286 100644 --- a/repos/ports/ports/netperf.hash +++ b/repos/ports/ports/netperf.hash @@ -1 +1 @@ -6db34a7949b8942c256b881977e91fbf53638dd6 +56f2157a43b51cb0a534f251187dbc00038b276a diff --git a/repos/ports/ports/virtualbox6.hash b/repos/ports/ports/virtualbox6.hash index a1455e97db..cf83bd1ff0 100644 --- a/repos/ports/ports/virtualbox6.hash +++ b/repos/ports/ports/virtualbox6.hash @@ -1 +1 @@ -4f4c05a80b5767a0132c333a352fada6ba8965a8 +4fe7913734f0dbabae9fae0684e34fe1fe60e8b2 diff --git a/repos/ports/recipes/pkg/gdb_x86/hash b/repos/ports/recipes/pkg/gdb_x86/hash index 5df5ed0942..aa70aad12a 100644 --- a/repos/ports/recipes/pkg/gdb_x86/hash +++ b/repos/ports/recipes/pkg/gdb_x86/hash @@ -1 +1 @@ -2024-08-28 4394f51ecbb9a10c70c9410f149170fcab11f953 +2024-10-29 e523378763becbc24a928f89e464bd60519031df diff --git a/repos/ports/recipes/pkg/lighttpd/hash b/repos/ports/recipes/pkg/lighttpd/hash index d49b27a694..fd9cc3ad05 100644 --- a/repos/ports/recipes/pkg/lighttpd/hash +++ b/repos/ports/recipes/pkg/lighttpd/hash @@ -1 +1 @@ -2024-08-28 ad5882ef30cdd8b4877035ac4f84683984507c1d +2024-10-29 c4047f781e15a982e72158e2c6686060e2ef1a02 diff --git a/repos/ports/recipes/pkg/report_dump/hash b/repos/ports/recipes/pkg/report_dump/hash index 67d14f97b8..7d3e6fc49d 100644 --- a/repos/ports/recipes/pkg/report_dump/hash +++ b/repos/ports/recipes/pkg/report_dump/hash @@ -1 +1 @@ -2024-08-28 51a904ffdd7bebdbea6faf1c57bf782ad0c63bd2 +2024-10-29 548ad120f9ac2c48fce80ffd6c80b61aa679ba09 diff --git a/repos/ports/recipes/pkg/socat_tcp/hash b/repos/ports/recipes/pkg/socat_tcp/hash index 05a7a968a1..a75a2b5bc3 100644 --- a/repos/ports/recipes/pkg/socat_tcp/hash +++ b/repos/ports/recipes/pkg/socat_tcp/hash @@ -1 +1 @@ -2024-08-28 216e167a569e6622a741075f98bf893b4ec63444 +2024-10-29 03996b5c3e5a5bbcd19abba04067616e448c36b2 diff --git a/repos/ports/recipes/pkg/system_shell/hash b/repos/ports/recipes/pkg/system_shell/hash index 4f118d2398..2e753177ac 100644 --- a/repos/ports/recipes/pkg/system_shell/hash +++ b/repos/ports/recipes/pkg/system_shell/hash @@ -1 +1 @@ -2024-08-28 cad8de09ea5c0489f231ff7ee49139fd610ff5c2 +2024-11-04 47dba8404ad1727db406071f4f95b693bbddc1c1 diff --git a/repos/ports/recipes/pkg/system_shell/runtime b/repos/ports/recipes/pkg/system_shell/runtime index 8f5e8f0be7..632646cf3b 100644 --- a/repos/ports/recipes/pkg/system_shell/runtime +++ b/repos/ports/recipes/pkg/system_shell/runtime @@ -1,4 +1,4 @@ -<runtime ram="76M" caps="1000" binary="init" config="system_shell.config"> +<runtime ram="108M" caps="1000" binary="init" config="system_shell.config"> <requires> <gui/> diff --git a/repos/ports/recipes/pkg/vbox5-nova-capture/hash b/repos/ports/recipes/pkg/vbox5-nova-capture/hash index 8d67d00048..17a016827a 100644 --- a/repos/ports/recipes/pkg/vbox5-nova-capture/hash +++ b/repos/ports/recipes/pkg/vbox5-nova-capture/hash @@ -1 +1 @@ -2024-08-28 6dbfb1d9b58fa987f70385c0b3752979a6fd3ed9 +2024-10-29 a5acb0351e4fc9600ea4aac2295d285c4fd6bf05 diff --git a/repos/ports/recipes/pkg/vbox5-nova-sculpt/hash b/repos/ports/recipes/pkg/vbox5-nova-sculpt/hash index 1bc0df732e..6a46af54c0 100644 --- a/repos/ports/recipes/pkg/vbox5-nova-sculpt/hash +++ b/repos/ports/recipes/pkg/vbox5-nova-sculpt/hash @@ -1 +1 @@ -2024-08-28 84aa7821079008a2a71eb1566e4b47442877d927 +2024-10-29 0c0ae915b036d986d6fe70e8e8d5a38841ba7b64 diff --git a/repos/ports/recipes/pkg/vbox6-capture/hash b/repos/ports/recipes/pkg/vbox6-capture/hash index fe252f5dec..4f79c0eec9 100644 --- a/repos/ports/recipes/pkg/vbox6-capture/hash +++ b/repos/ports/recipes/pkg/vbox6-capture/hash @@ -1 +1 @@ -2024-08-28 4e69297a012cbda8eca0133fa70b9615df9e7dfd +2024-11-04 9b473ebfd3a952b5f7c71333c7ff8b089b58d3b0 diff --git a/repos/ports/recipes/pkg/vbox6/hash b/repos/ports/recipes/pkg/vbox6/hash index eeb74143a2..11e2b8a0b3 100644 --- a/repos/ports/recipes/pkg/vbox6/hash +++ b/repos/ports/recipes/pkg/vbox6/hash @@ -1 +1 @@ -2024-08-28 0a58077655c5675a68170f84e8b30182efd155a0 +2024-11-04 7e98b80e955c0730432617168975871016e5440f diff --git a/repos/ports/recipes/raw/system_shell/hash b/repos/ports/recipes/raw/system_shell/hash index 9b78064e4d..60b8f80899 100644 --- a/repos/ports/recipes/raw/system_shell/hash +++ b/repos/ports/recipes/raw/system_shell/hash @@ -1 +1 @@ -2021-10-14 6bd449b9b53a934bb0ae9dbab667f1beb6ed3d58 +2024-10-29 5ce626a0735a43ee1899dff5555375ebd7925eb1 diff --git a/repos/ports/recipes/raw/system_shell/system_shell.config b/repos/ports/recipes/raw/system_shell/system_shell.config index 047ceac944..d053f5b618 100644 --- a/repos/ports/recipes/raw/system_shell/system_shell.config +++ b/repos/ports/recipes/raw/system_shell/system_shell.config @@ -16,7 +16,7 @@ <default caps="100"/> <start name="terminal" caps="150"> - <resource name="RAM" quantum="16M"/> + <resource name="RAM" quantum="48M"/> <provides> <service name="Terminal"/> </provides> <config copy="yes" paste="yes"> <initial width="800" height="600"/> diff --git a/repos/ports/recipes/src/bash-minimal/hash b/repos/ports/recipes/src/bash-minimal/hash index e1ef58266c..68cabe0da3 100644 --- a/repos/ports/recipes/src/bash-minimal/hash +++ b/repos/ports/recipes/src/bash-minimal/hash @@ -1 +1 @@ -2024-08-28 9b6c29929a1123427f1934d39da13915b3a812c8 +2024-10-07 41ea091449832b11e250b7241100e326b14f8d12 diff --git a/repos/ports/recipes/src/bash/hash b/repos/ports/recipes/src/bash/hash index 62c31e1b50..76df4648d6 100644 --- a/repos/ports/recipes/src/bash/hash +++ b/repos/ports/recipes/src/bash/hash @@ -1 +1 @@ -2024-08-28 ff36bf51831fb9a77b33c018c8efa9ea57743829 +2024-10-07 7545f7e4a3297aa829621651c931bc51d4381d78 diff --git a/repos/ports/recipes/src/binutils_x86/hash b/repos/ports/recipes/src/binutils_x86/hash index f972e747b3..2b084f333e 100644 --- a/repos/ports/recipes/src/binutils_x86/hash +++ b/repos/ports/recipes/src/binutils_x86/hash @@ -1 +1 @@ -2024-08-28 5c8d4439c2359aeb8b518ad60e6e389934a9254f +2024-10-07 f69c9a8e21641fb524c22f4e462fc34244c2942d diff --git a/repos/ports/recipes/src/coreutils-minimal/hash b/repos/ports/recipes/src/coreutils-minimal/hash index 3459d31f79..f0c276c592 100644 --- a/repos/ports/recipes/src/coreutils-minimal/hash +++ b/repos/ports/recipes/src/coreutils-minimal/hash @@ -1 +1 @@ -2024-08-28 b6c770e9c11c446b9760c2d977a84568e44d6e15 +2024-10-07 4220c6dda032f4972234de32a4d49e05c022ca42 diff --git a/repos/ports/recipes/src/coreutils/hash b/repos/ports/recipes/src/coreutils/hash index 5b28a4a98f..4bcd73205a 100644 --- a/repos/ports/recipes/src/coreutils/hash +++ b/repos/ports/recipes/src/coreutils/hash @@ -1 +1 @@ -2024-08-28 42a27a2a3cb603b942a65e4ba19380f95cf10c58 +2024-10-07 16c5dc88342cc86eacf7d11213e62bd784a3998f diff --git a/repos/ports/recipes/src/diffutils/hash b/repos/ports/recipes/src/diffutils/hash index e2858c60fd..c74ddd1458 100644 --- a/repos/ports/recipes/src/diffutils/hash +++ b/repos/ports/recipes/src/diffutils/hash @@ -1 +1 @@ -2024-08-28 466e8e368502ba35bb20672e520ef5f45a107e88 +2024-10-07 8c6f275bc29f731d0074d9c4fed2cc4e15bb528d diff --git a/repos/ports/recipes/src/e2fsprogs-minimal/hash b/repos/ports/recipes/src/e2fsprogs-minimal/hash index eb1c178dda..7b44bd0afd 100644 --- a/repos/ports/recipes/src/e2fsprogs-minimal/hash +++ b/repos/ports/recipes/src/e2fsprogs-minimal/hash @@ -1 +1 @@ -2024-08-28 2d36df6b4252e787062b1821e890ec359b125597 +2024-10-07 6bfa7acf0be065529bd25d6df4bf89c4fdfc51d9 diff --git a/repos/ports/recipes/src/e2fsprogs/hash b/repos/ports/recipes/src/e2fsprogs/hash index 190da16f3c..9ea0f8ad58 100644 --- a/repos/ports/recipes/src/e2fsprogs/hash +++ b/repos/ports/recipes/src/e2fsprogs/hash @@ -1 +1 @@ -2024-08-28 502e44c1d4f0c41b317bee029c228f443f6098ac +2024-10-07 f7f3f28bebab2194ee72bfa5cf3183e318137ed7 diff --git a/repos/ports/recipes/src/findutils/hash b/repos/ports/recipes/src/findutils/hash index 92301dfbaa..4d83849430 100644 --- a/repos/ports/recipes/src/findutils/hash +++ b/repos/ports/recipes/src/findutils/hash @@ -1 +1 @@ -2024-08-28 503ce613e69d11ed61788b5d9e8d747444adc946 +2024-10-07 148484ede81072cf1da81d5ae807b158e04622ab diff --git a/repos/ports/recipes/src/gcc_x86/hash b/repos/ports/recipes/src/gcc_x86/hash index 8441feb6bf..c3d7fa2255 100644 --- a/repos/ports/recipes/src/gcc_x86/hash +++ b/repos/ports/recipes/src/gcc_x86/hash @@ -1 +1 @@ -2024-08-28 896e40df15aaee4d90ac00d4c0a7326fb4460365 +2024-10-07 c8c00ff1d2be72a689d6f4af9e945f092287e589 diff --git a/repos/ports/recipes/src/gdb_arm_64/hash b/repos/ports/recipes/src/gdb_arm_64/hash index 0bfd3b0d72..64e44c23ea 100644 --- a/repos/ports/recipes/src/gdb_arm_64/hash +++ b/repos/ports/recipes/src/gdb_arm_64/hash @@ -1 +1 @@ -2024-08-28 7932fb975a477c03f2e9a5fde2d71d2179e16d1c +2024-10-07 af4281be58dc7345184353442b065fab2fdbeea4 diff --git a/repos/ports/recipes/src/gdb_support/hash b/repos/ports/recipes/src/gdb_support/hash index b35b5cffab..5e4ee46dfc 100644 --- a/repos/ports/recipes/src/gdb_support/hash +++ b/repos/ports/recipes/src/gdb_support/hash @@ -1 +1 @@ -2024-08-28 160525362e3e0172754d9498f67b949995cca665 +2024-10-07 dc03fd17541f2b1255005fa9a74f4dfac7b10ecf diff --git a/repos/ports/recipes/src/gdb_x86/hash b/repos/ports/recipes/src/gdb_x86/hash index 65e37c813e..bc98ea3254 100644 --- a/repos/ports/recipes/src/gdb_x86/hash +++ b/repos/ports/recipes/src/gdb_x86/hash @@ -1 +1 @@ -2024-08-28 1cc48f86c6614b7e7cd1650a074a6dc3cd2ba87e +2024-10-07 a604c59503605324df91f0c6bcdaff0c662d7dbc diff --git a/repos/ports/recipes/src/gnumake/hash b/repos/ports/recipes/src/gnumake/hash index 4436582a6d..1e32cfe728 100644 --- a/repos/ports/recipes/src/gnumake/hash +++ b/repos/ports/recipes/src/gnumake/hash @@ -1 +1 @@ -2024-08-28 8690fe007d695a64c8308c027723899c032be33e +2024-10-07 2a76b398b7d7b015a2e1a37006e8a467571c5356 diff --git a/repos/ports/recipes/src/grep/hash b/repos/ports/recipes/src/grep/hash index a60a854223..ba8ecac8ce 100644 --- a/repos/ports/recipes/src/grep/hash +++ b/repos/ports/recipes/src/grep/hash @@ -1 +1 @@ -2024-08-28 5e30558b4743be8691f115f0657547ead7efab90 +2024-10-07 4706d7ca4889e66fe7fdacb3280405fbc8cdc231 diff --git a/repos/ports/recipes/src/less/hash b/repos/ports/recipes/src/less/hash index 55fbbfc7be..5328b6fb4c 100644 --- a/repos/ports/recipes/src/less/hash +++ b/repos/ports/recipes/src/less/hash @@ -1 +1 @@ -2024-08-28 679c10d6c9b26a6003e4d9d4994e3d658377d39e +2024-10-07 6910a003acd83f5627e960b413c598de0f4503ac diff --git a/repos/ports/recipes/src/lighttpd/hash b/repos/ports/recipes/src/lighttpd/hash index a05e8a435b..1aba45a406 100644 --- a/repos/ports/recipes/src/lighttpd/hash +++ b/repos/ports/recipes/src/lighttpd/hash @@ -1 +1 @@ -2024-08-28 6d0982dff4cdcd6befd92d32db9b50f4b42b3efb +2024-10-07 2c6397b43b92a78b5d260a372c8bdd9bef53770f diff --git a/repos/ports/recipes/src/sed/hash b/repos/ports/recipes/src/sed/hash index ebdafc88bc..aa452e585a 100644 --- a/repos/ports/recipes/src/sed/hash +++ b/repos/ports/recipes/src/sed/hash @@ -1 +1 @@ -2024-08-28 62a82a5180ac3851f666246cc97a232a7b233d4f +2024-10-07 dbea1c077c967a3df9e25fdfa1cb7b55c37185f8 diff --git a/repos/ports/recipes/src/socat/hash b/repos/ports/recipes/src/socat/hash index 3fdbffe213..312844fe5c 100644 --- a/repos/ports/recipes/src/socat/hash +++ b/repos/ports/recipes/src/socat/hash @@ -1 +1 @@ -2024-08-28 7d15fc79efbc8013b16d5276f790d22d0ba400f5 +2024-10-07 26cdfb5105878c87361d6865dc23f1ae7586570e diff --git a/repos/ports/recipes/src/tar/hash b/repos/ports/recipes/src/tar/hash index 1a4fecdd1f..a884162eed 100644 --- a/repos/ports/recipes/src/tar/hash +++ b/repos/ports/recipes/src/tar/hash @@ -1 +1 @@ -2024-08-28 287bb0eac40f29e808e480008a7dd8bba80b893d +2024-10-07 a7129f59052b49bdd8a08e15e6c348a186672860 diff --git a/repos/ports/recipes/src/tclsh/hash b/repos/ports/recipes/src/tclsh/hash index 39543313cb..da71f36e5a 100644 --- a/repos/ports/recipes/src/tclsh/hash +++ b/repos/ports/recipes/src/tclsh/hash @@ -1 +1 @@ -2024-08-28 8dc4d08e71190ca97bc5551420cbdad095e39471 +2024-10-07 02e9a1835903bff990783f4177c5e9e9276f77f2 diff --git a/repos/ports/recipes/src/vbox5-nova/hash b/repos/ports/recipes/src/vbox5-nova/hash index fbf700cc44..8550488d29 100644 --- a/repos/ports/recipes/src/vbox5-nova/hash +++ b/repos/ports/recipes/src/vbox5-nova/hash @@ -1 +1 @@ -2024-08-28 f86a140163f52f4cc7c2e939bf2239e4aeb8af4a +2024-10-29 4a1265515d5cc0ddb530e013af861ae04cd692bf diff --git a/repos/ports/recipes/src/vbox6/hash b/repos/ports/recipes/src/vbox6/hash index ab2c2679dc..c819066b65 100644 --- a/repos/ports/recipes/src/vbox6/hash +++ b/repos/ports/recipes/src/vbox6/hash @@ -1 +1 @@ -2024-08-28 02ef881acb967b01541c1d22d3d98b10b3b0b1b8 +2024-10-29 572b47889e29f242644ce786ac674ade73a2313b diff --git a/repos/ports/recipes/src/verify/hash b/repos/ports/recipes/src/verify/hash index b7a4e493fb..ad9954c571 100644 --- a/repos/ports/recipes/src/verify/hash +++ b/repos/ports/recipes/src/verify/hash @@ -1 +1 @@ -2024-08-28 72cec1781db63c8916cc112bcc606fddd181cdcf +2024-10-07 153ff50a18395d1024cee9701aef5d6282e2c4c4 diff --git a/repos/ports/recipes/src/vim-minimal/hash b/repos/ports/recipes/src/vim-minimal/hash index 8648c4d4fc..4994e7384c 100644 --- a/repos/ports/recipes/src/vim-minimal/hash +++ b/repos/ports/recipes/src/vim-minimal/hash @@ -1 +1 @@ -2024-08-28 fb72690406412c2c74cc3a94fa79e5a3877ddf70 +2024-10-07 365ebf28a7f24544afdaf0faa3f86afdd78409ce diff --git a/repos/ports/recipes/src/vim/hash b/repos/ports/recipes/src/vim/hash index 2a9b1f6bfe..51b85ac97a 100644 --- a/repos/ports/recipes/src/vim/hash +++ b/repos/ports/recipes/src/vim/hash @@ -1 +1 @@ -2024-08-28 c6be30ba52f1d330330e2cba646c93d7a951b132 +2024-10-07 eab4ea05f9b2b70855f0bc20890bea3ac1f9e262 diff --git a/repos/ports/recipes/src/which/hash b/repos/ports/recipes/src/which/hash index adad9f3289..0abb4e7ff0 100644 --- a/repos/ports/recipes/src/which/hash +++ b/repos/ports/recipes/src/which/hash @@ -1 +1 @@ -2024-08-28 b10eb92c70d57004792ee05d122a02d092b2eef2 +2024-10-07 576e4bff550079314235748f3cd4c6df98ed09e0 diff --git a/repos/ports/run/netperf.inc b/repos/ports/run/netperf.inc index 4173f6abd3..16df043016 100644 --- a/repos/ports/run/netperf.inc +++ b/repos/ports/run/netperf.inc @@ -244,8 +244,8 @@ if { $use_wifi_driver } { <ram/> <import> <inline name="wifi_config"> -<wifi_config connected_scan_interval="0" scan_interval="10" rfkill="no" verbose="no" verbose_state="no">} -append config "<network ssid=\"$wifi_ssid\" protection=\"WPA2\" passphrase=\"$wifi_psk\"/>" +<wifi_config>} +append config "<network ssid=\"$wifi_ssid\" protection=\"WPA2\" passphrase=\"$wifi_psk\" auto_connect=\"true\"/>" append config { </wifi_config> </inline> </import> diff --git a/repos/ports/run/vbox5_genode_usb_hid_raw.run b/repos/ports/run/vbox6_genode_usb_hid_raw.run similarity index 67% rename from repos/ports/run/vbox5_genode_usb_hid_raw.run rename to repos/ports/run/vbox6_genode_usb_hid_raw.run index 113fd93ab7..a91223290b 100644 --- a/repos/ports/run/vbox5_genode_usb_hid_raw.run +++ b/repos/ports/run/vbox6_genode_usb_hid_raw.run @@ -16,13 +16,17 @@ if { [have_include "power_on/qemu"] || ![have_spec nova] || ![have_spec x86_64]} create_boot_directory import_from_depot [depot_user]/src/[base_src] \ [depot_user]/src/acpi \ + [depot_user]/src/black_hole \ + [depot_user]/src/expat \ [depot_user]/src/fs_rom \ [depot_user]/src/init \ [depot_user]/src/jpeg \ [depot_user]/src/libc \ + [depot_user]/src/libdrm \ [depot_user]/src/libiconv \ [depot_user]/src/libyuv \ [depot_user]/src/log_terminal \ + [depot_user]/src/mesa \ [depot_user]/src/nitpicker \ [depot_user]/src/pc_usb_host \ [depot_user]/src/pci_decode \ @@ -31,9 +35,10 @@ import_from_depot [depot_user]/src/[base_src] \ [depot_user]/src/ps2 \ [depot_user]/src/report_rom \ [depot_user]/src/stdcxx \ - [depot_user]/src/vbox5-nova \ + [depot_user]/src/vbox6 \ [depot_user]/src/vesa_fb \ [depot_user]/src/vfs \ + [depot_user]/src/vfs_gpu \ [depot_user]/src/vfs_import \ [depot_user]/src/vfs_pipe \ [depot_user]/src/zlib @@ -49,12 +54,18 @@ install_config { <service name="RM"/> <service name="CPU"/> <service name="LOG"/> + <service name="VM"/> </parent-provides> <default-route> <any-service> <parent/> <any-child/> </any-service> </default-route> <default caps="150"/> + <start name="timer"> + <resource name="RAM" quantum="1M"/> + <provides> <service name="Timer"/> </provides> + </start> + <start name="report_rom" priority="-1"> <resource name="RAM" quantum="1M"/> <provides> <service name="Report"/> <service name="ROM"/> </provides> @@ -67,7 +78,7 @@ install_config { </start> <start name="acpi" caps="250"> - <resource name="RAM" quantum="4M"/> + <resource name="RAM" quantum="8M"/> <route> <service name="Report"> <child name="report_rom"/> </service> <any-service> <parent/> <any-child/> </any-service> @@ -92,65 +103,50 @@ install_config { <any-service> <parent/> <any-child/> </any-service> </route> <config> - <policy label_prefix="ps2"> <device name="ps2"/> </policy> - <policy label_prefix="fb" info="yes"> <pci class="VGA"/> </policy> - <policy label_prefix="usb" info="yes"> <pci class="USB"/> </policy> + <policy label_prefix="usb" info="yes"> <pci class="USB"/> </policy> </config> </start> - <start name="timer"> - <resource name="RAM" quantum="1M"/> - <provides><service name="Timer"/></provides> - </start> - <start name="usb" priority="-1"> <binary name="pc_usb_host"/> <resource name="RAM" quantum="16M"/> <provides> <service name="Usb"/> </provides> <config> <report devices="yes" config="yes"/> - <policy label_prefix="virtualbox"><device class="0x3"/></policy> + <policy label_prefix="virtualbox"> <device class="0x3"/> </policy> </config> <route> - <service name="IRQ"><child name="acpi" /></service> - <service name="Report"> <child name="report_rom" /> </service> + <service name="IRQ"> <child name="acpi"/> </service> + <service name="Report"> <child name="report_rom"/> </service> <any-service> <parent/> <any-child/> </any-service> </route> </start> <start name="nitpicker" priority="-1"> <resource name="RAM" quantum="12M"/> - <provides> - <service name="Gui"/> <service name="Capture"/> <service name="Event"/> - </provides> - <route> - <service name="Report"> <child name="report_rom" /> </service> - <any-service> <parent/> <any-child /> </any-service> - </route> + <provides> <service name="Gui"/> </provides> <config> - <capture/> <event/> <report focus="yes" hover="yes" /> - <domain name="pointer" layer="1" content="client" label="no" origin="pointer" /> - <domain name="cpu_load" layer="2" content="client" label="no" /> - <domain name="" layer="3" content="client" label="no" focus="click" hover="always" /> + <domain name="" layer="3" content="client" label="no" focus="click" hover="always"/> - <policy label_prefix="pointer" domain="pointer"/> - <policy label_prefix="cpu_load_display" domain="cpu_load"/> <default-policy domain=""/> </config> + <route> + <service name="Report"> <child name="report_rom"/> </service> + <any-service> <parent/> <any-child /> </any-service> + </route> </start> - <start name="pointer" priority="-1"> - <resource name="RAM" quantum="2M"/> - <provides> <service name="Report"/> </provides> - <config shapes="yes"/> - <route> - <service name="Gui"> <child name="nitpicker"/> </service> - <service name="ROM" label="hover"> <child name="report_rom"/> </service> - <service name="ROM" label="xray"> <child name="report_rom"/> </service> - <any-service> <parent/> </any-service> - </route> + <start name="black_hole"> + <resource name="RAM" quantum="1M"/> + <provides> + <service name="Event"/> + <service name="Nic"/> + </provides> + <config> + <event/> <nic/> + </config> </start> <start name="log_terminal" priority="-1"> @@ -161,19 +157,27 @@ install_config { </start> <start name="virtualbox" caps="800" priority="-2"> - <binary name="virtualbox5-nova"/> - <resource name="RAM" quantum="448M"/> - <config vbox_file="vm_genode_usb_hid_raw.vbox" vm_name="TestVM" xhci="yes"> + <binary name="virtualbox6"/> + <resource name="RAM" quantum="1024M"/> + <config vbox_file="vbox6_genode_usb_hid_raw.vbox" vm_name="TestVM" xhci="yes"> <vfs> <dir name="dev"> - <log/> <terminal/> + <log/> <terminal/> <null/> <inline name="rtc">2022-08-10 00:01</inline> </dir> <dir name="pipe"> <pipe/> </dir> - <rom name="vm_genode_usb_hid_raw.vbox" /> - <rom name="usb_hid_raw.iso" /> + <rom name="vbox6_genode_usb_hid_raw.vbox"/> + <rom name="usb_hid_raw.iso"/> </vfs> <libc stdout="/dev/log" stderr="/dev/log" pipe="/pipe" rtc="/dev/rtc"/> + <arg value="virtualbox"/> + <env key="VBOX_USER_HOME" value="/"/> + <env key="VBOX_LOG_DEST" value="file=/dev/log"/> + <env key="VBOX_LOG" value=""/> + <env key="VBOX_LOG_FLAGS" value="thread"/> + <env key="VBOX_RELEASE_LOG_DEST" value="file=/dev/log"/> + <env key="VBOX_RELEASE_LOG" value=""/> + <env key="VBOX_RELEASE_LOG_FLAGS" value="thread"/> </config> <route> <service name="Report"><child name="report_rom" /></service> @@ -208,19 +212,42 @@ exec -ignorestderr \ --include image/iso \ --include [repository_contains run/usb_hid_raw.run]/run/usb_hid_raw.run -exec ln -sf ${genode_dir}/repos/ports/run/vm_genode_usb_hid_raw.vbox bin/ +exec ln -sf ${genode_dir}/repos/ports/run/vbox6_genode_usb_hid_raw.vbox bin/ exec ln -sf ../../usb_hid_raw.iso bin/ -build_boot_image { usb_hid_raw.iso vm_genode_usb_hid_raw.vbox } +set boot_components [build_artifacts] + +append boot_components { usb_hid_raw.iso vbox6_genode_usb_hid_raw.vbox } + +build_boot_image $boot_components if { ![get_cmd_switch --autopilot] } { run_genode_until forever } # autopilot test -run_genode_until {\[init -\> log_terminal\] \[init -\> event_dump\] Input event #11\t} 150 +run_genode_until {\[init -\> log_terminal\] \[init -\> event_dump\] Input event #0\t} 90 -# pay only attention to the output of event_dump -grep_output {^\[init -\> log_terminal\] \[init -\> event_dump\]} +# remove everything before the first interesting line +regexp {(\[init -\> log_terminal\] \[init -\> event_dump\] Input event #0\t.*)} $output all output + +run_genode_until {.*\[init -\> event_dump\] Input event #11.*\n} 60 [output_spawn_id] + +# pay only attention to the output of init and its children +grep_output {^\[init } + +unify_output {(?n)^\[init -\> log_terminal\] \[init -\> usb_hid\] usb usb-[0-9]-[0-9]: input irq status -19 received} "" +unify_output {(?n) on usb-usbbus.*$} "" +unify_output {(?n) at usb-usbbus.*\)} ")" +unify_output {(?n)hid-generic.*input:} "hid-generic: input:" +unify_output {(?n)usb-[0-9]-[0-9]: USB disconnect, device number [0-9]} "usb-X-X: USB disconnect, device number X" +unify_output {(?n)device number [0-9]+} "device number X" +unify_output {(?n)input[0-9]} "inputX" +unify_output {(?n) as /devices/.*} "" +unify_output {(?n)^\[init -\> usb.*} "" +unify_output {(?n)^\[init -\> log_terminal\] \[init -\> usb.*} "" +unify_output {(?n)^.*dangling allocation.*$} "" +unify_output {(?n)^.*usbfs: process .* did not claim interface.*$} "" +trim_lines compare_output_to { [init -> log_terminal] [init -> event_dump] Input event #0 PRESS KEY_X 65534 key count: 1 diff --git a/repos/ports/run/vbox6_genode_usb_hid_raw.vbox b/repos/ports/run/vbox6_genode_usb_hid_raw.vbox new file mode 100644 index 0000000000..6f575ac33b --- /dev/null +++ b/repos/ports/run/vbox6_genode_usb_hid_raw.vbox @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<!-- +** DO NOT EDIT THIS FILE. +** If you make changes to this file while any VirtualBox related application +** is running, your changes will be overwritten later, without taking effect. +** Use VBoxManage or the VirtualBox Manager GUI to make changes. +--> +<VirtualBox xmlns="http://www.virtualbox.org/" version="1.18-genode"> + <Machine uuid="{dc7344b5-a8ab-4da6-8e95-be856b753b0b}" name="Ubuntu-22.04" OSType="Ubuntu_64" snapshotFolder="Snapshots" lastStateChange="2017-02-02T23:56:49Z"> + <MediaRegistry> + <DVDImages> + <Image uuid="{81763434-9a51-49e8-9444-528a5a28c4bc}" location="usb_hid_raw.iso"/> + </DVDImages> + </MediaRegistry> + <Hardware> + <CPU count="1" hotplug="false"> + <PAE enabled="true"/> + <LongMode enabled="true"/> + <HardwareVirtExLargePages enabled="false"/> + </CPU> + <Memory RAMSize="256"/> + <HID Pointing="PS2Mouse" Keyboard="PS2Keyboard"/> + <Boot> + <Order position="1" device="DVD"/> + <Order position="2" device="HardDisk"/> + <Order position="3" device="None"/> + <Order position="4" device="None"/> + </Boot> + <Display controller="VMSVGA" VRAMSize="128" monitorCount="1" accelerate3D="false"/> + <VideoCapture enabled="false"/> + <RemoteDisplay enabled="false"/> + <Paravirt provider="KVM"/> + <HPET enabled="false"/> + <Chipset type="ICH9"/> + <BIOS> + <IOAPIC enabled="true"/> + </BIOS> + <USB> + <Controllers> + <Controller name="OHCI" type="OHCI"/> + </Controllers> + </USB> + <Network> + <Adapter slot="0" enabled="true" MACAddress="080027235455" cable="false" speed="0" type="82540EM"> + <HostInterface/> + </Adapter> + </Network> + <UART> + <Port slot="0" enabled="true" IOBase="0x3f8" IRQ="4" path="/dev/terminal" hostMode="HostDevice"/> + <Port slot="1" enabled="false" IOBase="0x2f8" IRQ="3" hostMode="Disconnected"/> + </UART> + <LPT> + <Port slot="0" enabled="false" IOBase="0x378" IRQ="7"/> + <Port slot="1" enabled="false" IOBase="0x378" IRQ="7"/> + </LPT> + <AudioAdapter controller="HDA" driver="oss" enabled="false" enabledIn="false" enabledOut="false"/> + <RTC localOrUTC="UTC"/> + <SharedFolders/> + <Clipboard mode="Disabled"/> + <DragAndDrop mode="Disabled"/> + </Hardware> + <StorageControllers> + <StorageController name="SATA" type="AHCI" PortCount="2" useHostIOCache="true" Bootable="true"> + <AttachedDevice passthrough="false" tempeject="true" type="DVD" port="1" device="0"> + <Image uuid="{81763434-9a51-49e8-9444-528a5a28c4bc}"/> + </AttachedDevice> + </StorageController> + </StorageControllers> + </Machine> +</VirtualBox> diff --git a/repos/ports/run/vm_genode_usb_hid_raw.vbox b/repos/ports/run/vm_genode_usb_hid_raw.vbox deleted file mode 100644 index 0ee4948ccc..0000000000 --- a/repos/ports/run/vm_genode_usb_hid_raw.vbox +++ /dev/null @@ -1,163 +0,0 @@ -<?xml version="1.0"?> -<!-- -** DO NOT EDIT THIS FILE. -** If you make changes to this file while any VirtualBox related application -** is running, your changes will be overwritten later, without taking effect. -** Use VBoxManage or the VirtualBox Manager GUI to make changes. ---> -<VirtualBox xmlns="http://www.innotek.de/VirtualBox-settings" version="1.14-linux"> - <Machine uuid="{410f6221-6237-4833-b02c-a54000b7b190}" name="Genode" OSType="Other" snapshotFolder="Snapshots" lastStateChange="2014-10-30T13:26:17Z"> - <MediaRegistry> - <HardDisks/> - <DVDImages> - <Image uuid="{81763434-9a51-49e8-9444-528a5a28c4bc}" location="usb_hid_raw.iso"/> - </DVDImages> - <FloppyImages/> - </MediaRegistry> - <ExtraData> - <ExtraDataItem name="GUI/LastGuestSizeHint" value="720,400"/> - <ExtraDataItem name="GUI/LastNormalWindowPosition" value="513,100,720,422"/> - </ExtraData> - <Hardware version="2"> - <CPU count="1" hotplug="false"> - <HardwareVirtEx enabled="true"/> - <HardwareVirtExNestedPaging enabled="true"/> - <HardwareVirtExVPID enabled="true"/> - <HardwareVirtExUX enabled="false"/> - <PAE enabled="true"/> - <LongMode enabled="true"/> - <HardwareVirtExLargePages enabled="false"/> - <HardwareVirtForce enabled="false"/> - </CPU> - <Memory RAMSize="256" PageFusion="false"/> - <HID Pointing="PS2Mouse" Keyboard="PS2Keyboard"/> - <HPET enabled="false"/> - <Chipset type="ICH9"/> - <Boot> - <Order position="1" device="Floppy"/> - <Order position="2" device="DVD"/> - <Order position="3" device="HardDisk"/> - <Order position="4" device="None"/> - </Boot> - <Display VRAMSize="12" monitorCount="1" accelerate3D="false" accelerate2DVideo="false"/> - <VideoCapture enabled="false" screens="18446744073709551615" horzRes="1024" vertRes="768" rate="512" fps="25"/> - <RemoteDisplay enabled="false" authType="Null" authTimeout="5000"/> - <BIOS> - <ACPI enabled="true"/> - <IOAPIC enabled="true"/> - <Logo fadeIn="true" fadeOut="true" displayTime="0"/> - <BootMenu mode="MessageAndMenu"/> - <TimeOffset value="0"/> - <PXEDebug enabled="false"/> - </BIOS> - <USB> - <Controllers> - <Controller name="OHCI" type="OHCI"/> - </Controllers> - <DeviceFilters/> - </USB> - <Network> - <Adapter slot="0" enabled="false" MACAddress="08002785385E" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <InternalNetwork name="intnet"/> - <NATNetwork name="NatNetwork"/> - </DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </Adapter> - <Adapter slot="1" enabled="false" MACAddress="0800273AD0BB" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="2" enabled="false" MACAddress="0800270786C1" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="3" enabled="false" MACAddress="0800279B9C1E" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="4" enabled="false" MACAddress="080027B94C18" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="5" enabled="false" MACAddress="080027E38E65" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="6" enabled="false" MACAddress="0800275A8627" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - <Adapter slot="7" enabled="false" MACAddress="0800271CE60A" cable="true" speed="0" type="82540EM"> - <DisabledModes> - <NAT> - <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> - <Alias logging="false" proxy-only="false" use-same-ports="false"/> - </NAT> - </DisabledModes> - </Adapter> - </Network> - <UART> - <Port slot="0" enabled="true" IOBase="0x3f8" IRQ="4" path="/dev/terminal" hostMode="HostDevice"/> - <Port slot="1" enabled="false" IOBase="0x2f8" IRQ="3" hostMode="Disconnected"/> - </UART> - <LPT> - <Port slot="0" enabled="false" IOBase="0x378" IRQ="7"/> - <Port slot="1" enabled="false" IOBase="0x378" IRQ="7"/> - </LPT> - <AudioAdapter controller="AC97" driver="Pulse" enabled="false"/> - <RTC localOrUTC="UTC"/> - <SharedFolders/> - <Clipboard mode="Disabled"/> - <DragAndDrop mode="Disabled"/> - <IO> - <IoCache enabled="true" size="5"/> - <BandwidthGroups/> - </IO> - <HostPci> - <Devices/> - </HostPci> - <EmulatedUSB> - <CardReader enabled="false"/> - </EmulatedUSB> - <Guest memoryBalloonSize="0"/> - <GuestProperties> - <GuestProperty name="/VirtualBox/HostInfo/GUI/LanguageID" value="en_US" timestamp="1414675524029545000" flags=""/> - </GuestProperties> - </Hardware> - <StorageControllers> - <StorageController name="IDE" type="PIIX4" PortCount="2" useHostIOCache="true" Bootable="true"> - <AttachedDevice passthrough="false" tempeject="true" type="DVD" port="1" device="0"> - <Image uuid="{81763434-9a51-49e8-9444-528a5a28c4bc}"/> - </AttachedDevice> - </StorageController> - </StorageControllers> - </Machine> -</VirtualBox> diff --git a/repos/ports/src/app/netperf/netlib.patch b/repos/ports/src/app/netperf/netlib.patch index f99cd1a929..d572e213b6 100644 --- a/repos/ports/src/app/netperf/netlib.patch +++ b/repos/ports/src/app/netperf/netlib.patch @@ -1,28 +1,3 @@ -+++ src/app/netperf/src/netlib.c -@@ -1095,8 +1095,13 @@ - - #endif /* WIN32 */ - -+#ifdef GENODE_BUILD -+void -+start_do_not_use_timer(int time) -+#else - void - start_timer(int time) -+#endif - { - - #ifdef WIN32 -@@ -3059,7 +3063,9 @@ - (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF", - errno); - fflush(where); -+#ifndef GENODE_BUILD - exit(1); -+#endif - } - if (debug > 1) { - fprintf(where, "netperf: set_sock_buffer: %s of %d requested.\n", +++ src/app/netperf/src/netlib.h @@ -368,7 +368,7 @@ /* Let's define a macro to hide all of this. */ diff --git a/repos/ports/src/app/netperf/omni.patch b/repos/ports/src/app/netperf/omni.patch index 56747cba66..47c2091edf 100644 --- a/repos/ports/src/app/netperf/omni.patch +++ b/repos/ports/src/app/netperf/omni.patch @@ -83,32 +83,3 @@ index 826167a..3c10d0a 100644 int timed_out = 0; int pad_time = 0; -@@ -5312,6 +5312,28 @@ recv_omni() - need_to_accept = 0; - connected = 1; - -+#ifdef GENODE_BUILD -+ /* -+ * We don't support setitimer which uses signals. Instead set timeouts on -+ * the send and recv socket functions to be able to terminate if the host -+ * went away. -+ */ -+ struct timeval timeout; -+ /* XXX LWIP expect ms instead of seconds */ -+ timeout.tv_sec = 10 * 1000; -+ timeout.tv_usec = 0; -+ -+ int sock_error = setsockopt(data_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, -+ sizeof(timeout)); -+ if (sock_error) -+ fprintf(where, "could not send timeout for send - test may not terminate\n"); -+ -+ sock_error = setsockopt(data_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, -+ sizeof(timeout)); -+ if (sock_error) -+ fprintf(where, "could not send timeout for recv - test may not terminate\n"); -+#endif -+ - #ifdef KLUDGE_SOCKET_OPTIONS - /* this is for those systems which *INCORRECTLY* fail to pass - attributes across an accept() call. Including this goes diff --git a/repos/ports/src/app/netperf/target.mk b/repos/ports/src/app/netperf/target.mk index cae4fa29c3..b2b5baa808 100644 --- a/repos/ports/src/app/netperf/target.mk +++ b/repos/ports/src/app/netperf/target.mk @@ -9,17 +9,14 @@ SRC_C = netserver.c netlib.c netsh.c nettest_bsd.c dscp.c SRC_C += nettest_omni.c net_uuid.c SRC_C += netsys_none.c netsec_none.c netdrv_none.c netrt_none.c netslot_none.c netcpu_none.c -SRC_CC += timer.cc - INC_DIR += $(PRG_DIR) -CC_OPT += -DHAVE_CONFIG_H -DGENODE_BUILD +CC_OPT += -DHAVE_CONFIG_H CC_WARN = -Wall -Wno-unused -Wno-maybe-uninitialized -Wno-format-truncation \ -Wno-stringop-truncation -Wno-stringop-overflow CC_CXX_WARN_STRICT = -vpath timer.cc $(PRG_DIR) -vpath %.c $(NETPERF_DIR)/src +vpath %.c $(NETPERF_DIR)/src # vi: set ft=make : diff --git a/repos/ports/src/app/netperf/timer.cc b/repos/ports/src/app/netperf/timer.cc deleted file mode 100644 index 6121ceea29..0000000000 --- a/repos/ports/src/app/netperf/timer.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * \brief Timeout handling for netperf, based on test/alarm - * \author Alexander Boettcher - * \date 2014-01-10 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include <pthread.h> -#include <unistd.h> -#include <base/log.h> - -/* defined in "ports/contrib/netperf/src/netlib.c" */ -extern "C" int times_up; - -namespace { - - struct Timer_thread - { - pthread_t _pthread { }; - pthread_attr_t _attr { }; - pthread_mutex_t _mutex { PTHREAD_MUTEX_INITIALIZER }; - - int _seconds_left = 0; - - void _entry() - { - for (;;) { - sleep(1); - - pthread_mutex_lock(&_mutex); - if (_seconds_left) { - --_seconds_left; - if (_seconds_left == 0) { - times_up = true; - } - } - pthread_mutex_unlock(&_mutex); - } - } - - static void *_entry(void *arg) - { - Timer_thread &myself = *(Timer_thread *)arg; - myself._entry(); - - return nullptr; - } - - Timer_thread() - { - pthread_mutex_init(&_mutex, nullptr); - pthread_create(&_pthread, &_attr, _entry, this); - } - - void schedule_timeout(int seconds) - { - pthread_mutex_lock(&_mutex); - times_up = false; - _seconds_left = seconds; - pthread_mutex_unlock(&_mutex); - } - }; -} - - -extern "C" void -start_timer(int time) -{ - static Timer_thread timer_thread { }; - - timer_thread.schedule_timeout(time); -} diff --git a/repos/ports/src/virtualbox5/frontend/console.cc b/repos/ports/src/virtualbox5/frontend/console.cc index e8ba72f4ca..e3cc5f410f 100644 --- a/repos/ports/src/virtualbox5/frontend/console.cc +++ b/repos/ports/src/virtualbox5/frontend/console.cc @@ -291,7 +291,13 @@ void GenodeConsole::_handle_mode_change() Genodefb *fb = dynamic_cast<Genodefb *>(pFramebuffer); - fb->update_mode(_gui.mode()); + Gui::Rect const gui_win = _gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return _gui.panorama().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 800, 600 } }; }); }); + + fb->update_mode(gui_win); update_video_mode(); } @@ -340,7 +346,7 @@ void GenodeConsole::init_backends(IKeyboard * gKeyboard, IMouse * gMouse) HRESULT rc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer); Assert(SUCCEEDED(rc) && pFramebuffer); - _gui.mode_sigh(_mode_change_signal_dispatcher); + _gui.info_sigh(_mode_change_signal_dispatcher); _handle_mode_change(); } diff --git a/repos/ports/src/virtualbox5/frontend/fb.h b/repos/ports/src/virtualbox5/frontend/fb.h index 89e332779d..34ed4ce607 100644 --- a/repos/ports/src/virtualbox5/frontend/fb.h +++ b/repos/ports/src/virtualbox5/frontend/fb.h @@ -34,13 +34,13 @@ class Genodefb : Genode::Env &_env; Gui::Connection &_gui; Gui::Top_level_view _view { _gui }; - Fb_Genode::Mode _fb_mode { .area = { 1024, 768 } }; + Gui::Rect _gui_win { .at = { }, .area = { 1024, 768 } }; /* * The mode currently used by the VM. Can be smaller than the * framebuffer mode. */ - Fb_Genode::Mode _virtual_fb_mode; + Gui::Area _virtual_fb_mode; void *_attach() { @@ -64,23 +64,23 @@ class Genodefb : { if (!_fb_base) return; - size_t const max_h = Genode::min(_fb_mode.area.h, _virtual_fb_mode.area.h); - size_t const num_pixels = _fb_mode.area.w * max_h; - memset(_fb_base, 0, num_pixels * _fb_mode.bytes_per_pixel()); - _gui.framebuffer.refresh(0, 0, _virtual_fb_mode.area.w, _virtual_fb_mode.area.h); + size_t const max_h = Genode::min(_gui_win.area.h, _virtual_fb_mode.h); + size_t const num_pixels = _gui_win.area.w * max_h; + memset(_fb_base, 0, num_pixels * sizeof(Genode::Pixel_rgb888)); + _gui.framebuffer.refresh({ _gui_win.at, _virtual_fb_mode }); } void _adjust_buffer() { - _gui.buffer(_fb_mode, false); - _view.area(_fb_mode.area); + _gui.buffer({ .area = _gui_win.area, .alpha = false }); + _view.geometry(_gui_win); } - Fb_Genode::Mode _initial_setup() + Gui::Area _initial_setup() { _adjust_buffer(); _view.front(); - return _fb_mode; + return _gui_win.area; } public: @@ -96,14 +96,14 @@ class Genodefb : Assert(rc == VINF_SUCCESS); } - int w() const { return _fb_mode.area.w; } - int h() const { return _fb_mode.area.h; } + int w() const { return _gui_win.area.w; } + int h() const { return _gui_win.area.h; } - void update_mode(Fb_Genode::Mode mode) + void update_mode(Gui::Rect const gui_win) { Lock(); - _fb_mode = mode; + _gui_win = gui_win; if (_fb_base) _env.rm().detach(Genode::addr_t(_fb_base)); @@ -135,32 +135,32 @@ class Genodefb : /* save the new bitmap reference */ _display->QuerySourceBitmap(screen, _display_bitmap.asOutParam()); - bool const ok = (w <= (ULONG)_fb_mode.area.w) && - (h <= (ULONG)_fb_mode.area.h); + bool const ok = (w <= (ULONG)_gui_win.area.w) && + (h <= (ULONG)_gui_win.area.h); - bool const changed = (w != (ULONG)_virtual_fb_mode.area.w) || - (h != (ULONG)_virtual_fb_mode.area.h); + bool const changed = (w != (ULONG)_virtual_fb_mode.w) || + (h != (ULONG)_virtual_fb_mode.h); if (ok && changed) { Genode::log("fb resize : [", screen, "] ", - _virtual_fb_mode.area, " -> ", + _virtual_fb_mode, " -> ", w, "x", h, - " (host: ", _fb_mode.area, ")"); + " (host: ", _gui_win.area, ")"); - if ((w < (ULONG)_fb_mode.area.w) || - (h < (ULONG)_fb_mode.area.h)) { + if ((w < (ULONG)_gui_win.area.w) || + (h < (ULONG)_gui_win.area.h)) { /* clear the old content around the new, smaller area. */ _clear_screen(); } - _virtual_fb_mode = Fb_Genode::Mode { .area = { w, h } }; + _virtual_fb_mode = { w, h }; result = S_OK; } else if (changed) { Genode::log("fb resize : [", screen, "] ", - _virtual_fb_mode.area, " -> ", + _virtual_fb_mode, " -> ", w, "x", h, " ignored" - " (host: ", _fb_mode.area, ")"); + " (host: ", _gui_win.area, ")"); } Unlock(); @@ -213,8 +213,8 @@ class Genodefb : &ulBytesPerLine, &bitmapFormat); - Gui::Area const area_fb = Gui::Area(_fb_mode.area.w, - _fb_mode.area.h); + Gui::Area const area_fb = Gui::Area(_gui_win.area.w, + _gui_win.area.h); Gui::Area const area_vm = Gui::Area(ulWidth, ulHeight); using namespace Genode; @@ -251,7 +251,7 @@ class Genodefb : Lock(); - Gui::Area const area_fb = _fb_mode.area; + Gui::Area const area_fb = _gui_win.area; Gui::Area const area_vm = Gui::Area(width, height); using namespace Genode; @@ -290,8 +290,8 @@ class Genodefb : if (!supported) return E_POINTER; - *supported = ((width <= (ULONG)_fb_mode.area.w) && - (height <= (ULONG)_fb_mode.area.h)); + *supported = ((width <= (ULONG)_gui_win.area.w) && + (height <= (ULONG)_gui_win.area.h)); return S_OK; } diff --git a/repos/ports/src/virtualbox5/spec/nova/vcpu.h b/repos/ports/src/virtualbox5/spec/nova/vcpu.h index 216b91a2fd..38b735ab80 100644 --- a/repos/ports/src/virtualbox5/spec/nova/vcpu.h +++ b/repos/ports/src/virtualbox5/spec/nova/vcpu.h @@ -85,7 +85,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread>, private: - X86FXSTATE _emt_fpu_state __attribute__((aligned(0x10))); + X86FXSTATE _emt_fpu_state __attribute__((aligned(64))); pthread _pthread; pthread_cond_t _cond_wait; @@ -968,7 +968,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread>, /* save current FPU state */ fpu_save(reinterpret_cast<char *>(&_emt_fpu_state)); /* write FPU state from pCtx to utcb */ - memcpy(utcb->fpu, pCtx->pXStateR3, sizeof(utcb->fpu)); + memcpy(utcb->fpu, pCtx->pXStateR3, sizeof(X86FXSTATE)); /* tell kernel to transfer current fpu registers to vCPU */ utcb->mtd |= Mtd::FPU; @@ -984,7 +984,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread>, _current_vcpu = 0; /* write FPU state of vCPU in utcb to pCtx */ - static_assert(sizeof(X86FXSTATE) == sizeof(utcb->fpu), "fpu size mismatch"); + static_assert(sizeof(X86FXSTATE) <= sizeof(utcb->fpu), "fpu size mismatch"); Genode::memcpy(pCtx->pXStateR3, utcb->fpu, sizeof(X86FXSTATE)); /* load saved FPU state of EMT thread */ diff --git a/repos/ports/src/virtualbox6/include/fb.h b/repos/ports/src/virtualbox6/include/fb.h index f1db4d66a0..7e5db31934 100644 --- a/repos/ports/src/virtualbox6/include/fb.h +++ b/repos/ports/src/virtualbox6/include/fb.h @@ -33,13 +33,13 @@ class Genodefb : Genode::Env &_env; Gui::Connection &_gui; Gui::Top_level_view _view { _gui }; - Fb_Genode::Mode _fb_mode { .area = { 1024, 768 } }; + Gui::Rect _gui_win { { }, { 1024, 768 } }; /* * The mode currently used by the VM. Can be smaller than the * framebuffer mode. */ - Fb_Genode::Mode _virtual_fb_mode; + Gui::Area _virtual_fb_area; void *_attach() { @@ -62,23 +62,23 @@ class Genodefb : { if (!_fb_base) return; - size_t const max_h = Genode::min(_fb_mode.area.h, _virtual_fb_mode.area.h); - size_t const num_pixels = _fb_mode.area.w * max_h; - memset(_fb_base, 0, num_pixels * _fb_mode.bytes_per_pixel()); - _gui.framebuffer.refresh(0, 0, _virtual_fb_mode.area.w, _virtual_fb_mode.area.h); + size_t const max_h = Genode::min(_gui_win.area.h, _virtual_fb_area.h); + size_t const num_pixels = _gui_win.area.w * max_h; + memset(_fb_base, 0, num_pixels * sizeof(Genode::Pixel_rgb888)); + _gui.framebuffer.refresh({ _gui_win.at, _virtual_fb_area }); } void _adjust_buffer() { - _gui.buffer(_fb_mode, false); - _view.area(_fb_mode.area); + _gui.buffer({ .area = _gui_win.area, .alpha = false }); + _view.area(_gui_win.area); } - Fb_Genode::Mode _initial_setup() + Gui::Area _initial_setup() { _adjust_buffer(); _view.front(); - return _fb_mode; + return _gui_win.area; } public: @@ -89,7 +89,7 @@ class Genodefb : : _env(env), _gui(gui), - _virtual_fb_mode(_initial_setup()), + _virtual_fb_area(_initial_setup()), _display(display) { int rc = RTCritSectInit(&_fb_lock); @@ -98,14 +98,14 @@ class Genodefb : virtual ~Genodefb() { } - int w() const { return _fb_mode.area.w; } - int h() const { return _fb_mode.area.h; } + int w() const { return _gui_win.area.w; } + int h() const { return _gui_win.area.h; } - void update_mode(Fb_Genode::Mode mode) + void update_mode(Gui::Rect gui_win) { Lock(); - _fb_mode = mode; + _gui_win = gui_win; if (_fb_base) _env.rm().detach(Genode::addr_t(_fb_base)); @@ -137,32 +137,32 @@ class Genodefb : /* save the new bitmap reference */ _display->QuerySourceBitmap(screen, _display_bitmap.asOutParam()); - bool const ok = (w <= (ULONG)_fb_mode.area.w) && - (h <= (ULONG)_fb_mode.area.h); + bool const ok = (w <= (ULONG)_gui_win.area.w) && + (h <= (ULONG)_gui_win.area.h); - bool const changed = (w != (ULONG)_virtual_fb_mode.area.w) || - (h != (ULONG)_virtual_fb_mode.area.h); + bool const changed = (w != (ULONG)_virtual_fb_area.w) || + (h != (ULONG)_virtual_fb_area.h); if (ok && changed) { Genode::log("fb resize : [", screen, "] ", - _virtual_fb_mode.area, " -> ", + _virtual_fb_area, " -> ", w, "x", h, - " (host: ", _fb_mode.area, ")"); + " (host: ", _gui_win.area, ")"); - if ((w < (ULONG)_fb_mode.area.w) || - (h < (ULONG)_fb_mode.area.h)) { + if ((w < (ULONG)_gui_win.area.w) || + (h < (ULONG)_gui_win.area.h)) { /* clear the old content around the new, smaller area. */ _clear_screen(); } - _virtual_fb_mode = Fb_Genode::Mode { .area = { w, h } }; + _virtual_fb_area = { w, h }; result = S_OK; } else if (changed) { Genode::log("fb resize : [", screen, "] ", - _virtual_fb_mode.area, " -> ", + _virtual_fb_area, " -> ", w, "x", h, " ignored" - " (host: ", _fb_mode.area, ")"); + " (host: ", _gui_win.area, ")"); } Unlock(); @@ -215,8 +215,8 @@ class Genodefb : &ulBytesPerLine, &bitmapFormat); - Gui::Area const area_fb = Gui::Area(_fb_mode.area.w, - _fb_mode.area.h); + Gui::Area const area_fb = Gui::Area(_gui_win.area.w, + _gui_win.area.h); Gui::Area const area_vm = Gui::Area(ulWidth, ulHeight); using namespace Genode; @@ -253,7 +253,7 @@ class Genodefb : Lock(); - Gui::Area const area_fb = _fb_mode.area; + Gui::Area const area_fb = _gui_win.area; Gui::Area const area_vm = Gui::Area(width, height); using namespace Genode; @@ -292,8 +292,8 @@ class Genodefb : if (!supported) return E_POINTER; - *supported = ((width <= (ULONG)_fb_mode.area.w) && - (height <= (ULONG)_fb_mode.area.h)); + *supported = ((width <= (ULONG)_gui_win.area.w) && + (height <= (ULONG)_gui_win.area.h)); return S_OK; } diff --git a/repos/ports/src/virtualbox6/main.cc b/repos/ports/src/virtualbox6/main.cc index 96a58a635c..6735edcc03 100644 --- a/repos/ports/src/virtualbox6/main.cc +++ b/repos/ports/src/virtualbox6/main.cc @@ -302,7 +302,7 @@ struct Main : Event_handler Gui::Connection &gui = *new Registered<Gui::Connection>(_gui_connections, _env, label.string()); gui.input.sigh(_input_handler); - gui.mode_sigh(_fb_mode_handler); + gui.info_sigh(_fb_mode_handler); Genodefb *fb = new Genodefb(_env, gui, _idisplay); @@ -411,7 +411,7 @@ void Main::_sync_capslock() void Main::_handle_input() { auto handle_one_event = [&] (Input::Event const &ev) { - /* don't confuse guests and drop CapsLock events in ROM mode */ + /* don't confuse guests and drop CapsLock events in ROM mode */ if (_capslock.mode == Capslock::Mode::ROM) { if (ev.key_press(Input::KEY_CAPSLOCK) || ev.key_release(Input::KEY_CAPSLOCK)) @@ -438,7 +438,11 @@ void Main::_handle_fb_mode() Genodefb *fb = dynamic_cast<Genodefb *>(pFramebuffer); - fb->update_mode(gui.mode()); + Gui::Rect const gui_win = gui.window().convert<Gui::Rect>( + [&] (Gui::Rect rect) { return rect; }, + [&] (Gui::Undefined) { return Gui::Rect { { }, { 1024, 768 } }; }); + + fb->update_mode(gui_win); if ((fb->w() <= 1) && (fb->h() <= 1)) { /* interpret a size of 0x0 as indication to quit VirtualBox */ diff --git a/repos/ports/src/virtualbox6/patches/avx.patch b/repos/ports/src/virtualbox6/patches/avx.patch new file mode 100644 index 0000000000..542d132a87 --- /dev/null +++ b/repos/ports/src/virtualbox6/patches/avx.patch @@ -0,0 +1,75 @@ +--- a/src/virtualbox6/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp ++++ b/src/virtualbox6/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp +@@ -2470,6 +2470,8 @@ + pCpum->GuestFeatures.cbMaxExtendedState), + VERR_CPUM_IPE_1); + pVCpu0->cpum.s.Guest.aoffXState[iComponent] = pSubLeaf->uEbx; ++ /* store uEax to later on detect compact mode */ ++// pVCpu0->cpum.s.Guest.aoffXState[iComponent] = pSubLeaf->uEax; + } + + /* Copy the CPU #0 data to the other CPUs. */ +@@ -3558,6 +3560,8 @@ + VERR_CPUM_IPE_2); + continue; + case 1: ++ /* permit compact AVX mode, Intel: 13.2 ENUMERATION OF CPU SUPPORT FOR XSAVE INSTRUCTIONS AND XSAVE- SUPPORTED FEATURES */ ++// pCurLeaf->uEax &= 1 | 2; + pCurLeaf->uEax &= 0; + pCurLeaf->uEcx &= 0; + pCurLeaf->uEdx &= 0; +@@ -4285,7 +4289,8 @@ + rc = cpumR3CpuIdReadIsaExtCfgLegacy(pVM, pIsaExts, pCpumCfg, "SSE4.2", &pConfig->enmSse42, true); + AssertLogRelRCReturn(rc, rc); + +- bool const fMayHaveXSave = fNestedPagingAndFullGuestExec ++ bool const fEnforceHWusage = true; ++ bool const fMayHaveXSave = fEnforceHWusage + && pVM->cpum.s.HostFeatures.fXSaveRstor + && pVM->cpum.s.HostFeatures.fOpSysXSaveRstor; + uint64_t const fXStateHostMask = pVM->cpum.s.fXStateHostMask; +@@ -4296,7 +4301,7 @@ + * unrestricted guest execution mode. Not possible to force this one without + * host support at the moment. + */ +- rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "XSAVE", &pConfig->enmXSave, fNestedPagingAndFullGuestExec, ++ rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "XSAVE", &pConfig->enmXSave, fEnforceHWusage, + fMayHaveXSave /*fAllowed*/); + AssertLogRelRCReturn(rc, rc); + +@@ -4305,7 +4310,7 @@ + * XSAVE is exposed too. For the time being the default is to only expose this + * to VMs with nested paging and AMD-V or unrestricted guest execution mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "AVX", &pConfig->enmAvx, fNestedPagingAndFullGuestExec, ++ rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "AVX", &pConfig->enmAvx, fEnforceHWusage, + fMayHaveXSave && pConfig->enmXSave && (fXStateHostMask & XSAVE_C_YMM) /*fAllowed*/); + AssertLogRelRCReturn(rc, rc); + +@@ -4314,7 +4319,7 @@ + * XSAVE is exposed too. For the time being the default is to only expose this + * to VMs with nested paging and AMD-V or unrestricted guest execution mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "AVX2", &pConfig->enmAvx2, fNestedPagingAndFullGuestExec /* temporarily */, ++ rc = cpumR3CpuIdReadIsaExtCfgEx(pVM, pIsaExts, "AVX2", &pConfig->enmAvx2, fEnforceHWusage /* temporarily */, + fMayHaveXSave && pConfig->enmXSave && (fXStateHostMask & XSAVE_C_YMM) /*fAllowed*/); + AssertLogRelRCReturn(rc, rc); + +@@ -4323,7 +4328,7 @@ + * default is to only do this for VMs with nested paging and AMD-V or + * unrestricted guest mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "AESNI", &pConfig->enmAesNi, fNestedPagingAndFullGuestExec); ++ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "AESNI", &pConfig->enmAesNi, fEnforceHWusage); + AssertLogRelRCReturn(rc, rc); + + /** @cfgm{/CPUM/IsaExts/PCLMUL, isaextcfg, depends} +@@ -4425,7 +4430,7 @@ + * being the default is to only do this for VMs with nested paging and AMD-V or + * unrestricted guest mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "SSE4A", &pConfig->enmSse4A, fNestedPagingAndFullGuestExec); ++ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "SSE4A", &pConfig->enmSse4A, fEnforceHWusage); + AssertLogRelRCReturn(rc, rc); + + /** @cfgm{/CPUM/IsaExts/MISALNSSE, isaextcfg, depends} diff --git a/repos/ports/src/virtualbox6/patches/mousebuttons.patch b/repos/ports/src/virtualbox6/patches/mousebuttons.patch new file mode 100644 index 0000000000..2a50a0a16d --- /dev/null +++ b/repos/ports/src/virtualbox6/patches/mousebuttons.patch @@ -0,0 +1,189 @@ +--- a/src/virtualbox6/src/VBox/Devices/VMMDev/VMMDev.cpp ++++ b/src/virtualbox6/src/VBox/Devices/VMMDev/VMMDev.cpp +@@ -150,6 +150,90 @@ + #define VMMDEV_HEARTBEAT_DEFAULT_INTERVAL (2U*RT_NS_1SEC_64) + + ++/* ++ * Mouse-button event tracking ++ * ++ * If mouse press and release events are reported in quick succession (e.g., ++ * with Genode <button-scroll> detection enabled), the guest may miss events if ++ * fButtons is not collected quick enough. ++ */ ++ ++bool VMMDEV::MouseButtons::Button::pending() const ++{ ++ return _pending != Pending::NONE; ++} ++ ++bool VMMDEV::MouseButtons::Button::record(bool const press) ++{ ++ /* ++ * We begin recording only if the state changes, but keep recording ++ * afterwards until nothing is pending anymore. ++ */ ++ if (_pending == Pending::NONE && _pressed == press) ++ return false; ++ ++ switch (_pending) { ++ case Pending::NONE: _pending = press ? Pending::PRESS : Pending::RELEASE; break; ++ case Pending::PRESS: _pending = press ? Pending::PRESS : Pending::PRESS_RELEASE; break; ++ case Pending::PRESS_RELEASE: _pending = press ? Pending::PRESS : Pending::PRESS_RELEASE; break; ++ case Pending::RELEASE: _pending = !press ? Pending::RELEASE : Pending::RELEASE_PRESS; break; ++ case Pending::RELEASE_PRESS: _pending = !press ? Pending::RELEASE : Pending::RELEASE_PRESS; break; ++ } ++ ++ return true; ++} ++ ++bool VMMDEV::MouseButtons::Button::next() ++{ ++ switch (_pending) { ++ case Pending::NONE: break; ++ ++ case Pending::PRESS: _pending = Pending::NONE; _pressed = true; break; ++ case Pending::PRESS_RELEASE: _pending = Pending::RELEASE; _pressed = true; break; ++ case Pending::RELEASE: _pending = Pending::NONE; _pressed = false; break; ++ case Pending::RELEASE_PRESS: _pending = Pending::PRESS; _pressed = false; break; ++ } ++ ++ return _pressed; ++} ++ ++bool VMMDEV::MouseButtons::pending() const ++{ ++ return l.pending() || r.pending() || m.pending() || x1.pending() || x2.pending(); ++} ++ ++void VMMDEV::MouseButtons::clear() ++{ ++ l = r = m = x1 = x2 = { Pending::NONE, 0 }; ++} ++ ++bool VMMDEV::MouseButtons::record(unsigned fButtons) ++{ ++ bool pending = false; ++ ++ pending |= l.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_LEFT)); ++ pending |= r.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_RIGHT)); ++ pending |= m.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_MIDDLE)); ++ pending |= x1.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_X1)); ++ pending |= x2.record(!!(fButtons & VMMDEV_MOUSE_BUTTON_X2)); ++ ++ return pending; ++} ++ ++unsigned VMMDEV::MouseButtons::next() ++{ ++ unsigned next = 0; ++ ++ next |= l.next() ? VMMDEV_MOUSE_BUTTON_LEFT : 0; ++ next |= r.next() ? VMMDEV_MOUSE_BUTTON_RIGHT : 0; ++ next |= m.next() ? VMMDEV_MOUSE_BUTTON_MIDDLE : 0; ++ next |= x1.next() ? VMMDEV_MOUSE_BUTTON_X1 : 0; ++ next |= x2.next() ? VMMDEV_MOUSE_BUTTON_X2 : 0; ++ ++ return next; ++} ++ ++ + #ifndef VBOX_DEVICE_STRUCT_TESTCASE + #ifdef IN_RING3 + +@@ -1079,7 +1163,7 @@ + * @param pThis The VMMDev shared instance data. + * @param pReqHdr The header of the request to handle. + */ +-static int vmmdevReqHandler_GetMouseStatusEx(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr) ++static int vmmdevReqHandler_GetMouseStatusEx(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pThisCC, VMMDevRequestHeader *pReqHdr) + { + VMMDevReqMouseStatusEx *pReq = (VMMDevReqMouseStatusEx *)pReqHdr; + AssertMsgReturn(pReq->Core.header.size == sizeof(*pReq), ("%u\n", pReq->Core.header.size), VERR_INVALID_PARAMETER); +@@ -1099,7 +1183,14 @@ + pReq->Core.pointerYPos = pThis->yMouseAbs; + pReq->dz = pThis->dzMouse; + pReq->dw = pThis->dwMouse; +- pReq->fButtons = pThis->fMouseButtons; ++ ++ /* accumulated relative wheel motion consumed */ ++ pThis->dzMouse = 0; pThis->dwMouse = 0; ++ ++ pReq->fButtons = pThis->mouseButtons.next(); ++ if (pThis->mouseButtons.pending()) ++ vmmdevNotifyGuestWorker(pDevIns, pThis, pThisCC, VMMDEV_EVENT_MOUSE_POSITION_CHANGED); ++ + LogRel2(("VMMDev: vmmdevReqHandler_GetMouseStatusEx: mouseFeatures=%#x, xAbs=%d, yAbs=%d, zAbs=%d, wMouseRel=%d, fButtons=0x%x\n", + pReq->Core.mouseFeatures, pReq->Core.pointerXPos, pReq->Core.pointerYPos, pReq->dz, pReq->dw, pReq->fButtons)); + return VINF_SUCCESS; +@@ -2753,7 +2844,7 @@ + break; + + case VMMDevReq_GetMouseStatusEx: +- pReqHdr->rc = vmmdevReqHandler_GetMouseStatusEx(pThis, pReqHdr); ++ pReqHdr->rc = vmmdevReqHandler_GetMouseStatusEx(pDevIns, pThis, pThisCC, pReqHdr); + break; + + case VMMDevReq_SetMouseStatus: +@@ -3588,16 +3679,17 @@ + || pThis->yMouseAbs != yAbs + || dz + || dw +- || pThis->fMouseButtons != fButtons) ++ || pThis->mouseButtons.record(fButtons)) + { + Log2(("vmmdevIPort_SetAbsoluteMouse : settings absolute position to x = %d, y = %d, z = %d, w = %d, fButtons = 0x%x\n", + xAbs, yAbs, dz, dw, fButtons)); + + pThis->xMouseAbs = xAbs; + pThis->yMouseAbs = yAbs; +- pThis->dzMouse = dz; +- pThis->dwMouse = dw; +- pThis->fMouseButtons = fButtons; ++ ++ /* accumulate relative wheel motion */ ++ pThis->dzMouse += dz; ++ pThis->dwMouse += dw; + + VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_MOUSE_POSITION_CHANGED); + } +@@ -4114,7 +4206,7 @@ + * into saved state, but rather initialize to zeroes on load. */ + pThis->dzMouse = 0; + pThis->dwMouse = 0; +- pThis->fMouseButtons = 0; ++ pThis->mouseButtons.clear(); + + pHlp->pfnSSMGetBool(pSSM, &pThis->fNewGuestFilterMaskValid); + pHlp->pfnSSMGetU32(pSSM, &pThis->fNewGuestFilterMask); +--- a/src/virtualbox6/src/VBox/Devices/VMMDev/VMMDevState.h ++++ b/src/virtualbox6/src/VBox/Devices/VMMDev/VMMDevState.h +@@ -134,7 +134,27 @@ + int32_t yMouseAbs; + int32_t dzMouse; + int32_t dwMouse; +- uint32_t fMouseButtons; ++ ++ struct MouseButtons ++ { ++ enum class Pending { NONE, PRESS, PRESS_RELEASE, RELEASE, RELEASE_PRESS }; ++ ++ struct Button ++ { ++ Pending _pending; ++ bool _pressed; ++ ++ bool pending() const; ++ bool record(bool state); ++ bool next(); ++ } l, r, m, x1, x2; ++ ++ bool pending() const; ++ void clear(); ++ bool record(unsigned fButtons); ++ unsigned next(); ++ } mouseButtons; ++ + /** @} */ + /** Does the guest currently want the host pointer to be shown? */ + uint32_t fHostCursorRequested; diff --git a/repos/ports/src/virtualbox6/patches/rdrand.patch b/repos/ports/src/virtualbox6/patches/rdrand.patch new file mode 100644 index 0000000000..8826800a64 --- /dev/null +++ b/repos/ports/src/virtualbox6/patches/rdrand.patch @@ -0,0 +1,20 @@ +--- a/src/virtualbox6/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp ++++ b/src/virtualbox6/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp +@@ -4358,7 +4358,7 @@ + * the default is to only do this for VMs with nested paging and AMD-V or + * unrestricted guest mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "RDRAND", &pConfig->enmRdRand, fNestedPagingAndFullGuestExec); ++ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "RDRAND", &pConfig->enmRdRand, fEnforceHWusage); + AssertLogRelRCReturn(rc, rc); + + /** @cfgm{/CPUM/IsaExts/RDSEED, isaextcfg, depends} +@@ -4366,7 +4366,7 @@ + * the default is to only do this for VMs with nested paging and AMD-V or + * unrestricted guest mode. + */ +- rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "RDSEED", &pConfig->enmRdSeed, fNestedPagingAndFullGuestExec); ++ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "RDSEED", &pConfig->enmRdSeed, fEnforceHWusage); + AssertLogRelRCReturn(rc, rc); + + /** @cfgm{/CPUM/IsaExts/CLFLUSHOPT, isaextcfg, depends} diff --git a/repos/ports/src/virtualbox6/patches/series b/repos/ports/src/virtualbox6/patches/series index 45963c123e..4dba77e48f 100644 --- a/repos/ports/src/virtualbox6/patches/series +++ b/repos/ports/src/virtualbox6/patches/series @@ -14,3 +14,6 @@ pgmphys.patch sup_ioctl_query_func_size.patch disk_geometry.patch stack_size.patch +avx.patch +rdrand.patch +mousebuttons.patch diff --git a/repos/ports/src/virtualbox6/sup_vcpu.cc b/repos/ports/src/virtualbox6/sup_vcpu.cc index cff44179bb..b4af51dcba 100644 --- a/repos/ports/src/virtualbox6/sup_vcpu.cc +++ b/repos/ports/src/virtualbox6/sup_vcpu.cc @@ -265,12 +265,27 @@ template <typename VIRT> void Sup::Vcpu_impl<VIRT>::_transfer_state_to_vcpu(CPUM state.tpr_threshold.charge(pending_priority); } - /* export FPU state */ - AssertCompile(sizeof(Vcpu_state::Fpu::State) >= sizeof(X86FXSTATE)); + /* export FPU state - start */ + state.xcr0.charge(ctx.aXcr[0]); - _state->ref.fpu.charge([&](Vcpu_state::Fpu::State &fpu) { - ::memcpy(fpu._buffer, ctx.pXStateR3, sizeof(fpu)); + { + ::uint64_t ia32_xss = 0; + auto const rc = CPUMQueryGuestMsr(&_vmcpu, 0xDA0 /* MSR_IA32_XSS */, + &ia32_xss); + + if (rc == VINF_SUCCESS) + state.xss.charge(ia32_xss); + } + + _state->ref.fpu.charge([&](Vcpu_state::Fpu::State &fpu) { + unsigned fpu_size = min(_vm.cpum.s.HostFeatures.cbMaxExtendedState, + sizeof(fpu._buffer)); + + ::memcpy(fpu._buffer, ctx.pXStateR3, fpu_size); + + return fpu_size; }); + /* export FPU state - end */ { ::uint64_t tsc_aux = 0; @@ -413,12 +428,21 @@ template <typename VIRT> void Sup::Vcpu_impl<VIRT>::_transfer_state_to_vbox(CPUM APICSetTpr(pVCpu, tpr); - /* import FPU state */ + /* import FPU state - start */ _state->ref.fpu.with_state([&](Vcpu_state::Fpu::State const &fpu) { - ::memcpy(ctx.pXStateR3, fpu._buffer, sizeof(X86FXSTATE)); + unsigned fpu_size = min(_vm.cpum.s.HostFeatures.cbMaxExtendedState, + sizeof(fpu._buffer)); + + ::memcpy(ctx.pXStateR3, fpu._buffer, fpu_size); + return true; }); + CPUMSetGuestMsr (pVCpu, 0xDA0 /* MSR_IA32_XSS */, state.xss.value()); + CPUMSetGuestXcr0(pVCpu, state.xcr0.value()); + + /* import FPU state - end */ + /* do SVM/VMX-specific transfers */ VIRT::transfer_state_to_vbox(state, _vmcpu, ctx); } diff --git a/repos/ports/src/virtualbox6/sup_vcpu_svm.h b/repos/ports/src/virtualbox6/sup_vcpu_svm.h index 53f38ee497..39068661e5 100644 --- a/repos/ports/src/virtualbox6/sup_vcpu_svm.h +++ b/repos/ports/src/virtualbox6/sup_vcpu_svm.h @@ -77,6 +77,7 @@ Genode::Vm_connection::Exit_config const Sup::Svm::exit_config { /* ... */ }; | SVM_CTRL_INTERCEPT_WBINVD | SVM_CTRL_INTERCEPT_MONITOR | SVM_CTRL_INTERCEPT_RDTSCP + | SVM_CTRL_INTERCEPT_XSETBV | SVM_CTRL_INTERCEPT_MWAIT; unsigned Sup::Svm::ctrl_primary() diff --git a/repos/ports/src/virtualbox6/sup_vcpu_vmx.h b/repos/ports/src/virtualbox6/sup_vcpu_vmx.h index 21d2f73bb0..b6236accd4 100644 --- a/repos/ports/src/virtualbox6/sup_vcpu_vmx.h +++ b/repos/ports/src/virtualbox6/sup_vcpu_vmx.h @@ -81,6 +81,7 @@ unsigned Sup::Vmx::ctrl_secondary() | VMX_PROC_CTLS2_RDTSCP | VMX_PROC_CTLS2_EPT | VMX_PROC_CTLS2_INVPCID + | VMX_PROC_CTLS2_XSAVES_XRSTORS ; } diff --git a/tool/autopilot.list b/tool/autopilot.list index 406e3471d1..a5da125d99 100644 --- a/tool/autopilot.list +++ b/tool/autopilot.list @@ -86,7 +86,6 @@ tz_vmm usb_block usb_hid_raw usb_hid_reconnect -vbox5_genode_usb_hid_raw vbox5_ubuntu_16_04_32 vbox5_ubuntu_16_04_64 vbox5_win10_64 @@ -95,6 +94,7 @@ vbox5_win7_64 vbox5_win7_64_multiple vbox5_win7_64_raw vbox5_win7_64_share +vbox6_genode_usb_hid_raw verify vfs_cfg vfs_import diff --git a/tool/builddir/build.conf/repos_arm_v6 b/tool/builddir/build.conf/repos_arm_v6 index a00b0e1309..9e010ed15c 100644 --- a/tool/builddir/build.conf/repos_arm_v6 +++ b/tool/builddir/build.conf/repos_arm_v6 @@ -1,4 +1,6 @@ + # # Board support for Raspberry Pi family # #REPOSITORIES += $(GENODE_DIR)/repos/rpi + diff --git a/tool/builddir/build.conf/repos_arm_v7 b/tool/builddir/build.conf/repos_arm_v7 index a708c1522b..86ee83ee7f 100644 --- a/tool/builddir/build.conf/repos_arm_v7 +++ b/tool/builddir/build.conf/repos_arm_v7 @@ -1,3 +1,4 @@ + # # Board-support for Xilinx Zynq-7000 SoC # diff --git a/tool/builddir/build.conf/repos_arm_v8 b/tool/builddir/build.conf/repos_arm_v8 index 8bdd984dc9..7793e54b10 100644 --- a/tool/builddir/build.conf/repos_arm_v8 +++ b/tool/builddir/build.conf/repos_arm_v8 @@ -1,3 +1,4 @@ + # # Board support for i.MX SoC family # @@ -12,3 +13,4 @@ # Board support for Allwinner SoC family # #REPOSITORIES += $(GENODE_DIR)/repos/allwinner + diff --git a/tool/builddir/build.conf/repos_riscv b/tool/builddir/build.conf/repos_riscv index 2141a9716d..a0c0333057 100644 --- a/tool/builddir/build.conf/repos_riscv +++ b/tool/builddir/build.conf/repos_riscv @@ -1,3 +1,4 @@ + # # Board support for RISC-V Qemu / MiG-V # diff --git a/tool/builddir/build.conf/repos_x86 b/tool/builddir/build.conf/repos_x86 index 67d9230eb7..d41ebfd37a 100644 --- a/tool/builddir/build.conf/repos_x86 +++ b/tool/builddir/build.conf/repos_x86 @@ -1,3 +1,4 @@ + # # Drivers for x86 PC # diff --git a/tool/create_builddir b/tool/create_builddir index f465fbf49b..d78c9c0375 100755 --- a/tool/create_builddir +++ b/tool/create_builddir @@ -85,13 +85,13 @@ endif $(BUILD_DIR)/etc: @mkdir -p $@ -BUILD_CONF_X86 := run_x86 run_boot_dir repos repos_x86 -BUILD_CONF_ARM_V6 := run_arm_v6 run_boot_dir repos repos_arm_v6 -BUILD_CONF_ARM_V7 := run_arm_v7 run_boot_dir repos repos_arm_v7 +BUILD_CONF_X86 := run_x86 run_boot_dir repos_x86 repos +BUILD_CONF_ARM_V6 := run_arm_v6 run_boot_dir repos_arm_v6 repos +BUILD_CONF_ARM_V7 := run_arm_v7 run_boot_dir repos_arm_v7 repos BUILD_CONF(arm_v6) := $(BUILD_CONF_ARM_V6) BUILD_CONF(arm_v7a) := $(BUILD_CONF_ARM_V7) -BUILD_CONF(arm_v8a) := run_arm_v8 run_boot_dir repos repos_arm_v8 -BUILD_CONF(riscv) := run_riscv run_boot_dir repos repos_riscv +BUILD_CONF(arm_v8a) := run_arm_v8 run_boot_dir repos_arm_v8 repos +BUILD_CONF(riscv) := run_riscv run_boot_dir repos_riscv repos BUILD_CONF(x86_32) := run_x86_32 $(BUILD_CONF_X86) BUILD_CONF(x86_64) := run_x86_64 $(BUILD_CONF_X86) diff --git a/tool/run/boot_dir/foc b/tool/run/boot_dir/foc index 35c4be2ed8..805422c00b 100644 --- a/tool/run/boot_dir/foc +++ b/tool/run/boot_dir/foc @@ -92,7 +92,9 @@ proc run_boot_dir_x86 {binaries} { exec mv [run_dir]/image.elf [run_dir]/boot/image.elf - if {[have_include "image/iso"] || [have_include "image/disk"]} { + set options_bender "[boot_output]" + + if {[have_include "image/iso"] || [have_include "image/disk"] || [have_include image/uefi]} { if {[have_include "image/disk"]} { install_disk_bootloader_to_run_dir @@ -102,6 +104,11 @@ proc run_boot_dir_x86 {binaries} { install_iso_bootloader_to_run_dir } + if {[have_include image/uefi]} { + install_uefi_bootloader_to_run_dir + append options_bender " serial_fallback" + } + # # Generate GRUB2 config file # @@ -112,7 +119,7 @@ proc run_boot_dir_x86 {binaries} { # puts $fh "menuentry 'Genode on Fiasco.OC' {" puts $fh " insmod multiboot" - puts $fh " multiboot /boot/bender [boot_output]" + puts $fh " multiboot /boot/bender $options_bender" puts $fh " module /boot/bootstrap" puts $fh " module /boot/kernel fiasco [fiasco_serial_esc_arg]" puts $fh " module /boot/sigma0" @@ -126,7 +133,7 @@ proc run_boot_dir_x86 {binaries} { # run_image - if {[have_include "load/tftp"]} { + if {[have_spec x86] && [have_include "load/tftp"]} { # # Install PXE bootloader pulsar # @@ -136,7 +143,7 @@ proc run_boot_dir_x86 {binaries} { # Generate pulsar config file # set fh [open "[run_dir]/config-52-54-00-12-34-56" "WRONLY CREAT TRUNC"] - puts $fh " exec /boot/bender [boot_output]" + puts $fh " exec /boot/bender $options_bender" puts $fh " load /boot/bootstrap" puts $fh " load /boot/kernel -serial_esc" puts $fh " load /boot/sigma0" @@ -146,7 +153,7 @@ proc run_boot_dir_x86 {binaries} { generate_tftp_config } - if {[have_include "load/ipxe"]} { + if {[have_spec x86] && [have_include "load/ipxe"]} { create_ipxe_config update_ipxe_boot_dir create_symlink_for_iso diff --git a/tool/run/boot_dir/sel4 b/tool/run/boot_dir/sel4 index 992ac2818d..e4dd99a406 100644 --- a/tool/run/boot_dir/sel4 +++ b/tool/run/boot_dir/sel4 @@ -69,7 +69,7 @@ proc run_boot_dir {binaries} { if {[have_include image/uefi]} { install_uefi_bootloader_to_run_dir - set options_bender " serial_fallback" + append options_bender " serial_fallback" } #