diff --git a/ports/src/vancouver/console.cc b/ports/src/vancouver/console.cc new file mode 100644 index 0000000000..9aef0e8a09 --- /dev/null +++ b/ports/src/vancouver/console.cc @@ -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 +#include + +/* Genode includes */ +#include + +/* nitpicker graphics backend */ +#include +#include +#include + +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); + _mb.bus_memregion.add(this, receive_static); + + /* 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 + (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 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(); +} diff --git a/ports/src/vancouver/console.h b/ports/src/vancouver/console.h new file mode 100644 index 0000000000..a9e2a43633 --- /dev/null +++ b/ports/src/vancouver/console.h @@ -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 +#include +#include +#include +#include +#include + +/* NOVA userland includes */ +#include + +/* includes for I/O */ +#include +#include +#include +#include +#include + +using Genode::List; +using Genode::Thread; + +class Vancouver_console : public Thread<8192>, public StaticReceiver +{ + 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_ */ diff --git a/ports/src/vancouver/keyboard.cc b/ports/src/vancouver/keyboard.cc new file mode 100644 index 0000000000..bb23e1b8fd --- /dev/null +++ b/ports/src/vancouver/keyboard.cc @@ -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 + +/* vancouver generic keyboard helper */ +#include +#include + +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); +} diff --git a/ports/src/vancouver/keyboard.h b/ports/src/vancouver/keyboard.h new file mode 100644 index 0000000000..010d3a658d --- /dev/null +++ b/ports/src/vancouver/keyboard.h @@ -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 + +/* includes for I/O */ +#include +#include +#include + +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_ */ diff --git a/ports/src/vancouver/main.cc b/ports/src/vancouver/main.cc index c55de3a394..7ef332b7c2 100644 --- a/ports/src/vancouver/main.cc +++ b/ports/src/vancouver/main.cc @@ -59,7 +59,7 @@ /* local includes */ #include #include - +#include 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 { @@ -446,7 +472,7 @@ class Vcpu_dispatcher : public Genode::Thread, /* 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, 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, 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, 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 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 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 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 } 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 /* register host operations, called back by the VMM */ _motherboard.bus_hostop.add (this, receive_static); - _motherboard.bus_console.add (this, receive_static); _motherboard.bus_disk.add (this, receive_static); _motherboard.bus_timer.add (this, receive_static); _motherboard.bus_time.add (this, receive_static); @@ -1348,6 +1393,8 @@ class Machine : public StaticReceiver 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"); diff --git a/ports/src/vancouver/mono.tff b/ports/src/vancouver/mono.tff new file mode 120000 index 0000000000..110c35c004 --- /dev/null +++ b/ports/src/vancouver/mono.tff @@ -0,0 +1 @@ +../../../demo/src/server/nitlog/mono.tff \ No newline at end of file diff --git a/ports/src/vancouver/target.mk b/ports/src/vancouver/target.mk index 8f98c8341c..e9a841c026 100644 --- a/ports/src/vancouver/target.mk +++ b/ports/src/vancouver/target.mk @@ -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.