mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 14:37:50 +00:00
l4lx: ballooning by using new parent interface
Implement a ballooning mechanism in L4Linux similar to solutions like XEN's balloon driver. Therefore the new parent interface extensions for requesting and yielding resources are used. L4Linux registers a yield signal context at its parent. Whenever the parent triggers a yield, the balloon driver blows up, which means it requests all pages available, and then frees the corresponding backend memory.
This commit is contained in:
parent
705c73d3f3
commit
59d6157441
36
ports-foc/include/genode/balloon.h
Normal file
36
ports-foc/include/genode/balloon.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* \brief Genode C API balloon functions
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2013-09-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__GENODE__BALLOON_H_
|
||||
#define _INCLUDE__GENODE__BALLOON_H_
|
||||
|
||||
#include <l4/sys/compiler.h>
|
||||
#include <l4/sys/types.h>
|
||||
|
||||
#include <genode/linkage.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
L4_CV l4_cap_idx_t genode_balloon_irq_cap(void);
|
||||
|
||||
L4_CV void genode_balloon_free_chunk(unsigned long addr);
|
||||
|
||||
L4_CV void genode_balloon_free_done(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDE__GENODE__BALLOON_H_ */
|
@ -112,7 +112,7 @@ set config {
|
||||
</route>
|
||||
</start>
|
||||
<start name="nic_bridge">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Nic"/></provides>
|
||||
<route>
|
||||
<service name="Nic"> <child name="usb_drv"/> </service>
|
||||
@ -163,64 +163,23 @@ set config {
|
||||
<start name="cli_monitor">
|
||||
<resource name="RAM" quantum="2G"/>
|
||||
<config>
|
||||
<subsystem name="l4linux" help="L4Linux with 100 MiB RAM">
|
||||
<binary name="init"/>
|
||||
<resource name="RAM" quantum="116M"/>
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
<service name="Timer"/>
|
||||
<service name="Terminal"/>
|
||||
</parent-provides>
|
||||
<start name="l4linux">
|
||||
<resource name="RAM" quantum="1G"/>
|
||||
<config args="mem=100M console=ttyS0 l4x_rd=initrd.gz l4x_cpus=2 l4x_cpus_map=0,1"/>
|
||||
<route> <any-service> <parent/> </any-service> </route>
|
||||
</start>
|
||||
</config>
|
||||
</subsystem>
|
||||
<preservation name="RAM" quantum="16M" />
|
||||
<subsystem name="l4linux_net" help="L4Linux with network">
|
||||
<binary name="init"/>
|
||||
<resource name="RAM" quantum="116M"/>
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
<service name="Timer"/>
|
||||
<service name="Terminal"/>
|
||||
<service name="Nic"/>
|
||||
</parent-provides>
|
||||
<start name="l4linux">
|
||||
<resource name="RAM" quantum="1G"/>
|
||||
<config args="mem=100M console=ttyS0 l4x_rd=initrd.gz l4x_cpus=2 l4x_cpus_map=0,1"/>
|
||||
<route> <any-service> <parent/> </any-service> </route>
|
||||
</start>
|
||||
</config>
|
||||
<binary name="l4linux"/>
|
||||
<resource name="RAM" quantum="64M"/>
|
||||
<config args="mem=2G console=ttyS0 l4x_rd=initrd.gz l4x_cpus=2 l4x_cpus_map=0,1"/>
|
||||
</subsystem>
|
||||
<subsystem name="l4linux_emmc" help="L4Linux accessing the second eMMC partition">
|
||||
<binary name="l4linux"/>
|
||||
<resource name="RAM" quantum="100M"/>
|
||||
<config args="mem=64M console=ttyS0 l4x_rd=initrd.gz l4x_cpus=2 l4x_cpus_map=0,1">
|
||||
<resource name="RAM" quantum="64M"/>
|
||||
<config args="mem=2G console=ttyS0 l4x_rd=initrd.gz l4x_cpus=2 l4x_cpus_map=0,1">
|
||||
<block label="sda" />
|
||||
</config>
|
||||
</subsystem>
|
||||
<subsystem name="l4linux_sata" help="L4Linux accessing the second SATA partition">
|
||||
<binary name="l4linux"/>
|
||||
<resource name="RAM" quantum="100M"/>
|
||||
<config args="mem=64M console=ttyS0 l4x_rd=initrd.gz l4x_cpus=2 l4x_cpus_map=0,1">
|
||||
<resource name="RAM" quantum="64MM"/>
|
||||
<config args="mem=2G console=ttyS0 l4x_rd=initrd.gz l4x_cpus=2 l4x_cpus_map=0,1">
|
||||
<block label="sda" />
|
||||
</config>
|
||||
</subsystem>
|
||||
|
@ -1,4 +1,5 @@
|
||||
obj-y += genode_serial.o
|
||||
obj-y += genode_balloon.o
|
||||
obj-$(CONFIG_RTC_CLASS) += genode_rtc.o
|
||||
obj-$(CONFIG_FB) += genode_fb.o
|
||||
obj-$(CONFIG_BLOCK) += genode_block.o
|
||||
|
112
ports-foc/src/drivers/genode_balloon.c
Normal file
112
ports-foc/src/drivers/genode_balloon.c
Normal file
@ -0,0 +1,112 @@
|
||||
|
||||
/*
|
||||
* \brief Balloon driver to use Genode's dynamic memory balancing
|
||||
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
|
||||
* \date 2013-09-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 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.
|
||||
*/
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include <asm/tlb.h>
|
||||
|
||||
#include <l4/log/log.h>
|
||||
#include <genode/balloon.h>
|
||||
|
||||
#define GFP_BALLOON \
|
||||
(__GFP_IO | __GFP_FS | __GFP_HARDWALL | __GFP_HIGHMEM | __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC)
|
||||
|
||||
enum { CHUNK_CACHE_SIZE = 16384 };
|
||||
static void* chunk_cache[CHUNK_CACHE_SIZE];
|
||||
|
||||
|
||||
static void free_avail_pages(unsigned long data)
|
||||
{
|
||||
void *pages;
|
||||
unsigned i = 0;
|
||||
|
||||
LOG_printf("free_avail_pages\n");
|
||||
for (; i < CHUNK_CACHE_SIZE; i++) {
|
||||
pages = alloc_pages_exact(SZ_1M, GFP_BALLOON);
|
||||
if (!pages)
|
||||
break;
|
||||
chunk_cache[i] = pages;
|
||||
}
|
||||
|
||||
BUG_ON(i == CHUNK_CACHE_SIZE);
|
||||
|
||||
/* Ensure that ballooned highmem pages don't have kmaps. */
|
||||
kmap_flush_unused();
|
||||
flush_tlb_all();
|
||||
|
||||
for (; i > 0;) {
|
||||
genode_balloon_free_chunk((unsigned long)chunk_cache[--i]);
|
||||
free_pages_exact(chunk_cache[i], SZ_1M);
|
||||
}
|
||||
|
||||
LOG_printf("free_avail_pages done\n");
|
||||
genode_balloon_free_done();
|
||||
}
|
||||
|
||||
DECLARE_TASKLET(free_avail, free_avail_pages, 0);
|
||||
|
||||
static irqreturn_t event_interrupt(int irq, void *data)
|
||||
{
|
||||
tasklet_schedule(&free_avail);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static struct platform_device genode_balloon_device = {
|
||||
.name = "balloon-genode",
|
||||
};
|
||||
|
||||
|
||||
static int __init balloon_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned irq;
|
||||
l4_cap_idx_t irq_cap;
|
||||
|
||||
/*
|
||||
* touch the memory eager otherwise we run into trouble
|
||||
* when memory is empty and we balloon
|
||||
*/
|
||||
memset(&chunk_cache, 0, sizeof(chunk_cache));
|
||||
|
||||
/**
|
||||
* Obtain an IRQ for the device.
|
||||
*/
|
||||
irq_cap = genode_balloon_irq_cap();
|
||||
if ((irq = l4x_register_irq(irq_cap)) < 0)
|
||||
return -ENOMEM;
|
||||
if ((ret = request_irq(irq, event_interrupt, 0,
|
||||
"Genode balloon", &genode_balloon_device))) {
|
||||
printk(KERN_WARNING "%s: request_irq failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = platform_device_register(&genode_balloon_device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
subsys_initcall(balloon_init);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -20,6 +20,7 @@
|
||||
#include <base/env.h>
|
||||
#include <util/avl_tree.h>
|
||||
#include <rm_session/connection.h>
|
||||
#include <platform_env.h>
|
||||
|
||||
namespace Fiasco {
|
||||
#include <l4/sys/types.h>
|
||||
@ -56,7 +57,8 @@ namespace L4lx {
|
||||
Fiasco::l4_cap_idx_t ref() { return _ref; }
|
||||
|
||||
virtual Genode::Dataspace_capability cap() = 0;
|
||||
virtual bool map(Genode::size_t offset) = 0;
|
||||
virtual void map(Genode::size_t offset, bool greedy = false) = 0;
|
||||
virtual bool free(Genode::size_t offset) = 0;
|
||||
|
||||
/************************
|
||||
** Avl_node interface **
|
||||
@ -89,8 +91,9 @@ namespace L4lx {
|
||||
Genode::cap_idx_alloc()->alloc_range(1)->kcap())
|
||||
: Dataspace(name, size, ref), _cap(ds) {}
|
||||
|
||||
Genode::Dataspace_capability cap() { return _cap; }
|
||||
bool map(Genode::size_t offset) { return true; }
|
||||
Genode::Dataspace_capability cap() { return _cap; }
|
||||
void map(Genode::size_t offset, bool greedy) { }
|
||||
bool free(Genode::size_t offset) { return false; }
|
||||
};
|
||||
|
||||
|
||||
@ -98,72 +101,54 @@ namespace L4lx {
|
||||
{
|
||||
private:
|
||||
|
||||
class Chunk : public Genode::Avl_node<Chunk>
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::size_t _offset;
|
||||
Genode::size_t _size;
|
||||
Genode::Dataspace_capability _cap;
|
||||
|
||||
public:
|
||||
|
||||
Chunk(Genode::size_t off, Genode::size_t size,
|
||||
Genode::Dataspace_capability cap)
|
||||
: _offset(off), _size(size), _cap(cap) {}
|
||||
|
||||
Genode::size_t offset() { return _offset; }
|
||||
Genode::size_t size() { return _size; }
|
||||
Genode::Dataspace_capability cap() { return _cap; }
|
||||
|
||||
bool higher(Chunk *n) { return n->_offset > _offset; }
|
||||
|
||||
Chunk *find_by_offset(Genode::size_t off)
|
||||
{
|
||||
if (off >= _offset && off < _offset+_size) return this;
|
||||
|
||||
Chunk *n = Genode::Avl_node<Chunk>::child(off > _offset);
|
||||
return n ? n->find_by_offset(off) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
Genode::Rm_connection _rm;
|
||||
Genode::Avl_tree<Chunk> _chunks;
|
||||
Genode::size_t _chunk_size;
|
||||
Genode::size_t _chunk_size_log2;
|
||||
Genode::Rm_connection _rm_con;
|
||||
Genode::Expanding_rm_session_client _rm;
|
||||
Genode::Ram_dataspace_capability *_chunks;
|
||||
|
||||
public:
|
||||
|
||||
enum {
|
||||
CHUNK_SIZE_LOG2 = 20,
|
||||
CHUNK_SIZE = 1 << CHUNK_SIZE_LOG2,
|
||||
};
|
||||
|
||||
Chunked_dataspace(const char* name,
|
||||
Genode::size_t size,
|
||||
Fiasco::l4_cap_idx_t ref,
|
||||
Genode::size_t chunk_size)
|
||||
: Dataspace(name, size, ref), _rm(0, size), _chunk_size(chunk_size),
|
||||
_chunk_size_log2(Genode::log2(_chunk_size)) {}
|
||||
|
||||
Genode::Dataspace_capability cap() { return _rm.dataspace(); }
|
||||
|
||||
bool map(Genode::size_t off)
|
||||
Fiasco::l4_cap_idx_t ref)
|
||||
: Dataspace(name, size, ref), _rm_con(0, size), _rm(_rm_con.cap())
|
||||
{
|
||||
off = Genode::align_addr((off-(_chunk_size-1)), _chunk_size_log2);
|
||||
_chunks = (Genode::Ram_dataspace_capability*) Genode::env()->heap()->alloc(
|
||||
sizeof(Genode::Ram_dataspace_capability) * (size/CHUNK_SIZE));
|
||||
}
|
||||
|
||||
Chunk* c = _chunks.first() ? _chunks.first()->find_by_offset(off) : 0;
|
||||
if (c) return true;
|
||||
Genode::Dataspace_capability cap() { return _rm_con.dataspace(); }
|
||||
|
||||
try {
|
||||
Genode::Dataspace_capability cap =
|
||||
Genode::env()->ram_session()->alloc(_chunk_size);
|
||||
_chunks.insert(new (Genode::env()->heap())
|
||||
Chunk(off, _chunk_size, cap));
|
||||
_rm.attach(cap, 0, 0, true, off);
|
||||
return true;
|
||||
} catch(Genode::Ram_session::Quota_exceeded) {
|
||||
PWRN("Could not allocate new dataspace chunk");
|
||||
} catch(Genode::Rm_session::Attach_failed) {
|
||||
PWRN("Attach of chunk dataspace of size %zx to %p failed",
|
||||
_chunk_size, (void*) off);
|
||||
void map(Genode::size_t off, bool greedy)
|
||||
{
|
||||
off = Genode::align_addr((off-(CHUNK_SIZE-1)), CHUNK_SIZE_LOG2);
|
||||
int i = off / CHUNK_SIZE;
|
||||
if (_chunks[i].valid()) return;
|
||||
|
||||
Genode::size_t ram_avail = Genode::env()->ram_session()->avail();
|
||||
if (greedy && ram_avail < 4*CHUNK_SIZE) {
|
||||
char buf[128];
|
||||
Genode::snprintf(buf, sizeof(buf), "ram_quota=%zd",
|
||||
4*CHUNK_SIZE - ram_avail);
|
||||
Genode::env()->parent()->resource_request(buf);
|
||||
}
|
||||
return false;
|
||||
|
||||
_chunks[i] = Genode::env()->ram_session()->alloc(CHUNK_SIZE);
|
||||
_rm.attach(_chunks[i], 0, 0, true, off, false);
|
||||
}
|
||||
|
||||
bool free(Genode::size_t off)
|
||||
{
|
||||
off = Genode::align_addr((off-(CHUNK_SIZE-1)), CHUNK_SIZE_LOG2);
|
||||
int i = off / CHUNK_SIZE;
|
||||
if (!_chunks[i].valid()) return false;
|
||||
Genode::env()->ram_session()->free(_chunks[i]);
|
||||
_chunks[i] = Genode::Ram_dataspace_capability();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
111
ports-foc/src/lib/l4lx/include/platform_env.h
Normal file
111
ports-foc/src/lib/l4lx/include/platform_env.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* \brief Platform environment of Genode process
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2006-07-28
|
||||
*
|
||||
* This file is a generic variant of the platform environment, which is
|
||||
* suitable for platforms such as L4ka::Pistachio and L4/Fiasco. On other
|
||||
* platforms, it may be replaced by a platform-specific version residing
|
||||
* in the corresponding 'base-<platform>' repository.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM_ENV_H_
|
||||
#define _PLATFORM_ENV_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/env.h>
|
||||
#include <base/heap.h>
|
||||
#include <rm_session/client.h>
|
||||
#include <util/arg_string.h>
|
||||
|
||||
namespace Genode {
|
||||
struct Expanding_rm_session_client;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Repeatedly try to execute a function 'func'
|
||||
*
|
||||
* If the function 'func' throws an exception of type 'EXC', the 'handler'
|
||||
* is called and the function call is retried.
|
||||
*
|
||||
* \param EXC exception type to handle
|
||||
* \param func functor to execute
|
||||
* \param handler exception handler executed if 'func' raised an exception
|
||||
* of type 'EXC'
|
||||
* \param attempts number of attempts to execute 'func' before giving up
|
||||
* and reflecting the exception 'EXC' to the caller. If not
|
||||
* specified, attempt infinitely.
|
||||
*/
|
||||
template <typename EXC, typename FUNC, typename HANDLER>
|
||||
auto retry(FUNC func, HANDLER handler, unsigned attempts = ~0U) -> decltype(func())
|
||||
{
|
||||
for (unsigned i = 0; attempts == ~0U || i < attempts; i++)
|
||||
try { return func(); }
|
||||
catch (EXC) { handler(); }
|
||||
|
||||
throw EXC();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Client object for a session that may get its session quota upgraded
|
||||
*/
|
||||
template <typename CLIENT>
|
||||
struct Upgradeable_client : CLIENT
|
||||
{
|
||||
typedef Genode::Capability<typename CLIENT::Rpc_interface> Capability;
|
||||
|
||||
Capability _cap;
|
||||
|
||||
Upgradeable_client(Capability cap) : CLIENT(cap), _cap(cap) { }
|
||||
|
||||
void upgrade_ram(Genode::size_t quota)
|
||||
{
|
||||
PINF("upgrading quota donation for Env::%s (%zd bytes)",
|
||||
CLIENT::Rpc_interface::service_name(), quota);
|
||||
|
||||
char buf[128];
|
||||
Genode::snprintf(buf, sizeof(buf), "ram_quota=%zd", quota);
|
||||
|
||||
Genode::env()->parent()->upgrade(_cap, buf);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Genode::Expanding_rm_session_client : Upgradeable_client<Genode::Rm_session_client>
|
||||
{
|
||||
Expanding_rm_session_client(Rm_session_capability cap)
|
||||
: Upgradeable_client<Genode::Rm_session_client>(cap) { }
|
||||
|
||||
Local_addr attach(Dataspace_capability ds, size_t size, off_t offset,
|
||||
bool use_local_addr, Local_addr local_addr,
|
||||
bool executable)
|
||||
{
|
||||
return retry<Rm_session::Out_of_metadata>(
|
||||
[&] () {
|
||||
return Rm_session_client::attach(ds, size, offset,
|
||||
use_local_addr,
|
||||
local_addr,
|
||||
executable); },
|
||||
[&] () { upgrade_ram(8*1024); });
|
||||
}
|
||||
|
||||
Pager_capability add_client(Thread_capability thread)
|
||||
{
|
||||
return retry<Rm_session::Out_of_metadata>(
|
||||
[&] () { return Rm_session_client::add_client(thread); },
|
||||
[&] () { upgrade_ram(8*1024); });
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _PLATFORM_ENV_H_ */
|
@ -14,7 +14,6 @@
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/capability.h>
|
||||
#include <os/config.h>
|
||||
#include <rm_session/connection.h>
|
||||
|
||||
/* L4lx includes */
|
||||
@ -31,36 +30,18 @@ static const bool DEBUG = false;
|
||||
|
||||
extern "C" {
|
||||
|
||||
static const unsigned long _chunk_size()
|
||||
{
|
||||
enum { DEFAULT_CHUNK_SIZE = 16*1024*1024 };
|
||||
|
||||
Genode::Number_of_bytes result = DEFAULT_CHUNK_SIZE;
|
||||
|
||||
try {
|
||||
Genode::config()->xml_node().sub_node("ram")
|
||||
.attribute("chunk_size")
|
||||
.value(&result);
|
||||
} catch(...) { }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
long l4re_ma_alloc(unsigned long size, l4re_ds_t const mem,
|
||||
unsigned long flags)
|
||||
{
|
||||
static const unsigned long chunk_size = _chunk_size();
|
||||
|
||||
using namespace L4lx;
|
||||
|
||||
if (DEBUG)
|
||||
PDBG("size=%lx mem=%lx flags=%lx", size, mem, flags);
|
||||
|
||||
Dataspace *ds;
|
||||
if (size > chunk_size) {
|
||||
if (Genode::log2(size) >= Chunked_dataspace::CHUNK_SIZE_LOG2) {
|
||||
ds = new (Genode::env()->heap())
|
||||
Chunked_dataspace("lx_memory", size, mem, chunk_size);
|
||||
Chunked_dataspace("lx_memory", size, mem);
|
||||
} else {
|
||||
Genode::Dataspace_capability cap =
|
||||
Genode::env()->ram_session()->alloc(size);
|
||||
|
@ -1,13 +1,66 @@
|
||||
#include <env.h>
|
||||
#include <rm.h>
|
||||
|
||||
#include <vcpu.h>
|
||||
#include <linux.h>
|
||||
|
||||
namespace Fiasco {
|
||||
#include <genode/net.h>
|
||||
#include <l4/sys/irq.h>
|
||||
#include <l4/util/util.h>
|
||||
#include <l4/sys/linkage.h>
|
||||
}
|
||||
|
||||
extern "C" L4_CV int l4x_forward_pf(Fiasco::l4_umword_t addr,
|
||||
Fiasco::l4_umword_t pc, int extra_write)
|
||||
static bool ballooning = false;
|
||||
static Genode::Lock balloon_lock;
|
||||
|
||||
namespace {
|
||||
|
||||
class Signal_thread : public Genode::Thread<8192>
|
||||
{
|
||||
private:
|
||||
|
||||
Fiasco::l4_cap_idx_t _cap;
|
||||
Genode::Lock *_sync;
|
||||
|
||||
protected:
|
||||
|
||||
void entry()
|
||||
{
|
||||
using namespace Fiasco;
|
||||
using namespace Genode;
|
||||
|
||||
Signal_receiver receiver;
|
||||
Signal_context rx;
|
||||
Signal_context_capability cap(receiver.manage(&rx));
|
||||
Genode::env()->parent()->yield_sigh(cap);
|
||||
_sync->unlock();
|
||||
|
||||
while (true) {
|
||||
receiver.wait_for_signal();
|
||||
Genode::env()->parent()->yield_request();
|
||||
{
|
||||
Genode::Lock::Guard guard(balloon_lock);
|
||||
ballooning = true;
|
||||
if (l4_error(l4_irq_trigger(_cap)) != -1)
|
||||
PWRN("IRQ net trigger failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Signal_thread(Fiasco::l4_cap_idx_t cap, Genode::Lock *sync)
|
||||
: Genode::Thread<8192>("net-signal-thread"), _cap(cap), _sync(sync) {
|
||||
start(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
L4_CV int l4x_forward_pf(Fiasco::l4_umword_t addr,
|
||||
Fiasco::l4_umword_t pc, int extra_write)
|
||||
{
|
||||
using namespace Fiasco;
|
||||
|
||||
@ -15,8 +68,16 @@ extern "C" L4_CV int l4x_forward_pf(Fiasco::l4_umword_t addr,
|
||||
Genode::addr_t ds_start_addr = addr;
|
||||
L4lx::Region *r = L4lx::Env::env()->rm()->find_region(&ds_start_addr, &size);
|
||||
L4lx::Dataspace *ds = r ? r->ds() : 0;
|
||||
if (ds && !ds->map(addr - r->addr()))
|
||||
return 0;
|
||||
|
||||
while (ds) {
|
||||
try {
|
||||
ds->map(addr - r->addr(), !ballooning);
|
||||
break;
|
||||
} catch(Genode::Rm_session::Attach_failed) {
|
||||
PWRN("Attach of chunk dataspace of failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!extra_write)
|
||||
l4_touch_ro((void*)l4_trunc_page(addr), L4_LOG2_PAGESIZE);
|
||||
@ -26,3 +87,36 @@ extern "C" L4_CV int l4x_forward_pf(Fiasco::l4_umword_t addr,
|
||||
}
|
||||
|
||||
|
||||
Fiasco::l4_cap_idx_t genode_balloon_irq_cap()
|
||||
{
|
||||
Linux::Irq_guard guard;
|
||||
|
||||
static Genode::Native_capability cap = L4lx::vcpu_connection()->alloc_irq();
|
||||
static Genode::Lock lock(Genode::Lock::LOCKED);
|
||||
static Signal_thread th(cap.dst(), &lock);
|
||||
lock.lock();
|
||||
return cap.dst();
|
||||
}
|
||||
|
||||
|
||||
bool genode_balloon_free_chunk(unsigned long addr)
|
||||
{
|
||||
Linux::Irq_guard guard;
|
||||
|
||||
Genode::addr_t ds_start_addr = addr;
|
||||
Genode::size_t size = L4_PAGESIZE;
|
||||
L4lx::Region *r = L4lx::Env::env()->rm()->find_region(&ds_start_addr, &size);
|
||||
L4lx::Dataspace *ds = r ? r->ds() : 0;
|
||||
return ds ? ds->free(addr - r->addr()) : false;
|
||||
}
|
||||
|
||||
|
||||
void genode_balloon_free_done()
|
||||
{
|
||||
Linux::Irq_guard ig;
|
||||
Genode::Lock::Guard guard(balloon_lock);
|
||||
ballooning = false;
|
||||
Genode::env()->parent()->yield_response();
|
||||
}
|
||||
|
||||
}
|
||||
|
90
ports-foc/src/server/balloon/main.cc
Normal file
90
ports-foc/src/server/balloon/main.cc
Normal file
@ -0,0 +1,90 @@
|
||||
#include <balloon_session/balloon_session.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <root/component.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/env.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
class Session_component;
|
||||
static List<Session_component> session_list;
|
||||
|
||||
|
||||
class Session_component : public Rpc_object<Balloon_session, Session_component>,
|
||||
public List<Session_component>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
Signal_context_capability _handler;
|
||||
|
||||
public:
|
||||
|
||||
Session_component() {
|
||||
session_list.insert(this); }
|
||||
|
||||
~Session_component() {
|
||||
session_list.remove(this); };
|
||||
|
||||
int increase_quota(Ram_session_capability ram_session, size_t amount)
|
||||
{
|
||||
PDBG("increase ram_quota of client by %zx", amount);
|
||||
while (true) ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void balloon_handler(Signal_context_capability handler) {
|
||||
_handler = handler; }
|
||||
|
||||
Signal_context_capability handler() { return _handler; }
|
||||
};
|
||||
|
||||
|
||||
class Root : public Genode::Root_component<Session_component>
|
||||
{
|
||||
protected:
|
||||
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
size_t ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota").ulong_value(0);
|
||||
|
||||
if (ram_quota < sizeof(Session_component))
|
||||
throw Root::Quota_exceeded();
|
||||
|
||||
return new (md_alloc()) Session_component();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Rpc_entrypoint *session_ep,
|
||||
Allocator *md_alloc)
|
||||
: Root_component(session_ep, md_alloc) { }
|
||||
};
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
enum { STACK_SIZE = 1024*sizeof(Genode::addr_t) };
|
||||
|
||||
static Timer::Connection timer;
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "balloon_ep");
|
||||
static ::Root root(&ep, env()->heap());
|
||||
env()->parent()->announce(ep.manage(&root));
|
||||
|
||||
while (true) {
|
||||
Session_component *c = session_list.first();
|
||||
while (c) {
|
||||
if (c->handler().valid()) {
|
||||
PINF("request memory from client!");
|
||||
Signal_transmitter transmitter(c->handler());
|
||||
transmitter.submit();
|
||||
}
|
||||
c = c->next();
|
||||
}
|
||||
timer.msleep(10000);
|
||||
}
|
||||
return 0;
|
||||
}
|
3
ports-foc/src/server/balloon/target.mk
Normal file
3
ports-foc/src/server/balloon/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = balloon
|
||||
LIBS = base
|
||||
SRC_CC = main.cc
|
Loading…
Reference in New Issue
Block a user