/*P:100 This is the Launcher code, a simple program which lays out the
* "physical" memory for the new Guest by mapping the kernel image and the
* virtual devices, then reads repeatedly from /dev/lguest to run the Guest.
*
* The only trick: the Makefile links it at a high address so it will be clear
* of the guest memory region. It means that each Guest cannot have more than
* about 2.5G of memory on a normally configured Host. :*/
#define _LARGEFILE64_SOURCE
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <err.h>
#include <stdint.h>
#include <stdlib.h>
#include <elf.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdbool.h>
#include <errno.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <time.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <linux/if_tun.h>
#include <sys/uio.h>
#include <termios.h>
#include <getopt.h>
#include <zlib.h>
typedef unsigned long long u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
#include "../../include/linux/lguest_launcher.h"
#include "../../include/asm-i386/e820.h"
#define PAGE_PRESENT 0x7 /* Present, RW, Execute */
#define NET_PEERNUM 1
#define BRIDGE_PFX "bridge:"
#ifndef SIOCBRADDIF
#define SIOCBRADDIF 0x89a2 /* add interface to bridge */
#endif
static bool verbose;
#define verbose(args...) \
do { if (verbose) printf(args); } while(0)
static int waker_fd;
static u32 top;
struct device_list
{
fd_set infds;
int max_infd;
struct lguest_device_desc *descs;
struct device *dev;
struct device **lastdev;
};
struct device
{
struct device *next;
struct lguest_device_desc *desc;
void *mem;
/* Watch this fd if handle_input non-NULL. */
int fd;
bool (*handle_input)(int fd, struct device *me);
/* Watch DMA to this key if handle_input non-NULL. */
unsigned long watch_key;
u32 (*handle_output)(int fd, const struct iovec *iov,
unsigned int num, struct device *me);
/* Device-specific data. */
void *priv;
};
static int open_or_die(const char *name, int flags)
{
int fd = open(name, flags);
if (fd < 0)
err(1, "Failed to open %s", name);
return fd;
}
static void *map_zeroed_pages(unsigned long addr, unsigned int num)
{
static int fd = -1;
if (fd == -1)
fd = open_or_die("/dev/zero", O_RDONLY);
if (mmap((void *)addr, getpagesize() * num,
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0)
!= (void *)addr)
err(1, "Mmaping %u pages of /dev/zero @%p", num, (void *)addr);
return (void *)addr;
}
/* Find magic string marking entry point, return entry point. */
static unsigned long entry_point(void *start, void *end,
unsigned long page_offset)
{
void *p;
for (p = start; p < end; p++)
if (memcmp(p, "GenuineLguest", strlen("GenuineLguest")) == 0)
return (long)p + strlen("GenuineLguest") + page_offset;
err(1, "Is this image a genuine lguest?");
}
/* Returns the entry point */
static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
unsigned long *page_offset)
{
void *addr;
Elf32_Phdr phdr[ehdr->e_phnum];
unsigned int i;
unsigned long start = -1UL, end = 0;
/* Sanity checks. */
if (ehdr->e_type != ET_EXEC
|| ehdr->e_machine != EM_386
|| ehdr->e_phentsize != sizeof(Elf32_Phdr)
|| ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr))
errx(1, "Malformed elf header");
if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0)
err(1, "Seeking to program headers");
if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
err(1, "Reading program headers");
*page_offset = 0;
/* We map the loadable segments at virtual addresses corresponding
* to their physical addresses (our virtual == guest physical). */
for (i = 0; i