vancouver: Console support

The guest VM can now be provided with a framebuffer and keyboard input.

Mouse positioning of the guest is a problem. Because the PS2 model applies
some calculations to the movement values, it can happen that overflows mess
with the cursor.  Therefore the handling was changed and only movements of 1
and -1 are sent.  Since absolute positioning is not possible with PS2, we
have to live with this limitation until USB HID is implemented.

For the framebuffer size in Vancouver the configuration value in the machine
XML node is used.  It is possible to map the corresponding memory area
directly to the guest, regardless if it is from nitpicker,
liquid_framebuffer or vesa_drv.  The guest is provided with two modes (text
mode 3 and graphics mode 0x114 (0x314 in Linux).

Pressing LWIN+END while a VM has focus resets the virtual machine. Also,
RESET and DEBUG key presses will not be forwarded to the VM anymore.
It is possible to dump a VM's state by pressing LWIN+INS keys.

The text console is able to detect idle mode, unmaps the buffer from the
guest and stops interpreting.  Upon the next pagefault in this area, it
resumes operation again.  The code uses a simple checksum mechanism instead
of a large buffer and memcmp to detect an idle text console.  False
positives don't matter very much.
This commit is contained in:
Markus Partheymueller 2012-10-11 11:04:37 +02:00 committed by Norman Feske
parent 2d2373a03b
commit 1ca0a66ea9
7 changed files with 694 additions and 22 deletions

View File

@ -0,0 +1,311 @@
/*
* \brief Manager of all VM requested console functionality
* \author Markus Partheymueller
* \date 2012-07-31
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2012 Intel Corporation
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*
* The code is partially based on the Vancouver VMM, which is distributed
* under the terms of the GNU General Public License version 2.
*
* Modifications by Intel Corporation are contributed under the terms and
* conditions of the GNU General Public License version 2.
*/
/* local includes */
#include <console.h>
#include <keyboard.h>
/* Genode includes */
#include <base/snprintf.h>
/* nitpicker graphics backend */
#include <nitpicker_gfx/chunky_canvas.h>
#include <nitpicker_gfx/pixel_rgb565.h>
#include <nitpicker_gfx/font.h>
extern char _binary_mono_tff_start;
Font default_font(&_binary_mono_tff_start);
extern Genode::Lock global_lock;
extern bool console_init;
using Genode::env;
using Genode::Dataspace_client;
bool fb_active = true;
static unsigned mouse_value(Input::Event * ev)
{
/* bit 3 is always set */
unsigned ret = 0x8;
/* signs and movements */
int x=0, y=0;
if (ev->rx() > 0) x = 1;
if (ev->rx() < 0) x = -1;
if (ev->ry() > 0) y = 1;
if (ev->ry() < 0) y = -1;
if (x > 0)
ret |= (1 << 8);
if (x < 0)
ret |= (0xfe << 8) | (1 << 4);
if (y < 0) /* nitpicker's negative is PS2 positive */
ret |= (1 << 16);
if (y > 0)
ret |= (0xfe << 16) | (1 << 5);
/* buttons */
ret |= ((ev->code() == Input::BTN_MIDDLE ? 1 : 0) << 2);
ret |= ((ev->code() == Input::BTN_RIGHT ? 1 : 0) << 1);
ret |= ((ev->code() == Input::BTN_LEFT ? 1 : 0) << 0);
/* ps2mouse model expects 3 in the first byte */
return (ret << 8) | 0x3;
}
/*
* Console implementation
*/
/* bus callbacks */
bool Vancouver_console::receive(MessageConsole &msg)
{
if (msg.type == MessageConsole::TYPE_ALLOC_VIEW) {
_guest_fb = msg.ptr;
if (msg.size < _fb_size)
_fb_size = msg.size;
_regs = msg.regs;
msg.view = 0;
} else if (msg.type == MessageConsole::TYPE_SWITCH_VIEW) {
/* XXX: For now, we only have one view. */
} else if (msg.type == MessageConsole::TYPE_GET_MODEINFO) {
/*
* We supply two modes to the guest, text mode and one
* configured graphics mode 16-bit.
*/
if (msg.index == 0) {
msg.info->_vesa_mode = 3;
msg.info->attr = 0x1;
msg.info->resolution[0] = 80;
msg.info->resolution[1] = 25;
msg.info->bytes_per_scanline = 80*2;
msg.info->bytes_scanline = 80*2;
msg.info->bpp = 4;
msg.info->phys_base = 0xb8000;
msg.info->_phys_size = 0x8000;
return true;
} else if (msg.index == 1) {
/*
* It's important to set the _vesa_mode field, otherwise the
* device model is going to ignore this mode.
*/
msg.info->_vesa_mode = 0x114;
msg.info->attr = 0x39f;
msg.info->resolution[0] = _fb_mode.width();
msg.info->resolution[1] = _fb_mode.height();
msg.info->bytes_per_scanline = _fb_mode.width()*2;
msg.info->bytes_scanline = _fb_mode.width()*2;
msg.info->bpp = 16;
msg.info->vbe1[0] = 0x5; /* red mask size */
msg.info->vbe1[1] = 0xb; /* red field position */
msg.info->vbe1[2] = 0x6; /* green mask size */
msg.info->vbe1[3] = 0x5; /* green field position */
msg.info->vbe1[4] = 0x5; /* blue mask size */
msg.info->vbe1[5] = 0x0; /* blue field position */
msg.info->vbe1[6] = 0x0; /* reserved mask size */
msg.info->vbe1[7] = 0x0; /* reserved field position */
msg.info->vbe1[8] = 0x0; /* direct color mode info */
msg.info->phys_base = 0xe0000000;
msg.info->_phys_size = _fb_mode.width()*_fb_mode.height()*2;
return true;
} else return false;
}
return true;
}
bool Vancouver_console::receive(MessageMemRegion &msg)
{
if (msg.page >= 0xb8 && msg.page <= 0xbf) {
/* we had a fault in the text framebuffer */
if (!fb_active) fb_active = true;
Logging::printf("Reactivating text buffer loop.\n");
}
}
void Vancouver_console::entry()
{
Logging::printf("Hello, this is VancouverConsole.\n");
/* register host operations */
_mb.bus_console.add(this, receive_static<MessageConsole>);
_mb.bus_memregion.add(this, receive_static<MessageMemRegion>);
/* create environment for input/output */
/*
* Init sessions to the required external services
*/
enum { CONFIG_ALPHA = false };
static Framebuffer::Connection framebuffer;
static Input::Connection input;
static Timer::Connection timer;
Genode::Dataspace_capability ev_ds_cap = input.dataspace();
Input::Event *ev_buf = static_cast<Input::Event *>
(env()->rm_session()->attach(ev_ds_cap));
_fb_size = Dataspace_client(framebuffer.dataspace()).size();
_fb_mode = framebuffer.mode();
_pixels = env()->rm_session()->attach(framebuffer.dataspace());
Chunky_canvas<Pixel_rgb565> canvas((Pixel_rgb565 *) _pixels,
Area(_fb_mode.width(),
_fb_mode.height()));
/*
* Handle input events
*/
unsigned long count = 0;
bool revoked = false;
Vancouver_keyboard vkeyb(_mb);
Genode::uint64_t checksum1 = 0;
Genode::uint64_t checksum2 = 0;
unsigned unchanged = 0;
bool cmp_even = 1;
console_init = true;
while (1) {
while (!input.is_pending()) {
/* transfer text buffer content into chunky canvas */
if (_regs && ++count % 10 == 0 && _regs->mode == 0
&& _guest_fb && !revoked && fb_active) {
memset(_pixels, 0, _fb_size);
if (cmp_even) checksum1 = 0;
else checksum2 = 0;
for (int j=0; j<25; j++) {
for (int i=0; i<80; i++) {
Point where(i*8, j*15);
char character = *((char *) (_guest_fb+0x18000+j*80*2+i*2));
char colorvalue = *((char *) (_guest_fb+0x18000+j*80*2+i*2+1));
char buffer[2];
Genode::snprintf(buffer, 1, "%c", character);
char fg = colorvalue & 0xf;
if (fg == 0x8) fg = 0x7;
unsigned lum = ((fg & 0x8) >> 3)*127;
Color color(((fg & 0x4) >> 2)*127+lum, /* R+luminosity */
((fg & 0x2) >> 1)*127+lum, /* G+luminosity */
(fg & 0x1)*127+lum /* B+luminosity */);
canvas.draw_string(where, &default_font, color, buffer);
/* Checksum for comparing */
if (cmp_even) checksum1 += character;
else checksum2 += character;
}
}
/* compare checksums to detect idle buffer */
if (checksum1 == checksum2) {
unchanged++;
/* if we copy the same data 10 times, unmap the text buffer from guest */
if (unchanged == 10) {
/* protect against thread interference */
global_lock.lock();
env()->rm_session()->detach((void *)_guest_fb);
env()->rm_session()->attach_at(_fb_ds, (Genode::addr_t)_guest_fb);
unchanged = 0;
fb_active = false;
global_lock.unlock();
Logging::printf("Deactivated text buffer loop.\n");
}
} else unchanged = 0;
cmp_even = !cmp_even;
} else if (_regs && _guest_fb && _regs->mode != 0) {
if (!revoked) {
/* protect against thread interference */
global_lock.lock();
env()->rm_session()->detach((void *)_guest_fb);
env()->rm_session()->attach_at(framebuffer.dataspace(),
(Genode::addr_t)_guest_fb);
/* if the VGA model expects a larger FB, pad to that size. */
if (_fb_size < _vm_fb_size) {
Genode::Ram_dataspace_capability _backup =
Genode::env()->ram_session()->alloc(_vm_fb_size-_fb_size);
env()->rm_session()->attach_at(_backup,
(Genode::addr_t) (_guest_fb+_fb_size));
}
revoked = true;
global_lock.unlock();
}
}
framebuffer.refresh(0, 0, _fb_mode.width(), _fb_mode.height());
timer.msleep(10);
}
for (int i = 0, num_ev = input.flush(); i < num_ev; i++) {
Input::Event *ev = &ev_buf[i];
/* update mouse model (PS2) */
unsigned mouse = mouse_value(ev);
MessageInput msg(0x10001, mouse);
_mb.bus_input.send(msg);
if (ev->type() == Input::Event::PRESS) {
if (ev->code() <= 0xee) {
vkeyb.handle_keycode_press(ev->code());
}
}
if (ev->type() == Input::Event::RELEASE) {
if (ev->code() <= 0xee) { /* keyboard event */
vkeyb.handle_keycode_release(ev->code());
}
}
}
}
}
Vancouver_console::Vancouver_console(Motherboard &mb, Genode::size_t vm_fb_size,
Genode::Dataspace_capability fb_ds)
:
_vm_fb_size(vm_fb_size), _mb(mb), _fb_size(0), _pixels(0), _guest_fb(0),
_regs(0), _fb_ds(fb_ds)
{
start();
}

View File

@ -0,0 +1,74 @@
/*
* \brief Manager of all VM requested console functionality
* \author Markus Partheymueller
* \date 2012-07-31
*/
/*
* Copyright (C) 2012 Intel Corporation
* 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.
*
* The code is partially based on the Vancouver VMM, which is distributed
* under the terms of the GNU General Public License version 2.
*
* Modifications by Intel Corporation are contributed under the terms and
* conditions of the GNU General Public License version 2.
*/
#ifndef _CONSOLE_H_
#define _CONSOLE_H_
/* Genode includes */
#include <util/string.h>
#include <base/sleep.h>
#include <framebuffer_session/connection.h>
#include <input_session/connection.h>
#include <timer_session/connection.h>
#include <dataspace/client.h>
/* NOVA userland includes */
#include <nul/motherboard.h>
/* includes for I/O */
#include <base/env.h>
#include <util/list.h>
#include <nitpicker_session/connection.h>
#include <nitpicker_view/client.h>
#include <input/event.h>
using Genode::List;
using Genode::Thread;
class Vancouver_console : public Thread<8192>, public StaticReceiver<Vancouver_console>
{
private:
Motherboard &_mb;
short *_pixels;
char *_guest_fb;
unsigned long _fb_size;
Genode::Dataspace_capability _fb_ds;
Genode::size_t _vm_fb_size;
VgaRegs *_regs;
Framebuffer::Mode _fb_mode;
public:
/* bus callbacks */
bool receive(MessageConsole &msg);
bool receive(MessageMemRegion &msg);
/* initialisation */
void entry();
/**
* Constructor
*/
Vancouver_console(Motherboard &mb, Genode::size_t vm_fb_size,
Genode::Dataspace_capability fb_ds);
};
#endif /* _CONSOLE_H_ */

View File

@ -0,0 +1,171 @@
/*
* \brief Keyboard manager
* \author Markus Partheymueller
* \date 2012-07-31
*/
/*
* Copyright (C) 2012 Intel Corporation
* 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.
*
* The code is partially based on the Vancouver VMM, which is distributed
* under the terms of the GNU General Public License version 2.
*
* Modifications by Intel Corporation are contributed under the terms and
* conditions of the GNU General Public License version 2.
*/
/* local includes */
#include <keyboard.h>
/* vancouver generic keyboard helper */
#include <host/keyboard.h>
#include <nul/vcpu.h>
extern Genode::Lock global_lock;
Vancouver_keyboard::Vancouver_keyboard(Motherboard &mb)
: _mb(mb), _flags(0) { }
void Vancouver_keyboard::handle_keycode_press(unsigned keycode)
{
unsigned orig_keycode = keycode;
switch (keycode) {
/* modifiers */
case Input::KEY_LEFTSHIFT: _flags |= KBFLAG_LSHIFT; keycode = 0x12; break;
case Input::KEY_RIGHTSHIFT: _flags |= KBFLAG_RSHIFT; keycode = 0x59; break;
case Input::KEY_LEFTALT: _flags |= KBFLAG_LALT; keycode = 0x11; break;
case Input::KEY_RIGHTALT: _flags |= KBFLAG_RALT; keycode = 0x11; break;
case Input::KEY_LEFTCTRL: _flags |= KBFLAG_LCTRL; keycode = 0x14; break;
case Input::KEY_RIGHTCTRL: _flags |= KBFLAG_RCTRL; keycode = 0x14; break;
case Input::KEY_LEFTMETA: _flags |= KBFLAG_LWIN; keycode = 0x1f; return;
case Input::KEY_RIGHTMETA: _flags |= KBFLAG_RWIN; keycode = 0x27; return;
case Input::KEY_KPSLASH: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x35); break;
case Input::KEY_KPENTER: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x1c); break;
case Input::KEY_F11: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x57); break;
case Input::KEY_F12: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x58); break;
case Input::KEY_INSERT: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x52); break;
case Input::KEY_DELETE: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x53); break;
case Input::KEY_HOME: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x47); break;
case Input::KEY_END: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x4f); break;
case Input::KEY_PAGEUP: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x49); break;
case Input::KEY_PAGEDOWN: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x51); break;
case Input::KEY_LEFT: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x4b); break;
case Input::KEY_RIGHT: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x4d); break;
case Input::KEY_UP: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x48); break;
case Input::KEY_DOWN: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x50); break;
/* up to 0x53, the Genode key codes correspond to scan code set 1 */
default:
if (keycode <= 0x53) {
keycode = GenericKeyboard::translate_sc1_to_sc2(keycode);
break;
} else return;
}
MessageInput msg(0x10000, _flags | keycode);
/* debug */
if ((_flags & KBFLAG_LWIN) && orig_keycode == Input::KEY_INSERT) {
Logging::printf("DEBUG key\n");
/* we send an empty event */
CpuEvent msg(VCpu::EVENT_DEBUG);
for (VCpu *vcpu = _mb.last_vcpu; vcpu; vcpu=vcpu->get_last())
vcpu->bus_event.send(msg);
}
/* reset */
else if ((_flags & KBFLAG_LWIN) && orig_keycode == Input::KEY_END) {
Genode::Lock::Guard guard(global_lock);
Logging::printf("Reset VM\n");
MessageLegacy msg2(MessageLegacy::RESET, 0);
_mb.bus_legacy.send_fifo(msg2);
}
else _mb.bus_input.send(msg);
_flags &= ~(KBFLAG_EXTEND0 | KBFLAG_RELEASE | KBFLAG_EXTEND1);
}
void Vancouver_keyboard::handle_keycode_release(unsigned keycode)
{
_flags |= KBFLAG_RELEASE;
switch (keycode) {
/* modifiers */
case Input::KEY_LEFTSHIFT: _flags |= KBFLAG_LSHIFT; keycode = 0x12; break;
case Input::KEY_RIGHTSHIFT: _flags |= KBFLAG_RSHIFT; keycode = 0x59; break;
case Input::KEY_LEFTALT: _flags |= KBFLAG_LALT; keycode = 0x11; break;
case Input::KEY_RIGHTALT: _flags |= KBFLAG_RALT; keycode = 0x11; break;
case Input::KEY_LEFTCTRL: _flags |= KBFLAG_LCTRL; keycode = 0x14; break;
case Input::KEY_RIGHTCTRL: _flags |= KBFLAG_RCTRL; keycode = 0x14; break;
case Input::KEY_LEFTMETA: _flags |= KBFLAG_LWIN; keycode = 0x1f; break;
case Input::KEY_RIGHTMETA: _flags |= KBFLAG_RWIN; keycode = 0x27; break;
case Input::KEY_KPSLASH: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x35); break;
case Input::KEY_KPENTER: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x1c); break;
case Input::KEY_F11: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x57); break;
case Input::KEY_F12: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x58); break;
case Input::KEY_INSERT: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x52); break;
case Input::KEY_DELETE: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x53); break;
case Input::KEY_HOME: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x47); break;
case Input::KEY_END: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x4f); break;
case Input::KEY_PAGEUP: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x49); break;
case Input::KEY_PAGEDOWN: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x51); break;
case Input::KEY_LEFT: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x4b); break;
case Input::KEY_RIGHT: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x4d); break;
case Input::KEY_UP: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x48); break;
case Input::KEY_DOWN: _flags |= KBFLAG_EXTEND0;
keycode = GenericKeyboard::translate_sc1_to_sc2(0x50); break;
/* up to 0x53, the Genode key codes correspond to scan code set 1 */
default:
if (keycode <= 0x53) {
keycode = GenericKeyboard::translate_sc1_to_sc2(keycode);
break;
} else return;
}
MessageInput msg(0x10000, _flags | keycode);
_mb.bus_input.send(msg);
_flags &= ~(KBFLAG_EXTEND0 | KBFLAG_RELEASE | KBFLAG_EXTEND1);
}

View File

@ -0,0 +1,50 @@
/*
* \brief Keyboard manager
* \author Markus Partheymueller
* \date 2012-07-31
*/
/*
* Copyright (C) 2012 Intel Corporation
* 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.
*
* The code is partially based on the Vancouver VMM, which is distributed
* under the terms of the GNU General Public License version 2.
*
* Modifications by Intel Corporation are contributed under the terms and
* conditions of the GNU General Public License version 2.
*/
#ifndef _KEYBOARD_H_
#define _KEYBOARD_H_
/* NOVA userland includes */
#include <nul/motherboard.h>
/* includes for I/O */
#include <base/env.h>
#include <input/event.h>
#include <input/keycodes.h>
class Vancouver_keyboard
{
private:
Motherboard &_mb;
unsigned _flags;
public:
/**
* Constructor
*/
Vancouver_keyboard(Motherboard &mb);
void handle_keycode_press(unsigned keycode);
void handle_keycode_release(unsigned keycode);
};
#endif /* _KEYBOARD_H_ */

View File

@ -59,7 +59,7 @@
/* local includes */
#include <device_model_registry.h>
#include <boot_module_provider.h>
#include <console.h>
enum {
PAGE_SIZE_LOG2 = 12UL,
@ -81,6 +81,8 @@ enum { verbose_io = false };
Genode::Lock global_lock(Genode::Lock::LOCKED);
Genode::Lock timeouts_lock(Genode::Lock::UNLOCKED);
volatile bool console_init = false;
/* Timer Service */
using Genode::Thread;
@ -167,8 +169,12 @@ class Guest_memory
Genode::Rm_connection _reservation;
Genode::Ram_dataspace_capability _ds;
Genode::Ram_dataspace_capability _fb_ds;
Genode::size_t _fb_size;
char *_local_addr;
char *_fb_addr;
public:
@ -193,12 +199,15 @@ class Guest_memory
* used as guest-physical and device memory,
* allocated from core's RAM service
*/
Guest_memory(Genode::size_t backing_store_size)
Guest_memory(Genode::size_t backing_store_size, Genode::size_t fb_size)
:
_fb_size(fb_size),
_reservation(0, backing_store_size),
_ds(Genode::env()->ram_session()->alloc(backing_store_size)),
_ds(Genode::env()->ram_session()->alloc(backing_store_size-fb_size)),
_fb_ds(Genode::env()->ram_session()->alloc(fb_size)),
_local_addr(0),
remaining_size(backing_store_size)
_fb_addr(0),
remaining_size(backing_store_size-fb_size)
{
try {
@ -208,14 +217,16 @@ class Guest_memory
* attachment of anything at the zero page.
*/
Genode::env()->rm_session()->attach_at(_reservation.dataspace(),
PAGE_SIZE, 0, PAGE_SIZE);
PAGE_SIZE, 0, PAGE_SIZE);
/*
* RAM used as backing store for guest-physical memory
*/
_local_addr = Genode::env()->rm_session()->attach(_ds);
_fb_addr = Genode::env()->rm_session()->attach_at(_fb_ds,
((Genode::addr_t) _local_addr)+backing_store_size-fb_size);
} catch (Genode::Rm_session::Region_conflict) { }
} catch (Genode::Rm_session::Region_conflict) { }
}
@ -227,6 +238,9 @@ class Guest_memory
/* detach and free backing store */
Genode::env()->rm_session()->detach((void *)_local_addr);
Genode::env()->ram_session()->free(_ds);
Genode::env()->rm_session()->detach((void *)_fb_addr);
Genode::env()->ram_session()->free(_fb_ds);
}
/**
@ -236,6 +250,18 @@ class Guest_memory
{
return _local_addr;
}
/**
* Return pointer to lo locally mapped fb backing store
*/
char *backing_store_fb_local_base()
{
return _fb_addr;
}
Genode::size_t fb_size() { return _fb_size; }
Genode::Dataspace_capability fb_ds() { return _fb_ds; }
};
class Vcpu_thread : Genode::Thread<STACK_SIZE> {
@ -446,7 +472,7 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
/* calculate maximal aligned order of page to be mapped */
do {
crd = Nova::Mem_crd(map_page, map_order,
Nova::Rights(true, true, true));
crd_save.rights());
map_order += 1;
map_page &= ~((1UL << map_order) - 1);
@ -455,7 +481,7 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
while (cut_start <= map_page &&
((map_page + (1UL << map_order)) <= (cut_start + cut_size)) &&
!(hotspot & ((1UL << map_order) - 1)));
return true;
}
@ -469,7 +495,7 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
MessageMemRegion mem_region(vm_fault_addr >> PAGE_SIZE_LOG2);
if (!_motherboard.bus_memregion.send(mem_region, true) ||
if (!_motherboard.bus_memregion.send(mem_region, false) ||
!mem_region.ptr)
return false;
@ -487,8 +513,17 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
Genode::addr_t vmm_memory_fault = vmm_memory_base +
(vm_fault_addr - (mem_region.start_page << PAGE_SIZE_LOG2));
bool read=true, write=true, execute=true;
/* XXX: Not yet supported by Vancouver.
if (mem_region.attr == (DESC_TYPE_MEM | DESC_RIGHT_R)) {
if (verbose_npt)
Logging::printf("Mapping readonly to %p (err:%x, attr:%x)\n",
vm_fault_addr, utcb->qual[0], mem_region.attr);
write = execute = false;
}*/
Nova::Mem_crd crd(vmm_memory_fault >> PAGE_SIZE_LOG2, 0,
Nova::Rights(true, true, true));
Nova::Rights(read, write, execute));
if (!max_map_crd(crd, vmm_memory_base >> PAGE_SIZE_LOG2,
mem_region.start_page,
@ -962,6 +997,8 @@ class Machine : public StaticReceiver<Machine>
Boot_module_provider &_boot_modules;
Alarm_thread *_alarm_thread;
bool _alloc_fb_mem; /* For detecting FB alloc message */
public:
/*********************************************
@ -980,12 +1017,22 @@ class Machine : public StaticReceiver<Machine>
if (verbose_debug)
Logging::printf("OP_GUEST_MEM value=0x%lx\n", msg.value);
if (_alloc_fb_mem) {
msg.len = _guest_memory.fb_size();
msg.ptr = _guest_memory.backing_store_local_base();
_alloc_fb_mem = false;
Logging::printf(" -> len=0x%lx, ptr=0x%p\n",
msg.len, msg.ptr);
return true;
}
if (msg.value >= _guest_memory.remaining_size) {
msg.value = 0;
} else {
msg.len = _guest_memory.remaining_size - msg.value;
msg.ptr = _guest_memory.backing_store_local_base() + msg.value;
}
if (verbose_debug)
Logging::printf(" -> len=0x%lx, ptr=0x%p\n",
msg.len, msg.ptr);
@ -999,6 +1046,12 @@ class Machine : public StaticReceiver<Machine>
if (verbose_debug)
Logging::printf("OP_ALLOC_FROM_GUEST\n");
if (msg.value == _guest_memory.fb_size()) {
_alloc_fb_mem = true;
msg.phys = _guest_memory.remaining_size;
return true;
}
if (msg.value > _guest_memory.remaining_size)
return false;
@ -1122,19 +1175,12 @@ class Machine : public StaticReceiver<Machine>
}
default:
PWRN("HostOp %d not implemented", msg.type);
return false;
}
}
bool receive(MessageConsole &msg)
{
if (verbose_debug)
Logging::printf("MessageConsole\n");
return true;
}
bool receive(MessageDisk &msg)
{
if (verbose_debug)
@ -1231,7 +1277,6 @@ class Machine : public StaticReceiver<Machine>
/* register host operations, called back by the VMM */
_motherboard.bus_hostop.add (this, receive_static<MessageHostOp>);
_motherboard.bus_console.add (this, receive_static<MessageConsole>);
_motherboard.bus_disk.add (this, receive_static<MessageDisk>);
_motherboard.bus_timer.add (this, receive_static<MessageTimer>);
_motherboard.bus_time.add (this, receive_static<MessageTime>);
@ -1348,6 +1393,8 @@ class Machine : public StaticReceiver<Machine>
Logging::printf("INIT done\n");
}
Motherboard& get_mb() { return _motherboard; }
~Machine()
{
Genode::env()->rm_session()->detach(_hip);
@ -1379,11 +1426,21 @@ int main(int argc, char **argv)
/* request max available memory */
Genode::addr_t vm_size = Genode::env()->ram_session()->avail();
/* reserve some memory for the VMM */
vm_size -= 256 * 1024;
vm_size -= 8 * 1024 * 1024;
/* calculate max memory for the VM */
vm_size = vm_size & ~((1UL << PAGE_SIZE_LOG2) - 1);
static Guest_memory guest_memory(vm_size);
/* Find out framebuffer size (default: 4 MiB) */
Genode::addr_t fb_size = 4*1024*1024;
try {
Genode::Xml_node node = Genode::config()->xml_node().sub_node("vga");
Genode::Xml_node::Attribute arg = node.attribute("fb_size");
unsigned long val;
arg.value(&val);
fb_size = val*1024;
} catch (...) { }
static Guest_memory guest_memory(vm_size, fb_size);
/* diagnostic messages */
Genode::printf("[0x%08lx, 0x%08lx) - %lu MiB - guest physical memory\n",
@ -1417,6 +1474,12 @@ int main(int argc, char **argv)
static Machine machine(boot_modules, guest_memory);
/* Create Console Thread */
Vancouver_console vcon(machine.get_mb(), fb_size, guest_memory.fb_ds());
/* Wait for services */
while (!console_init);
machine.setup_devices(Genode::config()->xml_node().sub_node("machine"));
Genode::printf("\n--- Booting VM ---\n");

View File

@ -0,0 +1 @@
../../../demo/src/server/nitlog/mono.tff

View File

@ -10,8 +10,10 @@ ifeq ($(wildcard $(VANCOUVER_DIR)),)
REQUIRES += prepare_ports_vancouver
endif
LIBS += cxx env thread alarm signal server
LIBS += cxx env blit thread alarm signal server
SRC_CC = main.cc nova_user_env.cc device_model_registry.cc
SRC_CC += console.cc keyboard.cc
SRC_BIN = mono.tff
#
# '82576vfmmio.inc' is apparently missing from the NOVA userland distribution.