/* * \brief Port of VirtualBox to Genode * \author Norman Feske * \date 2013-08-20 */ /* * Copyright (C) 2013 Genode Labs GmbH * * This file is distributed under the terms of the GNU General Public License * version 2. */ /* Genode includes */ #include #include #include #include /* libc includes */ #include /* Virtualbox includes of VBoxBFE */ #include #include void *operator new (Genode::size_t size) { return Genode::env()->heap()->alloc(size); } void *operator new [] (Genode::size_t size) { return Genode::env()->heap()->alloc(size); } void operator delete(void * p) { if (Genode::env()->heap()->need_size_for_free()) { PERR("leaking memory - delete operator is missing size information"); return; } Genode::env()->heap()->free(p, 0); } namespace { template class Args { private: int _argc = 0; char *_argv[MAX_ARGS] = { }; public: class Too_many_arguments { }; void add(char const *arg) { /* argv[MAX_ARGS - 1] must be unused and set to 0 */ if (_argc >= MAX_ARGS - 1) throw Too_many_arguments(); /* XXX yes const-casting hurts but main() needs char**, if in * doubt we should strdup() here, right? */ _argv[_argc++] = const_cast(arg); } char *** argvp() { static char ** argv = _argv; return &argv; } int argc() { return _argc; } }; } /* unnamed namespace */ extern "C" { /* make output of Virtualbox visible */ size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { if (!stream || !ptr || !(fileno(stdout) == fileno(stream) || fileno(stderr) == fileno(stream))) return EOF; char const * cptr = reinterpret_cast(ptr); for (size_t j = 0; j < nmemb; j++) for (size_t i = 0; i < size; i++) Genode::printf("%c", cptr[j * size + i]); return nmemb; } int fprintf(FILE *stream, const char *format, ...) /* called by RTAssertMsg1 */ { if (!stream || !(fileno(stdout) == fileno(stream) || fileno(stderr) == fileno(stream))) return EOF; va_list list; va_start(list, format); Genode::vprintf(format, list); va_end(list); return 0; } int fputs(const char *s, FILE *stream) /* called by RTAssertMsg2Weak */ { if (!stream || !(fileno(stdout) == fileno(stream) || fileno(stderr) == fileno(stream))) return EOF; fwrite(s, Genode::strlen(s), 1, stream); } /* our libc provides a _nanosleep function */ int _nanosleep(const struct timespec *req, struct timespec *rem); int nanosleep(const struct timespec *req, struct timespec *rem) { return _nanosleep(req, rem); } /* * Genode way of using a configuration. Wrap VBox main until we throught it * out eventually. */ /* main function of VBox is in Frontends/VBoxBFE/VBoxBFE.cpp */ extern "C" DECLEXPORT(int) TrustedMain (int argc, char **argv, char **envp); int main() { static char c_mem[16]; static char c_vram[16]; static char c_type[4]; static char c_file[128]; static bool bOverlay = false; static Args<64> args; /* request max available memory */ size_t vm_size = Genode::env()->ram_session()->avail(); enum { VMM_MEMORY = 88 * 1024 * 1024, /* let a bit memory for the VMM */ VRAM_MEMORY = 8 * 1024 * 1024, /* video memory */ }; if (vm_size < VMM_MEMORY + VRAM_MEMORY) { PERR("not enough memory available - need %u, available only %zu " "- exit", VMM_MEMORY + VRAM_MEMORY, vm_size); return 1; } vm_size -= VMM_MEMORY + VRAM_MEMORY; try { using namespace Genode; Xml_node node = config()->xml_node().sub_node("image"); Xml_node::Attribute type = node.attribute("type"); Xml_node::Attribute file = node.attribute("file"); try { Xml_node::Attribute overlay = node.attribute("overlay"); overlay.value(c_type, sizeof(c_type)); if (!strcmp(c_type, "yes")) bOverlay = true; } catch (...) { } type.value(c_type, sizeof(c_type)); file.value(c_file, sizeof(c_file)); } catch (...) { PERR("C++ exception during xml parsing"); return 2; } args.add("virtualbox"); Genode::snprintf(c_mem, sizeof(c_mem), "%u", vm_size / 1024 / 1024); args.add("-m"); args.add(c_mem); Genode::snprintf(c_vram, sizeof(c_vram), "%u", VRAM_MEMORY / 1024 / 1024); args.add("-vram"); args.add(c_vram); args.add("-boot"); if (!Genode::strcmp(c_type, "iso")) { args.add("d"); args.add("-cdrom"); } else if (!Genode::strcmp(c_type, "vdi")) { args.add("c"); args.add("-hda"); } else { PERR("invalid configuration - abort"); return 3; } args.add(c_file); args.add("-ioapic"); if (bOverlay) args.add("-overlay"); /* shared folder setup */ unsigned shares = 0; try { using namespace Genode; for (Xml_node node = config()->xml_node().sub_node("share"); true; node = node.next("share")) { Xml_node::Attribute share_dir_host = node.attribute("host"); Xml_node::Attribute share_dir_guest = node.attribute("guest"); char * dir_host = new char[share_dir_host.value_size()]; char * dir_guest = new char[share_dir_guest.value_size()]; share_dir_host.value(dir_host, share_dir_host.value_size()); share_dir_guest.value(dir_guest, share_dir_guest.value_size()); args.add("-share"); args.add(dir_host), args.add(dir_guest); shares ++; } } catch(Genode::Xml_node::Nonexistent_sub_node) { } PINF("start %s image '%s' with %zu MB guest memory=%zu and %u shared folders", c_type, c_file, vm_size / 1024 / 1024, Genode::env()->ram_session()->avail(), shares); if (RT_FAILURE(RTR3InitExe(args.argc(), args.argvp(), 0))) { PERR("Intialization of VBox Runtime failed."); return 5; } return TrustedMain(args.argc(), *args.argvp(), NULL); } } /* extern "C" */