[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] This patch adds a 32bit gateway to the Bochs BIOS. The 32 bit code is



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxxx
# Date 1169829048 0
# Node ID 480436ef6255aa1a38e2cafc9a63f565f633f6fc
# Parent  b97780b7080dd61abcdbad166d999fde7fe49d16
This patch adds a 32bit gateway to the Bochs BIOS. The 32 bit code is
compiled with gcc and linked into the hvmloader as a byte-array.
Hvmloader allocates memory (rounded up to next 64kb) from the e820
table
below 4GB, copies and relocates the 32bit code in the allocated area
and
copies a jumptable (located in a section '.biosjumptable') pointing to
the 'exported' functions into the Bochs BIOS's memory area to link the
two code sections. The memory area has been reserved and can be
identified with the signature '___JMPT'.

In the Bochs BIOS only stub functions are provided. These load the
index
of a particular function in the jump table, switch to protected mode
and
call the function in the high memory area.  The stack is prepared such
that functions compiled by gcc can just pick the parameters from the
stack as usual - this means that the 16bit real-mode return address is
taken off the stack. The stub functions should have the same signature
as those in 32bit space. For ABI compatibility reasons parameters
inside
the Bochs BIOS stubs should all be 32bit wide.

This patch includes a test function that calls three gcc-compiled
functions in the high memory area and displays their success status.
Simple tests are done doing multiplication and addition of 32-bit
numbers and reading and modification of a static variable. These
functions test the interface and the relocation code. The test code is
removed in patch part 3.

Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxx>
---
 tools/firmware/Makefile                       |    2 
 tools/firmware/hvmloader/32bitbios_support.c  |  169 +++++++++
 tools/firmware/hvmloader/Makefile             |    2 
 tools/firmware/hvmloader/config.h             |    7 
 tools/firmware/hvmloader/hvmloader.c          |    1 
 tools/firmware/hvmloader/mp_tables.c          |   11 
 tools/firmware/hvmloader/util.c               |    9 
 tools/firmware/hvmloader/util.h               |    5 
 tools/firmware/rombios/32bit/32bitbios.c      |   60 +++
 tools/firmware/rombios/32bit/Makefile         |   31 +
 tools/firmware/rombios/32bit/jumptable.h      |   11 
 tools/firmware/rombios/32bit/mkhex            |   26 +
 tools/firmware/rombios/32bit/rombios_compat.h |   92 ++++
 tools/firmware/rombios/32bitgateway.c         |  486 ++++++++++++++++++++++++++
 tools/firmware/rombios/32bitgateway.h         |   18 
 tools/firmware/rombios/32bitprotos.h          |   22 +
 tools/firmware/rombios/Makefile               |    2 
 tools/firmware/rombios/rombios.c              |   20 +
 18 files changed, 960 insertions(+), 14 deletions(-)

diff -r b97780b7080d -r 480436ef6255 tools/firmware/Makefile
--- a/tools/firmware/Makefile   Fri Jan 26 15:45:51 2007 +0000
+++ b/tools/firmware/Makefile   Fri Jan 26 16:30:48 2007 +0000
@@ -7,7 +7,7 @@ INST_DIR := $(DESTDIR)/usr/lib/xen/boot
 INST_DIR := $(DESTDIR)/usr/lib/xen/boot
 
 SUBDIRS :=
-SUBDIRS += rombios
+SUBDIRS += rombios rombios/32bit
 SUBDIRS += vgabios
 SUBDIRS += vmxassist
 SUBDIRS += hvmloader
diff -r b97780b7080d -r 480436ef6255 
tools/firmware/hvmloader/32bitbios_support.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/hvmloader/32bitbios_support.c      Fri Jan 26 16:30:48 
2007 +0000
@@ -0,0 +1,169 @@
+/*
+ * 32bitbios_support.c - relocation of 32bit BIOS implementation
+ *
+ * Stefan Berger, stefanb@xxxxxxxxxx
+ * Copyright (c) 2006, International Business Machines Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <elf.h>
+#include <xen/hvm/e820.h>
+#include "util.h"
+#include "config.h"
+
+#include "../rombios/32bit/32bitbios_flat.h"
+#include "../rombios/32bit/jumptable.h"
+
+
+/*
+ * relocate ELF file of type ET_REL
+ */
+static int relocate_elf(unsigned char *elfarray) {
+    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
+    Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
+    int i;
+
+    if (ehdr->e_type != ET_REL) {
+        printf("Not a relocatabel BIOS object file. Has type %d, need %d\n",
+               ehdr->e_type, ET_REL);
+        return -1;
+    }
+
+    for (i = 0; i < ehdr->e_shnum; i++) {
+        if (!(shdr[i]).sh_flags & SHF_ALLOC) {
+            shdr[i].sh_addr = 0;
+            continue;
+        }
+        shdr[i].sh_addr = (Elf32_Addr)&elfarray[shdr[i].sh_offset];
+    }
+
+    for (i = 0; i < ehdr->e_shnum; i++) {
+        if (shdr[i].sh_type == SHT_REL && shdr[i].sh_addr != 0) {
+            Elf32_Shdr *targetsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_info]);
+            Elf32_Shdr *symtabsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_link]);
+            Elf32_Sym  *syms      = (Elf32_Sym *)symtabsec->sh_addr;
+            Elf32_Rel  *rels      = (Elf32_Rel *)shdr[i].sh_addr;
+            unsigned char *code   = (unsigned char *)targetsec->sh_addr;
+            int j;
+
+            for (j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++) {
+                int idx           = ELF32_R_SYM(rels[j].r_info);
+                Elf32_Sym *symbol = &syms[idx];
+                uint32_t *loc     = (uint32_t *)&code[rels[j].r_offset];
+                uint32_t fix      = shdr[symbol->st_shndx].sh_addr +
+                                    symbol->st_value;
+
+                switch (ELF32_R_TYPE(rels[j].r_info)) {
+                    case R_386_PC32:
+                        *loc += (fix - (uint32_t)loc);
+                    break;
+
+                    case R_386_32:
+                        *loc += fix;
+                    break;
+                }
+            }
+        } else if (shdr[i].sh_type == SHT_RELA) {
+            return -2;
+        }
+    }
+    return 0;
+}
+
+/* scan the rombios for the destination of the jumptable */
+static char* get_jump_table_start(void)
+{
+    char *bios_mem;
+
+    for ( bios_mem = (char *)ROMBIOS_BEGIN;
+          bios_mem != (char *)ROMBIOS_END;
+          bios_mem++ ) {
+        if (strncmp(bios_mem, "___JMPT", 7) == 0)
+            return bios_mem;
+    }
+
+    return NULL;
+}
+
+/* copy relocated jumptable into the rombios */
+static int copy_jumptable(unsigned char *elfarray)
+{
+    int rc = 0;
+    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
+    Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
+    Elf32_Shdr *shdr_strings = (Elf32_Shdr *)&shdr[ehdr->e_shstrndx];
+    char *secstrings = (char *)&elfarray[shdr_strings->sh_offset];
+    uint32_t *rombiosjumptable = (uint32_t *)get_jump_table_start();
+    uint32_t *biosjumptable    = NULL;
+    int i;
+
+    if (rombiosjumptable == NULL) {
+        return -3;
+    }
+
+     /* find the section with the jump table  and copy to lower BIOS memory */
+    for (i = 0; i < ehdr->e_shnum; i++) {
+        if (!strcmp(JUMPTABLE_SECTION_NAME, secstrings + shdr[i].sh_name)) {
+            uint32_t biosjumptableentries;
+            biosjumptable        = (uint32_t *)shdr[i].sh_addr;
+            biosjumptableentries = shdr[i].sh_size / 4;
+            for (int j = 0; j < biosjumptableentries; j++) {
+                rombiosjumptable[j] = biosjumptable[j];
+                if (biosjumptable[j] == 0 &&
+                    j < (biosjumptableentries - 1)) {
+                    printf("WARNING: jumptable entry %d is NULL!\n",j);
+                }
+            }
+            break;
+        }
+    }
+
+    if (biosjumptable == NULL) {
+        printf("Could not find " JUMPTABLE_SECTION_NAME " section in file.\n");
+        rc = -4;
+    }
+
+    return 0;
+}
+
+static int relocate_32bitbios(unsigned char *elfarray, uint32_t elfarraysize)
+{
+    int rc = 0;
+    uint32_t mask = (64 * 1024) - 1;
+    uint32_t to_malloc = (elfarraysize + mask) & ~mask; /* round to 64kb */
+    unsigned char *highbiosarea;
+
+    highbiosarea = (unsigned char *)(long)
+                           e820_malloc((uint64_t)to_malloc,
+                                       E820_RESERVED,
+                                       (uint64_t)0xffffffff);
+
+    if (highbiosarea != 0) {
+        memcpy(highbiosarea, elfarray, elfarraysize);
+        rc = relocate_elf(highbiosarea);
+        if (rc == 0) {
+            rc = copy_jumptable(highbiosarea);
+        }
+    } else {
+        rc = -5;
+    }
+
+    return rc;
+}
+
+int highbios_setup(void)
+{
+    return relocate_32bitbios((unsigned char *)highbios_array,
+                              sizeof(highbios_array));
+}
diff -r b97780b7080d -r 480436ef6255 tools/firmware/hvmloader/Makefile
--- a/tools/firmware/hvmloader/Makefile Fri Jan 26 15:45:51 2007 +0000
+++ b/tools/firmware/hvmloader/Makefile Fri Jan 26 16:30:48 2007 +0000
@@ -35,7 +35,7 @@ CFLAGS  += -fno-builtin -O2 -msoft-float
 CFLAGS  += -fno-builtin -O2 -msoft-float
 LDFLAGS  = -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR)
 
-SRCS = hvmloader.c mp_tables.c util.c smbios.c
+SRCS = hvmloader.c mp_tables.c util.c smbios.c 32bitbios_support.c
 OBJS = $(patsubst %.c,%.o,$(SRCS))
 
 .PHONY: all
diff -r b97780b7080d -r 480436ef6255 tools/firmware/hvmloader/config.h
--- a/tools/firmware/hvmloader/config.h Fri Jan 26 15:45:51 2007 +0000
+++ b/tools/firmware/hvmloader/config.h Fri Jan 26 16:30:48 2007 +0000
@@ -11,4 +11,11 @@
 #define PCI_ISA_DEVFN       0x08    /* dev 1, fn 0 */
 #define PCI_ISA_IRQ_MASK    0x0c60U /* ISA IRQs 5,6,10,11 are PCI connected */
 
+#define ROMBIOS_SEG            0xF000
+#define ROMBIOS_BEGIN          0x000F0000
+#define ROMBIOS_SIZE           0x00010000
+#define ROMBIOS_MAXOFFSET      0x0000FFFF
+#define ROMBIOS_END            (ROMBIOS_BEGIN + ROMBIOS_SIZE)
+
+
 #endif /* __HVMLOADER_CONFIG_H__ */
diff -r b97780b7080d -r 480436ef6255 tools/firmware/hvmloader/hvmloader.c
--- a/tools/firmware/hvmloader/hvmloader.c      Fri Jan 26 15:45:51 2007 +0000
+++ b/tools/firmware/hvmloader/hvmloader.c      Fri Jan 26 16:30:48 2007 +0000
@@ -314,6 +314,7 @@ int main(void)
 
     printf("Loading ROMBIOS ...\n");
     memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
+    highbios_setup();
 
     apic_setup();
     pci_setup();
diff -r b97780b7080d -r 480436ef6255 tools/firmware/hvmloader/mp_tables.c
--- a/tools/firmware/hvmloader/mp_tables.c      Fri Jan 26 15:45:51 2007 +0000
+++ b/tools/firmware/hvmloader/mp_tables.c      Fri Jan 26 16:30:48 2007 +0000
@@ -45,12 +45,6 @@ typedef   signed long int64_t;
 typedef   signed long int64_t;
 #endif
 
-#define ROMBIOS_SEG            0xF000
-#define ROMBIOS_BEGIN          0x000F0000
-#define ROMBIOS_SIZE           0x00010000 
-#define ROMBIOS_MAXOFFSET      0x0000FFFF
-#define ROMBIOS_END            (ROMBIOS_BEGIN + ROMBIOS_SIZE)
-
 /* number of non-processor MP table entries */
 #define NR_NONPROC_ENTRIES     18
 
@@ -311,10 +305,7 @@ void* get_mp_table_start(void)
           bios_mem != (char *)ROMBIOS_END; 
           bios_mem++ )
     {
-        if ( bios_mem[0] == '_' && bios_mem[1] == '_' &&
-             bios_mem[2] == '_' && bios_mem[3] == 'H' &&
-             bios_mem[4] == 'V' && bios_mem[5] == 'M' &&
-             bios_mem[6] == 'M' && bios_mem[7] == 'P' )
+        if ( strncmp(bios_mem, "___HVMMP", 8) == 0)
             return bios_mem;
     }
 
diff -r b97780b7080d -r 480436ef6255 tools/firmware/hvmloader/util.c
--- a/tools/firmware/hvmloader/util.c   Fri Jan 26 15:45:51 2007 +0000
+++ b/tools/firmware/hvmloader/util.c   Fri Jan 26 16:30:48 2007 +0000
@@ -91,6 +91,15 @@ int strcmp(const char *cs, const char *c
     return res;
 }
 
+int strncmp(const char *s1, const char *s2, uint32_t n)
+{
+       uint32_t ctr;
+       for (ctr = 0; ctr < n; ctr++)
+               if (s1[ctr] != s2[ctr])
+                       return (int)(s1[ctr] - s2[ctr]);
+       return 0;
+}
+
 void *memcpy(void *dest, const void *src, unsigned n)
 {
     int t0, t1, t2;
diff -r b97780b7080d -r 480436ef6255 tools/firmware/hvmloader/util.h
--- a/tools/firmware/hvmloader/util.h   Fri Jan 26 15:45:51 2007 +0000
+++ b/tools/firmware/hvmloader/util.h   Fri Jan 26 16:30:48 2007 +0000
@@ -53,6 +53,7 @@ int get_apic_mode(void);
 
 /* String and memory functions */
 int strcmp(const char *cs, const char *ct);
+int strncmp(const char *s1, const char *s2, uint32_t n);
 char *strcpy(char *dest, const char *src);
 char *strncpy(char *dest, const char *src, unsigned n);
 unsigned strlen(const char *s);
@@ -77,6 +78,10 @@ int vprintf(const char *fmt, va_list ap)
 /* Allocate region of specified type in the e820 table. */
 uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask);
 
+/* Prepare the 32bit BIOS */
+int highbios_setup(void);
+
+
 #define isdigit(c) ((c) >= '0' && (c) <= '9')
 
 #endif /* __HVMLOADER_UTIL_H__ */
diff -r b97780b7080d -r 480436ef6255 tools/firmware/rombios/32bit/32bitbios.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/rombios/32bit/32bitbios.c  Fri Jan 26 16:30:48 2007 +0000
@@ -0,0 +1,60 @@
+/*
+ *  32bitbios - jumptable for those function reachable from 16bit area
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author: Stefan Berger <stefanb@xxxxxxxxxx>
+ */
+#include "rombios_compat.h"
+#include "jumptable.h"
+#include "32bitprotos.h"
+
+/* same prototypes as in the 16bit BIOS */
+Bit32u multiply(Bit32u a, Bit32u b)
+{
+       return a*b;
+}
+
+Bit32u add(Bit32u a, Bit32u b)
+{
+       return a+b;
+}
+
+static Bit32u stat_a = 0x1;
+Bit32u set_static(Bit32u a)
+{
+       Bit32u _a = stat_a;
+       stat_a = a;
+       return _a;
+}
+
+
+/*
+   the jumptable that will be copied into the rombios in the 0xf000 segment
+   for every function that is to be called from the lower BIOS, make an entry
+   here.
+ */
+#define TABLE_ENTRY(idx, func) [idx] = (uint32_t)func
+uint32_t jumptable[IDX_LAST+1] __attribute__((section 
(JUMPTABLE_SECTION_NAME))) =
+{
+       TABLE_ENTRY(IDX_MULTIPLY   , multiply),
+       TABLE_ENTRY(IDX_ADD        , add),
+       TABLE_ENTRY(IDX_SET_STATIC , set_static),
+
+
+       TABLE_ENTRY(IDX_LAST       , 0)     /* keep last */
+};
diff -r b97780b7080d -r 480436ef6255 tools/firmware/rombios/32bit/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/rombios/32bit/Makefile     Fri Jan 26 16:30:48 2007 +0000
@@ -0,0 +1,31 @@
+
+override XEN_TARGET_ARCH = x86_32
+XEN_ROOT = ../../../..
+CFLAGS :=
+include $(XEN_ROOT)/tools/Rules.mk
+
+TARGET = 32bitbios_flat.h
+
+CFLAGS += -fno-builtin -O2 -msoft-float
+CFLAGS += -I../
+
+MODULES = 32bitbios.o
+
+.PHONY: all
+
+all : $(TARGET)
+
+clean ::
+       rm -rf *.o $(TARGET)
+
+$(TARGET) : 32bitbios_all.o $(SOURCES)
+       unref=`nm -u 32bitbios_all.o`
+       @if [ "$$unref" != "" ]; then \
+               echo "There are unresolved symbols in the BIOS.";       \
+               echo $$unref ;                                          \
+       else                                                            \
+               bash mkhex highbios_array 32bitbios_all.o > $(TARGET); \
+       fi
+
+32bitbios_all.o : 32bitbios.o $(MODULES)
+       ld $(LDFLAGS_DIRECT) -r $(MODULES) -o 32bitbios_all.o
diff -r b97780b7080d -r 480436ef6255 tools/firmware/rombios/32bit/jumptable.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/rombios/32bit/jumptable.h  Fri Jan 26 16:30:48 2007 +0000
@@ -0,0 +1,11 @@
+#ifndef JUMPTABLE_H
+#define JUMPTABLE_H
+
+/*
+   name of the section the 32bit BIOS must have and where the array of
+   function poiners is built; hvmloader looks for this section and copies
+   it into the lower BIOS in the 0xf000 segment
+ */
+#define JUMPTABLE_SECTION_NAME ".biosjumptable"
+
+#endif
diff -r b97780b7080d -r 480436ef6255 tools/firmware/rombios/32bit/mkhex
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/rombios/32bit/mkhex        Fri Jan 26 16:30:48 2007 +0000
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+#
+# mkhex: Generate C embeddable hexdumps
+#
+# Leendert van Doorn, leendert@xxxxxxxxxxxxxx
+# Copyright (c) 2005, International Business Machines Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope 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., 59 Temple
+# Place - Suite 330, Boston, MA 02111-1307 USA.
+#
+
+echo "unsigned $1[] = {"
+od -v -t x $2 | sed 's/^[0-9]* /0x/' | sed 's/ /, 0x/g' | sed 's/$/,/'
+echo "};"
+
diff -r b97780b7080d -r 480436ef6255 
tools/firmware/rombios/32bit/rombios_compat.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/rombios/32bit/rombios_compat.h     Fri Jan 26 16:30:48 
2007 +0000
@@ -0,0 +1,92 @@
+#ifndef ROMBIOS_COMPAT
+#define ROMBIOS_COMPAT
+
+/*
+ * Compatibility functions and structures for transitioning between
+ * 16 bit Bochs BIOS and 32 bit BIOS code.
+ */
+#include <stdint.h>
+
+#define ADDR_FROM_SEG_OFF(seg, off)  (void *)((((uint32_t)(seg)) << 4) + (off))
+
+typedef uint8_t  Bit8u;
+typedef uint16_t Bit16u;
+typedef uint32_t Bit32u;
+
+#define SetCF(x)   (x)->u.r8.flagsl |= 0x01
+#define SetZF(x)   (x)->u.r8.flagsl |= 0x40
+#define ClearCF(x) (x)->u.r8.flagsl &= 0xfe
+#define ClearZF(x) (x)->u.r8.flagsl &= 0xbf
+#define GetCF(x)   ((x)->u.r8.flagsl & 0x01)
+
+#define SET_CF()     *FLAGS |= 0x0001
+#define CLEAR_CF()   *FLAGS &= 0xfffe
+#define GET_CF()     (*FLAGS & 0x0001)
+
+#define SET_ZF()     *FLAGS |= 0x0040
+#define CLEAR_ZF()   *FLAGS &= 0xffbf
+
+
+typedef struct {
+ union {
+  struct {
+    Bit32u edi, esi, ebp, esp;
+    Bit32u ebx, edx, ecx, eax;
+    } r32;
+  struct {
+    Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
+    Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
+    } r16;
+  struct {
+    Bit32u filler[4];
+    Bit8u  bl, bh;
+    Bit16u filler1;
+    Bit8u  dl, dh;
+    Bit16u filler2;
+    Bit8u  cl, ch;
+    Bit16u filler3;
+    Bit8u  al, ah;
+    Bit16u filler4;
+    } r8;
+  } u;
+} __attribute__((packed)) pushad_regs_t;
+
+
+
+static inline Bit32u read_dword(Bit16u seg, Bit16u off)
+{
+       uint32_t *addr = (uint32_t *)ADDR_FROM_SEG_OFF(seg,off);
+       return *addr;
+}
+
+static inline Bit16u read_word(Bit16u seg, Bit16u off)
+{
+       uint16_t *addr = (uint16_t *)ADDR_FROM_SEG_OFF(seg,off);
+       return *addr;
+}
+
+static inline Bit8u read_byte(Bit16u seg, Bit16u off)
+{
+       uint8_t *addr = (uint8_t *)ADDR_FROM_SEG_OFF(seg,off);
+       return *addr;
+}
+
+static inline void write_dword(Bit16u seg, Bit16u off, Bit32u val)
+{
+       uint32_t *addr = (uint32_t *)ADDR_FROM_SEG_OFF(seg,off);
+       *addr = val;
+}
+
+static inline void write_word(Bit16u seg, Bit16u off, Bit16u val)
+{
+       uint16_t *addr = (uint16_t *)ADDR_FROM_SEG_OFF(seg,off);
+       *addr = val;
+}
+
+static inline void write_byte(Bit16u seg, Bit16u off, Bit8u val)
+{
+       uint8_t *addr = (uint8_t *)ADDR_FROM_SEG_OFF(seg,off);
+       *addr = val;
+}
+
+#endif
diff -r b97780b7080d -r 480436ef6255 tools/firmware/rombios/32bitgateway.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/rombios/32bitgateway.c     Fri Jan 26 16:30:48 2007 +0000
@@ -0,0 +1,486 @@
+/*
+ *  Implementation of a gateway into 32bit space. Stub functions
+ *  can be called from Bochs BIOS which call functions with a compatible
+ *  signature in 32bit space. All interrupts are disabled while in
+ *  32 bit mode.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author: Stefan Berger <stefanb@xxxxxxxxxx>
+ */
+
+/*
+ * Note:
+ *  BCC's ABI does not require to preserve any 16bit registers ax, bx, cs, dx
+ *  by a called function. So these registers need not be preserved while
+ *  calling a function in 32bit space, either.
+ *
+ *  When bcc calls a function with 16bit parameters it pushes 2 bytes onto
+ *  the stack for such a parameter. GCC, however, expects 32bit parameters
+ *  (4 bytes) even for uint16_t, so casting to 32bit from bcc is a good idea.
+ */
+
+#define SEGMENT_OFFSET  0xf0000
+#define REAL_MODE_CODE_SEGMENT  0xf000
+
+#define START_PM_CODE  USE32
+#define END_PM_CODE    USE16
+
+/* definition of used code/data segment descriptors */
+#define PM_NORMAL_CS (gdt_entry_pm_cs       - gdt_base)
+#define PM_16BIT_CS  (gdt_entry_pm_16bit_cs - gdt_base)
+#define PM_32BIT_DS  (gdt_entry_pm_32bit_ds - gdt_base)
+
+  ASM_START
+
+    ; Switch into protected mode to allow access to 32 bit addresses.
+    ; This function allows switching into protected mode.
+    ; (the specs says big real mode, but that will not work)
+    ;
+    ; preserves all registers and prepares cs, ds, es, ss for usage
+    ; in protected mode; while in prot.mode interrupts remain disabled
+switch_to_protmode:
+    cli
+
+    ; have to fix the stack for proper return address in 32 bit mode
+    push WORD #(REAL_MODE_CODE_SEGMENT>>12)    ;extended return address
+    push bp                                    ;pop@A1
+    mov bp, sp
+    push eax                                   ;pop@A2
+    mov eax, 2[bp]                             ; fix return address
+    rol eax, #16
+    mov 2[bp], eax
+
+    mov eax, esp
+    ror eax, #16                               ; hi(esp)
+
+    push bx                                    ; preserve before function call
+    push cx
+    push dx
+
+    push ax                                    ; prepare stack for
+    push es                                    ; call
+    push ds
+    push cs
+    push ss
+    call _store_segment_registers
+    add sp, #10                                        ; pop ax,es-ss
+
+    pop dx                                     ; restore after function call
+    pop cx
+    pop bx
+
+    ; calculate protected-mode esp from ss:sp
+    and esp, #0xffff
+    xor eax, eax
+    mov ax, ss
+    rol eax, #4
+    add eax, esp
+    mov esp, eax
+
+    seg cs
+    lgdt my_gdtdesc                            ; switch to own table
+
+    mov eax, cr0
+    or al, #0x1                                ; protected mode 'on'
+    mov cr0, eax
+
+    jmpf DWORD (SEGMENT_OFFSET | switch_to_protmode_goon_1), #PM_NORMAL_CS
+
+    START_PM_CODE
+
+switch_to_protmode_goon_1:
+    mov ax, #PM_32BIT_DS                       ; 32 bit segment that allows
+    mov ds, ax                                 ; to reach all 32 bit
+    mov es, ax                                 ; addresses
+    mov ss, ax
+
+    pop eax                                    ;@A2
+    pop bp                                     ;@A1
+    ret
+
+    END_PM_CODE
+
+
+
+    .align 16
+gdt_base:
+    ; see Intel SW Dev. Manuals section 3.4.5, Volume 3 for meaning of bits
+    .word 0,0
+    .byte 0,0,0,0
+
+gdt_entry_pm_cs:
+    ; 32 bit code segment for protected mode
+    .word 0xffff, 0x0000
+    .byte 0x00, 0x9a, 0xcf, 0x00
+
+gdt_entry_pm_16bit_cs:
+    ; temp. 16 bit code segment used while in protected mode
+    .word 0xffff, 0x0000
+    .byte SEGMENT_OFFSET >> 16, 0x9a, 0x0, 0x0
+
+gdt_entry_pm_32bit_ds:
+    ; (32 bit) data segment (r/w) reaching all possible areas in 32bit memory
+    ; 4kb granularity
+    .word 0xffff, 0x0000
+    .byte 0x0, 0x92, 0xcf, 0x0
+gdt_entry_end:
+
+my_gdtdesc:
+    .word (gdt_entry_end - gdt_base) - 1
+    .long gdt_base | SEGMENT_OFFSET
+
+
+realmode_gdtdesc:                              ;to be used in real mode
+    .word 0xffff
+    .long 0x0
+
+
+
+switch_to_realmode:
+    ; Implementation of switching from protected mode to real mode
+    ; restores all registers and prepares cs, es, ds, ss to be used
+    ; in real mode
+    START_PM_CODE
+
+    ; need to fix up the stack to return in 16 bit mode
+    ; currently the 32 bit return address is on the stack
+    push bp                                    ;pop@A1
+    mov bp, sp
+    push eax                                   ;pop@X
+
+    mov eax, [bp]                              ; return address low 16bits
+                                               ; and 'bp' are being moved
+    mov 2[bp], eax
+
+    pop eax                                    ;@X
+    add sp, #2                                 ; adjust stack for 'lost' bytes
+
+    push eax                                   ;pop@1
+    push bx                                    ;pop@2
+    push si                                    ;pop@3
+
+    call _ebda_ss_offset32                     ; get the offset of the ss
+    mov bx, ax                                 ; entry within the ebda.
+
+    jmpf switch_to_realmode_goon_1, #PM_16BIT_CS
+
+    END_PM_CODE
+
+switch_to_realmode_goon_1:
+    mov eax, cr0
+    and al, #0xfe                              ; protected mode 'off'
+    mov cr0, eax
+
+    jmpf switch_to_realmode_goon_2, #REAL_MODE_CODE_SEGMENT
+
+switch_to_realmode_goon_2:
+
+    ; get orig. 'ss' without using the stack (no 'call'!)
+    xor eax, eax                       ; clear upper 16 bits (and lower)
+    mov ax, #0x40                      ; where is the ebda located?
+    mov ds, ax
+    mov si, #0xe
+    seg ds
+    mov ax, [si]                       ; ax = segment of ebda
+
+    mov ds, ax                         ; segment of ebda
+    seg ds
+    mov ax, [bx]                       ; stack segment - bx has been set above
+    mov ss, ax
+
+    ; from esp and ss calculate real-mode sp
+    rol eax, #4
+    sub esp, eax
+
+    push dx                            ;preserve before call(s)
+    push cx
+    push bx
+
+    call _get_register_ds              ; get orig. 'ds'
+    mov ds, ax
+    call _get_register_es              ; get orig. 'es'
+    mov es, ax
+    call _get_register_esp_hi          ; fix the upper 16 bits of esp
+    ror esp, #16
+    mov sp, ax
+    rol esp, #16
+
+    pop bx
+    pop cx
+    pop dx
+
+    seg cs
+    lgdt realmode_gdtdesc
+
+    sti                                                ; allow interrupts
+
+    pop si                                     ;@3
+    pop bx                                     ;@2
+    pop eax                                    ;@1
+    pop bp                                     ;@A1
+
+    ret
+
+    ASM_END
+
+/*
+ * Helper function to get the offset of the reg_ss within the ebda struct
+ * Only 'C' can tell the offset.
+ */
+Bit16u
+ebda_ss_offset32()
+{
+    ASM_START
+    START_PM_CODE                              // need to have this
+    ASM_END                                    // compiled for protected mode
+    return &EbdaData->upcall.reg_ss;           // 'C' knows the offset!
+    ASM_START
+    END_PM_CODE
+    ASM_END
+}
+
+/*
+ * Two often-used functions
+ */
+Bit16u
+read_word_from_ebda(offset)
+    Bit16u offset;
+{
+       Bit16u ebda_seg = read_word(0x0040, 0x000E);
+       return read_word(ebda_seg, offset);
+}
+
+Bit32u
+read_dword_from_ebda(offset)
+    Bit16u offset;
+{
+       Bit16u ebda_seg = read_word(0x0040, 0x000E);
+       return read_dword(ebda_seg, offset);
+}
+
+/*
+ * Store registers in the EBDA; used to keep the registers'
+ * content in a well-defined place during protected mode execution
+ */
+  void
+store_segment_registers(ss, cs, ds, es, esp_hi)
+  Bit16u ss, cs, ds, es, esp_hi;
+{
+       Bit16u ebda_seg = read_word(0x0040, 0x000E);
+       write_word(ebda_seg, &EbdaData->upcall.reg_ss, ss);
+       write_word(ebda_seg, &EbdaData->upcall.reg_cs, cs);
+       write_word(ebda_seg, &EbdaData->upcall.reg_ds, ds);
+       write_word(ebda_seg, &EbdaData->upcall.reg_es, es);
+       write_word(ebda_seg, &EbdaData->upcall.esp_hi, esp_hi);
+}
+
+
+  void
+store_returnaddress(retaddr)
+   Bit16u retaddr;
+{
+       Bit16u ebda_seg = read_word(0x0040, 0x000E);
+       write_word(ebda_seg, &EbdaData->upcall.retaddr, retaddr);
+}
+
+Bit16u
+get_returnaddress()
+{
+       return read_word_from_ebda(&EbdaData->upcall.retaddr);
+}
+
+/*
+ * get the segment register 'cs' value from the EBDA
+ */
+Bit16u
+get_register_cs()
+{
+       return read_word_from_ebda(&EbdaData->upcall.reg_cs);
+}
+
+/*
+ * get the segment register 'ds' value from the EBDA
+ */
+Bit16u
+get_register_ds()
+{
+       return read_word_from_ebda(&EbdaData->upcall.reg_ds);
+}
+
+/*
+ * get the segment register 'es' value from the EBDA
+ */
+Bit16u
+get_register_es()
+{
+       return read_word_from_ebda(&EbdaData->upcall.reg_es);
+}
+
+/*
+ * get the upper 16 bits of the esp from the EBDA
+ */
+Bit16u
+get_register_esp_hi()
+{
+       return read_word_from_ebda(&EbdaData->upcall.esp_hi);
+}
+
+
+
+/********************************************************/
+
+
+ASM_START
+
+Upcall:
+       ; do the upcall into 32 bit space
+       ; clear the stack frame so that 32 bit space sees all the parameters
+       ; on the stack as if they were prepared for it
+       ; ---> take the 16 bit return address off the stack and remember it
+       ;
+       ; Input:
+       ; bx: index of function to call
+       ; Ouput:
+       ; dx, ax: 32 bit result of call (even if 'void' is expected)
+
+       push bp                         ;pop @1
+       mov bp, sp
+       push si                         ;pop @2
+
+       mov ax, 2[bp]                   ; 16 bit return address
+       push ax
+       call _store_returnaddress       ; store away
+       pop ax
+
+       rol bx, #2
+       mov si, #jmptable
+       seg cs
+       mov eax, dword ptr [si+bx]      ; address to call from table
+
+       pop si                          ;@2
+       pop bp                          ;@1
+
+       add sp, #2                      ; remove 16bit return address from stack
+
+       call switch_to_protmode
+       START_PM_CODE
+
+       call eax                        ; call 32bit function
+       push eax                        ; preserve result
+
+       call switch_to_realmode         ; back to realmode
+       END_PM_CODE
+
+       pop eax                         ; get result
+
+       push word 0x0000                ; placeholder for 16 bit return address
+       push bp
+       mov bp,sp
+       push eax                        ; preserve work register
+
+       call _get_returnaddress
+       mov 2[bp], ax                   ; 16bit return address onto stack
+
+       pop eax
+       pop bp
+
+       ror eax, #16                    ; result into dx/ax
+       mov dx, ax                      ; hi(res) -> dx
+       ror eax, #16
+
+       ret
+
+
+/* macro for functions to declare their call into 32bit space */
+MACRO DoUpcall
+       mov bx, #?1
+       jmp Upcall
+MEND
+
+
+ASM_END
+
+#include "32bitprotos.h"
+#include "32bitgateway.h"
+
+/********************************************************************
+  Collection of stub functions for functions executed in 32bit space
+ *******************************************************************/
+
+Bit32u multiply(a, b) /* for testing */
+   Bit32u a;
+   Bit32u b;
+{
+       ASM_START
+       DoUpcall IDX_MULTIPLY
+       ASM_END
+}
+
+Bit32u add(a, b) /* for testing */
+   Bit32u a;
+   Bit32u b;
+{
+       ASM_START
+       DoUpcall IDX_ADD
+       ASM_END
+}
+
+Bit32u set_static(a, b) /* for testing */
+   Bit32u a;
+   Bit32u b;
+{
+       ASM_START
+       DoUpcall IDX_SET_STATIC
+       ASM_END
+}
+
+/* a function to test the gateway */
+void
+test_gateway()
+{
+       Bit32u res;
+       Bit16u err = 0;
+
+       printf("32bit gateway ");
+       res = multiply(11111L,222L);
+       if (err = 0 && res != 11111L * 222L) {
+               printf("not working correctly: multiply\n");
+               err = 1;
+       }
+
+       res = add(111111L, 222222L);
+       if (err = 0 && res != 111111L + 222222L) {
+               printf("not working correctly: add\n");
+               err = 1;
+       }
+
+       res = set_static(0x12345678L);
+       if (err = 0 && res != 0x1L) {
+               printf("not working correctly: set_static (1)\n");
+               err = 1;
+       }
+       res = set_static(0x11111111L);
+       if (err = 0 && res != 0x12345678L) {
+               printf("not working correctly: set_static (2)\n");
+               err = 1;
+       }
+
+       if (err == 0) {
+               printf("working correctly\n");
+       }
+}
diff -r b97780b7080d -r 480436ef6255 tools/firmware/rombios/32bitgateway.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/rombios/32bitgateway.h     Fri Jan 26 16:30:48 2007 +0000
@@ -0,0 +1,18 @@
+#ifndef GATEWAY
+#define GATEWAY
+
+#include "32bitprotos.h"
+
+void test_gateway();
+
+/* extension for the EBDA */
+typedef struct {
+  Bit16u reg_ss;
+  Bit16u reg_cs;
+  Bit16u reg_ds;
+  Bit16u reg_es;
+  Bit16u esp_hi;
+  Bit16u retaddr;
+} upcall_t;
+
+#endif
diff -r b97780b7080d -r 480436ef6255 tools/firmware/rombios/32bitprotos.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/rombios/32bitprotos.h      Fri Jan 26 16:30:48 2007 +0000
@@ -0,0 +1,22 @@
+#ifndef PROTOS_HIGHBIOS
+#define PROTOS_HIGHBIOS
+
+/* bcc does not like 'enum' */
+#define IDX_MULTIPLY   0
+#define IDX_ADD        1
+#define IDX_SET_STATIC 2
+#define IDX_LAST       3 /* keep last! */
+
+
+#ifdef GCC_PROTOS
+  #define PARMS(x...) x
+#else
+  /* bcc doesn't want any parameter types in prototypes */
+  #define PARMS(x...)
+#endif
+
+Bit32u multiply( PARMS(Bit32u a, Bit32u b) );
+Bit32u add( PARMS(Bit32u a, Bit32u b) );
+Bit32u set_static( PARMS(Bit32u) );
+
+#endif
diff -r b97780b7080d -r 480436ef6255 tools/firmware/rombios/Makefile
--- a/tools/firmware/rombios/Makefile   Fri Jan 26 15:45:51 2007 +0000
+++ b/tools/firmware/rombios/Makefile   Fri Jan 26 16:30:48 2007 +0000
@@ -12,7 +12,7 @@ clean:
        rm -f  rombios*.txt rombios*.sym usage biossums
        rm -f  BIOS-bochs-*
 
-BIOS-bochs-latest: rombios.c biossums
+BIOS-bochs-latest: rombios.c biossums 32bitgateway.c
        gcc -DBX_SMP_PROCESSORS=1 -E -P $< > _rombios_.c
        bcc -o rombios.s -C-c -D__i86__ -0 -S _rombios_.c
        sed -e 's/^\.text//' -e 's/^\.data//' rombios.s > _rombios_.s
diff -r b97780b7080d -r 480436ef6255 tools/firmware/rombios/rombios.c
--- a/tools/firmware/rombios/rombios.c  Fri Jan 26 15:45:51 2007 +0000
+++ b/tools/firmware/rombios/rombios.c  Fri Jan 26 16:30:48 2007 +0000
@@ -722,6 +722,8 @@ typedef struct {
     } cdemu_t;
 #endif // BX_ELTORITO_BOOT
   
+#include "32bitgateway.h"
+
   // for access to EBDA area
   //     The EBDA structure should conform to 
   //     http://www.cybertrails.com/~fys/rombios.htm document
@@ -745,6 +747,7 @@ typedef struct {
     cdemu_t cdemu;
 #endif // BX_ELTORITO_BOOT
 
+    upcall_t upcall;
     } ebda_data_t;
   
   #define EbdaData ((ebda_data_t *) 0)
@@ -1852,6 +1855,7 @@ print_bios_banner()
   printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, 
BX_SMP_PROCESSORS>1?"s":"");
   printf("%s %s\n", bios_cvs_version_string, bios_date_string);
   printf("\n");
+  test_gateway();
 }
 
 
@@ -8852,6 +8856,10 @@ use16 386
 #include "apmbios.S"
 
 #endif
+
+ASM_END
+#include "32bitgateway.c"
+ASM_START
 
 ;--------------------
 #if BX_PCIBIOS
@@ -10691,13 +10699,23 @@ static Bit8u vgafont8[128*8]=
 };
 
 #ifdef HVMASSIST
+ASM_START
+
+// space for addresses in 32bit BIOS area; currently 256/4 entries
+// are allocated
+.org 0xcb00
+jmptable:
+db 0x5F, 0x5F, 0x5F, 0x4A, 0x4D, 0x50, 0x54 ;; ___JMPT
+dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;;  64 bytes
+dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 128 bytes
+dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 192 bytes
+
 //
 // MP Tables
 // just carve out some blank space for HVMLOADER to write the MP tables to
 //
 // NOTE: There should be enough space for a 32 processor entry MP table
 //
-ASM_START
 .org 0xcc00
 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;;  64 bytes

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.