summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/arch/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/arch/amd64')
-rw-r--r--qemu/roms/openbios/arch/amd64/Kconfig48
-rw-r--r--qemu/roms/openbios/arch/amd64/boot.c41
-rw-r--r--qemu/roms/openbios/arch/amd64/build.xml6
-rw-r--r--qemu/roms/openbios/arch/amd64/builtin.c25
-rw-r--r--qemu/roms/openbios/arch/amd64/console.c417
-rw-r--r--qemu/roms/openbios/arch/amd64/context.c124
-rw-r--r--qemu/roms/openbios/arch/amd64/context.h48
-rw-r--r--qemu/roms/openbios/arch/amd64/defconfig65
-rw-r--r--qemu/roms/openbios/arch/amd64/init.fs83
-rw-r--r--qemu/roms/openbios/arch/amd64/ldscript73
-rw-r--r--qemu/roms/openbios/arch/amd64/lib.c56
-rw-r--r--qemu/roms/openbios/arch/amd64/linux_load.c647
-rw-r--r--qemu/roms/openbios/arch/amd64/multiboot.c125
-rw-r--r--qemu/roms/openbios/arch/amd64/multiboot.h96
-rw-r--r--qemu/roms/openbios/arch/amd64/openbios.c108
-rw-r--r--qemu/roms/openbios/arch/amd64/openbios.h29
-rw-r--r--qemu/roms/openbios/arch/amd64/plainboot.c21
-rw-r--r--qemu/roms/openbios/arch/amd64/relocate.h1
-rw-r--r--qemu/roms/openbios/arch/amd64/segment.c134
-rw-r--r--qemu/roms/openbios/arch/amd64/segment.h30
-rw-r--r--qemu/roms/openbios/arch/amd64/switch.S116
-rw-r--r--qemu/roms/openbios/arch/amd64/sys_info.c58
22 files changed, 2351 insertions, 0 deletions
diff --git a/qemu/roms/openbios/arch/amd64/Kconfig b/qemu/roms/openbios/arch/amd64/Kconfig
new file mode 100644
index 000000000..f1f677dba
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/Kconfig
@@ -0,0 +1,48 @@
+mainmenu "OpenBIOS Configuration"
+
+config AMD64
+ bool
+ default y
+ help
+ Building for AMD64 hardware.
+
+config LITTLE_ENDIAN
+ bool
+ default y
+ help
+ AMD64 is little endian.
+
+
+menu "Kernel binaries (AMD64)"
+
+config IMAGE_ELF
+ bool "ELF image (for LinuxBIOS)"
+ default y
+ help
+ Build a simple elf image that can be used with LinuxBIOS
+ This image will be called openbios.elf
+
+config IMAGE_ELF_EMBEDDED
+ bool "ELF image with embedded dictionary"
+ default y
+ help
+ Build an elf image with embedded dictionary. This image
+ can easily be used with etherboot.
+ The image filename is openbios.full
+
+config IMAGE_ELF_MULTIBOOT
+ bool "Multiboot image"
+ default y
+ help
+ Build a multiboot image for booting with grub
+
+endmenu
+
+menu "Build hosted UNIX Binary"
+source "arch/unix/Kconfig"
+endmenu
+
+source "kernel/Kconfig"
+source "forth/Kconfig"
+source "libopenbios/Kconfig"
+source "drivers/Kconfig"
diff --git a/qemu/roms/openbios/arch/amd64/boot.c b/qemu/roms/openbios/arch/amd64/boot.c
new file mode 100644
index 000000000..0e1fe7efd
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/boot.c
@@ -0,0 +1,41 @@
+/*
+ *
+ */
+#undef BOOTSTRAP
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "libopenbios/elfload.h"
+#include "arch/common/nvram.h"
+#include "libc/diskio.h"
+#include "libopenbios/sys_info.h"
+
+int elf_load(struct sys_info *, const char *filename, const char *cmdline);
+int linux_load(struct sys_info *, const char *filename, const char *cmdline);
+
+void boot(void);
+
+void boot(void)
+{
+ char *path=pop_fstr_copy(), *param;
+
+ // char *param="root=/dev/hda2 console=ttyS0,115200n8 console=tty0";
+
+ if(!path) {
+ printk("[x86] Booting default not supported.\n");
+ return;
+ }
+
+ param = strchr(path, ' ');
+ if(param) {
+ *param = '\0';
+ param++;
+ }
+
+ printk("[x86] Booting file '%s' with parameters '%s'\n",path, param);
+
+ if (elf_load(&sys_info, path, param) == LOADER_NOT_SUPPORT)
+ if (linux_load(&sys_info, path, param) == LOADER_NOT_SUPPORT)
+ printk("Unsupported image format\n");
+
+ free(path);
+}
diff --git a/qemu/roms/openbios/arch/amd64/build.xml b/qemu/roms/openbios/arch/amd64/build.xml
new file mode 100644
index 000000000..8f436d001
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/build.xml
@@ -0,0 +1,6 @@
+<build condition="AMD64">
+ <dictionary name="openbios-amd64" init="openbios" target="forth">
+ <object source="init.fs"/>
+ <object source="QEMU,VGA.bin" target="fcode" condition="DRIVER_VGA" />
+ </dictionary>
+</build>
diff --git a/qemu/roms/openbios/arch/amd64/builtin.c b/qemu/roms/openbios/arch/amd64/builtin.c
new file mode 100644
index 000000000..93ced0ae3
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/builtin.c
@@ -0,0 +1,25 @@
+/* tag: openbios forth starter for builtin dictionary for amd64
+ *
+ * Copyright (C) 2003 Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+#include "config.h"
+#include <asm/types.h>
+#include "libopenbios/sys_info.h"
+
+/*
+ * wrap an array around the hex'ed dictionary file
+ */
+
+#include "static-dict.h"
+
+void collect_multiboot_info(struct sys_info *info);
+void collect_multiboot_info(struct sys_info *info)
+{
+ info->dict_start=(unsigned long *)forth_dictionary;
+ info->dict_end=(unsigned long *)((ucell)forth_dictionary +
+ sizeof(forth_dictionary));
+}
diff --git a/qemu/roms/openbios/arch/amd64/console.c b/qemu/roms/openbios/arch/amd64/console.c
new file mode 100644
index 000000000..71a22b681
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/console.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2003, 2004 Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+#include "config.h"
+#include "kernel/kernel.h"
+#include "openbios.h"
+
+#ifdef CONFIG_DEBUG_CONSOLE
+
+/* ******************************************************************
+ * serial console functions
+ * ****************************************************************** */
+
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+
+#define RBR(x) x==2?0x2f8:0x3f8
+#define THR(x) x==2?0x2f8:0x3f8
+#define IER(x) x==2?0x2f9:0x3f9
+#define IIR(x) x==2?0x2fa:0x3fa
+#define LCR(x) x==2?0x2fb:0x3fb
+#define MCR(x) x==2?0x2fc:0x3fc
+#define LSR(x) x==2?0x2fd:0x3fd
+#define MSR(x) x==2?0x2fe:0x3fe
+#define SCR(x) x==2?0x2ff:0x3ff
+#define DLL(x) x==2?0x2f8:0x3f8
+#define DLM(x) x==2?0x2f9:0x3f9
+
+static int uart_charav(int port)
+{
+ if (!port)
+ return -1;
+ return ((inb(LSR(port)) & 1) != 0);
+}
+
+static char uart_getchar(int port)
+{
+ if (!port)
+ return -1;
+ while (!uart_charav(port));
+ return ((char) inb(RBR(port)) & 0177);
+}
+
+static void uart_putchar(int port, unsigned char c)
+{
+ if (!port)
+ return;
+ if (c == '\n')
+ uart_putchar(port, '\r');
+ while (!(inb(LSR(port)) & 0x20));
+ outb(c, THR(port));
+}
+
+static void uart_init_line(int port, unsigned long baud)
+{
+ int i, baudconst;
+
+ if (!port)
+ return;
+
+ switch (baud) {
+ case 115200:
+ baudconst = 1;
+ break;
+ case 57600:
+ baudconst = 2;
+ break;
+ case 38400:
+ baudconst = 3;
+ break;
+ case 19200:
+ baudconst = 6;
+ break;
+ case 9600:
+ default:
+ baudconst = 12;
+ break;
+ }
+
+ outb(0x87, LCR(port));
+ outb(0x00, DLM(port));
+ outb(baudconst, DLL(port));
+ outb(0x07, LCR(port));
+ outb(0x0f, MCR(port));
+
+ for (i = 10; i > 0; i--) {
+ if (inb(LSR(port)) == (unsigned int) 0)
+ break;
+ inb(RBR(port));
+ }
+}
+
+int uart_init(int port, unsigned long speed)
+{
+ if (port)
+ uart_init_line(port, speed);
+ return -1;
+}
+
+static void serial_putchar(int c)
+{
+ uart_putchar(CONFIG_SERIAL_PORT, (unsigned char) (c & 0xff));
+}
+
+static void serial_cls(void)
+{
+ serial_putchar(27);
+ serial_putchar('[');
+ serial_putchar('H');
+ serial_putchar(27);
+ serial_putchar('[');
+ serial_putchar('J');
+}
+
+#endif
+
+/* ******************************************************************
+ * simple polling video/keyboard console functions
+ * ****************************************************************** */
+
+#ifdef CONFIG_DEBUG_CONSOLE_VGA
+
+/* raw vga text mode */
+#define COLUMNS 80 /* The number of columns. */
+#define LINES 25 /* The number of lines. */
+#define ATTRIBUTE 7 /* The attribute of an character. */
+
+#define VGA_BASE 0xB8000 /* The video memory address. */
+
+/* VGA Index and Data Registers */
+#define VGA_REG_INDEX 0x03D4 /* VGA index register */
+#define VGA_REG_DATA 0x03D5 /* VGA data register */
+
+#define VGA_IDX_CURMSL 0x09 /* cursor maximum scan line */
+#define VGA_IDX_CURSTART 0x0A /* cursor start */
+#define VGA_IDX_CUREND 0x0B /* cursor end */
+#define VGA_IDX_CURLO 0x0F /* cursor position (low 8 bits) */
+#define VGA_IDX_CURHI 0x0E /* cursor position (high 8 bits) */
+
+/* Save the X and Y position. */
+static int xpos, ypos;
+/* Point to the video memory. */
+static volatile unsigned char *video = (unsigned char *) VGA_BASE;
+
+static void video_initcursor(void)
+{
+ u8 val;
+ outb(VGA_IDX_CURMSL, VGA_REG_INDEX);
+ val = inb(VGA_REG_DATA) & 0x1f; /* maximum scan line -1 */
+
+ outb(VGA_IDX_CURSTART, VGA_REG_INDEX);
+ outb(0, VGA_REG_DATA);
+
+ outb(VGA_IDX_CUREND, VGA_REG_INDEX);
+ outb(val, VGA_REG_DATA);
+}
+
+
+
+static void video_poscursor(unsigned int x, unsigned int y)
+{
+ unsigned short pos;
+
+ /* Calculate new cursor position as a function of x and y */
+ pos = (y * COLUMNS) + x;
+
+ /* Output the new position to VGA card */
+ outb(VGA_IDX_CURLO, VGA_REG_INDEX); /* output low 8 bits */
+ outb((u8) (pos), VGA_REG_DATA);
+ outb(VGA_IDX_CURHI, VGA_REG_INDEX); /* output high 8 bits */
+ outb((u8) (pos >> 8), VGA_REG_DATA);
+
+};
+
+
+static void video_newline(void)
+{
+ xpos = 0;
+
+ if (ypos < LINES - 1) {
+ ypos++;
+ } else {
+ int i;
+ memmove((void *) video, (void *) (video + 2 * COLUMNS),
+ (LINES - 1) * COLUMNS * 2);
+
+ for (i = ((LINES - 1) * 2 * COLUMNS);
+ i < 2 * COLUMNS * LINES;) {
+ video[i++] = 0;
+ video[i++] = ATTRIBUTE;
+ }
+ }
+
+}
+
+/* Put the character C on the screen. */
+static void video_putchar(int c)
+{
+ int p=1;
+
+ if (c == '\n' || c == '\r') {
+ video_newline();
+ return;
+ }
+
+ if (c == '\b') {
+ if (xpos) xpos--;
+ c=' ';
+ p=0;
+ }
+
+
+ if (xpos >= COLUMNS)
+ video_newline();
+
+ *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
+ *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE;
+
+ if (p)
+ xpos++;
+
+ video_poscursor(xpos, ypos);
+}
+
+static void video_cls(void)
+{
+ int i;
+
+ for (i = 0; i < 2 * COLUMNS * LINES;) {
+ video[i++] = 0;
+ video[i++] = ATTRIBUTE;
+ }
+
+
+ xpos = 0;
+ ypos = 0;
+
+ video_initcursor();
+ video_poscursor(xpos, ypos);
+}
+
+void video_init(void)
+{
+ video=phys_to_virt((unsigned char*)VGA_BASE);
+}
+
+/*
+ * keyboard driver
+ */
+
+static char normal[] = {
+ 0x0, 0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-',
+ '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o',
+ 'p', '[', ']', 0xa, 0x0, 'a', 's', 'd', 'f', 'g', 'h', 'j',
+ 'k', 'l', ';', 0x27, 0x60, 0x0, 0x5c, 'z', 'x', 'c', 'v', 'b',
+ 'n', 'm', ',', '.', '/', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '0', 0x7f
+};
+
+static char shifted[] = {
+ 0x0, 0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_',
+ '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O',
+ 'P', '{', '}', 0xa, 0x0, 'A', 'S', 'D', 'F', 'G', 'H', 'J',
+ 'K', 'L', ':', 0x22, '~', 0x0, '|', 'Z', 'X', 'C', 'V', 'B',
+ 'N', 'M', '<', '>', '?', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '7', '8',
+ '9', 0x0, '4', '5', '6', 0x0, '1', '2', '3', '0', 0x7f
+};
+
+static int key_ext;
+static int key_lshift = 0, key_rshift = 0, key_caps = 0;
+
+static char last_key;
+
+static void keyboard_cmd(unsigned char cmd, unsigned char val)
+{
+ outb(cmd, 0x60);
+ /* wait until keyboard controller accepts cmds: */
+ while (inb(0x64) & 2);
+ outb(val, 0x60);
+ while (inb(0x64) & 2);
+}
+
+static char keyboard_poll(void)
+{
+ unsigned int c;
+ if (inb(0x64) & 1) {
+ c = inb(0x60);
+ switch (c) {
+ case 0xe0:
+ key_ext = 1;
+ return 0;
+ case 0x2a:
+ key_lshift = 1;
+ return 0;
+ case 0x36:
+ key_rshift = 1;
+ return 0;
+ case 0xaa:
+ key_lshift = 0;
+ return 0;
+ case 0xb6:
+ key_rshift = 0;
+ return 0;
+ case 0x3a:
+ if (key_caps) {
+ key_caps = 0;
+ keyboard_cmd(0xed, 0);
+ } else {
+ key_caps = 1;
+ keyboard_cmd(0xed, 4); /* set caps led */
+ }
+ return 0;
+ }
+
+ if (key_ext) {
+ // void printk(const char *format, ...);
+ printk("extended keycode: %x\n", c);
+
+ key_ext = 0;
+ return 0;
+ }
+
+ if (c & 0x80) /* unhandled key release */
+ return 0;
+
+ if (key_lshift || key_rshift)
+ return key_caps ? normal[c] : shifted[c];
+ else
+ return key_caps ? shifted[c] : normal[c];
+ }
+ return 0;
+}
+
+static int keyboard_dataready(void)
+{
+ if (last_key)
+ return 1;
+
+ last_key = keyboard_poll();
+
+ return (last_key != 0);
+}
+
+static unsigned char keyboard_readdata(void)
+{
+ char tmp;
+ while (!keyboard_dataready());
+ tmp = last_key;
+ last_key = 0;
+ return tmp;
+}
+#endif
+
+
+/* ******************************************************************
+ * common functions, implementing simple concurrent console
+ * ****************************************************************** */
+
+int arch_putchar(int c)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ serial_putchar(c);
+#endif
+#ifdef CONFIG_DEBUG_CONSOLE_VGA
+ video_putchar(c);
+#endif
+ return c;
+}
+
+int arch_availchar(void)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ if (uart_charav(CONFIG_SERIAL_PORT))
+ return 1;
+#endif
+#ifdef CONFIG_DEBUG_CONSOLE_VGA
+ if (keyboard_dataready())
+ return 1;
+#endif
+ return 0;
+}
+
+int arch_getchar(void)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ if (uart_charav(CONFIG_SERIAL_PORT))
+ return (uart_getchar(CONFIG_SERIAL_PORT));
+#endif
+#ifdef CONFIG_DEBUG_CONSOLE_VGA
+ if (keyboard_dataready())
+ return (keyboard_readdata());
+#endif
+ return 0;
+}
+
+void cls(void)
+{
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ serial_cls();
+#endif
+#ifdef CONFIG_DEBUG_CONSOLE_VGA
+ video_cls();
+#endif
+}
+
+struct _console_ops arch_console_ops = {
+ .putchar = arch_putchar,
+ .availchar = arch_availchar,
+ .getchar = arch_getchar
+};
+
+#endif // CONFIG_DEBUG_CONSOLE
diff --git a/qemu/roms/openbios/arch/amd64/context.c b/qemu/roms/openbios/arch/amd64/context.c
new file mode 100644
index 000000000..2e4df6a3d
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/context.c
@@ -0,0 +1,124 @@
+/*
+ * context switching
+ * 2003-10 by SONE Takeshi
+ */
+
+#include "config.h"
+#include "kernel/kernel.h"
+#include "segment.h"
+#include "context.h"
+
+#define MAIN_STACK_SIZE 16384
+#define IMAGE_STACK_SIZE 4096
+
+#define debug printk
+
+static void start_main(void); /* forward decl. */
+void __exit_context(void); /* assembly routine */
+
+/*
+ * Main context structure
+ * It is placed at the bottom of our stack, and loaded by assembly routine
+ * to start us up.
+ */
+struct context main_ctx __attribute__((section (".initctx"))) = {
+ .gdt_base = (uint64_t) gdt,
+ .gdt_limit = GDT_LIMIT,
+ .cs = FLAT_CS,
+ .ds = FLAT_DS,
+ .es = FLAT_DS,
+ .fs = FLAT_DS,
+ .gs = FLAT_DS,
+ .ss = FLAT_DS,
+ .esp = (uint32_t) ESP_LOC(&main_ctx),
+ .eip = (uint32_t) start_main,
+ .return_addr = (uint32_t) __exit_context,
+};
+
+/* This is used by assembly routine to load/store the context which
+ * it is to switch/switched. */
+struct context *__context = &main_ctx;
+
+/* Stack for loaded ELF image */
+static uint8_t image_stack[IMAGE_STACK_SIZE];
+
+/* Pointer to startup context (physical address) */
+unsigned long __boot_ctx;
+
+/*
+ * Main starter
+ * This is the C function that runs first.
+ */
+static void start_main(void)
+{
+ int retval;
+ extern int openbios(void);
+
+ /* Save startup context, so we can refer to it later.
+ * We have to keep it in physical address since we will relocate. */
+ __boot_ctx = virt_to_phys(__context);
+
+ /* Start the real fun */
+ retval = openbios();
+
+ /* Pass return value to startup context. Bootloader may see it. */
+ boot_ctx->eax = retval;
+
+ /* Returning from here should jump to __exit_context */
+ __context = boot_ctx;
+}
+
+/* Setup a new context using the given stack.
+ */
+struct context *
+init_context(uint8_t *stack, uint32_t stack_size, int num_params)
+{
+ struct context *ctx;
+
+ ctx = (struct context *)
+ (stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t)));
+ memset(ctx, 0, sizeof(*ctx));
+
+ /* Fill in reasonable default for flat memory model */
+ ctx->gdt_base = virt_to_phys(gdt);
+ ctx->gdt_limit = GDT_LIMIT;
+ ctx->cs = FLAT_CS;
+ ctx->ds = FLAT_DS;
+ ctx->es = FLAT_DS;
+ ctx->fs = FLAT_DS;
+ ctx->gs = FLAT_DS;
+ ctx->ss = FLAT_DS;
+ ctx->esp = virt_to_phys(ESP_LOC(ctx));
+ ctx->return_addr = virt_to_phys(__exit_context);
+
+ return ctx;
+}
+
+/* Switch to another context. */
+struct context *switch_to(struct context *ctx)
+{
+ struct context *save, *ret;
+
+ debug("switching to new context:\n");
+ save = __context;
+ __context = ctx;
+ asm ("pushl %cs; call __switch_context");
+ ret = __context;
+ __context = save;
+ return ret;
+}
+
+/* Start ELF Boot image */
+uint32_t start_elf(uint32_t entry_point, uint32_t param)
+{
+ struct context *ctx;
+
+ ctx = init_context(image_stack, sizeof image_stack, 1);
+ ctx->eip = entry_point;
+ ctx->param[0] = param;
+ ctx->eax = 0xe1fb007;
+ ctx->ebx = param;
+
+ ctx = switch_to(ctx);
+ return ctx->eax;
+}
diff --git a/qemu/roms/openbios/arch/amd64/context.h b/qemu/roms/openbios/arch/amd64/context.h
new file mode 100644
index 000000000..4c3832efb
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/context.h
@@ -0,0 +1,48 @@
+#ifndef AMD64_CONTEXT_H
+#define AMD64_CONTEXT_H
+
+struct context {
+ /* Stack Segment, placed here because of the alignment issue... */
+ uint16_t ss;
+ /* Used with sgdt/lgdt */
+ uint16_t gdt_limit;
+ uint64_t gdt_base;
+ /* General registers, accessed with pushal/popal */
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp; /* points just below eax */
+ uint32_t ebx;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t eax;
+#define ESP_LOC(ctx) (&(ctx)->gs)
+ /* Segment registers */
+ uint32_t gs;
+ uint32_t fs;
+ uint32_t es;
+ uint32_t ds;
+ /* Flags */
+ uint32_t eflags;
+ /* Code segment:offset */
+ uint32_t eip;
+ uint32_t cs;
+ /* Optional stack contents */
+ uint32_t return_addr;
+ uint32_t param[0];
+};
+
+/* Create a new context in the given stack */
+struct context *
+init_context(uint8_t *stack, uint32_t stack_size, int num_param);
+
+/* Switch context */
+struct context *switch_to(struct context *);
+
+/* Holds physical address of boot context */
+extern unsigned long __boot_ctx;
+
+/* This can always be safely used to refer to the boot context */
+#define boot_ctx ((struct context *) phys_to_virt(__boot_ctx))
+
+#endif /* AMD64_CONTEXT_H */
diff --git a/qemu/roms/openbios/arch/amd64/defconfig b/qemu/roms/openbios/arch/amd64/defconfig
new file mode 100644
index 000000000..570a6c869
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/defconfig
@@ -0,0 +1,65 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_AMD64=y
+CONFIG_LITTLE_ENDIAN=y
+
+#
+# Kernel binaries (AMD64)
+#
+# CONFIG_IMAGE_ELF is not set
+# CONFIG_IMAGE_ELF_EMBEDDED is not set
+# CONFIG_IMAGE_ELF_MULTIBOOT is not set
+
+#
+# Build hosted UNIX Binary
+#
+CONFIG_HOST_UNIX=y
+# CONFIG_PLUGIN_PCI is not set
+
+#
+# Kernel Debugging
+#
+# CONFIG_DEBUG is not set
+CONFIG_DEBUG_CONSOLE=y
+CONFIG_DEBUG_CONSOLE_SERIAL=y
+CONFIG_SERIAL_PORT=1
+CONFIG_SERIAL_SPEED=115200
+CONFIG_DEBUG_CONSOLE_VGA=y
+
+#
+# Module Configuration
+#
+CONFIG_CMDLINE=y
+CONFIG_DEBLOCKER=y
+
+#
+# Filesystem Configuration
+#
+CONFIG_DISK_LABEL=y
+CONFIG_PART_SUPPORT=y
+CONFIG_PC_PARTS=y
+CONFIG_FS=y
+CONFIG_GRUBFS=y
+CONFIG_FSYS_EXT2FS=y
+CONFIG_FSYS_FAT=y
+CONFIG_FSYS_JFS=y
+# CONFIG_FSYS_MINIX is not set
+CONFIG_FSYS_REISERFS=y
+CONFIG_FSYS_XFS=y
+CONFIG_FSYS_ISO9660=y
+# CONFIG_FSYS_FFS is not set
+# CONFIG_FSYS_VSTAFS is not set
+# CONFIG_DEBUG_FS is not set
+
+#
+# Miscellaneous
+#
+CONFIG_LINUXBIOS=y
+
+#
+# Drivers
+#
+CONFIG_DRIVER_PCI=y
+CONFIG_DRIVER_IDE=y
+# CONFIG_DEBUG_IDE is not set
diff --git a/qemu/roms/openbios/arch/amd64/init.fs b/qemu/roms/openbios/arch/amd64/init.fs
new file mode 100644
index 000000000..fda3acdc8
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/init.fs
@@ -0,0 +1,83 @@
+include config.fs
+
+:noname
+ ." Type 'help' for detailed information" cr
+ \ ." boot secondary slave cdrom: " cr
+ \ ." 0 > boot hd:2,\boot\vmlinuz root=/dev/hda2" cr
+ ; DIAG-initializer
+
+" /" find-device
+
+new-device
+ " memory" device-name
+ \ 12230 encode-int " reg" property
+ external
+ : open true ;
+ : close ;
+ \ claim ( phys size align -- base )
+ \ release ( phys size -- )
+finish-device
+
+new-device
+ " cpus" device-name
+ 1 " #address-cells" int-property
+ 0 " #size-cells" int-property
+
+ external
+ : open true ;
+ : close ;
+ : decode-unit parse-hex ;
+
+finish-device
+
+: make-openable ( path )
+ find-dev if
+ begin ?dup while
+ \ install trivial open and close methods
+ dup active-package! is-open
+ parent
+ repeat
+ then
+;
+
+: preopen ( chosen-str node-path )
+ 2dup make-openable
+
+ " /chosen" find-device
+ open-dev ?dup if
+ encode-int 2swap property
+ else
+ 2drop
+ then
+;
+
+:noname
+ set-defaults
+; SYSTEM-initializer
+
+\ preopen device nodes (and store the ihandles under /chosen)
+:noname
+ " memory" " /memory" preopen
+ " mmu" " /cpus/@0" preopen
+ " stdout" " /builtin/console" preopen
+ " stdin" " /builtin/console" preopen
+
+; SYSTEM-initializer
+
+\ use the tty interface if available
+:noname
+ " /builtin/console" find-dev if drop
+ " /builtin/console" " input-device" $setenv
+ " /builtin/console" " output-device" $setenv
+ then
+; SYSTEM-initializer
+
+:noname
+ " keyboard" input
+; CONSOLE-IN-initializer
+
+\ Load VGA FCode driver blob
+[IFDEF] CONFIG_DRIVER_VGA
+ -1 value vga-driver-fcode
+ " QEMU,VGA.bin" $encode-file to vga-driver-fcode
+[THEN]
diff --git a/qemu/roms/openbios/arch/amd64/ldscript b/qemu/roms/openbios/arch/amd64/ldscript
new file mode 100644
index 000000000..8976c7af0
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/ldscript
@@ -0,0 +1,73 @@
+OUTPUT_FORMAT(elf32-i386)
+OUTPUT_ARCH(i386)
+
+ENTRY(entry)
+
+/* Initial load address
+ * To be loaded by GRUB, this must be >= 1MB
+ */
+BASE_ADDR = 0x100000;
+
+/* 16KB heap and stack */
+HEAP_SIZE = 16384;
+STACK_SIZE = 16384;
+
+SECTIONS
+{
+ . = BASE_ADDR;
+
+ /* Put Multiboot header near beginning of file, if any. */
+ .hdr : { *(.hdr) *(.hdr.*) }
+
+ /* Start of the program.
+ * Now the version string is in the note, we must include it
+ * in the program. Otherwise we lose the string after relocation. */
+ . = ALIGN(16);
+ _start = .;
+
+ /* Putting ELF notes near beginning of file might help bootloaders.
+ * We discard .note sections other than .note.ELFBoot,
+ * because some versions of GCC generates useless ones. */
+ .note : { *(.note.ELFBoot) }
+
+ /* Normal sections */
+ .text : { *(.text) *(.text.*) }
+ .rodata : {
+ . = ALIGN(4);
+ sound_drivers_start = .;
+ *(.rodata.sound_drivers)
+ sound_drivers_end = .;
+ *(.rodata)
+ *(.rodata.*)
+ }
+ .data : { *(.data) *(.data.*) }
+
+ .bss : {
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+
+ /* Put heap and stack here, so they are included in PT_LOAD segment
+ * and the bootloader is aware of it. */
+
+ . = ALIGN(16);
+ _heap = .;
+ . += HEAP_SIZE;
+ . = ALIGN(16);
+ _eheap = .;
+
+ _stack = .;
+ . += STACK_SIZE;
+ . = ALIGN(16);
+ _estack = .;
+ }
+
+ .initctx : {
+ /* Initial contents of stack. This MUST BE just after the stack. */
+ *(.initctx)
+ }
+
+ _end = .;
+
+ /DISCARD/ : { *(.comment) *(.note) }
+}
diff --git a/qemu/roms/openbios/arch/amd64/lib.c b/qemu/roms/openbios/arch/amd64/lib.c
new file mode 100644
index 000000000..f04458e1a
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/lib.c
@@ -0,0 +1,56 @@
+/* lib.c
+ * tag: simple function library
+ *
+ * Copyright (C) 2003 Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+#include "config.h"
+#include "asm/types.h"
+#include <stdarg.h>
+#include "libc/stdlib.h"
+#include "libc/vsprintf.h"
+#include "kernel/kernel.h"
+
+/* Format a string and print it on the screen, just like the libc
+ * function printf.
+ */
+int printk( const char *fmt, ... )
+{
+ char *p, buf[512];
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ for( p=buf; *p; p++ )
+ putchar(*p);
+ return i;
+}
+
+// dumb quick memory allocator until we get a decent thing here.
+
+#define MEMSIZE 128*1024
+static char memory[MEMSIZE];
+static void *memptr=memory;
+static int memsize=MEMSIZE;
+
+void *malloc(int size)
+{
+ void *ret=(void *)0;
+ if(memsize>=size) {
+ memsize-=size;
+ ret=memptr;
+ memptr+=size;
+ }
+ return ret;
+}
+
+void free(void *ptr)
+{
+ /* Nothing yet */
+}
diff --git a/qemu/roms/openbios/arch/amd64/linux_load.c b/qemu/roms/openbios/arch/amd64/linux_load.c
new file mode 100644
index 000000000..f1ed98df1
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/linux_load.c
@@ -0,0 +1,647 @@
+/*
+ * Linux/i386 loader
+ * Supports bzImage, zImage and Image format.
+ *
+ * Based on work by Steve Gehlbach.
+ * Portions are taken from mkelfImage.
+ *
+ * 2003-09 by SONE Takeshi
+ */
+
+#include "config.h"
+#include "kernel/kernel.h"
+#include "libopenbios/bindings.h"
+#include "libopenbios/sys_info.h"
+#include "context.h"
+#include "segment.h"
+#include "loadfs.h"
+
+#define printf printk
+#define debug printk
+#define strtoull_with_suffix strtol
+
+#define LINUX_PARAM_LOC 0x90000
+#define COMMAND_LINE_LOC 0x91000
+#define GDT_LOC 0x92000
+#define STACK_LOC 0x93000
+
+#define E820MAX 32 /* number of entries in E820MAP */
+struct e820entry {
+ unsigned long long addr; /* start of memory segment */
+ unsigned long long size; /* size of memory segment */
+ unsigned long type; /* type of memory segment */
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
+#define E820_NVS 4
+};
+
+/* The header of Linux/i386 kernel */
+struct linux_header {
+ uint8_t reserved1[0x1f1]; /* 0x000 */
+ uint8_t setup_sects; /* 0x1f1 */
+ uint16_t root_flags; /* 0x1f2 */
+ uint8_t reserved2[6]; /* 0x1f4 */
+ uint16_t vid_mode; /* 0x1fa */
+ uint16_t root_dev; /* 0x1fc */
+ uint16_t boot_sector_magic; /* 0x1fe */
+ /* 2.00+ */
+ uint8_t reserved3[2]; /* 0x200 */
+ uint8_t header_magic[4]; /* 0x202 */
+ uint16_t protocol_version; /* 0x206 */
+ uint32_t realmode_swtch; /* 0x208 */
+ uint16_t start_sys; /* 0x20c */
+ uint16_t kver_addr; /* 0x20e */
+ uint8_t type_of_loader; /* 0x210 */
+ uint8_t loadflags; /* 0x211 */
+ uint16_t setup_move_size; /* 0x212 */
+ uint32_t code32_start; /* 0x214 */
+ uint32_t ramdisk_image; /* 0x218 */
+ uint32_t ramdisk_size; /* 0x21c */
+ uint8_t reserved4[4]; /* 0x220 */
+ /* 2.01+ */
+ uint16_t heap_end_ptr; /* 0x224 */
+ uint8_t reserved5[2]; /* 0x226 */
+ /* 2.02+ */
+ uint32_t cmd_line_ptr; /* 0x228 */
+ /* 2.03+ */
+ uint32_t initrd_addr_max; /* 0x22c */
+} __attribute__ ((packed));
+
+
+/* Paramters passed to 32-bit part of Linux
+ * This is another view of the structure above.. */
+struct linux_params {
+ uint8_t orig_x; /* 0x00 */
+ uint8_t orig_y; /* 0x01 */
+ uint16_t ext_mem_k; /* 0x02 -- EXT_MEM_K sits here */
+ uint16_t orig_video_page; /* 0x04 */
+ uint8_t orig_video_mode; /* 0x06 */
+ uint8_t orig_video_cols; /* 0x07 */
+ uint16_t unused2; /* 0x08 */
+ uint16_t orig_video_ega_bx; /* 0x0a */
+ uint16_t unused3; /* 0x0c */
+ uint8_t orig_video_lines; /* 0x0e */
+ uint8_t orig_video_isVGA; /* 0x0f */
+ uint16_t orig_video_points; /* 0x10 */
+
+ /* VESA graphic mode -- linear frame buffer */
+ uint16_t lfb_width; /* 0x12 */
+ uint16_t lfb_height; /* 0x14 */
+ uint16_t lfb_depth; /* 0x16 */
+ uint32_t lfb_base; /* 0x18 */
+ uint32_t lfb_size; /* 0x1c */
+ uint16_t cl_magic; /* 0x20 */
+#define CL_MAGIC_VALUE 0xA33F
+ uint16_t cl_offset; /* 0x22 */
+ uint16_t lfb_linelength; /* 0x24 */
+ uint8_t red_size; /* 0x26 */
+ uint8_t red_pos; /* 0x27 */
+ uint8_t green_size; /* 0x28 */
+ uint8_t green_pos; /* 0x29 */
+ uint8_t blue_size; /* 0x2a */
+ uint8_t blue_pos; /* 0x2b */
+ uint8_t rsvd_size; /* 0x2c */
+ uint8_t rsvd_pos; /* 0x2d */
+ uint16_t vesapm_seg; /* 0x2e */
+ uint16_t vesapm_off; /* 0x30 */
+ uint16_t pages; /* 0x32 */
+ uint8_t reserved4[12]; /* 0x34 -- 0x3f reserved for future expansion */
+
+ //struct apm_bios_info apm_bios_info; /* 0x40 */
+ uint8_t apm_bios_info[0x40];
+ //struct drive_info_struct drive_info; /* 0x80 */
+ uint8_t drive_info[0x20];
+ //struct sys_desc_table sys_desc_table; /* 0xa0 */
+ uint8_t sys_desc_table[0x140];
+ uint32_t alt_mem_k; /* 0x1e0 */
+ uint8_t reserved5[4]; /* 0x1e4 */
+ uint8_t e820_map_nr; /* 0x1e8 */
+ uint8_t reserved6[9]; /* 0x1e9 */
+ uint16_t mount_root_rdonly; /* 0x1f2 */
+ uint8_t reserved7[4]; /* 0x1f4 */
+ uint16_t ramdisk_flags; /* 0x1f8 */
+#define RAMDISK_IMAGE_START_MASK 0x07FF
+#define RAMDISK_PROMPT_FLAG 0x8000
+#define RAMDISK_LOAD_FLAG 0x4000
+ uint8_t reserved8[2]; /* 0x1fa */
+ uint16_t orig_root_dev; /* 0x1fc */
+ uint8_t reserved9[1]; /* 0x1fe */
+ uint8_t aux_device_info; /* 0x1ff */
+ uint8_t reserved10[2]; /* 0x200 */
+ uint8_t param_block_signature[4]; /* 0x202 */
+ uint16_t param_block_version; /* 0x206 */
+ uint8_t reserved11[8]; /* 0x208 */
+ uint8_t loader_type; /* 0x210 */
+#define LOADER_TYPE_LOADLIN 1
+#define LOADER_TYPE_BOOTSECT_LOADER 2
+#define LOADER_TYPE_SYSLINUX 3
+#define LOADER_TYPE_ETHERBOOT 4
+#define LOADER_TYPE_KERNEL 5
+ uint8_t loader_flags; /* 0x211 */
+ uint8_t reserved12[2]; /* 0x212 */
+ uint32_t kernel_start; /* 0x214 */
+ uint32_t initrd_start; /* 0x218 */
+ uint32_t initrd_size; /* 0x21c */
+ uint8_t reserved12_5[8]; /* 0x220 */
+ uint32_t cmd_line_ptr; /* 0x228 */
+ uint8_t reserved13[164]; /* 0x22c */
+ struct e820entry e820_map[E820MAX]; /* 0x2d0 */
+ uint8_t reserved16[688]; /* 0x550 */
+#define COMMAND_LINE_SIZE 256
+ /* Command line is copied here by 32-bit i386/kernel/head.S.
+ * So I will follow the boot protocol, rather than putting it
+ * directly here. --ts1 */
+ uint8_t command_line[COMMAND_LINE_SIZE]; /* 0x800 */
+ uint8_t reserved17[1792]; /* 0x900 - 0x1000 */
+};
+
+uint64_t forced_memsize;
+
+/* Load the first part the file and check if it's Linux */
+static uint32_t load_linux_header(struct linux_header *hdr)
+{
+ int load_high;
+ uint32_t kern_addr;
+
+ if (lfile_read(hdr, sizeof *hdr) != sizeof *hdr) {
+ debug("Can't read Linux header\n");
+ return 0;
+ }
+ if (hdr->boot_sector_magic != 0xaa55) {
+ debug("Not a Linux kernel image\n");
+ return 0;
+ }
+
+ /* Linux is found. Print some information */
+ if (memcmp(hdr->header_magic, "HdrS", 4) != 0) {
+ /* This may be floppy disk image or something.
+ * Perform a simple (incomplete) sanity check. */
+ if (hdr->setup_sects >= 16
+ || file_size() - (hdr->setup_sects<<9) >= 512<<10) {
+ debug("This looks like a bootdisk image but not like Linux...\n");
+ return 0;
+ }
+
+ printf("Possible very old Linux");
+ /* This kernel does not even have a protocol version.
+ * Force the value. */
+ hdr->protocol_version = 0; /* pre-2.00 */
+ } else
+ printf("Found Linux");
+ if (hdr->protocol_version >= 0x200 && hdr->kver_addr) {
+ char kver[256];
+ file_seek(hdr->kver_addr + 0x200);
+ if (lfile_read(kver, sizeof kver) != 0) {
+ kver[255] = 0;
+ printf(" version %s", kver);
+ }
+ }
+ debug(" (protocol %#x)", hdr->protocol_version);
+ load_high = 0;
+ if (hdr->protocol_version >= 0x200) {
+ debug(" (loadflags %#x)", hdr->loadflags);
+ load_high = hdr->loadflags & 1;
+ }
+ if (load_high) {
+ printf(" bzImage");
+ kern_addr = 0x100000;
+ } else {
+ printf(" zImage or Image");
+ kern_addr = 0x1000;
+ }
+ printf(".\n");
+
+ return kern_addr;
+}
+
+/* Set up parameters for 32-bit kernel */
+static void
+init_linux_params(struct linux_params *params, struct linux_header *hdr)
+{
+ debug("Setting up paramters at %#lx\n", virt_to_phys(params));
+ memset(params, 0, sizeof *params);
+
+ /* Copy some useful values from header */
+ params->mount_root_rdonly = hdr->root_flags;
+ params->orig_root_dev = hdr->root_dev;
+
+ /* Video parameters.
+ * This assumes we have VGA in standard 80x25 text mode,
+ * just like our vga.c does.
+ * Cursor position is filled later to allow some more printf's. */
+ params->orig_video_mode = 3;
+ params->orig_video_cols = 80;
+ params->orig_video_lines = 25;
+ params->orig_video_isVGA = 1;
+ params->orig_video_points = 16;
+
+ params->loader_type = 0xff; /* Unregistered Linux loader */
+}
+
+/* Memory map */
+static void
+set_memory_size(struct linux_params *params, struct sys_info *info)
+{
+ int i;
+ uint64_t end;
+ uint32_t ramtop = 0;
+ struct e820entry *linux_map;
+ struct memrange *filo_map;
+
+ linux_map = params->e820_map;
+ filo_map = info->memrange;
+ for (i = 0; i < info->n_memranges; i++, linux_map++, filo_map++) {
+ if (i < E820MAX) {
+ /* Convert to BIOS e820 style */
+ linux_map->addr = filo_map->base;
+ linux_map->size = filo_map->size;
+ linux_map->type = E820_RAM;
+ debug("%016Lx - %016Lx\n", linux_map->addr,
+ linux_map->addr + linux_map->size);
+ params->e820_map_nr = i+1;
+ }
+
+ /* Find out top of RAM. XXX This ignores hole above 1MB */
+ end = filo_map->base + filo_map->size;
+ if (end < (1ULL << 32)) { /* don't count memory above 4GB */
+ if (end > ramtop)
+ ramtop = (uint32_t) end;
+ }
+ }
+ debug("ramtop=%#x\n", ramtop);
+ /* Size of memory above 1MB in KB */
+ params->alt_mem_k = (ramtop - (1<<20)) >> 10;
+ /* old style, 64MB max */
+ if (ramtop >= (64<<20))
+ params->ext_mem_k = (63<<10);
+ else
+ params->ext_mem_k = params->alt_mem_k;
+ debug("ext_mem_k=%d, alt_mem_k=%d\n", params->ext_mem_k, params->alt_mem_k);
+}
+
+/*
+ * Parse command line
+ * Some parameters, like initrd=<file>, are not passed to kernel,
+ * we are responsible to process them.
+ * Parameters for kernel are copied to kern_cmdline. Returns name of initrd.
+ */
+static char *parse_command_line(const char *orig_cmdline, char *kern_cmdline)
+{
+ const char *start, *sep, *end, *val;
+ char name[64];
+ int len;
+ int k_len;
+ int to_kern;
+ char *initrd = 0;
+ int toolong = 0;
+
+ forced_memsize = 0;
+
+ if (!orig_cmdline) {
+ *kern_cmdline = 0;
+ return 0;
+ }
+
+ k_len = 0;
+ debug("original command line: \"%s\"\n", orig_cmdline);
+ debug("kernel command line at %#lx\n", virt_to_phys(kern_cmdline));
+
+ start = orig_cmdline;
+ while (*start == ' ')
+ start++;
+ while (*start) {
+ end = strchr(start, ' ');
+ if (!end)
+ end = start + strlen(start);
+ sep = strchr(start, '=');
+ if (!sep || sep > end)
+ sep = end;
+ len = sep - start;
+ if (len >= sizeof(name))
+ len = sizeof(name) - 1;
+ memcpy(name, start, len);
+ name[len] = 0;
+
+ if (*sep == '=') {
+ val = sep + 1;
+ len = end - val;
+ } else {
+ val = 0;
+ len = 0;
+ }
+
+ /* Only initrd= and mem= are handled here. vga= is not,
+ * which I believe is a paramter to the realmode part of Linux,
+ * which we don't execute. */
+ if (strcmp(name, "initrd") == 0) {
+ if (!val)
+ printf("Missing filename to initrd parameter\n");
+ else {
+ initrd = malloc(len + 1);
+ memcpy(initrd, val, len);
+ initrd[len] = 0;
+ debug("initrd=%s\n", initrd);
+ }
+ /* Don't pass this to kernel */
+ to_kern = 0;
+ } else if (strcmp(name, "mem") == 0) {
+ if (!val)
+ printf("Missing value for mem parameter\n");
+ else {
+ forced_memsize = strtoull_with_suffix(val, (char**)&val, 0);
+ if (forced_memsize == 0)
+ printf("Invalid mem option, ignored\n");
+ if (val != end) {
+ printf("Garbage after mem=<size>, ignored\n");
+ forced_memsize = 0;
+ }
+ debug("mem=%Lu\n", forced_memsize);
+ }
+ /* mem= is for both loader and kernel */
+ to_kern = 1;
+ } else
+ to_kern = 1;
+
+ if (to_kern) {
+ /* Copy to kernel command line buffer */
+ if (k_len != 0)
+ kern_cmdline[k_len++] = ' '; /* put separator */
+ len = end - start;
+ if (k_len + len >= COMMAND_LINE_SIZE) {
+ len = COMMAND_LINE_SIZE - k_len - 1;
+ if (!toolong) {
+ printf("Kernel command line is too long; truncated to "
+ "%d bytes\n", COMMAND_LINE_SIZE-1);
+ toolong = 1;
+ }
+ }
+ memcpy(kern_cmdline + k_len, start, len);
+ k_len += len;
+ }
+
+ start = end;
+ while (*start == ' ')
+ start++;
+ }
+ kern_cmdline[k_len] = 0;
+ debug("kernel command line (%d bytes): \"%s\"\n", k_len, kern_cmdline);
+
+ return initrd;
+}
+
+/* Set command line location */
+static void set_command_line_loc(struct linux_params *params,
+ struct linux_header *hdr)
+{
+ if (hdr->protocol_version >= 0x202) {
+ /* new style */
+ params->cmd_line_ptr = COMMAND_LINE_LOC;
+ } else {
+ /* old style */
+ params->cl_magic = CL_MAGIC_VALUE;
+ params->cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC;
+ }
+}
+
+/* Load 32-bit part of kernel */
+static int load_linux_kernel(struct linux_header *hdr, uint32_t kern_addr)
+{
+ uint32_t kern_offset, kern_size;
+
+ if (hdr->setup_sects == 0)
+ hdr->setup_sects = 4;
+ kern_offset = (hdr->setup_sects + 1) * 512;
+ file_seek(kern_offset);
+ kern_size = file_size() - kern_offset;
+ debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size);
+
+#if 0
+ if (using_devsize) {
+ printf("Attempt to load up to end of device as kernel; "
+ "specify the image size\n");
+ return 0;
+ }
+#endif
+
+ printf("Loading kernel... ");
+ if (lfile_read(phys_to_virt(kern_addr), kern_size) != kern_size) {
+ printf("Can't read kernel\n");
+ return 0;
+ }
+ printf("ok\n");
+
+ return kern_size;
+}
+
+static int load_initrd(struct linux_header *hdr, struct sys_info *info,
+ uint32_t kern_end, struct linux_params *params, const char *initrd_file)
+{
+ uint32_t max;
+ uint32_t start, end, size;
+ uint64_t forced;
+ extern char _start[], _end[];
+
+ if (!file_open(initrd_file)) {
+ printf("Can't open initrd: %s\n", initrd_file);
+ return -1;
+ }
+
+#if 0
+ if (using_devsize) {
+ printf("Attempt to load up to end of device as initrd; "
+ "specify the image size\n");
+ return -1;
+ }
+#endif
+
+ size = file_size();
+
+
+ /* Find out the kernel's restriction on how high the initrd can be
+ * placed */
+ if (hdr->protocol_version >= 0x203)
+ max = hdr->initrd_addr_max;
+ else
+ max = 0x38000000; /* Hardcoded value for older kernels */
+
+ /* FILO itself is at the top of RAM. (relocated)
+ * So, try putting initrd just below us. */
+ end = virt_to_phys(_start);
+ if (end > max)
+ end = max;
+
+ /* If "mem=" option is given, we have to put the initrd within
+ * the specified range. */
+ if (forced_memsize) {
+ forced = forced_memsize;
+ if (forced > max)
+ forced = max;
+ /* If the "mem=" is lower, it's easy */
+ if (forced <= end)
+ end = forced;
+ else {
+ /* Otherwise, see if we can put it above us */
+ if (virt_to_phys(_end) + size <= forced)
+ end = forced; /* Ok */
+ }
+ }
+
+ start = end - size;
+ start &= ~0xfff; /* page align */
+ end = start + size;
+
+ debug("start=%#x end=%#x\n", start, end);
+
+ if (start < kern_end) {
+ printf("Initrd is too big to fit in memory\n");
+ return -1;
+ }
+
+ printf("Loading initrd... ");
+ if (lfile_read(phys_to_virt(start), size) != size) {
+ printf("Can't read initrd\n");
+ return -1;
+ }
+ printf("ok\n");
+
+ params->initrd_start = start;
+ params->initrd_size = size;
+
+ return 0;
+}
+
+static void hardware_setup(void)
+{
+ /* Disable nmi */
+ outb(0x80, 0x70);
+
+ /* Make sure any coprocessor is properly reset.. */
+ outb(0, 0xf0);
+ outb(0, 0xf1);
+
+ /* we're getting screwed again and again by this problem of the 8259.
+ * so we're going to leave this lying around for inclusion into
+ * crt0.S on an as-needed basis.
+ *
+ * well, that went ok, I hope. Now we have to reprogram the interrupts :-(
+ * we put them right after the intel-reserved hardware interrupts, at
+ * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
+ * messed this up with the original PC, and they haven't been able to
+ * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
+ * which is used for the internal hardware interrupts as well. We just
+ * have to reprogram the 8259's, and it isn't fun.
+ */
+
+ outb(0x11, 0x20); /* initialization sequence to 8259A-1 */
+ outb(0x11, 0xA0); /* and to 8259A-2 */
+
+ outb(0x20, 0x21); /* start of hardware int's (0x20) */
+ outb(0x28, 0xA1); /* start of hardware int's 2 (0x28) */
+
+ outb(0x04, 0x21); /* 8259-1 is master */
+ outb(0x02, 0xA1); /* 8259-2 is slave */
+
+ outb(0x01, 0x21); /* 8086 mode for both */
+ outb(0x01, 0xA1);
+
+ outb(0xFF, 0xA1); /* mask off all interrupts for now */
+ outb(0xFB, 0x21); /* mask all irq's but irq2 which is cascaded */
+}
+
+/* Start Linux */
+static int start_linux(uint32_t kern_addr, struct linux_params *params)
+{
+ struct segment_desc *linux_gdt;
+ struct context *ctx;
+ //extern int cursor_x, cursor_y;
+
+ ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0);
+
+ /* Linux expects GDT being in low memory */
+ linux_gdt = phys_to_virt(GDT_LOC);
+ memset(linux_gdt, 0, 13*sizeof(struct segment_desc));
+ /* Normal kernel code/data segments */
+ linux_gdt[2] = gdt[FLAT_CODE];
+ linux_gdt[3] = gdt[FLAT_DATA];
+ /* 2.6 kernel uses 12 and 13, but head.S uses backward-compatible
+ * segments (2 and 3), so it SHOULD not be a problem.
+ * However, some distro kernels (eg. RH9) with backported threading
+ * patch use 12 and 13 also when booting... */
+ linux_gdt[12] = gdt[FLAT_CODE];
+ linux_gdt[13] = gdt[FLAT_DATA];
+ ctx->gdt_base = GDT_LOC;
+ ctx->gdt_limit = 14*8-1;
+ ctx->cs = 0x10;
+ ctx->ds = 0x18;
+ ctx->es = 0x18;
+ ctx->fs = 0x18;
+ ctx->gs = 0x18;
+ ctx->ss = 0x18;
+
+ /* Parameter location */
+ ctx->esi = virt_to_phys(params);
+
+ /* Entry point */
+ ctx->eip = kern_addr;
+
+ debug("eip=%#x\n", kern_addr);
+ printf("Jumping to entry point...\n");
+
+#ifdef VGA_CONSOLE
+ /* Update VGA cursor position.
+ * This must be here because the printf changes the value! */
+ params->orig_x = cursor_x;
+ params->orig_y = cursor_y;
+#endif
+
+ /* Go... */
+ ctx = switch_to(ctx);
+
+ /* It's impossible but... */
+ printf("Returned with eax=%#x\n", ctx->eax);
+
+ return ctx->eax;
+}
+
+int linux_load(struct sys_info *info, const char *file, const char *cmdline)
+{
+ struct linux_header hdr;
+ struct linux_params *params;
+ uint32_t kern_addr, kern_size;
+ char *initrd_file = 0;
+
+ if (!file_open(file))
+ return -1;
+
+ kern_addr = load_linux_header(&hdr);
+ if (kern_addr == 0)
+ return LOADER_NOT_SUPPORT;
+
+ params = phys_to_virt(LINUX_PARAM_LOC);
+ init_linux_params(params, &hdr);
+ set_memory_size(params, info);
+ initrd_file = parse_command_line(cmdline, phys_to_virt(COMMAND_LINE_LOC));
+ set_command_line_loc(params, &hdr);
+
+ kern_size = load_linux_kernel(&hdr, kern_addr);
+ if (kern_size == 0) {
+ if (initrd_file)
+ free(initrd_file);
+ return -1;
+ }
+
+ if (initrd_file) {
+ if (load_initrd(&hdr, info, kern_addr+kern_size, params, initrd_file)
+ != 0) {
+ free(initrd_file);
+ return -1;
+ }
+ free(initrd_file);
+ }
+
+ hardware_setup();
+
+ start_linux(kern_addr, params);
+ return 0;
+}
diff --git a/qemu/roms/openbios/arch/amd64/multiboot.c b/qemu/roms/openbios/arch/amd64/multiboot.c
new file mode 100644
index 000000000..4271bd52b
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/multiboot.c
@@ -0,0 +1,125 @@
+/* Support for Multiboot */
+
+#include "config.h"
+#include "asm/io.h"
+#include "libopenbios/sys_info.h"
+#include "multiboot.h"
+
+#define printf printk
+#ifdef CONFIG_DEBUG_BOOT
+#define debug printk
+#else
+#define debug(x...)
+#endif
+
+struct mbheader {
+ unsigned int magic, flags, checksum;
+};
+const struct mbheader multiboot_header
+ __attribute__((section (".hdr"))) =
+{
+ MULTIBOOT_HEADER_MAGIC,
+ MULTIBOOT_HEADER_FLAGS,
+ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+};
+
+/* Multiboot information structure, provided by loader to us */
+
+struct multiboot_mmap {
+ unsigned entry_size;
+ unsigned base_lo, base_hi;
+ unsigned size_lo, size_hi;
+ unsigned type;
+};
+
+#define MULTIBOOT_MEM_VALID 0x01
+#define MULTIBOOT_BOOT_DEV_VALID 0x02
+#define MULTIBOOT_CMDLINE_VALID 0x04
+#define MULTIBOOT_MODS_VALID 0x08
+#define MULTIBOOT_AOUT_SYMS_VALID 0x10
+#define MULTIBOOT_ELF_SYMS_VALID 0x20
+#define MULTIBOOT_MMAP_VALID 0x40
+
+void collect_multiboot_info(struct sys_info *info);
+void collect_multiboot_info(struct sys_info *info)
+{
+ struct multiboot_info *mbinfo;
+ struct multiboot_mmap *mbmem;
+ unsigned mbcount, mbaddr;
+ int i;
+ struct memrange *mmap;
+ int mmap_count;
+ module_t *mod;
+
+ if (info->boot_type != 0x2BADB002)
+ return;
+
+ debug("Using Multiboot information at %#lx\n", info->boot_data);
+
+ mbinfo = phys_to_virt(info->boot_data);
+
+ if (mbinfo->mods_count != 1) {
+ printf("Multiboot: no dictionary\n");
+ return;
+ }
+
+ mod = (module_t *) mbinfo->mods_addr;
+ info->dict_start=(unsigned long *)mod->mod_start;
+ info->dict_end=(unsigned long *)mod->mod_end;
+
+ if (mbinfo->flags & MULTIBOOT_MMAP_VALID) {
+ /* convert mmap records */
+ mbmem = phys_to_virt(mbinfo->mmap_addr);
+ mbcount = mbinfo->mmap_length / (mbmem->entry_size + 4);
+ mmap = malloc(mbcount * sizeof(struct memrange));
+ mmap_count = 0;
+ mbaddr = mbinfo->mmap_addr;
+ for (i = 0; i < mbcount; i++) {
+ mbmem = phys_to_virt(mbaddr);
+ debug("%08x%08x %08x%08x (%d)\n",
+ mbmem->base_hi,
+ mbmem->base_lo,
+ mbmem->size_hi,
+ mbmem->size_lo,
+ mbmem->type);
+ if (mbmem->type == 1) { /* Only normal RAM */
+ mmap[mmap_count].base = mbmem->base_lo
+ + (((unsigned long long) mbmem->base_hi) << 32);
+ mmap[mmap_count].size = mbmem->size_lo
+ + (((unsigned long long) mbmem->size_hi) << 32);
+ mmap_count++;
+ }
+ mbaddr += mbmem->entry_size + 4;
+ if (mbaddr >= mbinfo->mmap_addr + mbinfo->mmap_length)
+ break;
+ }
+ /* simple sanity check - there should be at least 2 RAM segments
+ * (base 640k and extended) */
+ if (mmap_count >= 2)
+ goto got_it;
+
+ printf("Multiboot mmap is broken\n");
+ free(mmap);
+ /* fall back to mem_lower/mem_upper */
+ }
+
+ if (mbinfo->flags & MULTIBOOT_MEM_VALID) {
+ /* use mem_lower and mem_upper */
+ mmap_count = 2;
+ mmap = malloc(2 * sizeof(*mmap));
+ mmap[0].base = 0;
+ mmap[0].size = mbinfo->mem_lower << 10;
+ mmap[1].base = 1 << 20; /* 1MB */
+ mmap[1].size = mbinfo->mem_upper << 10;
+ goto got_it;
+ }
+
+ printf("Can't get memory information from Multiboot\n");
+ return;
+
+got_it:
+ info->memrange = mmap;
+ info->n_memranges = mmap_count;
+
+ return;
+}
diff --git a/qemu/roms/openbios/arch/amd64/multiboot.h b/qemu/roms/openbios/arch/amd64/multiboot.h
new file mode 100644
index 000000000..17cf202ec
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/multiboot.h
@@ -0,0 +1,96 @@
+/* multiboot.h
+ * tag: header for multiboot
+ *
+ * Copyright (C) 2003-2004 Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+/* magic number for multiboot header */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/* flags for multiboot header */
+#define MULTIBOOT_HEADER_FLAGS 0x00010003
+
+/* magic number passed by multiboot-compliant boot loader. */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+/* The size of our stack (8KB). */
+#define STACK_SIZE 0x2000
+
+/* C symbol format. HAVE_ASM_USCORE is defined by configure. */
+#ifdef HAVE_ASM_USCORE
+# define EXT_C(sym) _ ## sym
+#else
+# define EXT_C(sym) sym
+#endif
+
+#ifndef ASM
+/* We don't want these declarations in boot.S */
+
+/* multiboot header */
+typedef struct multiboot_header {
+ unsigned long magic;
+ unsigned long flags;
+ unsigned long checksum;
+ unsigned long header_addr;
+ unsigned long load_addr;
+ unsigned long load_end_addr;
+ unsigned long bss_end_addr;
+ unsigned long entry_addr;
+} multiboot_header_t;
+
+/* symbol table for a.out */
+typedef struct aout_symbol_table {
+ unsigned long tabsize;
+ unsigned long strsize;
+ unsigned long addr;
+ unsigned long reserved;
+} aout_symbol_table_t;
+
+/* section header table for ELF */
+typedef struct elf_section_header_table {
+ unsigned long num;
+ unsigned long size;
+ unsigned long addr;
+ unsigned long shndx;
+} elf_section_header_table_t;
+
+/* multiboot information */
+typedef struct multiboot_info {
+ unsigned long flags;
+ unsigned long mem_lower;
+ unsigned long mem_upper;
+ unsigned long boot_device;
+ unsigned long cmdline;
+ unsigned long mods_count;
+ unsigned long mods_addr;
+ union {
+ aout_symbol_table_t aout_sym;
+ elf_section_header_table_t elf_sec;
+ } u;
+ unsigned long mmap_length;
+ unsigned long mmap_addr;
+} multiboot_info_t;
+
+/* module structure */
+typedef struct module {
+ unsigned long mod_start;
+ unsigned long mod_end;
+ unsigned long string;
+ unsigned long reserved;
+} module_t;
+
+/* memory map. Be careful that the offset 0 is base_addr_low
+ but no size. */
+typedef struct memory_map {
+ unsigned long size;
+ unsigned long base_addr_low;
+ unsigned long base_addr_high;
+ unsigned long length_low;
+ unsigned long length_high;
+ unsigned long type;
+} memory_map_t;
+
+#endif /* ! ASM */
diff --git a/qemu/roms/openbios/arch/amd64/openbios.c b/qemu/roms/openbios/arch/amd64/openbios.c
new file mode 100644
index 000000000..15d3b6254
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/openbios.c
@@ -0,0 +1,108 @@
+/* tag: openbios forth environment, executable code
+ *
+ * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+#include "config.h"
+#include "libopenbios/openbios.h"
+#include "libopenbios/bindings.h"
+#include "asm/types.h"
+#include "dict.h"
+#include "kernel/kernel.h"
+#include "kernel/stack.h"
+#include "libopenbios/sys_info.h"
+#include "openbios.h"
+#include "relocate.h"
+
+void boot(void);
+
+#define DICTIONARY_SIZE (256*1024) /* 256K for the dictionary */
+static char intdict[DICTIONARY_SIZE];
+
+static void init_memory(void)
+{
+ /* push start and end of available memory to the stack
+ * so that the forth word QUIT can initialize memory
+ * management. For now we use hardcoded memory between
+ * 0x10000 and 0x9ffff (576k). If we need more memory
+ * than that we have serious bloat.
+ */
+
+ PUSH(0x10000);
+ PUSH(0x9FFFF);
+}
+
+static void
+arch_init( void )
+{
+ void setup_timers(void);
+
+ openbios_init();
+ modules_init();
+#ifdef CONFIG_DRIVER_IDE
+ setup_timers();
+ ob_ide_init("/pci/pci-ata", 0x1f0, 0x3f6, 0x170, 0x376);
+#endif
+ device_end();
+ bind_func("platform-boot", boot );
+}
+
+extern struct _console_ops arch_console_ops;
+
+int openbios(void)
+{
+#ifdef CONFIG_DEBUG_CONSOLE
+ init_console(arch_console_ops);
+#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
+ uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED);
+#endif
+ /* Clear the screen. */
+ cls();
+#endif
+
+ collect_sys_info(&sys_info);
+
+ dict=intdict;
+ dictlimit = DICTIONARY_SIZE;
+
+ load_dictionary((char *)sys_info.dict_start,
+ sys_info.dict_end-sys_info.dict_start);
+ forth_init();
+
+ relocate(&sys_info);
+
+#ifdef CONFIG_DEBUG_CONSOLE
+ video_init();
+#endif
+#ifdef CONFIG_DEBUG_BOOT
+ printk("forth started.\n");
+ printk("initializing memory...");
+#endif
+
+ init_memory();
+
+#ifdef CONFIG_DEBUG_BOOT
+ printk("done\n");
+#endif
+
+ PUSH_xt( bind_noname_func(arch_init) );
+ fword("PREPOST-initializer");
+
+ PC = (ucell)findword("initialize-of");
+
+ if (!PC) {
+ printk("panic: no dictionary entry point.\n");
+ return -1;
+ }
+#ifdef CONFIG_DEBUG_DICTIONARY
+ printk("done (%d bytes).\n", dicthead);
+ printk("Jumping to dictionary...\n");
+#endif
+
+ enterforth((xt_t)PC);
+
+ return 0;
+}
diff --git a/qemu/roms/openbios/arch/amd64/openbios.h b/qemu/roms/openbios/arch/amd64/openbios.h
new file mode 100644
index 000000000..2d49dbf54
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/openbios.h
@@ -0,0 +1,29 @@
+/*
+ * Creation Date: <2004/01/15 16:14:05 samuel>
+ * Time-stamp: <2004/01/15 16:14:05 samuel>
+ *
+ * <openbios.h>
+ *
+ *
+ *
+ * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+#ifndef _H_OPENBIOS
+#define _H_OPENBIOS
+
+int openbios(void);
+
+/* console.c */
+extern void cls(void);
+#ifdef CONFIG_DEBUG_CONSOLE
+extern int uart_init(int port, unsigned long speed);
+extern void video_init(void);
+#endif
+
+#endif /* _H_OPENBIOS */
diff --git a/qemu/roms/openbios/arch/amd64/plainboot.c b/qemu/roms/openbios/arch/amd64/plainboot.c
new file mode 100644
index 000000000..08dab2d12
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/plainboot.c
@@ -0,0 +1,21 @@
+/* tag: openbios fixed address forth starter
+ *
+ * Copyright (C) 2003 Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+#include "config.h"
+#include "libopenbios/sys_info.h"
+#include "multiboot.h"
+
+#define FIXED_DICTSTART 0xfffe0000
+#define FIXED_DICTEND 0xfffeffff
+
+void collect_multiboot_info(struct sys_info *info);
+void collect_multiboot_info(struct sys_info *info)
+{
+ info->dict_start=(unsigned long *)FIXED_DICTSTART;
+ info->dict_end=(unsigned long *)FIXED_DICTEND;
+}
diff --git a/qemu/roms/openbios/arch/amd64/relocate.h b/qemu/roms/openbios/arch/amd64/relocate.h
new file mode 100644
index 000000000..d91160a03
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/relocate.h
@@ -0,0 +1 @@
+void relocate(struct sys_info *);
diff --git a/qemu/roms/openbios/arch/amd64/segment.c b/qemu/roms/openbios/arch/amd64/segment.c
new file mode 100644
index 000000000..09763bd14
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/segment.c
@@ -0,0 +1,134 @@
+/* Segmentation of the AMD64 architecture.
+ *
+ * 2003-07 by SONE Takeshi
+ */
+
+#include "config.h"
+#include "kernel/kernel.h"
+#include "libopenbios/sys_info.h"
+#include "relocate.h"
+#include "segment.h"
+
+#define printf printk
+#ifdef CONFIG_DEBUG_BOOT
+#define debug printk
+#else
+#define debug(x...)
+#endif
+
+/* i386 lgdt argument */
+struct gdtarg {
+ unsigned short limit;
+ unsigned int base;
+} __attribute__((packed));
+
+/* How far the virtual address (used in C) is different from physical
+ * address. Since we start in flat mode, the initial value is zero. */
+unsigned long virt_offset = 0;
+
+/* GDT, the global descriptor table */
+struct segment_desc gdt[NUM_SEG] = {
+ /* 0x00: null segment */
+ {0, 0, 0, 0, 0, 0},
+ /* 0x08: flat code segment */
+ {0xffff, 0, 0, 0x9f, 0xcf, 0},
+ /* 0x10: flat data segment */
+ {0xffff, 0, 0, 0x93, 0xcf, 0},
+ /* 0x18: code segment for relocated execution */
+ {0xffff, 0, 0, 0x9f, 0xcf, 0},
+ /* 0x20: data segment for relocated execution */
+ {0xffff, 0, 0, 0x93, 0xcf, 0},
+};
+
+extern char _start[], _end[];
+
+void relocate(struct sys_info *info)
+{
+ int i;
+ unsigned long prog_addr;
+ unsigned long prog_size;
+ unsigned long addr, new_base;
+ unsigned long long segsize;
+ unsigned long new_offset;
+ unsigned d0, d1, d2;
+ struct gdtarg gdtarg;
+#define ALIGNMENT 16
+
+ prog_addr = virt_to_phys(&_start);
+ prog_size = virt_to_phys(&_end) - virt_to_phys(&_start);
+ debug("Current location: %#lx-%#lx\n", prog_addr, prog_addr+prog_size-1);
+
+ new_base = 0;
+ for (i = 0; i < info->n_memranges; i++) {
+ if (info->memrange[i].base >= 1ULL<<32)
+ continue;
+ segsize = info->memrange[i].size;
+ if (info->memrange[i].base + segsize > 1ULL<<32)
+ segsize = (1ULL<<32) - info->memrange[i].base;
+ if (segsize < prog_size+ALIGNMENT)
+ continue;
+ addr = info->memrange[i].base + segsize - prog_size;
+ addr &= ~(ALIGNMENT-1);
+ if (addr >= prog_addr && addr < prog_addr + prog_size)
+ continue;
+ if (prog_addr >= addr && prog_addr < addr + prog_size)
+ continue;
+ if (addr > new_base)
+ new_base = addr;
+ }
+ if (new_base == 0) {
+ printf("Can't find address to relocate\n");
+ return;
+ }
+
+ debug("Relocating to %#lx-%#lx... ",
+ new_base, new_base + prog_size - 1);
+
+ /* New virtual address offset */
+ new_offset = new_base - (unsigned long) &_start;
+
+ /* Tweak the GDT */
+ gdt[RELOC_CODE].base_0 = (unsigned short) new_offset;
+ gdt[RELOC_CODE].base_16 = (unsigned char) (new_offset>>16);
+ gdt[RELOC_CODE].base_24 = (unsigned char) (new_offset>>24);
+ gdt[RELOC_DATA].base_0 = (unsigned short) new_offset;
+ gdt[RELOC_DATA].base_16 = (unsigned char) (new_offset>>16);
+ gdt[RELOC_DATA].base_24 = (unsigned char) (new_offset>>24);
+
+ /* Load new GDT and reload segments */
+ gdtarg.base = new_offset + (unsigned long) gdt;
+ gdtarg.limit = GDT_LIMIT;
+ __asm__ __volatile__ (
+ "rep; movsb\n\t" /* copy everything */
+ "lgdt %3\n\t"
+ "ljmp %4, $1f\n1:\t"
+ "movw %5, %%ds\n\t"
+ "movw %5, %%es\n\t"
+ "movw %5, %%fs\n\t"
+ "movw %5, %%gs\n\t"
+ "movw %5, %%ss\n"
+ : "=&S" (d0), "=&D" (d1), "=&c" (d2)
+ : "m" (gdtarg), "n" (RELOC_CS), "q" ((unsigned short) RELOC_DS),
+ "0" (&_start), "1" (new_base), "2" (prog_size));
+
+ virt_offset = new_offset;
+ debug("ok\n");
+}
+
+#if 0
+/* Copy GDT to new location and reload it */
+void move_gdt(unsigned long newgdt)
+{
+ struct gdtarg gdtarg;
+
+ debug("Moving GDT to %#lx...", newgdt);
+ memcpy(phys_to_virt(newgdt), gdt, sizeof gdt);
+ gdtarg.base = newgdt;
+ gdtarg.limit = GDT_LIMIT;
+ debug("reloading GDT...");
+ __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg));
+ debug("reloading CS for fun...");
+ __asm__ __volatile__ ("ljmp %0, $1f\n1:" : : "n" (RELOC_CS));
+ debug("ok\n");
+}
+#endif
diff --git a/qemu/roms/openbios/arch/amd64/segment.h b/qemu/roms/openbios/arch/amd64/segment.h
new file mode 100644
index 000000000..0371a80ae
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/segment.h
@@ -0,0 +1,30 @@
+
+/* Segment indexes. Must match the gdt definition in segment.c. */
+enum {
+ NULL_SEG,
+ FLAT_CODE,
+ FLAT_DATA,
+ RELOC_CODE,
+ RELOC_DATA,
+ NUM_SEG,
+};
+
+/* Values for segment selector register */
+#define FLAT_CS (FLAT_CODE << 3)
+#define FLAT_DS (FLAT_DATA << 3)
+#define RELOC_CS (RELOC_CODE << 3)
+#define RELOC_DS (RELOC_DATA << 3)
+
+/* i386 segment descriptor */
+struct segment_desc {
+ unsigned short limit_0;
+ unsigned short base_0;
+ unsigned char base_16;
+ unsigned char types;
+ unsigned char flags;
+ unsigned char base_24;
+};
+
+extern struct segment_desc gdt[NUM_SEG];
+
+#define GDT_LIMIT ((NUM_SEG << 3) - 1)
diff --git a/qemu/roms/openbios/arch/amd64/switch.S b/qemu/roms/openbios/arch/amd64/switch.S
new file mode 100644
index 000000000..66668150d
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/switch.S
@@ -0,0 +1,116 @@
+ .globl entry, __switch_context, __exit_context, halt
+
+ .text
+ .align 4
+
+/*
+ * Entry point
+ * We start execution from here.
+ * It is assumed that CPU is in 32-bit protected mode and
+ * all segments are 4GB and base zero (flat model).
+ */
+entry:
+ /* Save boot context and switch to our main context.
+ * Main context is statically defined in C.
+ */
+ pushl %cs
+ call __switch_context
+
+ /* We get here when the main context switches back to
+ * the boot context.
+ * Return to previous bootloader.
+ */
+ ret
+
+/*
+ * Switch execution context
+ * This saves registers, segments, and GDT in the stack, then
+ * switches the stack, and restores everything from the new stack.
+ * This function takes no argument. New stack pointer is
+ * taken from global variable __context, and old stack pointer
+ * is also saved to __context. This way we can just jump to
+ * this routine to get back to the original context.
+ *
+ * Call this routine with lcall or pushl %cs; call.
+ */
+__switch_context:
+ /* Save everything in current stack */
+ pushfl /* 56 */
+ pushl %ds /* 52 */
+ pushl %es /* 48 */
+ pushl %fs /* 44 */
+ pushl %gs /* 40 */
+ pushal /* 8 */
+ subl $8, %esp
+ movw %ss, (%esp) /* 0 */
+ sgdt 2(%esp) /* 2 */
+
+#if 0
+ /* Swap %cs and %eip on the stack, so lret will work */
+ movl 60(%esp), %eax
+ xchgl %eax, 64(%esp)
+ movl %eax, 60(%esp)
+#endif
+
+ /* At this point we don't know if we are on flat segment
+ * or relocated. So compute the address offset from %eip.
+ * Assuming CS.base==DS.base==SS.base.
+ */
+ call 1f
+1: popl %ebx
+ subl $1b, %ebx
+
+ /* Interrupts are not allowed... */
+ cli
+
+ /* Current context pointer is our stack pointer */
+ movl %esp, %esi
+
+ /* Normalize the ctx pointer */
+ subl %ebx, %esi
+
+ /* Swap it with new value */
+ xchgl %esi, __context(%ebx)
+
+ /* Adjust new ctx pointer for current address offset */
+ addl %ebx, %esi
+
+ /* Load new %ss and %esp to temporary */
+ movzwl (%esi), %edx
+ movl 20(%esi), %eax
+
+ /* Load new GDT */
+ lgdt 2(%esi)
+
+ /* Load new stack segment with new GDT */
+ movl %edx, %ss
+
+ /* Set new stack pointer, but we have to adjust it because
+ * pushal saves %esp value before pushal, and we want the value
+ * after pushal.
+ */
+ leal -32(%eax), %esp
+
+ /* Load the rest from new stack */
+ popal
+ popl %gs
+ popl %fs
+ popl %es
+ popl %ds
+ popfl
+
+ /* Finally, load new %cs and %eip */
+ lret
+
+__exit_context:
+ /* Get back to the original context */
+ pushl %cs
+ call __switch_context
+
+ /* We get here if the other context attempt to switch to this
+ * dead context. This should not happen. */
+
+halt:
+ cli
+ hlt
+ jmp halt
diff --git a/qemu/roms/openbios/arch/amd64/sys_info.c b/qemu/roms/openbios/arch/amd64/sys_info.c
new file mode 100644
index 000000000..d62070be0
--- /dev/null
+++ b/qemu/roms/openbios/arch/amd64/sys_info.c
@@ -0,0 +1,58 @@
+#include "config.h"
+#include "kernel/kernel.h"
+#include "libopenbios/sys_info.h"
+#include "context.h"
+
+#define printf printk
+#ifdef CONFIG_DEBUG_BOOT
+#define debug printk
+#else
+#define debug(x...)
+#endif
+
+void collect_multiboot_info(struct sys_info *);
+void collect_sys_info(struct sys_info *info);
+
+void collect_sys_info(struct sys_info *info)
+{
+ int i;
+ unsigned long long total = 0;
+ struct memrange *mmap;
+
+ /* Pick up paramters given by bootloader to us */
+ info->boot_type = boot_ctx->eax;
+ info->boot_data = boot_ctx->ebx;
+ info->boot_arg = boot_ctx->param[0];
+ debug("boot eax = %#lx\n", info->boot_type);
+ debug("boot ebx = %#lx\n", info->boot_data);
+ debug("boot arg = %#lx\n", info->boot_arg);
+
+ collect_elfboot_info(info);
+#ifdef CONFIG_LINUXBIOS
+ collect_linuxbios_info(info);
+#endif
+#ifdef CONFIG_IMAGE_ELF_MULTIBOOT
+ collect_multiboot_info(info);
+#endif
+
+ if (!info->memrange) {
+ printf("Can't get memory map from firmware. "
+ "Using hardcoded default.\n");
+ info->n_memranges = 2;
+ info->memrange = malloc(2 * sizeof(struct memrange));
+ info->memrange[0].base = 0;
+ info->memrange[0].size = 640*1024;
+ info->memrange[1].base = 1024*1024;
+ info->memrange[1].size = 32*1024*1024
+ - info->memrange[1].base;
+ }
+
+ debug("\n");
+ mmap=info->memrange;
+ for (i = 0; i < info->n_memranges; i++) {
+ debug("%016Lx-", mmap[i].base);
+ debug("%016Lx\n", mmap[i].base+mmap[i].size);
+ total += mmap[i].size;
+ }
+ debug("RAM %Ld MB\n", (total + 512*1024) >> 20);
+}