[Lguest] small program running as a guest

Matias Zabaljauregui zabaljauregui at gmail.com
Mon Jun 22 09:47:27 EST 2009


Hello list, 

	just want to share my first (successful) attempt to run a small program as a Lguest guest. 
I want to document all my steps so if someone else wants to try his own experiment, 
some documentation will be available. So if you find out I did something really stupid here, please let me know.

1) I use a linker script to create my elf with the executable segment at 0x100000 phys addr  and  0xc0100000 virt addr   (just like linux kernel)

2) Lguest will create the identity (y = x) and linear (y = x + 0xc0000000) mappings, so we don't need to worry about setting page tables (for this simple program)

3) Our elf stores the entry point, and lguest initializes eip with the corresponding value. Our entry point is in assembly: 

-----
.section .start
.globl start
.func start
start:	
	movl $0xc0030000, %esp  # initial stack pointer
	call main		# jump to C code
1:	jmp 1b			# should not return, but if it does, spin.
.endfunc
-----

4) OK, enough assembly code for me... Now we have a stack and can jump to C code. I put everything in 1 file, just for testing
    but here only show main() function (the whole C code is at the end of this text):

-----
int main (void)
{
	char welcome[] = "\n\nWelcome!\nThis is PuppyToy\nA minimal guest for Lguest\n\n";
	extern char _start_bss, _end_bss;

	/*Initialize bss*/
	unsigned char *p = (unsigned char *) &_start_bss;
	while (p < (unsigned char *)&_end_bss)
		*p++ = 0;

	/* $LHCALL_LGUEST_INIT */
	kvm_hypercall2(1, (unsigned long)&lguest_data - lguest_data.kernel_address, 0);

	/* Say hi!*/	
	print(welcome, sizeof(welcome));

	/* LHCALL_SHUTDOWN(LGUEST_SHUTDOWN_POWEROFF) */
	kvm_hypercall2(2, 0, 1); 

	return 0;
}
-----

5) That's it. The rest of C code is made of existing data types embedded in my file, 
and the definition of print() function  based on (copied from) lguest's early_put_chars(). 


Finally, one question: given the proximity of the deadline for this work, do you consider a realistic goal
to even think in writing some sort of virtio-console 'driver' for my toy ? 


Thank you in advance
Matias







I hope your eyes doesn't get hurt because of this code:
-----
 
/*Minimal stuff for making of this a one-file toy */

#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define NULL ((void *) 0)

typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;

#define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"

static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
				  unsigned long p2)
{
	long ret;
	asm volatile(KVM_HYPERCALL
		     : "=a"(ret)
		     : "a"(nr), "b"(p1), "c"(p2)
		     : "memory");
	return ret;
}

#define LHCALL_RING_SIZE 64

struct hcall_args {
	unsigned long arg0, arg1, arg2, arg3, arg4;
};

struct lguest_data
{
	unsigned int irq_enabled;
	/* DECLARE_BITMAP(blocked_interrupts, LGUEST_IRQS) */
	unsigned long blocked_interrupts[DIV_ROUND_UP(32, 8 * sizeof(long))];
	unsigned long cr2;
	struct timespec {
		long		tv_sec;
		long		tv_nsec;
	} time;
	int irq_pending;
	uint8_t hcall_status[LHCALL_RING_SIZE];
	struct hcall_args hcalls[LHCALL_RING_SIZE];
	unsigned long reserve_mem;
	uint32_t tsc_khz;
	unsigned long pgdir;
	unsigned long noirq_start, noirq_end;
	unsigned long kernel_address;
	unsigned int syscall_vec;
};

struct lguest_data lguest_data = {
	.kernel_address = 0xc0000000,
	.syscall_vec = 0x80,
};

/* My early_put_chars() */
static int print(const char *buf, int count)
{
	char scratch[100];  //why just 17 in boot.c ?
	unsigned int len = count, i = 0;

	if (len > sizeof(scratch) - 1)
		len = sizeof(scratch) - 1;
	scratch[len] = '\0';

	for(;i < len; i++) {
		scratch[i] = buf[i];
	}

	/* LHCALL_NOTIFY */
	kvm_hypercall2(17, (unsigned long)scratch - 0xc0000000, 0);

	return len;
}

int main (void)
{
	char welcome[] = "\n\nWelcome!\nThis is PuppyToy\nA minimal guest for Lguest\n\n";
	extern char _start_bss, _end_bss;

	/*Initialize bss*/
	unsigned char *p = (unsigned char *) &_start_bss;
	while (p < (unsigned char *)&_end_bss)
		*p++ = 0;

	/* $LHCALL_LGUEST_INIT */
	kvm_hypercall2(1, (unsigned long)&lguest_data - lguest_data.kernel_address, 0);

	/* Say hi!*/	
	print(welcome, sizeof(welcome));

	/* LHCALL_SHUTDOWN(LGUEST_SHUTDOWN_POWEROFF) */
	kvm_hypercall2(2, 0, 1); 

	return 0;
}
-----






More information about the Lguest mailing list