[coreboot] New patch to review for filo: 16d77de Rename i386 to x86, in accordance with libpayload
Patrick Georgi (patrick@georgi-clan.de)
gerrit at coreboot.org
Wed Dec 19 13:56:16 CET 2012
Patrick Georgi (patrick at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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);
+}
More information about the coreboot
mailing list