Patrick Georgi (patrick@georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2057
-gerrit
commit 16d77debbf4a46d10e1e8abd105c8d5e6de9ebd9 Author: Patrick Georgi patrick@georgi-clan.de Date: Wed Dec 19 13:55:00 2012 +0100
Rename i386 to x86, in accordance with libpayload
Change-Id: Idd2239832f35d74d2034dd8b271ab36a7f82e096 Signed-off-by: Patrick Georgi patrick@georgi-clan.de --- Makefile | 2 +- i386/Makefile.inc | 23 -- i386/artecboot.c | 159 --------- i386/context.c | 135 ------- i386/context.h | 65 ---- i386/include/arch/byteorder.h | 64 ---- i386/include/arch/elf.h | 5 - i386/include/arch/eltorito.h | 3 - i386/include/arch/timer.h | 32 -- i386/ldscript | 93 ----- i386/linux_load.c | 803 ------------------------------------------ i386/segment.c | 135 ------- i386/segment.h | 47 --- i386/switch.S | 116 ------ i386/sys_info.c | 34 -- i386/timer.c | 38 -- i386/wince_load.c | 385 -------------------- x86/Makefile.inc | 23 ++ x86/artecboot.c | 159 +++++++++ x86/context.c | 135 +++++++ x86/context.h | 65 ++++ x86/include/arch/byteorder.h | 64 ++++ x86/include/arch/elf.h | 5 + x86/include/arch/eltorito.h | 3 + x86/include/arch/timer.h | 32 ++ x86/ldscript | 93 +++++ x86/linux_load.c | 803 ++++++++++++++++++++++++++++++++++++++++++ x86/segment.c | 135 +++++++ x86/segment.h | 47 +++ x86/switch.S | 116 ++++++ x86/sys_info.c | 34 ++ x86/timer.c | 38 ++ x86/wince_load.c | 385 ++++++++++++++++++++ 33 files changed, 2138 insertions(+), 2138 deletions(-)
diff --git a/Makefile b/Makefile index 20b21bf..46010b3 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ INCPAYLOAD = $(LIBPAYLOAD_PREFIX)/include LIBGCC = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) GCCINCDIR = $(shell $(CC) -print-search-dirs | head -n 1 | cut -d' ' -f2)include
-ARCHDIR-$(CONFIG_TARGET_I386) := i386 +ARCHDIR-$(CONFIG_TARGET_I386) := x86
CPPFLAGS := -nostdinc -imacros $(obj)/config.h CPPFLAGS += -I$(INCPAYLOAD) -I$(INCPAYLOAD)/$(ARCHDIR-y) diff --git a/i386/Makefile.inc b/i386/Makefile.inc deleted file mode 100644 index ce3e5c8..0000000 --- a/i386/Makefile.inc +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (C) 2008 by coresystems GmbH -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -TARGETS-$(CONFIG_TARGET_I386) += i386/context.o i386/switch.S.o i386/segment.o -TARGETS-$(CONFIG_TARGET_I386) += i386/timer.o i386/sys_info.o -TARGETS-$(CONFIG_LINUX_LOADER) += i386/linux_load.o -TARGETS-$(CONFIG_WINCE_LOADER) += i386/wince_load.o -TARGETS-$(CONFIG_ARTEC_BOOT) += i386/artecboot.o diff --git a/i386/artecboot.c b/i386/artecboot.c deleted file mode 100644 index 697a05b..0000000 --- a/i386/artecboot.c +++ /dev/null @@ -1,159 +0,0 @@ -/******************************************************************************* - * - * FILO Artecboot loader, enables multiboot through custom header - * - * Copyright 2006 Andrei Birjukov andrei.birjukov@artecdesign.ee and - * Artec Design LLC http://www.artecdesign.ee - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ******************************************************************************/ - -#include <libpayload.h> -#include <config.h> -#include <fs.h> -#include "artecboot.h" -#include "../fs/filesys.h" - -#define DEBUG_THIS CONFIG_DEBUG_ARTECBOOT -#include <debug.h> - -static ARTECBOOT_HEADER bootHdr; - -int artecboot_load(const char *file, const char *cmdline) -{ - int i; - - printf("Starting the Artecboot loader...\n"); - // clear the boot header - memset(&bootHdr, 0, sizeof(bootHdr)); - - // try opening the boot parameter file - if (!file_open(file)) - { - printf("Boot error: failed to open image file: %s\n", file); - return LOADER_NOT_SUPPORT; - } - - file_seek(0); // seek to the beginning of the parameter file - - // now read out the boot header - if(file_read(&bootHdr, sizeof(ARTECBOOT_HEADER)) != sizeof(ARTECBOOT_HEADER)) - { - printf("Boot error: failed reading the boot image header\n"); - file_close(); - return LOADER_NOT_SUPPORT; - } - - // check whether the parameter data is valid at all - if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC) - { - debug("No Artecboot signature found, aborting\n"); - file_close(); - return LOADER_NOT_SUPPORT; - } - - // check the version number - if(bootHdr.bootVersion > CURRENT_VERSION) - { - printf("Boot error: incompatible version number: %x\n", bootHdr.bootVersion); - file_close(); - return LOADER_NOT_SUPPORT; - } - - // shall we replace the command line? - if(bootHdr.bitFlags & FLAG_CMDLINE) - { - // check the command line and wipe out all junk - for(i=0; bootHdr.cmdLine[i] != 0; i++) - switch(bootHdr.cmdLine[i]) - { - case '\n': - case '\r': - bootHdr.cmdLine[i] = ' '; - break; - default: - // do nothing - break; - } - } - else if(cmdline) - strncpy(bootHdr.cmdLine, cmdline, sizeof(bootHdr.cmdLine)); - - // proceed basing on the specified OS type - switch(bootHdr.osType) - { - case OS_LINUX: - if(bootHdr.bitFlags & FLAG_INITRD) - { - char initrdParam[100]; - if(bootHdr.bitFlags & FLAG_FILESYSTEM) - { - // we are using a real filesystem, so format the initrd file as usually - sprintf(initrdParam, " initrd=%s", bootHdr.initrdFile); - } - else - { - // we are using a 'fake' filesystem, so use the image offset - sprintf(initrdParam, " initrd=%s@0x%x,0x%x", - dev_name, bootHdr.initrdStart, bootHdr.initrdSize); - } - - debug("adding initrd parameter: %s\n", initrdParam); - strncat(bootHdr.cmdLine, initrdParam, sizeof(bootHdr.cmdLine)); - } - - printf("Starting Linux loader...\n"); - - // if using a real filesystem, load the kernel image from a specified file - if(bootHdr.bitFlags & FLAG_FILESYSTEM) - linux_load(bootHdr.kernelFile, bootHdr.cmdLine); - // if using a 'fake' filesystem, consider reading from the same image - else - { - part_start = bootHdr.kernelStart >> DEV_SECTOR_BITS; - part_length = ((bootHdr.kernelSize-1) >> DEV_SECTOR_BITS) + 1; - filemax = bootHdr.kernelSize; - using_devsize = 0; - linux_load(file, bootHdr.cmdLine); - } - - break; - - case OS_WINCE: - - printf("Starting Windows CE loader...\n"); - // if using a real filesystem, load the kernel image from a specified file - if(bootHdr.bitFlags & FLAG_FILESYSTEM) - wince_load(bootHdr.kernelFile, bootHdr.cmdLine); - // if using a 'fake' filesystem, consider reading from the same image - else - { - part_start = bootHdr.kernelStart >> DEV_SECTOR_BITS; - part_length = ((bootHdr.kernelSize-1) >> DEV_SECTOR_BITS) + 1; - filemax = bootHdr.kernelSize; - wince_load(file, bootHdr.cmdLine); - } - - break; - - default: - printf("Boot error: unknown OS type, aborting: %d\n", bootHdr.osType); - return LOADER_NOT_SUPPORT; - } - - file_close(); - return 0; -} diff --git a/i386/context.c b/i386/context.c deleted file mode 100644 index a06b97d..0000000 --- a/i386/context.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * This file is part of FILO. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -/* - * context switching - * 2003-10 by SONE Takeshi - */ - -#include <libpayload.h> -#include <lib.h> -#include "segment.h" -#include "context.h" - -#define MAIN_STACK_SIZE 16384 -#define IMAGE_STACK_SIZE 4096 - -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 = (u32) gdt, - .gdt_limit = GDT_LIMIT, - .cs = FLAT_CS, .ds = FLAT_DS, - .es = FLAT_DS, .fs = FLAT_DS, - .gs = FLAT_DS, .ss = FLAT_DS, - .esp = (u32)ESP_LOC(&main_ctx), - .eip = (u32) start_main, - .return_addr = (u32) __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 u8 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 main(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 = main(); - - /* 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(u8 * stack, u32 stack_size, int num_params) -{ - struct context *ctx; - - ctx = (struct context *) (stack + stack_size - - (sizeof(*ctx) + num_params * sizeof(u32))); - 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; - - save = __context; - __context = ctx; - asm volatile ("push %%cs; call __switch_context" ::: "memory"); - ret = __context; - __context = save; - return ret; -} - -/* Start ELF Boot image */ -u32 start_elf(u32 entry_point, u32 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/i386/context.h b/i386/context.h deleted file mode 100644 index 44e9665..0000000 --- a/i386/context.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of FILO. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#ifndef i386_CONTEXT_H -#define i386_CONTEXT_H - -struct context { - /* Stack Segment, placed here because of the alignment issue... */ - u16 ss; - /* Used with sgdt/lgdt */ - u16 gdt_limit; - u32 gdt_base; - /* General registers, accessed with pushal/popal */ - u32 edi; - u32 esi; - u32 ebp; - u32 esp; /* points just below eax */ - u32 ebx; - u32 edx; - u32 ecx; - u32 eax; -#define ESP_LOC(ctx) (&(ctx)->gs) - /* Segment registers */ - u32 gs; - u32 fs; - u32 es; - u32 ds; - /* Flags */ - u32 eflags; - /* Code segment:offset */ - u32 eip; - u32 cs; - /* Optional stack contents */ - u32 return_addr; - u32 param[0]; -}; - -/* Create a new context in the given stack */ -struct context *init_context(u8 * stack, u32 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 /* i386_CONTEXT_H */ diff --git a/i386/include/arch/byteorder.h b/i386/include/arch/byteorder.h deleted file mode 100644 index afaebfa..0000000 --- a/i386/include/arch/byteorder.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef ARCH_ENDIAN_H -#define ARCH_ENDIAN_H - -static inline u16 __i386_bswap_16(u16 x) -{ - __asm__("xchgb %b0,%h0\n\t" - : "=q" (x) - : "0" (x)); - return x; -} - -static inline u32 __i386_bswap_32(u32 x) -{ - __asm__("xchgb %b0,%h0\n\t" - "rorl $16,%0\n\t" - "xchgb %b0,%h0" - : "=q" (x) - : "0" (x)); - return x; -} - - -#define __bswap_constant_16(x) \ - ((u16)((((u16)(x) & 0x00ff) << 8) | \ - (((u16)(x) & 0xff00) >> 8))) - -#define __bswap_constant_32(x) \ - ((u32)((((u32)(x) & 0x000000ffU) << 24) | \ - (((u32)(x) & 0x0000ff00U) << 8) | \ - (((u32)(x) & 0x00ff0000U) >> 8) | \ - (((u32)(x) & 0xff000000U) >> 24))) - -#define __bswap_16(x) \ - ((u16)(__builtin_constant_p(x) ? \ - __bswap_constant_16(x) : \ - __i386_bswap_16(x))) - - -#define __bswap_32(x) \ - ((u32)(__builtin_constant_p(x) ? \ - __bswap_constant_32(x) : \ - __i386_bswap_32(x))) - - -#define __BYTE_ORDER __LITTLE_ENDIAN - -#define le32_to_cpup(x) (*(u32 *)(x)) -#define cpu_to_le16p(x) (*(u16*)(x)) - -#define ntohl(x) __bswap_32(x) -#define htonl(x) __bswap_32(x) -#define ntohs(x) __bswap_16(x) -#define htons(x) __bswap_16(x) -#define cpu_to_le32(x) (x) -#define cpu_to_le16(x) (x) -#define cpu_to_be32(x) __bswap_32(x) -#define cpu_to_be16(x) __bswap_16(x) -#define le32_to_cpu(x) (x) -#define le16_to_cpu(x) (x) -#define be32_to_cpu(x) __bswap_32(x) -#define be16_to_cpu(x) __bswap_16(x) - -#endif /* ARCH_ENDIAN_H */ - diff --git a/i386/include/arch/elf.h b/i386/include/arch/elf.h deleted file mode 100644 index 86c6725..0000000 --- a/i386/include/arch/elf.h +++ /dev/null @@ -1,5 +0,0 @@ -#define ARCH_ELF_CLASS ELFCLASS32 -#define ARCH_ELF_DATA ELFDATA2LSB -#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_386 || (x)==EM_486) -typedef Elf32_Ehdr Elf_ehdr; -typedef Elf32_Phdr Elf_phdr; diff --git a/i386/include/arch/eltorito.h b/i386/include/arch/eltorito.h deleted file mode 100644 index d43e9aa..0000000 --- a/i386/include/arch/eltorito.h +++ /dev/null @@ -1,3 +0,0 @@ -#ifndef ELTORITO_PLATFORM -#define ELTORITO_PLATFORM ELTORITO_PLATFORM_X86 -#endif /* ELTORITO_PLATFORM */ diff --git a/i386/include/arch/timer.h b/i386/include/arch/timer.h deleted file mode 100644 index 3cdd9b4..0000000 --- a/i386/include/arch/timer.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of FILO. - * - * (C) 2004-2008 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef TIMER_H -#define TIMER_H - -extern u32 cpu_khz; - -u64 currticks(void); -int getrtsecs (void); - -#define TICKS_PER_SEC (cpu_khz * 1000) -#define TICKS_PER_USEC (cpu_khz / 1000) - - -#endif /* TIMER_H */ diff --git a/i386/ldscript b/i386/ldscript deleted file mode 100644 index b260c51..0000000 --- a/i386/ldscript +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is part of FILO. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* When started from General Software BIOS */ -/* BASE_ADDR = 0x40000; */ -/* When started from coreboot */ -BASE_ADDR = 0x100000; - - -OUTPUT_FORMAT(elf32-i386) -OUTPUT_ARCH(i386) - -ENTRY(entry) - -/* 1024KB heap and 64KB stack */ -HEAP_SIZE = 1 * 1024 * 1024; -STACK_SIZE = 64 * 1024; - -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(4096); - _start = .; - - /* Putting ELF notes near beginning of file might help bootloaders. - * We discard .note sections other than .note.ELFBoot and .note.pinfo, - * because some versions of GCC generates useless ones. */ - .note : { *(.note.ELFBoot) *(note.pinfo) } - - /* Normal sections */ - .boot : { *(.boot) *(.boot.*) } - .text : { *(.text) *(.text.*) } - .rodata : { - . = ALIGN(4); - drivers_start = .; - *(.rodata.drivers) - drivers_end = .; - *(.rodata) - *(.rodata.*) - } - .data : { *(.data) *(.data.*) } - - .bss : { - *(.sbss) - *(.sbss.*) - *(.bss) - *(.bss.*) - *(COMMON) - - /* heap and stack */ - - . = 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/i386/linux_load.c b/i386/linux_load.c deleted file mode 100644 index aa2f27e..0000000 --- a/i386/linux_load.c +++ /dev/null @@ -1,803 +0,0 @@ -/* - * This file is part of FILO. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * 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 <libpayload.h> -#include <libpayload-config.h> -#include <coreboot_tables.h> -#include <config.h> -#include <fs.h> -#include "context.h" -#include "segment.h" - -#define DEBUG_THIS CONFIG_DEBUG_LINUXLOAD -#include <debug.h> - -#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 { - u8 reserved1[0x1f1]; /* 0x000 */ - u8 setup_sects; /* 0x1f1 */ - u16 root_flags; /* 0x1f2 */ - u32 syssize; /* 0x1f4 (2.04+) */ - u8 reserved2[2]; /* 0x1f8 */ - u16 vid_mode; /* 0x1fa */ - u16 root_dev; /* 0x1fc */ - u16 boot_sector_magic; /* 0x1fe */ - /* 2.00+ */ - u8 reserved3[2]; /* 0x200 */ - u8 header_magic[4]; /* 0x202 */ - u16 protocol_version; /* 0x206 */ - u32 realmode_swtch; /* 0x208 */ - u16 start_sys; /* 0x20c */ - u16 kver_addr; /* 0x20e */ - u8 type_of_loader; /* 0x210 */ - u8 loadflags; /* 0x211 */ - u16 setup_move_size; /* 0x212 */ - u32 code32_start; /* 0x214 */ - u32 ramdisk_image; /* 0x218 */ - u32 ramdisk_size; /* 0x21c */ - u8 reserved4[4]; /* 0x220 */ - /* 2.01+ */ - u16 heap_end_ptr; /* 0x224 */ - u8 reserved5[2]; /* 0x226 */ - /* 2.02+ */ - u32 cmd_line_ptr; /* 0x228 */ - /* 2.03+ */ - u32 initrd_addr_max; /* 0x22c */ - /* 2.05+ */ - u32 kernel_alignment; /* 0x230 */ - u8 relocatable_kernel; /* 0x234 */ - u8 min_alignment; /* 0x235 (2.10+) */ - u8 reserved6[2]; /* 0x236 */ - /* 2.06+ */ - u32 cmdline_size; /* 0x238 */ - /* 2.07+ */ - u32 hardware_subarch; /* 0x23c */ - u64 hardware_subarch_data;/* 0x240 */ - /* 2.08+ */ - u32 payload_offset; /* 0x248 */ - u32 payload_length; /* 0x24c */ - /* 2.09+ */ - u64 setup_data; /* 0x250 */ - /* 2.10+ */ - u64 pref_address; /* 0x258 */ - u32 init_size; /* 0x260 */ -} __attribute__ ((packed)); - -/* Paramters passed to 32-bit part of Linux - * This is another view of the structure above.. */ -struct linux_params { - u8 orig_x; /* 0x00 */ - u8 orig_y; /* 0x01 */ - u16 ext_mem_k; /* 0x02 -- EXT_MEM_K sits here */ - u16 orig_video_page; /* 0x04 */ - u8 orig_video_mode; /* 0x06 */ - u8 orig_video_cols; /* 0x07 */ - u16 unused2; /* 0x08 */ - u16 orig_video_ega_bx; /* 0x0a */ - u16 unused3; /* 0x0c */ - u8 orig_video_lines; /* 0x0e */ - u8 orig_video_isVGA; /* 0x0f */ - u16 orig_video_points; /* 0x10 */ - - /* VESA graphic mode -- linear frame buffer */ - u16 lfb_width; /* 0x12 */ - u16 lfb_height; /* 0x14 */ - u16 lfb_depth; /* 0x16 */ - u32 lfb_base; /* 0x18 */ - u32 lfb_size; /* 0x1c */ - u16 cl_magic; /* 0x20 */ -#define CL_MAGIC_VALUE 0xA33F - u16 cl_offset; /* 0x22 */ - u16 lfb_linelength; /* 0x24 */ - u8 red_size; /* 0x26 */ - u8 red_pos; /* 0x27 */ - u8 green_size; /* 0x28 */ - u8 green_pos; /* 0x29 */ - u8 blue_size; /* 0x2a */ - u8 blue_pos; /* 0x2b */ - u8 rsvd_size; /* 0x2c */ - u8 rsvd_pos; /* 0x2d */ - u16 vesapm_seg; /* 0x2e */ - u16 vesapm_off; /* 0x30 */ - u16 pages; /* 0x32 */ - u8 reserved4[12]; /* 0x34 -- 0x3f reserved for future expansion */ - - //struct apm_bios_info apm_bios_info; /* 0x40 */ - u8 apm_bios_info[0x40]; - //struct drive_info_struct drive_info; /* 0x80 */ - u8 drive_info[0x20]; - //struct sys_desc_table sys_desc_table; /* 0xa0 */ - u8 sys_desc_table[0x140]; - u32 alt_mem_k; /* 0x1e0 */ - u8 reserved5[4]; /* 0x1e4 */ - u8 e820_map_nr; /* 0x1e8 */ - u8 reserved6[9]; /* 0x1e9 */ - u16 mount_root_rdonly; /* 0x1f2 */ - u8 reserved7[4]; /* 0x1f4 */ - u16 ramdisk_flags; /* 0x1f8 */ -#define RAMDISK_IMAGE_START_MASK 0x07FF -#define RAMDISK_PROMPT_FLAG 0x8000 -#define RAMDISK_LOAD_FLAG 0x4000 - u8 reserved8[2]; /* 0x1fa */ - u16 orig_root_dev; /* 0x1fc */ - u8 reserved9[1]; /* 0x1fe */ - u8 aux_device_info; /* 0x1ff */ - u8 reserved10[2]; /* 0x200 */ - u8 param_block_signature[4]; /* 0x202 */ - u16 param_block_version; /* 0x206 */ - u8 reserved11[8]; /* 0x208 */ - u8 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 - u8 loader_flags; /* 0x211 */ - u8 reserved12[2]; /* 0x212 */ - u32 kernel_start; /* 0x214 */ - u32 initrd_start; /* 0x218 */ - u32 initrd_size; /* 0x21c */ - u8 reserved12_5[8]; /* 0x220 */ - u32 cmd_line_ptr; /* 0x228 */ - u32 initrd_addr_max; /* 0x22c */ - u32 kernel_alignment; /* 0x230 */ - u8 relocatable_kernel; /* 0x234 */ - u8 reserved13[155]; /* 0x22c */ - struct e820entry e820_map[E820MAX]; /* 0x2d0 */ - u8 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 */ - u8 command_line[COMMAND_LINE_SIZE]; /* 0x800 */ - u8 reserved17[1792]; /* 0x900 - 0x1000 */ -}; - -u64 forced_memsize; - -/* Load the first part the file and check if it's Linux */ -static u32 load_linux_header(struct linux_header *hdr) -{ - u32 kern_addr = 0; - int load_high; - - if (file_read(hdr, sizeof *hdr) != sizeof *hdr) { - printf("Can't read Linux header\n"); - return 0; - } - - if (hdr->boot_sector_magic != 0xaa55) { - printf("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) { - printf("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 (file_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; - } - - /* determine kernel load address */ - if (hdr->protocol_version >= 0x20a) { - if (hdr->pref_address >> 32) { - debug(" (ignoring 64bit pref_address)"); - } else { - kern_addr = hdr->pref_address; - } - } - - if (hdr->protocol_version >= 0x205 && hdr->relocatable_kernel) { - printf(" relocatable"); - } - - if (load_high) { - printf(" bzImage"); - if (kern_addr == 0) - kern_addr = 0x100000; - } else { - printf(" zImage or Image"); - if (kern_addr == 0) - 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 */ - - /* copy alignment fields for relocatable kernels */ - if (hdr->protocol_version >= 0x205) { - params->relocatable_kernel = hdr->relocatable_kernel; - params->kernel_alignment = hdr->kernel_alignment; - } -} - -/* Memory map */ -static void set_memory_size(struct linux_params *params) -{ - int i; - uint64_t end; - u32 ramtop = 0; - struct e820entry *linux_map; - struct sysinfo_t *info = &lib_sysinfo; - 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 = filo_map->type; - debug("%016llx - %016llx (%d)\n", linux_map->addr, - linux_map->addr + linux_map->size, - linux_map->type); - 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 = (u32) 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); -} - -/* Video mode */ -static void set_video_mode(struct linux_params *params) -{ -#if CONFIG_COREBOOT_VIDEO_CONSOLE - /* Are we running on a framebuffer console? */ - if (!lib_sysinfo.framebuffer) - return; - - struct cb_framebuffer *fb = phys_to_virt(lib_sysinfo.framebuffer); - - params->lfb_width = fb->x_resolution; - params->lfb_height = fb->y_resolution; - params->lfb_depth = fb->bits_per_pixel; - params->lfb_linelength = fb->bytes_per_line; - params->lfb_base = fb->physical_address; - - // prolly not enough for the boot splash?! - params->lfb_size = - (params->lfb_linelength * params->lfb_height + 65535) >> 16; - params->red_size = fb->red_mask_size; - params->red_pos = fb->red_mask_pos; - params->green_size = fb->green_mask_size; - params->green_pos = fb->green_mask_pos; - params->blue_size = fb->blue_mask_size; - params->blue_pos = fb->blue_mask_pos; - params->rsvd_size = fb->reserved_mask_size; - params->rsvd_pos = fb->reserved_mask_pos; -#endif -} - -/* - * 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, u32 kern_addr) -{ - u32 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 (using_devsize) { - printf("Attempt to load up to end of device as kernel; " - "specify the image size\n"); - return 0; - } - - printf("Loading kernel... "); - if (file_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, - u32 kern_end, struct linux_params *params, - const char *initrd_file) -{ - u32 max; - u32 start, end, size; - uint64_t forced; - extern char _start[]; -#if 0 - extern char _end[]; -#endif - - if (!file_open(initrd_file)) { - printf("Can't open initrd: %s\n", initrd_file); - return -1; - } - if (using_devsize) { - printf("Attempt to load up to end of device as initrd; " - "specify the image size\n"); - return -1; - } - 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 - 1); - 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; -#if 0 - else { - /* Otherwise, see if we can put it above us. - * - * This would be a good idea if we could easily find - * out where the memory hole lives. - * - * There's nothing wrong with the initrd living below - * FILO. (stepan) - * - * The problems is even a 64bit kernel will live in - * 32bit address space, so if you have a lot of - * memory and specify mem=xG with x>4, the maximum - * allowed initrd address (2.6.x sets this to - * 0xffffffff) will be used for the high limit. - * (offset 22c in vmlinuz) - * - * you might want to enable this if you limit memory - * with mem=yG with y<4. - */ - if (virt_to_phys(_end) + size <= forced) - end = forced; /* Ok */ - } -#endif - } - - 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 (file_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(u32 kern_addr, struct linux_params *params) -{ - struct segment_desc *linux_gdt; - struct context *ctx; -#ifdef CONFIG_VGA_VIDEO_CONSOLE - unsigned int cursor_x, cursor_y, cursor_en; -#endif -#ifdef CONFIG_PCMCIA_CF - unsigned char *cf_bar; - int i; -#endif - - 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; - - /* set this field in any case to support relocatable kernels */ - params->kernel_start = kern_addr; - - debug("EIP=%#x\n", kern_addr); - printf("Jumping to entry point...\n"); - -#ifdef CONFIG_VGA_VIDEO_CONSOLE - /* Update VGA cursor position. - * This must be here because the printf changes the value! */ - video_console_get_cursor(&cursor_x, &cursor_y, &cursor_en); - params->orig_x = cursor_x; - params->orig_y = cursor_y; -#endif - -#ifdef CONFIG_PCMCIA_CF - cf_bar = phys_to_virt(pci_read_config32(PCI_DEV(0, 0xa, 1), 0x10)); - for (i = 0x836; i < 0x840; i++) { - cf_bar[i] = 0; - } -#endif - /* Go... */ - ctx = switch_to(ctx); - - /* It's impossible but... */ - printf("Returned with EAX=%#x\n", ctx->eax); - - return ctx->eax; -} - -int linux_load(const char *file, const char *cmdline) -{ - struct linux_header hdr; - struct linux_params *params; - u32 kern_addr, kern_size; - char *initrd_file = 0; - - if (!file_open(file)) - return -1; - - kern_addr = load_linux_header(&hdr); - if (kern_addr == 0) { - file_close(); - return LOADER_NOT_SUPPORT; - } - - params = phys_to_virt(LINUX_PARAM_LOC); - init_linux_params(params, &hdr); - set_memory_size(params); - set_video_mode(params); - 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); - file_close(); - return -1; - } - - if (initrd_file) { - if (load_initrd(&hdr, kern_addr + kern_size, - params, initrd_file) != 0) { - free(initrd_file); - file_close(); - return -1; - } - free(initrd_file); - } - - file_close(); -#if defined(CONFIG_USB) - usb_exit(); -#endif - - hardware_setup(); - - start_linux(kern_addr, params); - return 0; -} diff --git a/i386/segment.c b/i386/segment.c deleted file mode 100644 index ea38096..0000000 --- a/i386/segment.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * This file is part of FILO. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -/* Segmentation of the i386 architecture. - * - * 2003-07 by SONE Takeshi - */ - -#include <libpayload.h> -#include <coreboot_tables.h> -#include <config.h> -#include "segment.h" - -#define DEBUG_THIS CONFIG_DEBUG_SEGMENT -#include <debug.h> - -/* 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(void) -{ - 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; - struct sysinfo_t *info = &lib_sysinfo; -#define ALIGNMENT 0x1000 - - 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].type != CB_MEM_RAM) - continue; - 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; // for FILO - virtual_offset = new_offset; // for libpayload - - debug("ok\n"); -} diff --git a/i386/segment.h b/i386/segment.h deleted file mode 100644 index 43130e6..0000000 --- a/i386/segment.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of FILO. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -/* 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/i386/switch.S b/i386/switch.S deleted file mode 100644 index 50f5f71..0000000 --- a/i386/switch.S +++ /dev/null @@ -1,116 +0,0 @@ - .globl entry, __switch_context, __exit_context, halt - - .section ".boot", "xa" - .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/i386/sys_info.c b/i386/sys_info.c deleted file mode 100644 index 8e7d14e..0000000 --- a/i386/sys_info.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of FILO. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <libpayload.h> -#include <config.h> -#include <sys_info.h> -#include "context.h" -#define DEBUG_THIS CONFIG_DEBUG_SYS_INFO -#include <debug.h> - -void collect_sys_info(struct sys_info *info) -{ - /* 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); -} diff --git a/i386/timer.c b/i386/timer.c deleted file mode 100644 index 739c9ed..0000000 --- a/i386/timer.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of FILO. - * - * (C) 2004-2008 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <libpayload.h> -#include <arch/rdtsc.h> -#include <arch/timer.h> - -u64 currticks(void) -{ - /* Read the Time Stamp Counter */ - return rdtsc(); -} - -int getrtsecs (void) -{ - u64 t; - t=currticks(); - t=t/(TICKS_PER_SEC); - return (int)t; -} - - diff --git a/i386/wince_load.c b/i386/wince_load.c deleted file mode 100644 index 993815f..0000000 --- a/i386/wince_load.c +++ /dev/null @@ -1,385 +0,0 @@ -/******************************************************************************* - * - * WindowsCE/i386 loader - * - * Copyright 2006 Andrei Birjukov andrei.birjukov@artecdesign.ee and - * Artec Design LLC http://www.artecdesign.ee - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ******************************************************************************/ - -#include <libpayload.h> -#include <lib.h> -#include <fs.h> -#include <arch/io.h> -#include "context.h" -#include "segment.h" - -#define DEBUG_THIS DEBUG_WINCELOAD -#include <debug.h> - -#define BOOTARG_PTR_LOCATION 0x001FFFFC -#define BOOTARG_LOCATION 0x001FFF00 -#define BOOTARG_SIGNATURE 0x544F4F42 -#define BOOTARG_VERSION_SIG 0x12345678 -#define BOOTARG_MAJOR_VER 1 -#define BOOTARG_MINOR_VER 0 - -#define MAX_DEV_NAMELEN 16 // Should match EDBG_MAX_DEV_NAMELEN. - -#define LDRFL_USE_EDBG 0x0001 // Set to attempt to use debug Ethernet -// The following two flags are only looked at if LDRFL_USE_EDBG is set -#define LDRFL_ADDR_VALID 0x0002 // Set if EdbgAddr field is valid -#define LDRFL_JUMPIMG 0x0004 // If set, don't communicate with eshell to get -// The following flag is only used for backup FLASH operation -#define LDRFL_FLASH_BACKUP 0x80 -// configuration, use ucEshellFlags field. -// Use this constant in EdbgIRQ to specify that EDBG should run without an interrupt. -#define EDBG_IRQ_NONE 0xFF - -#define EDBG_ADAPTER_DEFAULT 2 -#define EDBG_ADAPTER_RTL8139 4 - -#define PSIZE (1500) // Max Packet Size -#define DSIZE (PSIZE+12) -#define BIN_HDRSIG_SIZE 7 - -#define ROM_SIGNATURE_OFFSET 0x40 // Offset from the image's physfirst address to the ROM signature. -#define ROM_SIGNATURE 0x43454345 -#define ROM_TOC_POINTER_OFFSET 0x44 // Offset from the image's physfirst address to the TOC pointer. -#define ROM_TOC_OFFSET_OFFSET 0x48 // Offset from the image's physfirst address to the TOC offset (from physfirst). - -#define GDT_LOC 0x92000 -#define STACK_LOC 0x93000 - -typedef struct _EDBG_ADDR { - u32 dwIP; - u16 wMAC[3]; - u16 wPort; -} EDBG_ADDR; - -typedef struct _BOOT_ARGS { - u8 ucVideoMode; - u8 ucComPort; - u8 ucBaudDivisor; - u8 ucPCIConfigType; - u32 dwSig; - u32 dwLen; - u8 ucLoaderFlags; - u8 ucEshellFlags; - u8 ucEdbgAdapterType; - u8 ucEdbgIRQ; - u32 dwEdbgBaseAddr; - u32 dwEdbgDebugZone; - EDBG_ADDR EdbgAddr; - EDBG_ADDR EshellHostAddr; - EDBG_ADDR DbgHostAddr; - EDBG_ADDR CeshHostAddr; - EDBG_ADDR KdbgHostAddr; - u32 DHCPLeaseTime; - u16 EdbgFlags; - u16 KitlTransport; - u32 dwEBootFlag; - u32 dwEBootAddr; - u32 dwLaunchAddr; - u32 pvFlatFrameBuffer; - u16 vesaMode; - u16 cxDisplayScreen; - u16 cyDisplayScreen; - u16 cxPhysicalScreen; - u16 cyPhysicalScreen; - u16 cbScanLineLength; - u16 bppScreen; - u8 RedMaskSize; - u8 RedMaskPosition; - u8 GreenMaskSize; - u8 GreenMaskPosition; - u8 BlueMaskSize; - u8 BlueMaskPosition; - u32 dwVersionSig; - u16 MajorVersion; - u16 MinorVersion; - u8 szDeviceNameRoot[MAX_DEV_NAMELEN]; - u32 dwImgStoreAddr; - u32 dwImgLoadAddr; - u32 dwImgLength; - u8 NANDBootFlags; - u8 NANDBusNumber; - u32 NANDSlotNumber; -} BOOT_ARGS; - -typedef struct _ROMHDR { - u32 dllfirst; - u32 dlllast; - u32 physfirst; - u32 physlast; - u32 nummods; - u32 ulRAMStart; - u32 ulRAMFree; - u32 ulRAMEnd; - u32 ulCopyEntries; - u32 ulCopyOffset; - u32 ulProfileLen; - u32 ulProfileOffset; - u32 numfiles; - u32 ulKernelFlags; - u32 ulFSRamPercent; - u32 ulDrivglobStart; - u32 ulDrivglobLen; - u16 usCPUType; - u16 usMiscFlags; - void *pExtensions; - u32 ulTrackingStart; - u32 ulTrackingLen; -} ROMHDR; - -typedef struct _SEGMENT_INFO { - u32 segAddr; - u32 segSize; - u32 checkSum; -} SEGMENT_INFO; - -typedef void (*PFN_LAUNCH) (); // WinCE launch function proto - -static u8 g_ceSignature[] = { 'B', '0', '0', '0', 'F', 'F', '\n' }; -static void **g_ppBootArgs = NULL; -BOOT_ARGS *g_pBootArgs = NULL; -static ROMHDR *pROMHeader = NULL; - -static u32 g_imageStart = 0; -static u32 g_imageSize = 0; -static u32 g_romOffset = 0; - -static int verifyCheckSum(u8 * pData, int nSize, u32 checkSum) -{ - // check the CRC - u32 crc = 0; - int i; - - for (i = 0; i < nSize; i++) - crc += *pData++; - - return (crc == checkSum); -} - -int wince_launch(u32 imageStart, u32 imageSize, - u32 entryPoint, ROMHDR * pRomHdr) -{ - struct segment_desc *wince_gdt; - struct context *ctx; - - debug("start Windows CE from address 0x%x, image loaded 0x%x,%d\n", - entryPoint, imageStart, imageSize); - - // initialize new stack - ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0); - - // initialize GDT in low memory - wince_gdt = phys_to_virt(GDT_LOC); - memset(wince_gdt, 0, 13 * sizeof(struct segment_desc)); - // flat kernel code/data segments - wince_gdt[2] = gdt[FLAT_CODE]; - wince_gdt[3] = gdt[FLAT_DATA]; - - wince_gdt[12] = gdt[FLAT_CODE]; - wince_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; - - // kernel entry point - ctx->eip = entryPoint; - - printf("Launching Windows CE...\n"); - - // go...! - ctx = switch_to(ctx); - - // may never return here - printf("returned with eax=%#x\n", ctx->eax); - return ctx->eax; -} - -void wince_init_bootarg(u32 entryPoint) -{ - // init the BOOT_ARGS pointer at the known address - g_ppBootArgs = phys_to_virt(BOOTARG_PTR_LOCATION); - *g_ppBootArgs = (void *) BOOTARG_LOCATION; - - // keep our BOOT_ARGS somewhere in a dry dark place - g_pBootArgs = phys_to_virt(BOOTARG_LOCATION); - - debug("BOOT_ARGS at addr 0x%x, pointer at 0x%x [%x]\n", - (unsigned int) *g_ppBootArgs, BOOTARG_PTR_LOCATION, - (unsigned int) g_ppBootArgs); - - memset(g_pBootArgs, 0, sizeof(BOOT_ARGS)); - - // this data was copied from WinCE EDBG boot args - g_pBootArgs->ucEdbgAdapterType = EDBG_ADAPTER_DEFAULT; - // use the first PCI NIC available - g_pBootArgs->ucEdbgIRQ = 0; - g_pBootArgs->dwEdbgBaseAddr = 0; - - // set the KITL device name to something adequate - strcpy((char *) g_pBootArgs->szDeviceNameRoot, "FILO"); - - g_pBootArgs->dwSig = BOOTARG_SIGNATURE; - g_pBootArgs->dwLen = sizeof(BOOT_ARGS); - g_pBootArgs->dwVersionSig = BOOTARG_VERSION_SIG; - g_pBootArgs->MajorVersion = BOOTARG_MAJOR_VER; - g_pBootArgs->MinorVersion = BOOTARG_MINOR_VER; - -/* - g_pBootArgs->ucVideoMode = 255; - g_pBootArgs->ucComPort = 1; - g_pBootArgs->ucBaudDivisor = 3; - g_pBootArgs->ucPCIConfigType = 1; - g_pBootArgs->ucLoaderFlags = 0x7; -*/ - - debug("Boot arguments initialized at 0x%x\n", - (unsigned int) *g_ppBootArgs); -} - -int wince_load(const char *file, const char *cmdline) -{ - u8 signBuf[BIN_HDRSIG_SIZE], *pDest = NULL; - SEGMENT_INFO segInfo; - u32 totalBytes = 0; - - if (!file_open(file)) { - printf("Failed opening image file: %s\n", file); - return LOADER_NOT_SUPPORT; - } - // read the image signature - file_read((void *) signBuf, BIN_HDRSIG_SIZE); - - if (memcmp(signBuf, g_ceSignature, BIN_HDRSIG_SIZE)) { - printf("Bad or unknown Windows CE image signature\n"); - file_close(); - return LOADER_NOT_SUPPORT; - } - // now read image start address and size - file_read((void *) &g_imageStart, sizeof(u32)); - file_read((void *) &g_imageSize, sizeof(u32)); - - if (!g_imageStart || !g_imageSize) // sanity check - { - printf("Invalid image descriptors\n"); - file_close(); - return LOADER_NOT_SUPPORT; - } - - printf("Windows CE BIN image, start 0x%x, length %d\n", - g_imageStart, g_imageSize); - - // main image reading loop - while (1) { - // first grab the segment descriptor - if (file_read(&segInfo, sizeof(SEGMENT_INFO)) < - sizeof(SEGMENT_INFO)) { - printf ("\nFailed reading image segment descriptor\n"); - file_close(); - return LOADER_NOT_SUPPORT; - } - - totalBytes += sizeof(SEGMENT_INFO); // update data counter - printf("#"); // that's a progress bar :) - - // now check if that's the last one - if (segInfo.segAddr == 0 && segInfo.checkSum == 0) - break; - - // map segment address to current address space - pDest = (u8 *) phys_to_virt(segInfo.segAddr); - debug("fetched segment address 0x%x [%x] size %d\n", - segInfo.segAddr, (unsigned int) pDest, - segInfo.segSize); - - // read the image segment data from VFS - if (file_read((void *) pDest, segInfo.segSize) < - segInfo.segSize) { - printf ("\nFailed reading image segment data (address 0x%x, size %d)\n", - segInfo.segAddr, segInfo.segSize); - file_close(); - return LOADER_NOT_SUPPORT; - } - // check the data integrity - if (!verifyCheckSum - (pDest, segInfo.segSize, segInfo.checkSum)) { - printf ("\nFailed verifying segment checksum at address 0x%x, size %d\n", - (unsigned int) pDest, segInfo.segSize); - file_close(); - return LOADER_NOT_SUPPORT; - } - // Look for ROMHDR to compute ROM offset. NOTE: romimage guarantees that the record containing - // the TOC signature and pointer will always come before the record that contains the ROMHDR contents. - - if (segInfo.segSize == sizeof(ROMHDR) && - (*(u32 *) phys_to_virt(g_imageStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE)) { - u32 tempOffset = - (segInfo.segAddr - - *(u32 *) phys_to_virt(g_imageStart + - ROM_SIGNATURE_OFFSET - + sizeof(long))); - ROMHDR *pROMhdr = (ROMHDR *) pDest; - - // check to make sure this record really contains the ROMHDR. - if ((pROMhdr->physfirst == (g_imageStart - tempOffset)) && - (pROMhdr->physlast == (g_imageStart - tempOffset + g_imageSize)) && - (u32) (((pROMhdr-> dllfirst << 16) & 0xffff0000) <= pROMhdr->dlllast) && - (u32) (((pROMhdr-> dllfirst << 16) & 0x0000ffff) <= pROMhdr->dlllast)) { - g_romOffset = tempOffset; - debug("\nROM offset = 0x%x\n", g_romOffset); - } - } - - totalBytes += segInfo.segSize; // update data counter - } - - // we should have moved all image segments to RAM by now - printf("\nOS image loaded.\n"); - - // check for pTOC signature ("CECE") here, after image in place - if (*(u32 *) phys_to_virt(g_imageStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE) { - // a pointer to the ROMHDR structure lives just past the ROM_SIGNATURE (which is a longword value). Note that - // this pointer is remapped since it might be a flash address (image destined for flash), but is actually cached - // in RAM. - - u32 cacheAddress = *(u32 *) phys_to_virt(g_imageStart + ROM_SIGNATURE_OFFSET + sizeof(u32)); - - pROMHeader = - (ROMHDR *) phys_to_virt(cacheAddress + g_romOffset); - debug("ROMHDR at address 0x%xh\n", - cacheAddress + g_romOffset); - } - - file_close(); - - // prepare the boot arguments - // note that the last segment size carries the launch address - wince_init_bootarg(segInfo.segSize); - - // finally, call the generic launch() function - return wince_launch(g_imageStart, g_imageSize, segInfo.segSize, - pROMHeader); -} diff --git a/x86/Makefile.inc b/x86/Makefile.inc new file mode 100644 index 0000000..f01ca72 --- /dev/null +++ b/x86/Makefile.inc @@ -0,0 +1,23 @@ +# +# Copyright (C) 2008 by coresystems GmbH +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +TARGETS-$(CONFIG_TARGET_I386) += x86/context.o x86/switch.S.o x86/segment.o +TARGETS-$(CONFIG_TARGET_I386) += x86/timer.o x86/sys_info.o +TARGETS-$(CONFIG_LINUX_LOADER) += x86/linux_load.o +TARGETS-$(CONFIG_WINCE_LOADER) += x86/wince_load.o +TARGETS-$(CONFIG_ARTEC_BOOT) += x86/artecboot.o diff --git a/x86/artecboot.c b/x86/artecboot.c new file mode 100644 index 0000000..697a05b --- /dev/null +++ b/x86/artecboot.c @@ -0,0 +1,159 @@ +/******************************************************************************* + * + * FILO Artecboot loader, enables multiboot through custom header + * + * Copyright 2006 Andrei Birjukov andrei.birjukov@artecdesign.ee and + * Artec Design LLC http://www.artecdesign.ee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ******************************************************************************/ + +#include <libpayload.h> +#include <config.h> +#include <fs.h> +#include "artecboot.h" +#include "../fs/filesys.h" + +#define DEBUG_THIS CONFIG_DEBUG_ARTECBOOT +#include <debug.h> + +static ARTECBOOT_HEADER bootHdr; + +int artecboot_load(const char *file, const char *cmdline) +{ + int i; + + printf("Starting the Artecboot loader...\n"); + // clear the boot header + memset(&bootHdr, 0, sizeof(bootHdr)); + + // try opening the boot parameter file + if (!file_open(file)) + { + printf("Boot error: failed to open image file: %s\n", file); + return LOADER_NOT_SUPPORT; + } + + file_seek(0); // seek to the beginning of the parameter file + + // now read out the boot header + if(file_read(&bootHdr, sizeof(ARTECBOOT_HEADER)) != sizeof(ARTECBOOT_HEADER)) + { + printf("Boot error: failed reading the boot image header\n"); + file_close(); + return LOADER_NOT_SUPPORT; + } + + // check whether the parameter data is valid at all + if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC) + { + debug("No Artecboot signature found, aborting\n"); + file_close(); + return LOADER_NOT_SUPPORT; + } + + // check the version number + if(bootHdr.bootVersion > CURRENT_VERSION) + { + printf("Boot error: incompatible version number: %x\n", bootHdr.bootVersion); + file_close(); + return LOADER_NOT_SUPPORT; + } + + // shall we replace the command line? + if(bootHdr.bitFlags & FLAG_CMDLINE) + { + // check the command line and wipe out all junk + for(i=0; bootHdr.cmdLine[i] != 0; i++) + switch(bootHdr.cmdLine[i]) + { + case '\n': + case '\r': + bootHdr.cmdLine[i] = ' '; + break; + default: + // do nothing + break; + } + } + else if(cmdline) + strncpy(bootHdr.cmdLine, cmdline, sizeof(bootHdr.cmdLine)); + + // proceed basing on the specified OS type + switch(bootHdr.osType) + { + case OS_LINUX: + if(bootHdr.bitFlags & FLAG_INITRD) + { + char initrdParam[100]; + if(bootHdr.bitFlags & FLAG_FILESYSTEM) + { + // we are using a real filesystem, so format the initrd file as usually + sprintf(initrdParam, " initrd=%s", bootHdr.initrdFile); + } + else + { + // we are using a 'fake' filesystem, so use the image offset + sprintf(initrdParam, " initrd=%s@0x%x,0x%x", + dev_name, bootHdr.initrdStart, bootHdr.initrdSize); + } + + debug("adding initrd parameter: %s\n", initrdParam); + strncat(bootHdr.cmdLine, initrdParam, sizeof(bootHdr.cmdLine)); + } + + printf("Starting Linux loader...\n"); + + // if using a real filesystem, load the kernel image from a specified file + if(bootHdr.bitFlags & FLAG_FILESYSTEM) + linux_load(bootHdr.kernelFile, bootHdr.cmdLine); + // if using a 'fake' filesystem, consider reading from the same image + else + { + part_start = bootHdr.kernelStart >> DEV_SECTOR_BITS; + part_length = ((bootHdr.kernelSize-1) >> DEV_SECTOR_BITS) + 1; + filemax = bootHdr.kernelSize; + using_devsize = 0; + linux_load(file, bootHdr.cmdLine); + } + + break; + + case OS_WINCE: + + printf("Starting Windows CE loader...\n"); + // if using a real filesystem, load the kernel image from a specified file + if(bootHdr.bitFlags & FLAG_FILESYSTEM) + wince_load(bootHdr.kernelFile, bootHdr.cmdLine); + // if using a 'fake' filesystem, consider reading from the same image + else + { + part_start = bootHdr.kernelStart >> DEV_SECTOR_BITS; + part_length = ((bootHdr.kernelSize-1) >> DEV_SECTOR_BITS) + 1; + filemax = bootHdr.kernelSize; + wince_load(file, bootHdr.cmdLine); + } + + break; + + default: + printf("Boot error: unknown OS type, aborting: %d\n", bootHdr.osType); + return LOADER_NOT_SUPPORT; + } + + file_close(); + return 0; +} diff --git a/x86/context.c b/x86/context.c new file mode 100644 index 0000000..a06b97d --- /dev/null +++ b/x86/context.c @@ -0,0 +1,135 @@ +/* + * This file is part of FILO. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/* + * context switching + * 2003-10 by SONE Takeshi + */ + +#include <libpayload.h> +#include <lib.h> +#include "segment.h" +#include "context.h" + +#define MAIN_STACK_SIZE 16384 +#define IMAGE_STACK_SIZE 4096 + +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 = (u32) gdt, + .gdt_limit = GDT_LIMIT, + .cs = FLAT_CS, .ds = FLAT_DS, + .es = FLAT_DS, .fs = FLAT_DS, + .gs = FLAT_DS, .ss = FLAT_DS, + .esp = (u32)ESP_LOC(&main_ctx), + .eip = (u32) start_main, + .return_addr = (u32) __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 u8 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 main(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 = main(); + + /* 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(u8 * stack, u32 stack_size, int num_params) +{ + struct context *ctx; + + ctx = (struct context *) (stack + stack_size - + (sizeof(*ctx) + num_params * sizeof(u32))); + 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; + + save = __context; + __context = ctx; + asm volatile ("push %%cs; call __switch_context" ::: "memory"); + ret = __context; + __context = save; + return ret; +} + +/* Start ELF Boot image */ +u32 start_elf(u32 entry_point, u32 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/x86/context.h b/x86/context.h new file mode 100644 index 0000000..44e9665 --- /dev/null +++ b/x86/context.h @@ -0,0 +1,65 @@ +/* + * This file is part of FILO. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef i386_CONTEXT_H +#define i386_CONTEXT_H + +struct context { + /* Stack Segment, placed here because of the alignment issue... */ + u16 ss; + /* Used with sgdt/lgdt */ + u16 gdt_limit; + u32 gdt_base; + /* General registers, accessed with pushal/popal */ + u32 edi; + u32 esi; + u32 ebp; + u32 esp; /* points just below eax */ + u32 ebx; + u32 edx; + u32 ecx; + u32 eax; +#define ESP_LOC(ctx) (&(ctx)->gs) + /* Segment registers */ + u32 gs; + u32 fs; + u32 es; + u32 ds; + /* Flags */ + u32 eflags; + /* Code segment:offset */ + u32 eip; + u32 cs; + /* Optional stack contents */ + u32 return_addr; + u32 param[0]; +}; + +/* Create a new context in the given stack */ +struct context *init_context(u8 * stack, u32 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 /* i386_CONTEXT_H */ diff --git a/x86/include/arch/byteorder.h b/x86/include/arch/byteorder.h new file mode 100644 index 0000000..afaebfa --- /dev/null +++ b/x86/include/arch/byteorder.h @@ -0,0 +1,64 @@ +#ifndef ARCH_ENDIAN_H +#define ARCH_ENDIAN_H + +static inline u16 __i386_bswap_16(u16 x) +{ + __asm__("xchgb %b0,%h0\n\t" + : "=q" (x) + : "0" (x)); + return x; +} + +static inline u32 __i386_bswap_32(u32 x) +{ + __asm__("xchgb %b0,%h0\n\t" + "rorl $16,%0\n\t" + "xchgb %b0,%h0" + : "=q" (x) + : "0" (x)); + return x; +} + + +#define __bswap_constant_16(x) \ + ((u16)((((u16)(x) & 0x00ff) << 8) | \ + (((u16)(x) & 0xff00) >> 8))) + +#define __bswap_constant_32(x) \ + ((u32)((((u32)(x) & 0x000000ffU) << 24) | \ + (((u32)(x) & 0x0000ff00U) << 8) | \ + (((u32)(x) & 0x00ff0000U) >> 8) | \ + (((u32)(x) & 0xff000000U) >> 24))) + +#define __bswap_16(x) \ + ((u16)(__builtin_constant_p(x) ? \ + __bswap_constant_16(x) : \ + __i386_bswap_16(x))) + + +#define __bswap_32(x) \ + ((u32)(__builtin_constant_p(x) ? \ + __bswap_constant_32(x) : \ + __i386_bswap_32(x))) + + +#define __BYTE_ORDER __LITTLE_ENDIAN + +#define le32_to_cpup(x) (*(u32 *)(x)) +#define cpu_to_le16p(x) (*(u16*)(x)) + +#define ntohl(x) __bswap_32(x) +#define htonl(x) __bswap_32(x) +#define ntohs(x) __bswap_16(x) +#define htons(x) __bswap_16(x) +#define cpu_to_le32(x) (x) +#define cpu_to_le16(x) (x) +#define cpu_to_be32(x) __bswap_32(x) +#define cpu_to_be16(x) __bswap_16(x) +#define le32_to_cpu(x) (x) +#define le16_to_cpu(x) (x) +#define be32_to_cpu(x) __bswap_32(x) +#define be16_to_cpu(x) __bswap_16(x) + +#endif /* ARCH_ENDIAN_H */ + diff --git a/x86/include/arch/elf.h b/x86/include/arch/elf.h new file mode 100644 index 0000000..86c6725 --- /dev/null +++ b/x86/include/arch/elf.h @@ -0,0 +1,5 @@ +#define ARCH_ELF_CLASS ELFCLASS32 +#define ARCH_ELF_DATA ELFDATA2LSB +#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_386 || (x)==EM_486) +typedef Elf32_Ehdr Elf_ehdr; +typedef Elf32_Phdr Elf_phdr; diff --git a/x86/include/arch/eltorito.h b/x86/include/arch/eltorito.h new file mode 100644 index 0000000..d43e9aa --- /dev/null +++ b/x86/include/arch/eltorito.h @@ -0,0 +1,3 @@ +#ifndef ELTORITO_PLATFORM +#define ELTORITO_PLATFORM ELTORITO_PLATFORM_X86 +#endif /* ELTORITO_PLATFORM */ diff --git a/x86/include/arch/timer.h b/x86/include/arch/timer.h new file mode 100644 index 0000000..3cdd9b4 --- /dev/null +++ b/x86/include/arch/timer.h @@ -0,0 +1,32 @@ +/* + * This file is part of FILO. + * + * (C) 2004-2008 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef TIMER_H +#define TIMER_H + +extern u32 cpu_khz; + +u64 currticks(void); +int getrtsecs (void); + +#define TICKS_PER_SEC (cpu_khz * 1000) +#define TICKS_PER_USEC (cpu_khz / 1000) + + +#endif /* TIMER_H */ diff --git a/x86/ldscript b/x86/ldscript new file mode 100644 index 0000000..b260c51 --- /dev/null +++ b/x86/ldscript @@ -0,0 +1,93 @@ +/* + * This file is part of FILO. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* When started from General Software BIOS */ +/* BASE_ADDR = 0x40000; */ +/* When started from coreboot */ +BASE_ADDR = 0x100000; + + +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) + +ENTRY(entry) + +/* 1024KB heap and 64KB stack */ +HEAP_SIZE = 1 * 1024 * 1024; +STACK_SIZE = 64 * 1024; + +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(4096); + _start = .; + + /* Putting ELF notes near beginning of file might help bootloaders. + * We discard .note sections other than .note.ELFBoot and .note.pinfo, + * because some versions of GCC generates useless ones. */ + .note : { *(.note.ELFBoot) *(note.pinfo) } + + /* Normal sections */ + .boot : { *(.boot) *(.boot.*) } + .text : { *(.text) *(.text.*) } + .rodata : { + . = ALIGN(4); + drivers_start = .; + *(.rodata.drivers) + drivers_end = .; + *(.rodata) + *(.rodata.*) + } + .data : { *(.data) *(.data.*) } + + .bss : { + *(.sbss) + *(.sbss.*) + *(.bss) + *(.bss.*) + *(COMMON) + + /* heap and stack */ + + . = 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/x86/linux_load.c b/x86/linux_load.c new file mode 100644 index 0000000..aa2f27e --- /dev/null +++ b/x86/linux_load.c @@ -0,0 +1,803 @@ +/* + * This file is part of FILO. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * 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 <libpayload.h> +#include <libpayload-config.h> +#include <coreboot_tables.h> +#include <config.h> +#include <fs.h> +#include "context.h" +#include "segment.h" + +#define DEBUG_THIS CONFIG_DEBUG_LINUXLOAD +#include <debug.h> + +#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 { + u8 reserved1[0x1f1]; /* 0x000 */ + u8 setup_sects; /* 0x1f1 */ + u16 root_flags; /* 0x1f2 */ + u32 syssize; /* 0x1f4 (2.04+) */ + u8 reserved2[2]; /* 0x1f8 */ + u16 vid_mode; /* 0x1fa */ + u16 root_dev; /* 0x1fc */ + u16 boot_sector_magic; /* 0x1fe */ + /* 2.00+ */ + u8 reserved3[2]; /* 0x200 */ + u8 header_magic[4]; /* 0x202 */ + u16 protocol_version; /* 0x206 */ + u32 realmode_swtch; /* 0x208 */ + u16 start_sys; /* 0x20c */ + u16 kver_addr; /* 0x20e */ + u8 type_of_loader; /* 0x210 */ + u8 loadflags; /* 0x211 */ + u16 setup_move_size; /* 0x212 */ + u32 code32_start; /* 0x214 */ + u32 ramdisk_image; /* 0x218 */ + u32 ramdisk_size; /* 0x21c */ + u8 reserved4[4]; /* 0x220 */ + /* 2.01+ */ + u16 heap_end_ptr; /* 0x224 */ + u8 reserved5[2]; /* 0x226 */ + /* 2.02+ */ + u32 cmd_line_ptr; /* 0x228 */ + /* 2.03+ */ + u32 initrd_addr_max; /* 0x22c */ + /* 2.05+ */ + u32 kernel_alignment; /* 0x230 */ + u8 relocatable_kernel; /* 0x234 */ + u8 min_alignment; /* 0x235 (2.10+) */ + u8 reserved6[2]; /* 0x236 */ + /* 2.06+ */ + u32 cmdline_size; /* 0x238 */ + /* 2.07+ */ + u32 hardware_subarch; /* 0x23c */ + u64 hardware_subarch_data;/* 0x240 */ + /* 2.08+ */ + u32 payload_offset; /* 0x248 */ + u32 payload_length; /* 0x24c */ + /* 2.09+ */ + u64 setup_data; /* 0x250 */ + /* 2.10+ */ + u64 pref_address; /* 0x258 */ + u32 init_size; /* 0x260 */ +} __attribute__ ((packed)); + +/* Paramters passed to 32-bit part of Linux + * This is another view of the structure above.. */ +struct linux_params { + u8 orig_x; /* 0x00 */ + u8 orig_y; /* 0x01 */ + u16 ext_mem_k; /* 0x02 -- EXT_MEM_K sits here */ + u16 orig_video_page; /* 0x04 */ + u8 orig_video_mode; /* 0x06 */ + u8 orig_video_cols; /* 0x07 */ + u16 unused2; /* 0x08 */ + u16 orig_video_ega_bx; /* 0x0a */ + u16 unused3; /* 0x0c */ + u8 orig_video_lines; /* 0x0e */ + u8 orig_video_isVGA; /* 0x0f */ + u16 orig_video_points; /* 0x10 */ + + /* VESA graphic mode -- linear frame buffer */ + u16 lfb_width; /* 0x12 */ + u16 lfb_height; /* 0x14 */ + u16 lfb_depth; /* 0x16 */ + u32 lfb_base; /* 0x18 */ + u32 lfb_size; /* 0x1c */ + u16 cl_magic; /* 0x20 */ +#define CL_MAGIC_VALUE 0xA33F + u16 cl_offset; /* 0x22 */ + u16 lfb_linelength; /* 0x24 */ + u8 red_size; /* 0x26 */ + u8 red_pos; /* 0x27 */ + u8 green_size; /* 0x28 */ + u8 green_pos; /* 0x29 */ + u8 blue_size; /* 0x2a */ + u8 blue_pos; /* 0x2b */ + u8 rsvd_size; /* 0x2c */ + u8 rsvd_pos; /* 0x2d */ + u16 vesapm_seg; /* 0x2e */ + u16 vesapm_off; /* 0x30 */ + u16 pages; /* 0x32 */ + u8 reserved4[12]; /* 0x34 -- 0x3f reserved for future expansion */ + + //struct apm_bios_info apm_bios_info; /* 0x40 */ + u8 apm_bios_info[0x40]; + //struct drive_info_struct drive_info; /* 0x80 */ + u8 drive_info[0x20]; + //struct sys_desc_table sys_desc_table; /* 0xa0 */ + u8 sys_desc_table[0x140]; + u32 alt_mem_k; /* 0x1e0 */ + u8 reserved5[4]; /* 0x1e4 */ + u8 e820_map_nr; /* 0x1e8 */ + u8 reserved6[9]; /* 0x1e9 */ + u16 mount_root_rdonly; /* 0x1f2 */ + u8 reserved7[4]; /* 0x1f4 */ + u16 ramdisk_flags; /* 0x1f8 */ +#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_PROMPT_FLAG 0x8000 +#define RAMDISK_LOAD_FLAG 0x4000 + u8 reserved8[2]; /* 0x1fa */ + u16 orig_root_dev; /* 0x1fc */ + u8 reserved9[1]; /* 0x1fe */ + u8 aux_device_info; /* 0x1ff */ + u8 reserved10[2]; /* 0x200 */ + u8 param_block_signature[4]; /* 0x202 */ + u16 param_block_version; /* 0x206 */ + u8 reserved11[8]; /* 0x208 */ + u8 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 + u8 loader_flags; /* 0x211 */ + u8 reserved12[2]; /* 0x212 */ + u32 kernel_start; /* 0x214 */ + u32 initrd_start; /* 0x218 */ + u32 initrd_size; /* 0x21c */ + u8 reserved12_5[8]; /* 0x220 */ + u32 cmd_line_ptr; /* 0x228 */ + u32 initrd_addr_max; /* 0x22c */ + u32 kernel_alignment; /* 0x230 */ + u8 relocatable_kernel; /* 0x234 */ + u8 reserved13[155]; /* 0x22c */ + struct e820entry e820_map[E820MAX]; /* 0x2d0 */ + u8 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 */ + u8 command_line[COMMAND_LINE_SIZE]; /* 0x800 */ + u8 reserved17[1792]; /* 0x900 - 0x1000 */ +}; + +u64 forced_memsize; + +/* Load the first part the file and check if it's Linux */ +static u32 load_linux_header(struct linux_header *hdr) +{ + u32 kern_addr = 0; + int load_high; + + if (file_read(hdr, sizeof *hdr) != sizeof *hdr) { + printf("Can't read Linux header\n"); + return 0; + } + + if (hdr->boot_sector_magic != 0xaa55) { + printf("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) { + printf("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 (file_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; + } + + /* determine kernel load address */ + if (hdr->protocol_version >= 0x20a) { + if (hdr->pref_address >> 32) { + debug(" (ignoring 64bit pref_address)"); + } else { + kern_addr = hdr->pref_address; + } + } + + if (hdr->protocol_version >= 0x205 && hdr->relocatable_kernel) { + printf(" relocatable"); + } + + if (load_high) { + printf(" bzImage"); + if (kern_addr == 0) + kern_addr = 0x100000; + } else { + printf(" zImage or Image"); + if (kern_addr == 0) + 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 */ + + /* copy alignment fields for relocatable kernels */ + if (hdr->protocol_version >= 0x205) { + params->relocatable_kernel = hdr->relocatable_kernel; + params->kernel_alignment = hdr->kernel_alignment; + } +} + +/* Memory map */ +static void set_memory_size(struct linux_params *params) +{ + int i; + uint64_t end; + u32 ramtop = 0; + struct e820entry *linux_map; + struct sysinfo_t *info = &lib_sysinfo; + 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 = filo_map->type; + debug("%016llx - %016llx (%d)\n", linux_map->addr, + linux_map->addr + linux_map->size, + linux_map->type); + 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 = (u32) 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); +} + +/* Video mode */ +static void set_video_mode(struct linux_params *params) +{ +#if CONFIG_COREBOOT_VIDEO_CONSOLE + /* Are we running on a framebuffer console? */ + if (!lib_sysinfo.framebuffer) + return; + + struct cb_framebuffer *fb = phys_to_virt(lib_sysinfo.framebuffer); + + params->lfb_width = fb->x_resolution; + params->lfb_height = fb->y_resolution; + params->lfb_depth = fb->bits_per_pixel; + params->lfb_linelength = fb->bytes_per_line; + params->lfb_base = fb->physical_address; + + // prolly not enough for the boot splash?! + params->lfb_size = + (params->lfb_linelength * params->lfb_height + 65535) >> 16; + params->red_size = fb->red_mask_size; + params->red_pos = fb->red_mask_pos; + params->green_size = fb->green_mask_size; + params->green_pos = fb->green_mask_pos; + params->blue_size = fb->blue_mask_size; + params->blue_pos = fb->blue_mask_pos; + params->rsvd_size = fb->reserved_mask_size; + params->rsvd_pos = fb->reserved_mask_pos; +#endif +} + +/* + * 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, u32 kern_addr) +{ + u32 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 (using_devsize) { + printf("Attempt to load up to end of device as kernel; " + "specify the image size\n"); + return 0; + } + + printf("Loading kernel... "); + if (file_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, + u32 kern_end, struct linux_params *params, + const char *initrd_file) +{ + u32 max; + u32 start, end, size; + uint64_t forced; + extern char _start[]; +#if 0 + extern char _end[]; +#endif + + if (!file_open(initrd_file)) { + printf("Can't open initrd: %s\n", initrd_file); + return -1; + } + if (using_devsize) { + printf("Attempt to load up to end of device as initrd; " + "specify the image size\n"); + return -1; + } + 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 - 1); + 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; +#if 0 + else { + /* Otherwise, see if we can put it above us. + * + * This would be a good idea if we could easily find + * out where the memory hole lives. + * + * There's nothing wrong with the initrd living below + * FILO. (stepan) + * + * The problems is even a 64bit kernel will live in + * 32bit address space, so if you have a lot of + * memory and specify mem=xG with x>4, the maximum + * allowed initrd address (2.6.x sets this to + * 0xffffffff) will be used for the high limit. + * (offset 22c in vmlinuz) + * + * you might want to enable this if you limit memory + * with mem=yG with y<4. + */ + if (virt_to_phys(_end) + size <= forced) + end = forced; /* Ok */ + } +#endif + } + + 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 (file_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(u32 kern_addr, struct linux_params *params) +{ + struct segment_desc *linux_gdt; + struct context *ctx; +#ifdef CONFIG_VGA_VIDEO_CONSOLE + unsigned int cursor_x, cursor_y, cursor_en; +#endif +#ifdef CONFIG_PCMCIA_CF + unsigned char *cf_bar; + int i; +#endif + + 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; + + /* set this field in any case to support relocatable kernels */ + params->kernel_start = kern_addr; + + debug("EIP=%#x\n", kern_addr); + printf("Jumping to entry point...\n"); + +#ifdef CONFIG_VGA_VIDEO_CONSOLE + /* Update VGA cursor position. + * This must be here because the printf changes the value! */ + video_console_get_cursor(&cursor_x, &cursor_y, &cursor_en); + params->orig_x = cursor_x; + params->orig_y = cursor_y; +#endif + +#ifdef CONFIG_PCMCIA_CF + cf_bar = phys_to_virt(pci_read_config32(PCI_DEV(0, 0xa, 1), 0x10)); + for (i = 0x836; i < 0x840; i++) { + cf_bar[i] = 0; + } +#endif + /* Go... */ + ctx = switch_to(ctx); + + /* It's impossible but... */ + printf("Returned with EAX=%#x\n", ctx->eax); + + return ctx->eax; +} + +int linux_load(const char *file, const char *cmdline) +{ + struct linux_header hdr; + struct linux_params *params; + u32 kern_addr, kern_size; + char *initrd_file = 0; + + if (!file_open(file)) + return -1; + + kern_addr = load_linux_header(&hdr); + if (kern_addr == 0) { + file_close(); + return LOADER_NOT_SUPPORT; + } + + params = phys_to_virt(LINUX_PARAM_LOC); + init_linux_params(params, &hdr); + set_memory_size(params); + set_video_mode(params); + 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); + file_close(); + return -1; + } + + if (initrd_file) { + if (load_initrd(&hdr, kern_addr + kern_size, + params, initrd_file) != 0) { + free(initrd_file); + file_close(); + return -1; + } + free(initrd_file); + } + + file_close(); +#if defined(CONFIG_USB) + usb_exit(); +#endif + + hardware_setup(); + + start_linux(kern_addr, params); + return 0; +} diff --git a/x86/segment.c b/x86/segment.c new file mode 100644 index 0000000..ea38096 --- /dev/null +++ b/x86/segment.c @@ -0,0 +1,135 @@ +/* + * This file is part of FILO. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/* Segmentation of the i386 architecture. + * + * 2003-07 by SONE Takeshi + */ + +#include <libpayload.h> +#include <coreboot_tables.h> +#include <config.h> +#include "segment.h" + +#define DEBUG_THIS CONFIG_DEBUG_SEGMENT +#include <debug.h> + +/* 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(void) +{ + 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; + struct sysinfo_t *info = &lib_sysinfo; +#define ALIGNMENT 0x1000 + + 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].type != CB_MEM_RAM) + continue; + 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; // for FILO + virtual_offset = new_offset; // for libpayload + + debug("ok\n"); +} diff --git a/x86/segment.h b/x86/segment.h new file mode 100644 index 0000000..43130e6 --- /dev/null +++ b/x86/segment.h @@ -0,0 +1,47 @@ +/* + * This file is part of FILO. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/* 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/x86/switch.S b/x86/switch.S new file mode 100644 index 0000000..50f5f71 --- /dev/null +++ b/x86/switch.S @@ -0,0 +1,116 @@ + .globl entry, __switch_context, __exit_context, halt + + .section ".boot", "xa" + .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/x86/sys_info.c b/x86/sys_info.c new file mode 100644 index 0000000..8e7d14e --- /dev/null +++ b/x86/sys_info.c @@ -0,0 +1,34 @@ +/* + * This file is part of FILO. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <libpayload.h> +#include <config.h> +#include <sys_info.h> +#include "context.h" +#define DEBUG_THIS CONFIG_DEBUG_SYS_INFO +#include <debug.h> + +void collect_sys_info(struct sys_info *info) +{ + /* 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); +} diff --git a/x86/timer.c b/x86/timer.c new file mode 100644 index 0000000..739c9ed --- /dev/null +++ b/x86/timer.c @@ -0,0 +1,38 @@ +/* + * This file is part of FILO. + * + * (C) 2004-2008 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <libpayload.h> +#include <arch/rdtsc.h> +#include <arch/timer.h> + +u64 currticks(void) +{ + /* Read the Time Stamp Counter */ + return rdtsc(); +} + +int getrtsecs (void) +{ + u64 t; + t=currticks(); + t=t/(TICKS_PER_SEC); + return (int)t; +} + + diff --git a/x86/wince_load.c b/x86/wince_load.c new file mode 100644 index 0000000..993815f --- /dev/null +++ b/x86/wince_load.c @@ -0,0 +1,385 @@ +/******************************************************************************* + * + * WindowsCE/i386 loader + * + * Copyright 2006 Andrei Birjukov andrei.birjukov@artecdesign.ee and + * Artec Design LLC http://www.artecdesign.ee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ******************************************************************************/ + +#include <libpayload.h> +#include <lib.h> +#include <fs.h> +#include <arch/io.h> +#include "context.h" +#include "segment.h" + +#define DEBUG_THIS DEBUG_WINCELOAD +#include <debug.h> + +#define BOOTARG_PTR_LOCATION 0x001FFFFC +#define BOOTARG_LOCATION 0x001FFF00 +#define BOOTARG_SIGNATURE 0x544F4F42 +#define BOOTARG_VERSION_SIG 0x12345678 +#define BOOTARG_MAJOR_VER 1 +#define BOOTARG_MINOR_VER 0 + +#define MAX_DEV_NAMELEN 16 // Should match EDBG_MAX_DEV_NAMELEN. + +#define LDRFL_USE_EDBG 0x0001 // Set to attempt to use debug Ethernet +// The following two flags are only looked at if LDRFL_USE_EDBG is set +#define LDRFL_ADDR_VALID 0x0002 // Set if EdbgAddr field is valid +#define LDRFL_JUMPIMG 0x0004 // If set, don't communicate with eshell to get +// The following flag is only used for backup FLASH operation +#define LDRFL_FLASH_BACKUP 0x80 +// configuration, use ucEshellFlags field. +// Use this constant in EdbgIRQ to specify that EDBG should run without an interrupt. +#define EDBG_IRQ_NONE 0xFF + +#define EDBG_ADAPTER_DEFAULT 2 +#define EDBG_ADAPTER_RTL8139 4 + +#define PSIZE (1500) // Max Packet Size +#define DSIZE (PSIZE+12) +#define BIN_HDRSIG_SIZE 7 + +#define ROM_SIGNATURE_OFFSET 0x40 // Offset from the image's physfirst address to the ROM signature. +#define ROM_SIGNATURE 0x43454345 +#define ROM_TOC_POINTER_OFFSET 0x44 // Offset from the image's physfirst address to the TOC pointer. +#define ROM_TOC_OFFSET_OFFSET 0x48 // Offset from the image's physfirst address to the TOC offset (from physfirst). + +#define GDT_LOC 0x92000 +#define STACK_LOC 0x93000 + +typedef struct _EDBG_ADDR { + u32 dwIP; + u16 wMAC[3]; + u16 wPort; +} EDBG_ADDR; + +typedef struct _BOOT_ARGS { + u8 ucVideoMode; + u8 ucComPort; + u8 ucBaudDivisor; + u8 ucPCIConfigType; + u32 dwSig; + u32 dwLen; + u8 ucLoaderFlags; + u8 ucEshellFlags; + u8 ucEdbgAdapterType; + u8 ucEdbgIRQ; + u32 dwEdbgBaseAddr; + u32 dwEdbgDebugZone; + EDBG_ADDR EdbgAddr; + EDBG_ADDR EshellHostAddr; + EDBG_ADDR DbgHostAddr; + EDBG_ADDR CeshHostAddr; + EDBG_ADDR KdbgHostAddr; + u32 DHCPLeaseTime; + u16 EdbgFlags; + u16 KitlTransport; + u32 dwEBootFlag; + u32 dwEBootAddr; + u32 dwLaunchAddr; + u32 pvFlatFrameBuffer; + u16 vesaMode; + u16 cxDisplayScreen; + u16 cyDisplayScreen; + u16 cxPhysicalScreen; + u16 cyPhysicalScreen; + u16 cbScanLineLength; + u16 bppScreen; + u8 RedMaskSize; + u8 RedMaskPosition; + u8 GreenMaskSize; + u8 GreenMaskPosition; + u8 BlueMaskSize; + u8 BlueMaskPosition; + u32 dwVersionSig; + u16 MajorVersion; + u16 MinorVersion; + u8 szDeviceNameRoot[MAX_DEV_NAMELEN]; + u32 dwImgStoreAddr; + u32 dwImgLoadAddr; + u32 dwImgLength; + u8 NANDBootFlags; + u8 NANDBusNumber; + u32 NANDSlotNumber; +} BOOT_ARGS; + +typedef struct _ROMHDR { + u32 dllfirst; + u32 dlllast; + u32 physfirst; + u32 physlast; + u32 nummods; + u32 ulRAMStart; + u32 ulRAMFree; + u32 ulRAMEnd; + u32 ulCopyEntries; + u32 ulCopyOffset; + u32 ulProfileLen; + u32 ulProfileOffset; + u32 numfiles; + u32 ulKernelFlags; + u32 ulFSRamPercent; + u32 ulDrivglobStart; + u32 ulDrivglobLen; + u16 usCPUType; + u16 usMiscFlags; + void *pExtensions; + u32 ulTrackingStart; + u32 ulTrackingLen; +} ROMHDR; + +typedef struct _SEGMENT_INFO { + u32 segAddr; + u32 segSize; + u32 checkSum; +} SEGMENT_INFO; + +typedef void (*PFN_LAUNCH) (); // WinCE launch function proto + +static u8 g_ceSignature[] = { 'B', '0', '0', '0', 'F', 'F', '\n' }; +static void **g_ppBootArgs = NULL; +BOOT_ARGS *g_pBootArgs = NULL; +static ROMHDR *pROMHeader = NULL; + +static u32 g_imageStart = 0; +static u32 g_imageSize = 0; +static u32 g_romOffset = 0; + +static int verifyCheckSum(u8 * pData, int nSize, u32 checkSum) +{ + // check the CRC + u32 crc = 0; + int i; + + for (i = 0; i < nSize; i++) + crc += *pData++; + + return (crc == checkSum); +} + +int wince_launch(u32 imageStart, u32 imageSize, + u32 entryPoint, ROMHDR * pRomHdr) +{ + struct segment_desc *wince_gdt; + struct context *ctx; + + debug("start Windows CE from address 0x%x, image loaded 0x%x,%d\n", + entryPoint, imageStart, imageSize); + + // initialize new stack + ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0); + + // initialize GDT in low memory + wince_gdt = phys_to_virt(GDT_LOC); + memset(wince_gdt, 0, 13 * sizeof(struct segment_desc)); + // flat kernel code/data segments + wince_gdt[2] = gdt[FLAT_CODE]; + wince_gdt[3] = gdt[FLAT_DATA]; + + wince_gdt[12] = gdt[FLAT_CODE]; + wince_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; + + // kernel entry point + ctx->eip = entryPoint; + + printf("Launching Windows CE...\n"); + + // go...! + ctx = switch_to(ctx); + + // may never return here + printf("returned with eax=%#x\n", ctx->eax); + return ctx->eax; +} + +void wince_init_bootarg(u32 entryPoint) +{ + // init the BOOT_ARGS pointer at the known address + g_ppBootArgs = phys_to_virt(BOOTARG_PTR_LOCATION); + *g_ppBootArgs = (void *) BOOTARG_LOCATION; + + // keep our BOOT_ARGS somewhere in a dry dark place + g_pBootArgs = phys_to_virt(BOOTARG_LOCATION); + + debug("BOOT_ARGS at addr 0x%x, pointer at 0x%x [%x]\n", + (unsigned int) *g_ppBootArgs, BOOTARG_PTR_LOCATION, + (unsigned int) g_ppBootArgs); + + memset(g_pBootArgs, 0, sizeof(BOOT_ARGS)); + + // this data was copied from WinCE EDBG boot args + g_pBootArgs->ucEdbgAdapterType = EDBG_ADAPTER_DEFAULT; + // use the first PCI NIC available + g_pBootArgs->ucEdbgIRQ = 0; + g_pBootArgs->dwEdbgBaseAddr = 0; + + // set the KITL device name to something adequate + strcpy((char *) g_pBootArgs->szDeviceNameRoot, "FILO"); + + g_pBootArgs->dwSig = BOOTARG_SIGNATURE; + g_pBootArgs->dwLen = sizeof(BOOT_ARGS); + g_pBootArgs->dwVersionSig = BOOTARG_VERSION_SIG; + g_pBootArgs->MajorVersion = BOOTARG_MAJOR_VER; + g_pBootArgs->MinorVersion = BOOTARG_MINOR_VER; + +/* + g_pBootArgs->ucVideoMode = 255; + g_pBootArgs->ucComPort = 1; + g_pBootArgs->ucBaudDivisor = 3; + g_pBootArgs->ucPCIConfigType = 1; + g_pBootArgs->ucLoaderFlags = 0x7; +*/ + + debug("Boot arguments initialized at 0x%x\n", + (unsigned int) *g_ppBootArgs); +} + +int wince_load(const char *file, const char *cmdline) +{ + u8 signBuf[BIN_HDRSIG_SIZE], *pDest = NULL; + SEGMENT_INFO segInfo; + u32 totalBytes = 0; + + if (!file_open(file)) { + printf("Failed opening image file: %s\n", file); + return LOADER_NOT_SUPPORT; + } + // read the image signature + file_read((void *) signBuf, BIN_HDRSIG_SIZE); + + if (memcmp(signBuf, g_ceSignature, BIN_HDRSIG_SIZE)) { + printf("Bad or unknown Windows CE image signature\n"); + file_close(); + return LOADER_NOT_SUPPORT; + } + // now read image start address and size + file_read((void *) &g_imageStart, sizeof(u32)); + file_read((void *) &g_imageSize, sizeof(u32)); + + if (!g_imageStart || !g_imageSize) // sanity check + { + printf("Invalid image descriptors\n"); + file_close(); + return LOADER_NOT_SUPPORT; + } + + printf("Windows CE BIN image, start 0x%x, length %d\n", + g_imageStart, g_imageSize); + + // main image reading loop + while (1) { + // first grab the segment descriptor + if (file_read(&segInfo, sizeof(SEGMENT_INFO)) < + sizeof(SEGMENT_INFO)) { + printf ("\nFailed reading image segment descriptor\n"); + file_close(); + return LOADER_NOT_SUPPORT; + } + + totalBytes += sizeof(SEGMENT_INFO); // update data counter + printf("#"); // that's a progress bar :) + + // now check if that's the last one + if (segInfo.segAddr == 0 && segInfo.checkSum == 0) + break; + + // map segment address to current address space + pDest = (u8 *) phys_to_virt(segInfo.segAddr); + debug("fetched segment address 0x%x [%x] size %d\n", + segInfo.segAddr, (unsigned int) pDest, + segInfo.segSize); + + // read the image segment data from VFS + if (file_read((void *) pDest, segInfo.segSize) < + segInfo.segSize) { + printf ("\nFailed reading image segment data (address 0x%x, size %d)\n", + segInfo.segAddr, segInfo.segSize); + file_close(); + return LOADER_NOT_SUPPORT; + } + // check the data integrity + if (!verifyCheckSum + (pDest, segInfo.segSize, segInfo.checkSum)) { + printf ("\nFailed verifying segment checksum at address 0x%x, size %d\n", + (unsigned int) pDest, segInfo.segSize); + file_close(); + return LOADER_NOT_SUPPORT; + } + // Look for ROMHDR to compute ROM offset. NOTE: romimage guarantees that the record containing + // the TOC signature and pointer will always come before the record that contains the ROMHDR contents. + + if (segInfo.segSize == sizeof(ROMHDR) && + (*(u32 *) phys_to_virt(g_imageStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE)) { + u32 tempOffset = + (segInfo.segAddr - + *(u32 *) phys_to_virt(g_imageStart + + ROM_SIGNATURE_OFFSET + + sizeof(long))); + ROMHDR *pROMhdr = (ROMHDR *) pDest; + + // check to make sure this record really contains the ROMHDR. + if ((pROMhdr->physfirst == (g_imageStart - tempOffset)) && + (pROMhdr->physlast == (g_imageStart - tempOffset + g_imageSize)) && + (u32) (((pROMhdr-> dllfirst << 16) & 0xffff0000) <= pROMhdr->dlllast) && + (u32) (((pROMhdr-> dllfirst << 16) & 0x0000ffff) <= pROMhdr->dlllast)) { + g_romOffset = tempOffset; + debug("\nROM offset = 0x%x\n", g_romOffset); + } + } + + totalBytes += segInfo.segSize; // update data counter + } + + // we should have moved all image segments to RAM by now + printf("\nOS image loaded.\n"); + + // check for pTOC signature ("CECE") here, after image in place + if (*(u32 *) phys_to_virt(g_imageStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE) { + // a pointer to the ROMHDR structure lives just past the ROM_SIGNATURE (which is a longword value). Note that + // this pointer is remapped since it might be a flash address (image destined for flash), but is actually cached + // in RAM. + + u32 cacheAddress = *(u32 *) phys_to_virt(g_imageStart + ROM_SIGNATURE_OFFSET + sizeof(u32)); + + pROMHeader = + (ROMHDR *) phys_to_virt(cacheAddress + g_romOffset); + debug("ROMHDR at address 0x%xh\n", + cacheAddress + g_romOffset); + } + + file_close(); + + // prepare the boot arguments + // note that the last segment size carries the launch address + wince_init_bootarg(segInfo.segSize); + + // finally, call the generic launch() function + return wince_launch(g_imageStart, g_imageSize, segInfo.segSize, + pROMHeader); +}