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@us.ibm.com>
This commit is contained in:
kaf24@localhost.localdomain committed 2007-01-26 16:30:48 +00:00
1 parent 247a0089e5
commit dd59dfdfb1
18 files changed
+960 -14

No files matched your search

+1 -1
View File
@@ -7,7 +7,7 @@ TARGET := hvmloader/hvmloader
INST_DIR := $(DESTDIR)/usr/lib/xen/boot
SUBDIRS :=
SUBDIRS += rombios
SUBDIRS += rombios rombios/32bit
SUBDIRS += vgabios
SUBDIRS += vmxassist
SUBDIRS += hvmloader
@@ -0,0 +1,169 @@
/*
* 32bitbios_support.c - relocation of 32bit BIOS implementation
*
* Stefan Berger, stefanb@us.ibm.com
* 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));
}
+1 -1
View File
@@ -35,7 +35,7 @@ OBJCOPY = objcopy
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
+7
View File
@@ -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__ */
+1
View File
@@ -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();
+1 -10
View File
@@ -45,12 +45,6 @@ typedef unsigned long uint64_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;
}
+9
View File
@@ -91,6 +91,15 @@ int strcmp(const char *cs, const char *ct)
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;
+5
View File
@@ -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__ */
+60
View File
@@ -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@us.ibm.com>
*/
#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 */
};
+31
View File
@@ -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
+11
View File
@@ -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
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
#
# mkhex: Generate C embeddable hexdumps
#
# Leendert van Doorn, leendert@watson.ibm.com
# 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 "};"
@@ -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
+486
View File
@@ -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@us.ibm.com>
*/
/*
* 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");
}
}
+18
View File
@@ -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
+22
View File
@@ -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
+1 -1
View File
@@ -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
+19 -1
View File
@@ -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();
}
@@ -8853,6 +8857,10 @@ use16 386
#endif
ASM_END
#include "32bitgateway.c"
ASM_START
;--------------------
#if BX_PCIBIOS
use32 386
@@ -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
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.