diff options
Diffstat (limited to 'roms/openbios/arch/amd64')
22 files changed, 2351 insertions, 0 deletions
diff --git a/roms/openbios/arch/amd64/Kconfig b/roms/openbios/arch/amd64/Kconfig new file mode 100644 index 00000000..f1f677db --- /dev/null +++ b/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/roms/openbios/arch/amd64/boot.c b/roms/openbios/arch/amd64/boot.c new file mode 100644 index 00000000..0e1fe7ef --- /dev/null +++ b/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/roms/openbios/arch/amd64/build.xml b/roms/openbios/arch/amd64/build.xml new file mode 100644 index 00000000..8f436d00 --- /dev/null +++ b/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/roms/openbios/arch/amd64/builtin.c b/roms/openbios/arch/amd64/builtin.c new file mode 100644 index 00000000..93ced0ae --- /dev/null +++ b/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/roms/openbios/arch/amd64/console.c b/roms/openbios/arch/amd64/console.c new file mode 100644 index 00000000..71a22b68 --- /dev/null +++ b/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/roms/openbios/arch/amd64/context.c b/roms/openbios/arch/amd64/context.c new file mode 100644 index 00000000..2e4df6a3 --- /dev/null +++ b/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/roms/openbios/arch/amd64/context.h b/roms/openbios/arch/amd64/context.h new file mode 100644 index 00000000..4c3832ef --- /dev/null +++ b/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/roms/openbios/arch/amd64/defconfig b/roms/openbios/arch/amd64/defconfig new file mode 100644 index 00000000..570a6c86 --- /dev/null +++ b/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/roms/openbios/arch/amd64/init.fs b/roms/openbios/arch/amd64/init.fs new file mode 100644 index 00000000..fda3acdc --- /dev/null +++ b/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/roms/openbios/arch/amd64/ldscript b/roms/openbios/arch/amd64/ldscript new file mode 100644 index 00000000..8976c7af --- /dev/null +++ b/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/roms/openbios/arch/amd64/lib.c b/roms/openbios/arch/amd64/lib.c new file mode 100644 index 00000000..f04458e1 --- /dev/null +++ b/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/roms/openbios/arch/amd64/linux_load.c b/roms/openbios/arch/amd64/linux_load.c new file mode 100644 index 00000000..f1ed98df --- /dev/null +++ b/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/roms/openbios/arch/amd64/multiboot.c b/roms/openbios/arch/amd64/multiboot.c new file mode 100644 index 00000000..4271bd52 --- /dev/null +++ b/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/roms/openbios/arch/amd64/multiboot.h b/roms/openbios/arch/amd64/multiboot.h new file mode 100644 index 00000000..17cf202e --- /dev/null +++ b/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/roms/openbios/arch/amd64/openbios.c b/roms/openbios/arch/amd64/openbios.c new file mode 100644 index 00000000..15d3b625 --- /dev/null +++ b/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/roms/openbios/arch/amd64/openbios.h b/roms/openbios/arch/amd64/openbios.h new file mode 100644 index 00000000..2d49dbf5 --- /dev/null +++ b/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/roms/openbios/arch/amd64/plainboot.c b/roms/openbios/arch/amd64/plainboot.c new file mode 100644 index 00000000..08dab2d1 --- /dev/null +++ b/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/roms/openbios/arch/amd64/relocate.h b/roms/openbios/arch/amd64/relocate.h new file mode 100644 index 00000000..d91160a0 --- /dev/null +++ b/roms/openbios/arch/amd64/relocate.h @@ -0,0 +1 @@ +void relocate(struct sys_info *); diff --git a/roms/openbios/arch/amd64/segment.c b/roms/openbios/arch/amd64/segment.c new file mode 100644 index 00000000..09763bd1 --- /dev/null +++ b/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/roms/openbios/arch/amd64/segment.h b/roms/openbios/arch/amd64/segment.h new file mode 100644 index 00000000..0371a80a --- /dev/null +++ b/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/roms/openbios/arch/amd64/switch.S b/roms/openbios/arch/amd64/switch.S new file mode 100644 index 00000000..66668150 --- /dev/null +++ b/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/roms/openbios/arch/amd64/sys_info.c b/roms/openbios/arch/amd64/sys_info.c new file mode 100644 index 00000000..d62070be --- /dev/null +++ b/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); +}  | 
