Skip to contentSkip to conversation

HV VM Fix map area for HV.

PATCH In review Steven Rostedt 2 participants 16 messages Mar 8, 2007 – Mar 9, 2007 1 message not in the archive

Subsystems (6)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

PATCH 1/13 HV VM Fix map area for HV.

plain text document attachment (hvvm.patch)
OK, some explaination is needed here. The goal of lguest with paravirt ops, is to have one kernel that can be loaded both as a host and a guest. To do this, we need to map an area in virtual memory that both the host and guest share. But I don't want any conflicts with the guest.

One solution is just to do a single area for boot up, and then use the vmalloc to map. But this gets quite complex, since we need to force the guest to map a given area, after the fact, hoping that it didn't map it someplace else before we get to the code to map it. This can be done, but doing it this way is (for now) much easier.

What I've done here, is to make a large area in the FIXMAP region. The guest will not use this area for anything, since it is reserved for only running a HV. So by making a FIXMAP area, we force this area reserved for HV use. Now the host can load the hypervisor text section into this area and force it mapped to the guest without worrying that the guest will want to use this area for anything else.

Each guest will have it's own shared data placed in this section too. The guest will only get the hypervisor text and its own section data mapped into this area. But the host will map the hypervisor text and all guest shared areas in this region. And what makes this so easy, is that the virtual addresses between the host and guest for these locations will be the same!

To explain this a little better, here's what the virtual addresses of the host and guests will look like:

Host Guest1 Guest2

 +-----------+   +-----------+  +-----------+
 |           |   |           |  |           |
 +-----------+   +-----------+  +-----------+
 | HV FIXMAP |   | HV FIXMAP |  | HV FIXMAP |
 |   TEXT    |   |   TEXT    |  |   TEXT    |
 +-----------+   +-----------+  +-----------+
 | GUEST 1   |   | GUEST 1   |  | UNMAPPED  |
 |SHARED DATA|   |SHARED DATA|  |           |
 +-----------+   +-----------+  +-----------+
 | GUEST 2   |   | UNMAPPED  |  | GUEST 2   |
 |SHARED DATA|   |           |  |SHARED DATA|
 +-----------+   |           |  +-----------+
 |           |   |           |  |           |
Cc Glauber de Oliveira Costa <[email protected]>
Cc Chris Wright <[email protected]>
Cc Ingo Molnar <[email protected]>
arch/x86_64/lguest/hv_vm.c new file +367 -0
Index: work-pv/arch/x86_64/lguest/hv_vm.c
===================================================================
@@ -0,0 +1,367 @@
+/*
+ *  arch/x86_64/lguest/hv_vm.c
+ *
+ *  Copyright (C) 2007 Steven Rostedt <[email protected]>, Red Hat
+ *
+ *  Some of this code was influenced by mm/vmalloc.c
+ *
+ *  FIXME: This should not be limited to lguest, but should be put
+ *         into the kernel proper, since this code should be
+ *         HV agnostic.
+ *
+ *  The purpose of the HV VM area is to create a virtual address
+ *  space that can be saved for use of sending information to and
+ *  from a guest.  A small hypervisor text section may be loaded
+ *  into this address and shared across all guests that use that
+ *  hypervisor.  Each guest may have a data page so that it can
+ *  communicate back and forth with the host.
+ *
+ *  The reason for this, is to allow an virtual address space that
+ *  will not be used by the guest for any other purpose.  This
+ *  allows a nice place to map code that will communicate to the guest.
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#include <asm/hv_vm.h>
+
+static DEFINE_MUTEX(hvvm_lock);
+
+static DECLARE_BITMAP(hvvm_avail_pages, NR_HV_PAGES);
+
+
+static void hvvm_pte_unmap(pmd_t *pmd, unsigned long addr)
+{
+	pte_t *pte;
+	pte_t ptent;
+
+	pte = pte_offset_kernel(pmd, addr);
+	ptent = ptep_get_and_clear(&init_mm, addr, pte);
+	WARN_ON(!pte_none(ptent) && !pte_present(ptent));
+}
+
+static inline void hvvm_pmd_unmap(pud_t *pud, unsigned long addr)
+{
+	pmd_t *pmd;
+
+	pmd = pmd_offset(pud, addr);
+	if (pmd_none_or_clear_bad(pmd))
+		return;
+	hvvm_pte_unmap(pmd, addr);
+}
+
+static inline void hvvm_pud_unmap(pgd_t *pgd, unsigned long addr)
+{
+	pud_t *pud;
+
+	pud = pud_offset(pgd, addr);
+	if (pud_none_or_clear_bad(pud))
+		return;
+	hvvm_pmd_unmap(pud, addr);
+}
+
+static void hvvm_unmap_page(unsigned long addr)
+{
+	pgd_t *pgd;
+
+	pgd = pgd_offset_k(addr);
+	hvvm_pud_unmap(pgd, addr);
+}
+
+static int hvvm_pte_alloc(pmd_t *pmd, unsigned long addr,
+			  unsigned long page, pgprot_t prot)
+{
+	pte_t *pte;
+
+	pte = pte_alloc_kernel(pmd, addr);
+	if (!pte)
+		return -ENOMEM;
+
+	WARN_ON(!pte_none(*pte));
+	set_pte_at(&init_mm, addr, pte,
+		   mk_pte(pfn_to_page(page >> PAGE_SHIFT), prot));
+
+	return 0;
+}
+
+static inline int hvvm_pmd_alloc(pud_t *pud, unsigned long addr,
+				 unsigned long page, pgprot_t prot)
+{
+	pmd_t *pmd;
+
+	pmd = pmd_alloc(&init_mm, pud, addr);
+	if (!pmd)
+		return -ENOMEM;
+	if (hvvm_pte_alloc(pmd, addr, page, prot))
+		return -ENOMEM;
+	return 0;
+}
+
+static inline int hvvm_pud_alloc(pgd_t *pgd, unsigned long addr,
+				 unsigned long page, pgprot_t prot)
+{
+	pud_t *pud;
+
+	pud = pud_alloc(&init_mm, pgd, addr);
+	if (!pud)
+		return -ENOMEM;
+	if (hvvm_pmd_alloc(pud, addr, page, prot))
+		return -ENOMEM;
+	return 0;
+}
+
+static int hvvm_alloc_page(unsigned long addr, unsigned long page, pgprot_t prot)
+{
+	pgd_t *pgd;
+	int err;
+
+	pgd = pgd_offset_k(addr);
+	err = hvvm_pud_alloc(pgd, addr, page, prot);
+	return err;
+}
+
+static unsigned long *get_vaddr(unsigned long paddr)
+{
+	paddr &= ~(0xfff);
+	return (unsigned long*)(paddr + PAGE_OFFSET);
+}
+
+unsigned long hvvm_get_actual_phys(void *addr, pgprot_t *prot)
+{
+	unsigned long vaddr;
+	unsigned long offset;
+	unsigned long cr3;
+	unsigned long pgd;
+	unsigned long pud;
+	unsigned long pmd;
+	unsigned long pte;
+	unsigned long mask;
+
+	unsigned long *p;
+
+	/*
+	 * Travers the page tables to get the actual
+	 * physical address. I want this to work for
+	 * all addresses, regardless of where they are mapped.
+	 */
+
+	/* FIXME: Do this better!! */
+
+	/* grab the start of the page tables */
+	asm ("movq %%cr3, %0" : "=r"(cr3));
+
+	p = get_vaddr(cr3);
+
+	offset = (unsigned long)addr;
+	offset >>= PGDIR_SHIFT;
+	offset &= PTRS_PER_PGD-1;
+
+	pgd = p[offset];
+
+	if (!(pgd & 1))
+		return 0;
+
+	p = get_vaddr(pgd);
+
+	offset = (unsigned long)addr;
+	offset >>= PUD_SHIFT;
+	offset &= PTRS_PER_PUD-1;
+
+	pud = p[offset];
+
+	if (!(pud & 1))
+		return 0;
+
+	p = get_vaddr(pud);
+
+	offset = (unsigned long)addr;
+	offset >>= PMD_SHIFT;
+	offset &= PTRS_PER_PMD-1;
+
+	pmd = p[offset];
+
+	if (!(pmd & 1))
+		return 0;
+
+	/* Now check to see if we are 2M pages or 4K pages */
+	if (pmd & (1 << 7)) {
+		/* stop here, we are 2M pages */
+		pte = pmd;
+		mask = (1<<21)-1;
+		goto calc;
+	}
+
+	p = get_vaddr(pmd);
+
+	offset = (unsigned long)addr;
+	offset >>= PAGE_SHIFT;
+	offset &= PTRS_PER_PTE-1;
+
+	pte = p[offset];
+	mask = PAGE_SIZE-1;
+
+ calc:
+
+	if (!(pte & 1))
+		return 0;
+
+	vaddr = pte & ~(0xfff) & ~(1UL << 63);
+
+	if (prot)
+		pgprot_val(*prot) = pte & 0xfff;
+
+	offset = (unsigned long)addr;
+	offset &= mask;
+
+	vaddr += offset;
+	/* Potentially clear the nx bit */
+	vaddr &= ~(1UL << 63);
+
+	return vaddr;
+}
+
+static unsigned long alloc_hv_pages(int pages)
+{
+	unsigned int bit = 0;
+	unsigned int found_bit;
+	int i;
+
+	/* FIXME : ADD LOCKING!!! */
+
+	/*
+	 * Scan the available bitmask for free pages.
+	 * 0 - available : 1 - used
+	 */
+	do {
+		bit = find_next_zero_bit(hvvm_avail_pages, NR_HV_PAGES, bit);
+		if (bit >= NR_HV_PAGES)
+			return 0;
+
+		found_bit = bit;
+
+		for (i=1; i < pages; i++) {
+			bit++;
+			if (test_bit(bit, hvvm_avail_pages))
+				break;
+		}
+	} while (i < pages);
+
+	if (i < pages)
+		return 0;
+
+	/*
+	 * OK we found a location where we can map our pages
+	 * so now we set them used, and do the mapping.
+	 */
+	bit = found_bit;
+	for (i=0; i < pages; i++)
+		set_bit(bit++, hvvm_avail_pages);
+
+	return HVVM_START + found_bit * PAGE_SIZE;
+}
+
+static void release_hv_pages(unsigned long addr, int pages)
+{
+	unsigned int bit;
+	int i;
+
+	/* FIXME : ADD LOCKING!!! */
+
+	bit = (addr - HVVM_START) / PAGE_SIZE;
+
+	for (i=0; i < pages; i++) {
+		BUG_ON(!test_bit(bit, hvvm_avail_pages));
+		clear_bit(bit++, hvvm_avail_pages);
+	}
+}
+
+
+/**
+ *	hvvm_map_pages - map an address to the HV VM area.
+ *	@vaddr:		virtual address to map
+ *	@pages:		Number of pages from that virtual address to map.
+ *	@hvaddr:	address returned that holds the mapping.
+ *
+ *	This function maps the pages represnted by addr into
+ * 	the HV VM area, and returns the address given to it.
+ *	NULL is returned on failure (no space left?)
+ */
+int hvvm_map_pages(void *vaddr, int pages, unsigned long *hvaddr)
+{
+	unsigned long paddr;
+	unsigned long addr;
+	pgprot_t prot;
+	int i;
+	int ret;
+
+	if ((unsigned long)vaddr & (PAGE_SIZE - 1)) {
+		printk("bad vaddr for hv mapping (%p)\n",
+		       vaddr);
+		return -EINVAL;
+	}
+
+	/*
+	 * First we need to find a place to allocate.
+	 */
+	/* FIXME - ADD LOCKING!!! */
+	addr = alloc_hv_pages(pages);
+	*hvaddr = addr;
+	printk("addr=%lx\n", addr);
+	if (!addr)
+		return -ENOMEM;
+
+	ret = -ENOMEM;
+
+	for (i=0; i < pages; i++, vaddr += PAGE_SIZE, addr += PAGE_SIZE) {
+		paddr = hvvm_get_actual_phys(vaddr, &prot);
+		printk("%d: paddr=%lx\n", i, paddr);
+		if (!paddr)
+			goto out;
+		ret = hvvm_alloc_page(addr, paddr, prot);
+		printk("%d: ret=%d addr=%lx\n", i, ret, addr);
+		if (ret < 0)
+			goto out;
+	}
+
+	addr = *hvaddr;
+	vaddr -= PAGE_SIZE * pages;
+	printk("vaddr=%p (%lx)\naddr=%p (%lx)\n",
+	       vaddr, *(unsigned long*)vaddr,
+	       (void*)addr, *(unsigned long*)addr);
+
+	return 0;
+out:
+	for (--i; i >=0; i--) {
+		addr -= PAGE_SIZE;
+		hvvm_unmap_page(addr);
+	}
+
+	release_hv_pages(addr, pages);
+	return ret;
+}
+
+void hvvm_unmap_pages(unsigned long addr, int pages)
+{
+	int i;
+
+	release_hv_pages(addr, pages);
+	for (i=0; i < pages; i++, addr += PAGE_SIZE)
+		hvvm_unmap_page(addr);
+}
+
+void hvvm_release_all(void)
+{
+	int bit;
+	unsigned long vaddr = HVVM_START;
+
+	for (bit=0; bit < NR_HV_PAGES; bit++, vaddr += PAGE_SIZE)
+		if (test_bit(bit, hvvm_avail_pages)) {
+			hvvm_unmap_page(vaddr);
+			clear_bit(bit, hvvm_avail_pages);
+		}
+}
include/asm-x86_64/fixmap.h +3 -0
Index: work-pv/include/asm-x86_64/fixmap.h
===================================================================
@@ -16,6 +16,7 @@
 #include <asm/page.h>
 #include <asm/vsyscall.h>
 #include <asm/vsyscall32.h>
+#include <asm/hv_vm.h>
 
 /*
  * Here we define all the compile-time 'special' virtual
@@ -40,6 +41,8 @@ enum fixed_addresses {
 	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
 	FIX_IO_APIC_BASE_0,
 	FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
+	FIX_HV_BASE,
+	FIX_HV_BASE_END = FIX_HV_BASE + HV_VIRT_SIZE - 1,
 	__end_of_fixed_addresses
 };
 
include/asm-x86_64/hv_vm.h new file +13 -0
Index: work-pv/include/asm-x86_64/hv_vm.h
===================================================================
@@ -0,0 +1,13 @@
+#ifndef _LINUX_HV_VM
+#define _LINUX_HV_VM
+
+#define NR_HV_PAGES  256 /* meg? */
+#define HV_VIRT_SIZE (NR_HV_PAGES << PAGE_SHIFT)
+
+#define HVVM_START (__fix_to_virt(FIX_HV_BASE_END))
+
+int hvvm_map_pages(void *vaddr, int pages, unsigned long *hvaddr);
+void hvvm_unmap_pages(unsigned long addr, int pages);
+void hvvm_release_all(void);
+
+#endif

--

#2 lore raw
Quoted 5 lines · Steven Rostedt

One solution is just to do a single area for boot up, and then use the vmalloc to map. But this gets quite complex, since we need to force the guest to map a given area, after the fact, hoping that it didn't map it someplace else before we get to the code to map it. This can be done, but doing it this way is (for now) much easier.

Well, this way was more code, but you're right about the theoretical failure mode of the vmalloc method.

Quoted 14 lines

Host Guest1 Guest2

 +-----------+   +-----------+  +-----------+
 |           |   |           |  |           |
 +-----------+   +-----------+  +-----------+
 | HV FIXMAP |   | HV FIXMAP |  | HV FIXMAP |
 |   TEXT    |   |   TEXT    |  |   TEXT    |
 +-----------+   +-----------+  +-----------+
 | GUEST 1   |   | GUEST 1   |  | UNMAPPED  |
 |SHARED DATA|   |SHARED DATA|  |           |
 +-----------+   +-----------+  +-----------+
 | GUEST 2   |   | UNMAPPED  |  | GUEST 2   |
 |SHARED DATA|   |           |  |SHARED DATA|
 +-----------+   |           |  +-----------+
 |           |   |           |  |           |

I think it's better to do this per-cpu, as in the recently posted 32-but patches. You have to copy in when changing guests, but you can support an infinite number of guests with (HV TEXTSIZE + NR_CPUS*2) pages.

Damn, I forgot to cc you on that patch. Sorry, I suck 8(

They went to lkml as:
[PATCH 7/9] lguest: use read-only pages rather than segments to protect high-mapped switcher [PATCH 8/9] lguest: Optimize away copy in and out of per-cpu guest pages

Cheers!
Rusty.

#3 lore raw

PATCH 2/13 hvvm export page utils

In reply to a message not in the archive

plain text document attachment (hvvm-mm-export.patch) I would like to have the HV VM code in the kernel proper, but until then, it needs to get at some of the memory page table utils (pud_alloc and friends). So as a module, we export this.

I probably can change HV VM to just be compiled in the kernel like some of the other lguest stuff too.

Cc Glauber de Oliveira Costa <[email protected]>
Cc Chris Wright <[email protected]>
mm/memory.c +7 -0
Index: work-pv/mm/memory.c
===================================================================
@@ -2798,3 +2798,10 @@ int access_process_vm(struct task_struct
 	return buf - old_buf;
 }
 EXPORT_SYMBOL_GPL(access_process_vm);
+
+/* temp until we put the hv vm stuff into the kernel */
+EXPORT_SYMBOL_GPL(__pud_alloc);
+EXPORT_SYMBOL_GPL(__pmd_alloc);
+EXPORT_SYMBOL_GPL(__pte_alloc_kernel);
+EXPORT_SYMBOL_GPL(pmd_clear_bad);
+EXPORT_SYMBOL_GPL(pud_clear_bad);

--

#4 lore raw

PATCH 3/13 lguest64 core

In reply to a message not in the archive

plain text document attachment (lguest64.patch)
This is the main core code for the lguest64.

Have fun, and don't hurt the puppies!

arch/x86_64/lguest/Makefile new file +24 -0
Index: work-pv/arch/x86_64/lguest/Makefile
===================================================================
@@ -0,0 +1,24 @@
+# Guest requires the paravirt_ops replacement and the bus driver.
+obj-$(CONFIG_LGUEST_GUEST) += lguest.o lguest_bus.o
+
+# Host requires the other files, which can be a module.
+obj-$(CONFIG_LGUEST)	+= lg.o
+lg-objs := core.o hypervisor.o lguest_user.o hv_vm.o page_tables.o \
+hypercalls.o io.o interrupts_and_traps.o lguest_debug.o
+
+# hypercalls.o page_tables.o interrupts_and_traps.o \
+#	segments.o io.o lguest_user.o
+
+# We use top 4MB for guest traps page, then hypervisor. */
+HYPE_ADDR := (0xFFC00000+4096)
+# The data is only 1k (256 interrupt handler pointers)
+HYPE_DATA_SIZE := 1024
+CFLAGS += -DHYPE_ADDR="$(HYPE_ADDR)" -DHYPE_DATA_SIZE="$(HYPE_DATA_SIZE)"
+
+##$(obj)/core.o: $(obj)/hypervisor-blob.c
+### This links the hypervisor in the right place and turns it into a C array.
+##$(obj)/hypervisor-raw: $(obj)/hypervisor.o
+##	@$(LD) -static -Tdata=`printf %#x $$(($(HYPE_ADDR)))` -Ttext=`printf %#x $$(($(HYPE_ADDR)+$(HYPE_DATA_SIZE)))` -o $@ $< && $(OBJCOPY) -O binary $@
+##$(obj)/hypervisor-blob.c: $(obj)/hypervisor-raw
+##	@od -tx1 -An -v $< | sed -e 's/^ /0x/' -e 's/$$/,/' -e 's/ /,0x/g' > $@
+
arch/x86_64/lguest/core.c new file +379 -0

379 lines not on this page · raw message

arch/x86_64/lguest/hypercalls.c new file +324 -0

324 lines not on this page · raw message

arch/x86_64/lguest/hypervisor.S new file +711 -0

711 lines not on this page · raw message

arch/x86_64/lguest/interrupts_and_traps.c new file +292 -0

292 lines not on this page · raw message

arch/x86_64/lguest/lguest.c new file +705 -0

705 lines not on this page · raw message

arch/x86_64/lguest/lguest.h new file +161 -0

161 lines not on this page · raw message

arch/x86_64/lguest/lguest_user.c new file +436 -0

404 lines not on this page · raw message

arch/x86_64/lguest/page_tables.c new file +1285 -0

1,285 lines not on this page · raw message

arch/x86_64/Makefile +1 -0
Index: work-pv/arch/x86_64/Makefile
===================================================================

Lines of this file are not shown. View the raw message.

include/asm-x86_64/lguest.h new file +350 -0

350 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

--

Part of the diff is not shown here. View the raw message.

#5 lore raw

Re: [RFC/PATCH LGUEST X86_64 03/13] lguest64 core

arch/x86_64/lguest/Makefile line 7

Quoted 2 lines · Steven Rostedt
arch/x86_64/lguest/Makefile new file +2 -0
+lg-objs := core.o hypervisor.o lguest_user.o hv_vm.o page_tables.o \
+hypercalls.o io.o interrupts_and_traps.o lguest_debug.o

Right, I missed the trick here: hypervisor.S doesn't require any relocations, so that fact that it's linked at the wrong address doesn't matter at all. Excuse me while I prepare a patch 8)

arch/x86_64/lguest/core.c line 289

Quoted 2 lines
arch/x86_64/lguest/core.c new file +2 -0
+extern long end_hyper_text;
+extern long start_hyper_text;

The standard way of doing this is "extern char end_hyper_text[];" doesn't matter on x86/x86-64, but on some platforms gcc can make assumptions about addresses based on the size of the variable (sbss etc). So nice to use that everywhere for asm constants.

Cheers,
Rusty.

#6 lore raw

PATCH 4/13 Useful debugging

In reply to a message not in the archive

plain text document attachment (lguest64-debug-utils.patch) This patch contains some nice features used to debug the lguest64 guest.

It has a way to print page tables for either the host or the guest.

It incorporates kallsyms, and can do a nice back trace of a guest when it crashes. The guest needs kallsyms obviously compiled in.
Note: This code needs to be fixed to be more secure!

Implements a lgdebug_print that can be used within the host that will only print when lguest_debug is true. There's a hypercall that the guest can call to turn this on.

There's also a function called lguest_set_debug(n) the makes it easy for the guest to turn it on. Where n=1 will turn on debugging prints, and n=0 will turn it off. (well n!=0 will turn it on).

Cc Glauber de Oliveira Costa <[email protected]>
Cc Chris Wright <[email protected]>
arch/x86_64/lguest/lguest_debug.c new file +532 -0
Index: work-pv/arch/x86_64/lguest/lguest_debug.c
===================================================================
@@ -0,0 +1,532 @@
+/*
+    lguest debug utils. Modified from various other parts of Linux.
+    What was modified is Copyright 2007 Steven Rostedt, Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+*/
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/freezer.h>
+#include <linux/kallsyms.h>
+#include <asm/paravirt.h>
+#include <asm/hv_vm.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include "lguest.h"
+
+int lguest_debug;
+
+static DEFINE_SPINLOCK(lgdebug_print_lock);
+#define LGDEBUG_BUF_SIZ 1024
+static char lgdebug_print_buf[LGDEBUG_BUF_SIZ];
+
+void lgdebug_vprint(const char *fmt, va_list ap)
+{
+	unsigned long flags;
+
+	if (!lguest_debug)
+		return;
+
+	spin_lock_irqsave(&lgdebug_print_lock, flags);
+	vsnprintf(lgdebug_print_buf, LGDEBUG_BUF_SIZ-1, fmt, ap);
+	printk("%s", lgdebug_print_buf);
+	spin_unlock_irqrestore(&lgdebug_print_lock, flags);
+}
+
+void lgdebug_print(const char *fmt, ...)
+{
+	va_list ap;
+
+	if (!lguest_debug)
+		return;
+
+	/* irq save? */
+	va_start(ap, fmt);
+	lgdebug_vprint(fmt, ap);
+	va_end(ap);
+}
+
+void lguest_dump_vcpu_regs(struct lguest_vcpu *vcpu)
+{
+	struct lguest_regs *regs = &vcpu->regs;
+
+	printk("Printing VCPU %d regs cr3: %016llx\n", vcpu->id, regs->cr3);
+	printk("RIP: %04llx: ", regs->cs & 0xffff);
+	lguest_print_address(vcpu, regs->rip);
+	printk("RSP: %04llx:%016llx  EFLAGS: %08llx\n", regs->ss, regs->rsp,
+		regs->rflags);
+	printk("RAX: %016llx RBX: %016llx RCX: %016llx\n",
+	       regs->rax, regs->rbx, regs->rcx);
+	printk("RDX: %016llx RSI: %016llx RDI: %016llx\n",
+	       regs->rdx, regs->rsi, regs->rdi);
+	printk("RBP: %016llx R08: %016llx R09: %016llx\n",
+	       regs->rbp, regs->r8, regs->r9);
+	printk("R10: %016llx R11: %016llx R12: %016llx\n",
+	       regs->r10, regs->r11, regs->r12);
+	printk("R13: %016llx R14: %016llx R15: %016llx\n",
+	       regs->r13, regs->r14, regs->r15);
+
+	printk("errcode: %llx   trapnum: %llx\n",
+	       regs->errcode, regs->trapnum);
+
+	lguest_dump_trace(vcpu, regs);
+}
+
+struct guest_ksym_stuff {
+	unsigned long *addresses;
+	unsigned long num_syms;
+	u8 *names;
+	u8 *token_table;
+	u16 *token_index;
+	unsigned long *markers;
+};
+
+static struct lguest_text_ptr *get_text_segs(struct lguest_vcpu *vcpu)
+{
+	struct lguest_guest_info *linfo = vcpu->guest;
+	struct lguest_text_ptr *segs, **p;
+	struct lguest_text_ptr *g;
+	unsigned long addr;
+	int i;
+
+	if (!linfo->lguest_data)
+		return NULL;
+
+	addr = lhread_u64(vcpu, (u64)&linfo->lguest_data->text);
+	if (!addr)
+		return NULL;
+
+	g = (struct lguest_text_ptr*)addr;
+
+	p = &segs;
+
+	/* only allow for 10 segs */
+	for (i=0; i < 10; i++) {
+		*p = kmalloc(sizeof(*segs), GFP_KERNEL);
+		if (!*p)
+			goto free_me;
+		(*p)->start = lhread_u64(vcpu, (u64)&g->start);
+		(*p)->end = lhread_u64(vcpu, (u64)&g->end);
+		addr = lhread_u64(vcpu, (u64)&g->next);
+		p = (struct lguest_text_ptr**)&((*p)->next);
+		if (!addr)
+			break;
+		g = (struct lguest_text_ptr*)addr;
+	}
+	*p = NULL;
+
+	return segs;
+
+free_me:
+	while (segs) {
+		g = (struct lguest_text_ptr*)segs->next;
+		kfree(segs);
+		segs = g;
+	}
+	return NULL;
+}
+
+static int is_text_seg(struct lguest_text_ptr *segs, unsigned long addr)
+{
+	while (segs) {
+		if (addr >= segs->start &&
+		    addr <= segs->end)
+			return 1;
+		segs = (struct lguest_text_ptr*)segs->next;
+	}
+	return 0;
+}
+
+static void put_text_segs(struct lguest_text_ptr *segs)
+{
+	struct lguest_text_ptr *p;
+
+	while (segs) {
+		p = (struct lguest_text_ptr*)segs->next;
+		kfree(segs);
+		segs = p;
+	}
+}
+
+static unsigned int expand_symbol(struct lguest_vcpu *vcpu,
+				  struct guest_ksym_stuff *kstuff,
+				  unsigned int off, char *result)
+{
+	int len, skipped_first = 0;
+	const u8 *tptr, *data;
+
+	/* get the compressed symbol length from the first symbol byte */
+	data = &kstuff->names[off];
+
+	len = lhread_u8(vcpu, (u64)data);
+
+	data++;
+
+	/* update the offset to return the offset for the next symbol on
+	 * the compressed stream */
+	off += len + 1;
+
+	/* for every byte on the compressed symbol data, copy the table
+	   entry for that byte */
+	while(len) {
+		u8 idx;
+		u16 tok;
+		idx = lhread_u8(vcpu, (u64)data);
+		tok = lhread_u16(vcpu, (u64)(&kstuff->token_index[idx]));
+		tptr = &kstuff->token_table[ tok ];
+		data++;
+		len--;
+
+		idx = lhread_u8(vcpu, (u64)tptr);
+		while (idx) {
+			if(skipped_first) {
+				*result = idx;
+				result++;
+			} else
+				skipped_first = 1;
+			tptr++;
+			idx = lhread_u8(vcpu, (u64)tptr);
+		}
+	}
+
+	*result = '\0';
+
+	/* return to offset to the next symbol */
+	return off;
+}
+
+static unsigned long get_symbol_pos(struct lguest_vcpu *vcpu,
+				    struct guest_ksym_stuff *kstuff,
+				    unsigned long addr,
+				    unsigned long *symbolsize,
+				    unsigned long *offset)
+{
+	unsigned long symbol_start = 0, symbol_end = 0;
+	unsigned long i, low, high, mid;
+
+	/* do a binary search on the sorted kallsyms_addresses array */
+	low = 0;
+	high = kstuff->num_syms;
+
+	while (high - low > 1) {
+		mid = (low + high) / 2;
+		if (kstuff->addresses[mid] <= addr)
+			low = mid;
+		else
+			high = mid;
+	}
+
+	/*
+	 * search for the first aliased symbol. Aliased
+	 * symbols are symbols with the same address
+	 */
+	while (low && kstuff->addresses[low-1] == kstuff->addresses[low])
+		--low;
+
+	symbol_start = kstuff->addresses[low];
+
+	/* Search for next non-aliased symbol */
+	for (i = low + 1; i < kstuff->num_syms; i++) {
+		if (kstuff->addresses[i] > symbol_start) {
+			symbol_end = kstuff->addresses[i];
+			break;
+		}
+	}
+
+	/* if we found no next symbol, we use the end of the section */
+	if (!symbol_end) {
+		return (unsigned long)(-1UL);
+#if 0
+		if (is_kernel_inittext(addr))
+			symbol_end = (unsigned long)_einittext;
+		else if (all_var)
+			symbol_end = (unsigned long)_end;
+		else
+			symbol_end = (unsigned long)_etext;
+#endif
+	}
+
+	*symbolsize = symbol_end - symbol_start;
+	*offset = addr - symbol_start;
+
+	return low;
+}
+
+static int is_ksym_addr(struct lguest_guest_info *linfo,
+			unsigned long addr)
+{
+	/* need to look up the segs */
+	return 1;
+}
+
+static unsigned int get_symbol_offset(struct lguest_vcpu *vcpu,
+				      struct guest_ksym_stuff *kstuff,
+				      unsigned long pos)
+{
+	const u8 *name;
+	int i;
+	unsigned long idx;
+
+	idx = lhread_u64(vcpu, (u64)&kstuff->markers[pos>>8]);
+
+	/* use the closest marker we have. We have markers every 256 positions,
+	 * so that should be close enough */
+	name = &kstuff->names[ idx ];
+
+	/* sequentially scan all the symbols up to the point we're searching for.
+	 * Every symbol is stored in a [<len>][<len> bytes of data] format, so we
+	 * just need to add the len to the current pointer for every symbol we
+	 * wish to skip */
+	for(i = 0; i < (pos&0xFF); i++) {
+		u8 c;
+		c = lhread_u8(vcpu, (u64)name);
+		name = name + c + 1;
+	}
+
+	return name - kstuff->names;
+}
+
+static const char *lguest_syms_lookup(struct lguest_vcpu *vcpu,
+				      unsigned long addr,
+				      unsigned long *symbolsize,
+				      unsigned long *offset,
+				      char **modname, char *namebuf)
+{
+	struct lguest_guest_info *linfo = vcpu->guest;
+	struct lguest_data *data = linfo->lguest_data;
+	struct guest_ksym_stuff kstuff;
+	const char *msym;
+	unsigned long *ptr;
+	int i;
+
+	kstuff.addresses = (unsigned long*)lhread_u64(vcpu, (u64)&data->kallsyms_addresses);
+	kstuff.num_syms = lhread_u64(vcpu, (u64)&data->kallsyms_num_syms);
+	kstuff.names = (u8*)lhread_u64(vcpu, (u64)&data->kallsyms_names);
+	kstuff.token_table = (u8*)lhread_u64(vcpu, (u64)&data->kallsyms_token_table);
+	kstuff.token_index = (u16*)lhread_u64(vcpu, (u64)&data->kallsyms_token_index);
+	kstuff.markers = (unsigned long*)lhread_u64(vcpu, (u64)&data->kallsyms_markers);
+
+	if (!kstuff.addresses || !kstuff.num_syms || !kstuff.names ||
+	    !kstuff.token_table || !kstuff.token_index || !kstuff.markers)
+		return NULL;
+
+	/* FIXME: Validate all the kstuff here!! */
+
+	ptr = kmalloc(sizeof(unsigned long)*kstuff.num_syms, GFP_KERNEL);
+	if (!ptr)
+		return NULL;
+
+	for (i=0; i < kstuff.num_syms; i++) {
+		/* FIXME: do this better! */
+		ptr[i] = lhread_u64(vcpu, (u64)&kstuff.addresses[i]);
+		if (i && ptr[i] < ptr[i-1]) {
+			kill_guest(linfo, "bad kallsyms table\n");
+			kstuff.addresses = ptr;
+			goto out;
+		}
+	}
+	kstuff.addresses = ptr;
+
+	namebuf[KSYM_NAME_LEN] = 0;
+	namebuf[0] = 0;
+
+	if (is_ksym_addr(linfo, addr)) {
+		unsigned long pos;
+
+		pos = get_symbol_pos(vcpu, &kstuff, addr, symbolsize, offset);
+		if (pos == (unsigned long)(-1UL))
+			goto out;
+
+		/* Grab name */
+		expand_symbol(vcpu, &kstuff,
+			      get_symbol_offset(vcpu, &kstuff, pos), namebuf);
+		*modname = NULL;
+		kfree(kstuff.addresses);
+		return namebuf;
+	}
+
+	/* see if it's in a module */
+	msym = module_address_lookup(addr, symbolsize, offset, modname);
+	if (msym) {
+		kfree(kstuff.addresses);
+		return strncpy(namebuf, msym, KSYM_NAME_LEN);
+	}
+
+out:
+	kfree(kstuff.addresses);
+	return NULL;
+}
+
+void lguest_print_address(struct lguest_vcpu *vcpu, unsigned long address)
+{
+	unsigned long offset = 0, symsize;
+	const char *symname;
+	char *modname;
+	char *delim = ":";
+	char namebuf[KSYM_NAME_LEN+1];
+
+	symname = lguest_syms_lookup(vcpu, address, &symsize, &offset,
+				     &modname, namebuf);
+	if (!symname) {
+		printk(" [<%016lx>]\n", address);
+		return;
+	}
+	if (!modname)
+		modname = delim = "";
+	printk(" [<%016lx>] %s%s%s%s+0x%lx/0x%lx\n",
+	       address, delim, modname, delim, symname, offset, symsize);
+
+}
+
+void lguest_dump_trace(struct lguest_vcpu *vcpu, struct lguest_regs *regs)
+{
+	unsigned long stack = regs->rsp;
+	unsigned long stack_end = (regs->rsp & PAGE_MASK) + PAGE_SIZE;
+	unsigned long start_kernel_map;
+	unsigned long page_offset;
+	unsigned long addr;
+	struct lguest_text_ptr *segs;
+
+	printk("Stack Dump:\n");
+	start_kernel_map = vcpu->guest->start_kernel_map;
+	page_offset = vcpu->guest->page_offset;
+
+	segs = get_text_segs(vcpu);
+	if (!segs)
+		return;
+
+	for (; stack < stack_end; stack += sizeof(stack)) {
+		addr = lhread_u64(vcpu, guest_pa(vcpu->guest, stack));
+		if (is_text_seg(segs, addr)) {
+			lguest_print_address(vcpu, addr);
+		}
+	}
+
+	put_text_segs(segs);
+}
+
+static u64 read_page(struct lguest_vcpu *vcpu, u64 page, u64 idx)
+{
+	u64 *ptr;
+
+	if (!vcpu) {
+		ptr = __va(page);
+		return ptr[idx];
+	}
+
+	return lhread_u64(vcpu, page+idx*sizeof(u64));
+}
+
+static void print_pte(u64 pte, u64 pgd_idx, u64 pud_idx, u64 pmd_idx, u64 pte_idx)
+{
+	printk("           %3llx: %llx\n", pte_idx, pte);
+	printk ("               (%llx)\n",
+		((pgd_idx&(1<<8)?(-1ULL):0ULL)<<48) |
+		(pgd_idx<<PGDIR_SHIFT) |
+		(pud_idx<<PUD_SHIFT) |
+		(pmd_idx<<PMD_SHIFT) |
+		(pte_idx<<PAGE_SHIFT));
+}
+
+static void print_pmd(struct lguest_vcpu *vcpu,
+		      u64 pmd, u64 pgd_idx, u64 pud_idx, u64 pmd_idx)
+{
+	u64 pte;
+	u64 ptr;
+	u64 i;
+
+	printk("        %3llx: %llx\n", pmd_idx, pmd);
+
+	/* 2M page? */
+	if (pmd & (1<<7)) {
+		printk ("            (%llx)\n",
+			((pgd_idx&(1<<8)?(-1ULL):0ULL)<<48) |
+			(pgd_idx<<PGDIR_SHIFT) |
+			(pud_idx<<PUD_SHIFT) |
+			(pmd_idx<<PMD_SHIFT));
+	} else {
+		pte = pmd & ~(0xfff) & ~(1UL << 63);
+		for (i=0; i < PTRS_PER_PTE; i++) {
+			ptr = read_page(vcpu, pte, i);
+			if (ptr)
+				print_pte(ptr, pgd_idx, pud_idx, pmd_idx, i);
+		}
+	}
+}
+
+static void print_pud(struct lguest_vcpu *vcpu,
+		      u64 pud, u64 pgd_idx, u64 pud_idx)
+{
+	u64 pmd;
+	u64 ptr;
+	u64 i;
+
+	printk("     %3llx: %llx\n", pud_idx, pud);
+
+	pmd = pud & ~(0xfff) & ~(1UL << 63);
+	for (i=0; i < PTRS_PER_PMD; i++) {
+		ptr = read_page(vcpu, pmd, i);
+		if (ptr)
+			print_pmd(vcpu, ptr, pgd_idx, pud_idx, i);
+	}
+}
+
+static void print_pgd(struct lguest_vcpu *vcpu,
+		      u64 pgd, u64 pgd_idx)
+{
+	u64 pud;
+	u64 ptr;
+	u64 i;
+
+	printk(" %3llx:  %llx\n", pgd_idx, pgd);
+	pud = pgd & ~(0xfff) & ~(1UL << 63);
+	for (i=0; i < PTRS_PER_PUD; i++) {
+		ptr = read_page(vcpu, pud, i);
+		if (ptr)
+			print_pud(vcpu, ptr, pgd_idx, i);
+	}
+
+}
+
+static void print_page_tables(struct lguest_vcpu *vcpu,
+			      u64 cr3)
+{
+	u64 pgd;
+	u64 ptr;
+	u64 i;
+
+	printk("cr3: %016llx\n", cr3);
+	pgd = cr3;
+
+	for (i=0; i < PTRS_PER_PGD; i++) {
+		ptr = read_page(vcpu, pgd, i);
+		if (ptr)
+			print_pgd(vcpu, ptr, i);
+	}
+}
+
+void lguest_print_page_tables(u64 *cr3)
+{
+	if (!cr3) {
+		printk("NULL cr3 pointer????\n");
+		return;
+	}
+	print_page_tables(NULL, __pa(cr3));
+}
+
+void lguest_print_guest_page_tables(struct lguest_vcpu *vcpu, u64 cr3)
+{
+	print_page_tables(vcpu, cr3);
+}

--

#7 lore raw

PATCH 5/13 asm-offsets update

In reply to a message not in the archive

plain text document attachment (lguest64-asm-offset.patch) This patch puts in the offsets used by Lguest64 in assembly.

arch/x86_64/kernel/asm-offsets.c +49 -0
Index: work-pv/arch/x86_64/kernel/asm-offsets.c
===================================================================
@@ -18,6 +18,9 @@
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #endif
+#ifdef CONFIG_LGUEST_GUEST
+#include <asm/lguest.h>
+#endif
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -89,5 +92,51 @@ int main(void)
 	ENTRY(read_cr2);
 	ENTRY(swapgs);
 #endif
+
+#ifdef CONFIG_LGUEST_GUEST
+#undef ENTRY
+#define ENTRY(entry)  DEFINE(LGUEST_VCPU_ ##entry, offsetof(struct lguest_vcpu, entry))
+	ENTRY(vcpu);
+	ENTRY(debug);
+	ENTRY(magic);
+	ENTRY(guest_syscall);
+	ENTRY(host_stack);
+	ENTRY(host_cr3);
+	ENTRY(host_gs_a);
+	ENTRY(host_gs_d);
+	ENTRY(host_proc_gs_a);
+	ENTRY(host_proc_gs_d);
+	ENTRY(guest_gs_a);
+	ENTRY(guest_gs_d);
+	ENTRY(gdt);
+	ENTRY(idt);
+	ENTRY(host_gdt);
+	ENTRY(host_idt);
+	ENTRY(host_gdt_ptr);
+	ENTRY(gdt_table);
+	DEFINE(LGUEST_VCPU_trapnum, offsetof(struct lguest_vcpu, regs.trapnum));
+	DEFINE(LGUEST_VCPU_errcode, offsetof(struct lguest_vcpu, regs.errcode));
+	DEFINE(LGUEST_VCPU_rflags, offsetof(struct lguest_vcpu, regs.rflags));
+	DEFINE(LGUEST_VCPU_host_idt_address, offsetof(struct lguest_vcpu, host_idt.address));
+	ENTRY(regs);
+	ENTRY(nmi_regs);
+	DEFINE(LGUEST_VCPU_errcode, offsetof(struct lguest_vcpu, regs.errcode));
+	ENTRY(nmi_gs_a);
+	ENTRY(nmi_gs_d);
+	ENTRY(nmi_gs_shadow_a);
+	ENTRY(nmi_gs_shadow_d);
+	ENTRY(nmi_stack_end);
+	ENTRY(nmi_gdt);
+	ENTRY(nmi_sw);
+#undef ENTRY
+#define ENTRY(entry)  DEFINE(LGUEST_DATA_##entry, offsetof(struct lguest_data, entry))
+	ENTRY(irq_enabled);
+#undef ENTRY
+#define ENTRY(entry)  DEFINE(LGUEST_REGS_##entry, offsetof(struct lguest_regs, entry))
+	ENTRY(errcode);
+	ENTRY(rip);
+	ENTRY(size);
+	BLANK();
+#endif
 	return 0;
 }

--

#8 lore raw

PATCH 6/13 lguest64 Kconfig

In reply to a message not in the archive

plain text document attachment (lguest64-kconfig.patch) Put the kconfig options for lguest64 in.

arch/x86_64/Kconfig +13 -0
Index: work-pv/arch/x86_64/Kconfig
===================================================================
@@ -320,6 +320,19 @@ config SCHED_MC
 
 source "kernel/Kconfig.preempt"
 
+config LGUEST
+	tristate "Lguest support"
+	depends on PARAVIRT
+	help
+	  Enable this is you think 32 bits are not enough fur a puppie.
+
+config LGUEST_GUEST
+	bool
+	depends on LGUEST
+	default y
+	help
+	  Guest definitions for lguest
+
 config NUMA
        bool "Non Uniform Memory Access (NUMA) Support"
        depends on SMP

--

#9 lore raw

Re: [RFC/PATCH LGUEST X86_64 06/13] lguest64 Kconfig

arch/x86_64/Kconfig config SCHED_MC · line 327

Quoted 5 lines · Steven Rostedt
arch/x86_64/Kconfig +5 -0
+config LGUEST
+	tristate "Lguest support"
+	depends on PARAVIRT
+	help
+	  Enable this is you think 32 bits are not enough fur a puppie.

8)

I think this deserves "&& EXPERIMENTAL" here 8)

Rusty.

#10 lore raw

PATCH 7/13 lguest64 loader

In reply to a message not in the archive

plain text document attachment (lguest64-loader.patch) I noticed that the lguest loader code for i386 was in Documentation/lguest. Well, that's fine (I guess) but it can't just be for i386. So I made a separate directory to put the loader code in. So now we have:

Documentation/lguest/i386/... for the lguest i386 loader.

and
Documentation/lguest/x86_64/... for the lguest x86_64 loader.

Documentation/lguest/i386/Makefile new file +21 -0
Index: work-pv/Documentation/lguest/i386/Makefile
===================================================================
@@ -0,0 +1,21 @@
+# This creates the demonstration utility "lguest" which runs a Linux guest.
+
+# We rely on CONFIG_PAGE_OFFSET to know where to put lguest binary.
+# Some shells (dash - ubunu) can't handle numbers that big so we cheat.
+include ../../../.config
+LGUEST_GUEST_TOP := ($(CONFIG_PAGE_OFFSET) - 0x08000000)
+
+CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 \
+	-static -DLGUEST_GUEST_TOP="$(LGUEST_GUEST_TOP)" -Wl,-T,lguest.lds
+LDLIBS:=-lz
+
+all: lguest.lds lguest
+
+# The linker script on x86 is so complex the only way of creating one
+# which will link our binary in the right place is to mangle the
+# default one.
+lguest.lds:
+	$(LD) --verbose | awk '/^==========/ { PRINT=1; next; } /SIZEOF_HEADERS/ { gsub(/0x[0-9A-F]*/, "$(LGUEST_GUEST_TOP)") } { if (PRINT) print $$0; }' > $@
+
+clean:
+	rm -f lguest.lds lguest
Documentation/lguest/i386/lguest.c new file +1039 -0

1,039 lines not on this page · raw message

Documentation/lguest/x86_64/Makefile new file +22 -0
Index: work-pv/Documentation/lguest/x86_64/Makefile
===================================================================
@@ -0,0 +1,22 @@
+# This creates the demonstration utility "lguest" which runs a Linux guest.
+
+# For now on x86_64 we'll hard code the location of the lguest binary loader.
+# But when we can get a relocatable kernel, we'll have to work to make this
+# dynamic.
+LGUEST_GUEST_TOP := 0x7f000000
+
+CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 \
+	-g \
+	-static -DLGUEST_GUEST_TOP="$(LGUEST_GUEST_TOP)" -Wl,-T,lguest.lds
+LDLIBS:=-lz
+
+all: lguest.lds lguest
+
+# The linker script on x86 is so complex the only way of creating one
+# which will link our binary in the right place is to mangle the
+# default one.
+lguest.lds: Makefile
+	$(LD) --verbose | awk '/^==========/ { PRINT=1; next; } /SIZEOF_HEADERS/ { gsub(/0x[0-9A-F]*/, "$(LGUEST_GUEST_TOP)") } { if (PRINT) print $$0; }' > $@
+
+clean:
+	rm -f lguest.lds lguest
Documentation/lguest/x86_64/lguest.c new file +1021 -0

1,021 lines not on this page · raw message

Documentation/lguest/Makefile deleted +0 -21
Index: work-pv/Documentation/lguest/Makefile
===================================================================
@@ -1,21 +0,0 @@
-# This creates the demonstration utility "lguest" which runs a Linux guest.
-
-# We rely on CONFIG_PAGE_OFFSET to know where to put lguest binary.
-# Some shells (dash - ubunu) can't handle numbers that big so we cheat.
-include ../../.config
-LGUEST_GUEST_TOP := ($(CONFIG_PAGE_OFFSET) - 0x08000000)
-
-CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 \
-	-static -DLGUEST_GUEST_TOP="$(LGUEST_GUEST_TOP)" -Wl,-T,lguest.lds
-LDLIBS:=-lz
-
-all: lguest.lds lguest
-
-# The linker script on x86 is so complex the only way of creating one
-# which will link our binary in the right place is to mangle the
-# default one.
-lguest.lds:
-	$(LD) --verbose | awk '/^==========/ { PRINT=1; next; } /SIZEOF_HEADERS/ { gsub(/0x[0-9A-F]*/, "$(LGUEST_GUEST_TOP)") } { if (PRINT) print $$0; }' > $@
-
-clean:
-	rm -f lguest.lds lguest
Documentation/lguest/lguest.c deleted +0 -1039

876 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

--

Part of the diff is not shown here. View the raw message.

#11 lore raw

PATCH 8/13 lguest64 user header.

In reply to a message not in the archive

plain text document attachment (lguest64-user.patch) This patch adds the header used by the lguest64 loader.

include/asm-x86_64/lguest_user.h new file +88 -0
Index: work-pv/include/asm-x86_64/lguest_user.h
===================================================================
@@ -0,0 +1,88 @@
+#ifndef _ASM_LGUEST_USER
+#define _ASM_LGUEST_USER
+
+/* Everything the "lguest" userspace program needs to know. */
+/* They can register up to 32 arrays of lguest_dma. */
+#define LGUEST_MAX_DMA		32
+
+/* How many devices?  Assume each one wants up to two dma arrays per device. */
+#define LGUEST_MAX_DEVICES (LGUEST_MAX_DMA/2)
+
+/* At most we can dma 16 lguest_dma in one op. */
+#define LGUEST_MAX_DMA_SECTIONS	16
+
+struct lguest_dma
+{
+	/* 0 if free to be used, filled by hypervisor. */
+ 	u64 used_len;
+	u64 addr[LGUEST_MAX_DMA_SECTIONS];
+	u16 len[LGUEST_MAX_DMA_SECTIONS];
+};
+
+/* This is found at address 0. */
+struct lguest_boot_info
+{
+	u32 max_pfn;
+	u32 initrd_size;
+	char cmdline[256];
+};
+
+struct lguest_block_page
+{
+	/* 0 is a read, 1 is a write. */
+	int type;
+	u32 sector; 	/* Offset in device = sector * 512. */
+	u32 bytes;	/* Length expected to be read/written in bytes */
+	/* 0 = pending, 1 = done, 2 = done, error */
+	int result;
+	u32 num_sectors; /* Disk length = num_sectors * 512 */
+};
+
+/* There is a shared page of these. */
+struct lguest_net
+{
+	union {
+		unsigned char mac[6];
+		struct {
+			u8 promisc;
+			u8 pad;
+			u16 guestid;
+		};
+	};
+};
+
+/* lguest_device_desc->type */
+#define LGUEST_DEVICE_T_CONSOLE	1
+#define LGUEST_DEVICE_T_NET	2
+#define LGUEST_DEVICE_T_BLOCK	3
+
+/* lguest_device_desc->status.  256 and above are device specific. */
+#define LGUEST_DEVICE_S_ACKNOWLEDGE	1 /* We have seen device. */
+#define LGUEST_DEVICE_S_DRIVER		2 /* We have found a driver */
+#define LGUEST_DEVICE_S_DRIVER_OK	4 /* Driver says OK! */
+#define LGUEST_DEVICE_S_REMOVED		8 /* Device has gone away. */
+#define LGUEST_DEVICE_S_REMOVED_ACK	16 /* Driver has been told. */
+#define LGUEST_DEVICE_S_FAILED		128 /* Something actually failed */
+
+#define LGUEST_NET_F_NOCSUM		0x4000 /* Don't bother checksumming */
+#define LGUEST_DEVICE_F_RANDOMNESS	0x8000 /* IRQ is fairly random */
+
+/* We have a page of these descriptors in the lguest_device page. */
+struct lguest_device_desc {
+	u16 type;
+	u16 features;
+	u16 status;
+	u16 num_pages;
+	u64 pfn;
+};
+
+/* Write command first word is a request. */
+enum lguest_req
+{
+	LHREQ_INITIALIZE, /* + pfnlimit, pgdir, start, pageoffset */
+	LHREQ_GETDMA, /* + addr (returns &lguest_dma, irq in ->used_len) */
+	LHREQ_IRQ, /* + irq */
+};
+
+
+#endif /* _ASM_LGUEST_USER */

--

#12 lore raw

PATCH 9/13 lguest64 devices

In reply to a message not in the archive

plain text document attachment (lguest64-device.patch)
We started working a little bit on the devices for lguest64. This is still very much a work-in-progress and needs much more work.

include/asm-x86_64/lguest_device.h new file +31 -0
Index: work-pv/include/asm-x86_64/lguest_device.h
===================================================================
@@ -0,0 +1,31 @@
+#ifndef _ASM_LGUEST_DEVICE_H
+#define _ASM_LGUEST_DEVICE_H
+/* Everything you need to know about lguest devices. */
+#include <linux/device.h>
+#include <asm/lguest.h>
+#include <asm/lguest_user.h>
+
+struct lguest_device {
+	/* Unique busid, and index into lguest_page->devices[] */
+	/* By convention, each device can use irq index+1 if it wants to. */
+	unsigned int index;
+
+	struct device dev;
+
+	/* Driver can hang data off here. */
+	void *private;
+};
+
+struct lguest_driver {
+	const char *name;
+	struct module *owner;
+	u16 device_type;
+	int (*probe)(struct lguest_device *dev);
+	void (*remove)(struct lguest_device *dev);
+
+	struct device_driver drv;
+};
+
+extern int register_lguest_driver(struct lguest_driver *drv);
+extern void unregister_lguest_driver(struct lguest_driver *drv);
+#endif /* _ASM_LGUEST_DEVICE_H */
arch/x86_64/lguest/lguest_bus.c new file +180 -0

180 lines not on this page · raw message

arch/x86_64/lguest/io.c new file +425 -0

425 lines not on this page · raw message

--

#13 lore raw

PATCH 10/13 dont compile in the lguest_net

In reply to a message not in the archive

plain text document attachment (lguest64-not-net.patch) Right now we don't have lguest_net compiling for x86_64. So turn it off for us.

Cc Glauber de Oliveira Costa <[email protected]>
Cc Chris Wright <[email protected]>
drivers/net/Makefile +2 -0
Index: work-pv/drivers/net/Makefile
===================================================================
@@ -217,4 +217,6 @@ obj-$(CONFIG_NETCONSOLE) += netconsole.o
 obj-$(CONFIG_FS_ENET) += fs_enet/
 
 obj-$(CONFIG_NETXEN_NIC) += netxen/
+ifneq ($(CONFIG_X86_64),y)
 obj-$(CONFIG_LGUEST_GUEST) += lguest_net.o
+endif

--

#14 lore raw

PATCH 11/13 x86_64 HVC attempt.

In reply to a message not in the archive

plain text document attachment (lguest64-hvc.patch) This is a start to try to get HVC working for x86_64.

drivers/char/Kconfig +6 -0
Index: work-pv/drivers/char/Kconfig
===================================================================
@@ -595,6 +595,12 @@ config HVC_CONSOLE
 	  pSeries machines when partitioned support a hypervisor virtual
 	  console. This driver allows each pSeries partition to have a console
 	  which is accessed via the HMC.
+config HVC_LGUEST
+	bool "lguest hypervisor console"
+	depends on LGUEST_GUEST
+	select HVC_DRIVER
+	help
+	  Totally fubar
 
 config HVC_ISERIES
 	bool "iSeries Hypervisor Virtual Console support"
drivers/char/Makefile +1 -1
Index: work-pv/drivers/char/Makefile
===================================================================
@@ -43,7 +43,7 @@ obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += am
 obj-$(CONFIG_SX)		+= sx.o generic_serial.o
 obj-$(CONFIG_RIO)		+= rio/ generic_serial.o
 obj-$(CONFIG_HVC_CONSOLE)	+= hvc_vio.o hvsi.o
-obj-$(CONFIG_LGUEST_GUEST)	+= hvc_lguest.o
+obj-$(CONFIG_HVC_GUEST)		+= hvc_lguest.o
 obj-$(CONFIG_HVC_ISERIES)	+= hvc_iseries.o
 obj-$(CONFIG_HVC_RTAS)		+= hvc_rtas.o
 obj-$(CONFIG_HVC_DRIVER)	+= hvc_console.o
drivers/char/hvc_lguest.c +6 -1
Index: work-pv/drivers/char/hvc_lguest.c
===================================================================
@@ -25,7 +25,6 @@ static int cons_irq;
 static int cons_offset;
 static char inbuf[256];
 static struct lguest_dma cons_input = { .used_len = 0,
-					.addr[0] = __pa(inbuf),
 					.len[0] = sizeof(inbuf),
 					.len[1] = 0 };
 
@@ -66,6 +65,12 @@ struct hv_ops lguest_cons = {
 
 static int __init cons_init(void)
 {
+	/*
+	 * Can't initialize this in the const declarations,
+	 * since __pa(inbuf) does not evaluate into a constant.
+	 */
+	cons_input.addr[0] = __pa(inbuf);
+
 	if (strcmp(paravirt_ops.name, "lguest") != 0)
 		return 0;
 

--

#15 lore raw

PATCH 12/13 dump stack on crash

In reply to a message not in the archive

plain text document attachment (lguest64-dump-panic.patch) it's nice to see a back trace dump when we do a panic.

Cc Glauber de Oliveira Costa <[email protected]>
Cc Chris Wright <[email protected]>
kernel/panic.c +1 -0
Index: work-pv/kernel/panic.c
===================================================================
@@ -78,6 +78,7 @@ NORET_TYPE void panic(const char * fmt, 
 	vsnprintf(buf, sizeof(buf), fmt, args);
 	va_end(args);
 	printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
+	dump_stack();
 	bust_spinlocks(0);
 
 	/*

--

#16 lore raw

PATCH 13/13 Hack to get output

In reply to a message not in the archive

plain text document attachment (lguest64-debug.patch) This is just a hack patch to get output from the guest. It calls lguest_vprint from printk which is a hypercall to the host to do the printk for the guest.

Chris Wright recommended that I put this into early_printk, but until I can get that to work, I'm posting this.

Cc Glauber de Oliveira Costa <[email protected]>
Cc Chris Wright <[email protected]>
kernel/printk.c +5 -0
Index: work-pv/kernel/printk.c
===================================================================
@@ -499,12 +499,17 @@ static int have_callable_console(void)
  * printf(3)
  */
 
+extern void lguest_vprint(const char *fmt, va_list ap);
 asmlinkage int printk(const char *fmt, ...)
 {
 	va_list args;
+	va_list lgargs;
 	int r;
 
 	va_start(args, fmt);
+	va_copy(lgargs, args);
+	lguest_vprint(fmt, lgargs);
+	va_end(lgargs);
 	r = vprintk(fmt, args);
 	va_end(args);
 

--