genode/repos/ports/src/virtualbox/main.cc

238 lines
5.6 KiB
C++

/*
* \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 <base/env.h>
#include <base/printf.h>
#include <os/config.h>
#include <base/snprintf.h>
/* libc includes */
#include <stdio.h>
/* Virtualbox includes of VBoxBFE */
#include <iprt/initterm.h>
#include <iprt/err.h>
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 <int MAX_ARGS>
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<char *>(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<const char *>(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" */