diff --git a/repos/base-nova/run/platform.run b/repos/base-nova/run/platform.run index c705e0092c..5bc8bd352c 100644 --- a/repos/base-nova/run/platform.run +++ b/repos/base-nova/run/platform.run @@ -35,7 +35,7 @@ install_config $config build_boot_image "core init test-platform" -append qemu_args "-nographic -m 128" +append qemu_args "-nographic -m 128 -smp 2" run_genode_until {Test finished} 150 diff --git a/repos/base-nova/src/test/platform/main.cc b/repos/base-nova/src/test/platform/main.cc index 73dd78ea97..5706914340 100644 --- a/repos/base-nova/src/test/platform/main.cc +++ b/repos/base-nova/src/test/platform/main.cc @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2015 Genode Labs GmbH + * Copyright (C) 2015-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -25,7 +25,9 @@ #include #include + #include +#include #include "server.h" @@ -412,6 +414,154 @@ void test_server_oom(Genode::Env &env) ep.dissolve(&component); } +class Pager : private Genode::Thread { + + private: + + Native_capability _call_to_map; + Ram_dataspace_capability _ds; + static addr_t _ds_mem; + + void entry() { } + + static void page_fault() + { + Thread * myself = Thread::myself(); + Nova::Utcb * utcb = reinterpret_cast(myself->utcb()); + + if (utcb->msg_words() != 1) { + Genode::error("unexpected"); + while (1) { } + } + + Genode::addr_t map_from = utcb->msg[0]; +// Genode::error("pager: got map request ", Genode::Hex(map_from)); + + utcb->set_msg_word(0); + utcb->mtd = 0; + + Nova::Mem_crd crd_map(map_from >> 12, 0, Nova::Rights(true, true, true)); + bool res = utcb->append_item(crd_map, 0); + (void)res; + + Nova::reply(myself->stack_top()); + } + + public: + + Pager(Genode::Env &env, Location location) + : + Thread(env, "pager", 0x1000, location, Weight(), env.cpu()), + _ds(env.ram().alloc (4096)) + { + _ds_mem = env.rm().attach(_ds); + touch_read(reinterpret_cast(_ds_mem)); + + /* request creation of a 'local' EC */ + Thread::native_thread().ec_sel = Native_thread::INVALID_INDEX - 1; + Thread::start(); + + Genode::warning("pager: created"); + + Native_capability thread_cap = + Capability_space::import(Thread::native_thread().ec_sel); + + Genode::Nova_native_pd_client native_pd(env.pd().native_pd()); + Nova::Mtd mtd (Nova::Mtd::QUAL | Nova::Mtd::EIP | Nova::Mtd::ESP); + Genode::addr_t entry = reinterpret_cast(page_fault); + + _call_to_map = native_pd.alloc_rpc_cap(thread_cap, entry, + mtd.value()); + } + + Native_capability call_to_map() { return _call_to_map; } + addr_t mem_st() { return _ds_mem; } +}; + +addr_t Pager::_ds_mem; + +class Cause_mapping : public Genode::Thread { + + private: + + Native_capability _call_to_map; + Rm_connection _rm; + Region_map_client _sub_rm; + addr_t _mem_nd; + addr_t _mem_st; + Nova::Rights const _mapping_rwx = {true, true, true}; + + public: + + unsigned volatile called = 0; + + Cause_mapping(Genode::Env &env, Native_capability call_to_map, + Genode::addr_t mem_st, Location location) + : + Thread(env, "mapper", 0x1000, location, Weight(), env.cpu()), + _call_to_map(call_to_map), + _rm(env), + _sub_rm(_rm.create(0x2000)), + _mem_nd(env.rm().attach(_sub_rm.dataspace())), + _mem_st(mem_st) + { } + + void entry() { + + log("mapper: hello"); + + Nova::Utcb * nova_utcb = reinterpret_cast(utcb()); + + while (true) { + called ++; +// log("mapper: request mapping ", Hex(_mem_nd), " ", called); + + Nova::Crd old = nova_utcb->crd_rcv; + +// touch_read((unsigned char *)_mem_st); + + nova_utcb->msg[0] = _mem_st; + nova_utcb->set_msg_word(1); + nova_utcb->crd_rcv = Nova::Mem_crd(_mem_nd >> 12, 0, + _mapping_rwx); + Nova::call(_call_to_map.local_name()); + //touch_read((unsigned char *)_mem_nd); + + nova_utcb->msg[0] = _mem_nd; + nova_utcb->set_msg_word(1); + nova_utcb->crd_rcv = Nova::Mem_crd((_mem_nd + 0x1000) >> 12, 0, + _mapping_rwx); + Nova::call(_call_to_map.local_name()); +// touch_read((unsigned char *)_mem_nd + 0x1000); + + nova_utcb->crd_rcv = old; + } + } + + void revoke_remote() + { + Nova::revoke(Nova::Mem_crd(_mem_nd >> 12, 0, _mapping_rwx), true); + } +}; + +void test_delegate_revoke_smp(Genode::Env &env) +{ + Affinity::Space cpus = env.cpu().affinity_space(); + Genode::log("detected ", cpus.width(), "x", cpus.height(), " " + "CPU", cpus.total() > 1 ? "s." : "."); + + Pager pager(env, cpus.location_of_index(1)); + Cause_mapping mapper(env, pager.call_to_map(), pager.mem_st(), + cpus.location_of_index(1)); + mapper.start(); + + for (unsigned i = 0; i < 2000; i++) { + mapper.revoke_remote(); + if (i % 1000 == 0) + Genode::log("main ", i, " ", mapper.called); + } +} + class Greedy : public Genode::Thread { private: @@ -557,6 +707,8 @@ Main::Main(Env &env) : env(env) check(res, "pt_ctrl %2u", i); } + test_delegate_revoke_smp(env); + /* test PAT kernel feature */ test_pat(env);