diff --git a/repos/base-nova/run/platform.run b/repos/base-nova/run/platform.run
index 638432ea73..5891bf0056 100644
--- a/repos/base-nova/run/platform.run
+++ b/repos/base-nova/run/platform.run
@@ -18,7 +18,7 @@ install_config {
-
+
}
@@ -27,6 +27,6 @@ build_boot_image "core init test-platform"
append qemu_args "-nographic -m 128"
-run_genode_until {Test finished} 15
+run_genode_until {Test finished} 150
puts "\nTest succeeded"
diff --git a/repos/base-nova/src/test/platform/main.cc b/repos/base-nova/src/test/platform/main.cc
index 779032b0fd..4057fb3478 100644
--- a/repos/base-nova/src/test/platform/main.cc
+++ b/repos/base-nova/src/test/platform/main.cc
@@ -16,10 +16,121 @@
#include
#include
-using namespace Genode;
+#include
+#include
+
+#include "server.h"
static unsigned failed = 0;
+using namespace Genode;
+
+void test_server_oom()
+{
+ using namespace Genode;
+
+ enum { STACK_SIZE = 4096 };
+
+ static Cap_connection cap;
+ static Rpc_entrypoint ep(&cap, STACK_SIZE, "rpc_ep");
+
+ Test::Component component;
+ Test::Capability session_cap = ep.manage(&component);
+ Test::Client client(session_cap);
+
+ /* case that during reply we get oom */
+ for (unsigned i = 0; i < 20000; i++) {
+ Genode::Native_capability got_cap = client.void_cap();
+
+ if (!got_cap.valid()) {
+ PERR("%u cap id %lx invalid", i, got_cap.local_name());
+ failed ++;
+ break;
+ }
+
+ /* be evil and keep this cap by manually incrementing the ref count */
+ Cap_index idx(cap_map()->find(got_cap.local_name()));
+ idx.inc();
+
+ if (i % 5000 == 4999)
+ PINF("received %u. cap", i);
+ }
+
+ /* case that during send we get oom */
+ for (unsigned i = 0; i < 20000; i++) {
+ /* be evil and switch translation off - server ever uses a new selector */
+ Genode::Native_capability send_cap = session_cap;
+ send_cap.solely_map();
+
+ if (!client.cap_void(send_cap)) {
+ PERR("sending %4u. cap failed", i);
+ failed ++;
+ break;
+ }
+
+ if (i % 5000 == 4999)
+ PINF("sent %u. cap", i);
+ }
+
+ ep.dissolve(&component);
+}
+
+class Greedy : public Thread<4096> {
+
+ public:
+
+ Greedy()
+ :
+ Thread<0x1000>("greedy")
+ { }
+
+ void entry() {
+ PINF("starting");
+
+ enum { SUB_RM_SIZE = 2UL * 1024 * 1024 * 1024 };
+
+ Genode::Rm_connection sub_rm(0, SUB_RM_SIZE);
+ addr_t const mem = env()->rm_session()->attach(sub_rm.dataspace());
+
+ Nova::Utcb * nova_utcb = reinterpret_cast(utcb());
+ Nova::Rights const mapping_rwx(true, true, true);
+
+ addr_t const page_fault_portal = tid().exc_pt_sel + 14;
+
+ PERR("cause mappings in range [0x%lx, 0x%lx) %p", mem,
+ mem + SUB_RM_SIZE - 1, &mem);
+
+ for (addr_t map_to = mem; map_to < mem + SUB_RM_SIZE; map_to += 4096) {
+
+ /* setup faked page fault information */
+ nova_utcb->items = ((addr_t)&nova_utcb->qual[2] - (addr_t)nova_utcb->msg) / sizeof(addr_t);
+ nova_utcb->ip = 0xbadaffe;
+ nova_utcb->qual[1] = (addr_t)&mem;
+ nova_utcb->crd_rcv = Nova::Mem_crd(map_to >> 12, 0, mapping_rwx);
+
+ /* trigger faked page fault */
+ Genode::uint8_t res = Nova::call(page_fault_portal);
+ if (res != Nova::NOVA_OK) {
+ PINF("call result=%u", res);
+ failed++;
+ return;
+ }
+
+ /* check that we really got the mapping */
+ touch_read(reinterpret_cast(map_to));
+
+ /* print status information in interval of 32M */
+ if (!(map_to & (32UL * 1024 * 1024 - 1))) {
+ printf("0x%lx\n", map_to);
+ /* trigger some work to see quota in kernel decreasing */
+// Nova::Rights rwx(true, true, true);
+// Nova::revoke(Nova::Mem_crd((map_to - 32 * 1024 * 1024) >> 12, 12, rwx));
+ }
+ }
+ printf("still alive - done\n");
+ }
+};
+
void check(uint8_t res, const char *format, ...)
{
static char buf[128];
@@ -73,6 +184,33 @@ int main(int argc, char **argv)
check(res, "pt_ctrl %2u", i);
}
+ /* upgrade available capability indices for this process */
+ unsigned index = 512 * 1024;
+ static char local[128][sizeof(Cap_range)];
+
+ for (unsigned i = 0; i < sizeof(local) / sizeof (local[0]); i++) {
+ Cap_range * range = reinterpret_cast(local[i]);
+ *range = Cap_range(index);
+
+ cap_map()->insert(range);
+
+ index = range->base() + range->elements();
+ };
+
+ /**
+ * Test to provoke out of memory during capability transfer of
+ * server/client.
+ *
+ * Set in hypervisor.ld the memory to a low value of about 1M to let
+ * trigger the test.
+ */
+ test_server_oom();
+
+ /* Test to provoke out of memory in kernel during interaction with core */
+ static Greedy core_pagefault_oom;
+ core_pagefault_oom.start();
+ core_pagefault_oom.join();
+
if (!failed)
printf("Test finished\n");
diff --git a/repos/base-nova/src/test/platform/server.h b/repos/base-nova/src/test/platform/server.h
new file mode 100644
index 0000000000..00eead2238
--- /dev/null
+++ b/repos/base-nova/src/test/platform/server.h
@@ -0,0 +1,81 @@
+/*
+ * \brief Dummy server interface
+ * \author Alexander Boettcher
+ */
+
+/*
+ * Copyright (C) 2013-2015 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.
+ */
+
+#pragma once
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+namespace Test { struct Session; struct Client; struct Component; }
+
+/**
+ * Test session interface definition
+ */
+struct Test::Session : Genode::Session
+{
+ static const char *service_name() { return "TEST"; }
+
+ GENODE_RPC(Rpc_cap_void, bool, cap_void,
+ Genode::Native_capability);
+ GENODE_RPC(Rpc_void_cap, Genode::Native_capability,
+ void_cap);
+
+ GENODE_RPC_INTERFACE(Rpc_cap_void, Rpc_void_cap);
+};
+
+struct Test::Client : Genode::Rpc_client
+{
+ Client(Capability cap) : Rpc_client(cap) { }
+
+ bool cap_void(Genode::Native_capability cap) {
+ return call(cap); }
+
+ Genode::Native_capability void_cap() {
+ return call(); }
+};
+
+struct Test::Component : Genode::Rpc_object
+{
+ /* Test to transfer a object capability during send */
+ bool cap_void(Genode::Native_capability);
+ /* Test to transfer a object capability during reply */
+ Genode::Native_capability void_cap();
+};
+
+namespace Test { typedef Genode::Capability Capability; }
+
+/**
+ * Session implementation
+ */
+bool Test::Component::cap_void(Genode::Native_capability got_cap) {
+ if (!got_cap.valid())
+ return false;
+
+ /* be evil and keep this cap by manually incrementing the ref count */
+ Genode::Cap_index idx(Genode::cap_map()->find(got_cap.local_name()));
+ idx.inc();
+
+ return true;
+}
+
+Genode::Native_capability Test::Component::void_cap() {
+ Genode::Native_capability send_cap = cap();
+ /* be evil and switch translation off - client ever uses a new selector */
+ send_cap.solely_map();
+ return send_cap;
+}