From c275218a89c0166c68ea884cdc9c6d7668a7d4e9 Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Mon, 29 Jan 2007 22:09:50 +0000 Subject: [PATCH] Add a first bit of a framework. Builds the following parts, in accordance to the newboot document: * reset vector (16 bytes) * vpd (240bytes) * boot block (8k - 256b) * lar archive (256-8 k) The boot block is kind of simple, still. It enables pmode, car, and starts looking for an initram module in the lar archive. Note: This doesnt do much at the moment, as gas seems to produce buggy code in init.S. Take this as a suggestion of how it might work and please provide patches fixing it and bringing it into shape. Signed-off-by: Stefan Reinauer Acked-by: Ronald G. Minnich git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@62 f3766cd6-281f-0410-b1cd-43a5c92072e9 --- Makefile | 2 +- arch/x86/Makefile.target | 81 ++-- arch/x86/cache_as_ram.S | 259 +++++++++++ arch/x86/cachemain.c | 92 ++++ arch/x86/config.h | 8 + arch/x86/console.c | 70 +++ arch/x86/init.S | 148 ++++++ arch/x86/init/Makefile | 22 - arch/x86/init/init.S | 436 ------------------ arch/x86/macros.h | 14 + arch/x86/mtrr.h | 45 ++ arch/x86/reset.S | 26 ++ arch/x86/serial.c | 110 +++++ console/vtxprintf.c | 309 +++++++++++++ include/cpu/generic/x86/arch/hlt.h | 9 + include/cpu/generic/x86/div64.h | 48 ++ include/fallback.h | 18 + include/lar.h | 39 ++ include/string.h | 130 ++++++ include/uart8250.h | 15 + lib/lar.c | 63 +++ lib/uart8250.c | 91 ++++ mainboard/emulation/qemu-i386/Makefile.target | 62 ++- mainboard/emulation/qemu-i386/initram.c | 24 + util/lar/list.c | 2 +- 25 files changed, 1627 insertions(+), 496 deletions(-) create mode 100644 arch/x86/cache_as_ram.S create mode 100644 arch/x86/cachemain.c create mode 100644 arch/x86/config.h create mode 100644 arch/x86/console.c create mode 100644 arch/x86/init.S delete mode 100644 arch/x86/init/Makefile delete mode 100644 arch/x86/init/init.S create mode 100644 arch/x86/macros.h create mode 100644 arch/x86/mtrr.h create mode 100644 arch/x86/reset.S create mode 100644 arch/x86/serial.c create mode 100644 console/vtxprintf.c create mode 100644 include/cpu/generic/x86/arch/hlt.h create mode 100644 include/cpu/generic/x86/div64.h create mode 100644 include/fallback.h create mode 100644 include/lar.h create mode 100644 include/string.h create mode 100644 include/uart8250.h create mode 100644 lib/lar.c create mode 100644 lib/uart8250.c create mode 100644 mainboard/emulation/qemu-i386/initram.c diff --git a/Makefile b/Makefile index 4019a41ae8..b54be4159d 100644 --- a/Makefile +++ b/Makefile @@ -418,7 +418,7 @@ include $(srctree)/arch/$(ARCH)/Makefile export KBUILD_DEFCONFIG config %config: scripts_basic outputmakefile FORCE - $(Q)mkdir -p include/linux + $(Q)mkdir -p include/linuxbios $(Q)$(MAKE) $(build)=scripts/kconfig $@ $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= .kernelrelease diff --git a/arch/x86/Makefile.target b/arch/x86/Makefile.target index cfa2125bb4..9de5dc64af 100644 --- a/arch/x86/Makefile.target +++ b/arch/x86/Makefile.target @@ -24,11 +24,15 @@ # might want to read # +CFLAGS := + linuxbios.jump: FORCE $(Q)echo "Building jump vector" - $(Q)dd if=/dev/zero of=$(objtree)/linuxbios.jump bs=16 count=1 # 0x10 - touch $(objtree)/linuxbios.jump - + $(Q)$(CC) -E $(srctree)/arch/x86/reset.S -o $(objtree)/reset.s -DBOOTBLK=0x1f00 -DRESRVED=0xf0 -DDATE=\"`date +%Y/%m/%d`\" + $(Q)$(AS) $(objtree)/reset.s -o $(objtree)/reset.o + $(Q)$(LD) -Ttext 0xfffffff0 -s --oformat binary $(objtree)/reset.o -o $(objtree)/linuxbios.jump + $(Q)chmod 644 $(objtree)/linuxbios.jump + $(Q)echo "Len: `wc -c < linuxbios.jump`" # # This part takes care of compression. It should build the compression modules @@ -68,35 +72,53 @@ linuxbios_ram: statictree.o payload: $(Q)echo "building payload" + # # build the lar archive # - -linuxbios.lar: lzma initram linuxbios_ram payload - $(Q)echo lar c $(objdir)/linuxbios.lar $^ - $(Q)dd if=/dev/zero of=$(objtree)/linuxbios.lar bs=57088 count=1 - +linuxbios.lar: $(objtree)/lar lzma linuxbios.initram linuxbios_ram payload + $(Q)echo "Building LinuxBIOS archive..." + $(Q)mkdir $(objtree)/lar.tmp + $(Q)mkdir $(objtree)/lar.tmp/normal + $(Q)cp $(objtree)/linuxbios.initram $(objtree)/lar.tmp/normal/initram + $(Q)cd $(objtree)/lar.tmp && ../lar c ../linuxbios.lar.pre normal/initram + # TODO: dynamically pad the lar archive. bs is image size - bootblock size (8k) + $(Q)dd if=$(objtree)/linuxbios.lar.pre of=$(objtree)/linuxbios.lar bs=253952 count=1 conv=sync # # this is going to be the enable car code, lar parser and such: # - -linuxbios.init: - $(Q)echo Building init from $^ - $(Q)dd if=/dev/zero of=$(objtree)/linuxbios.init bs=8192 count=1 +INITCFLAGS=-I$(srctree)/include/cpu/generic/x86 -I$(srctree)/include -fno-builtin -Os -# -# VPD or SIP ROM or ... how does nvidia call it? -# Some space to cope with dirty southbridge tricks. -# Do we want to put our own stuff there, too? -# - -#linuxbios.vpd: -# $(Q)printf "Building dummy VPD ..." -# $(Q)dd if=/dev/zero of=$(objtree)/linuxbios.vpd bs=240 count=1 # 0xf0 -# $(Q)printf "ok.\n" +linuxbios.init: + $(Q)echo Building linuxbios.init + # + # asm stub + $(Q)$(CC) -E $(srctree)/arch/x86/init.S -o $(objtree)/init.s + $(Q)$(AS) $(objtree)/init.s -o $(objtree)/init.o + # + # main + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/arch/x86/cachemain.c -o cachemain.o + # + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/lib/lar.c -o lar.o + # + # console lib + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/arch/x86/console.c -o console.o + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/arch/x86/serial.c -o serial.o + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/console/vtxprintf.c -o vtxprintf.o + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/lib/uart8250.c -o uart8250.o + + # TODO: dynamic start address 4G - 0x2000 (bootblock size) + $(Q)$(LD) -Ttext 0xffffe000 -s --oformat binary init.o cachemain.o console.o uart8250.o \ + serial.o vtxprintf.o lar.o -o linuxbios.init.pre + + # Pad boot block to 0x2000 - 0x100 + $(Q)dd if=linuxbios.init.pre of=linuxbios.init bs=7936 conv=sync + $(Q)echo "Len: `wc -c < linuxbios.init.pre`" + # + $(Q)test `wc -c < linuxbios.init.pre` -gt 7936 && echo "Error. Bootblock got too big" || true # # Compose the image: @@ -107,18 +129,9 @@ linuxbios.rom: linuxbios.lar linuxbios.init linuxbios.vpd linuxbios.jump $(objtree)/linuxbios.vpd $(objtree)/linuxbios.jump > \ $(objtree)/linuxbios.rom -# miscellaneous important targets. -$(objtree)/mainboard.o: $(objtree)/statictree.o - -$(objtree)/statictree.o: $(objtree)/statictree.c - $(CC) $(CFLAGS) $(LINUXBIOSINCLUDE) -c -o $(objtree)/statictree.o $(objtree)/statictree.c - -$(objtree)/statictree.c: mainboard/$(MAINBOARDDIR)/dts $(objtree)/dtc - $(objtree)/dtc -O lb mainboard/$(MAINBOARDDIR)/dts >$(objtree)/statictree.c - -$(objtree)/dtc: - $(MAKE) -C $(srctree)/util/dtc/ - cp $(srctree)/util/dtc/dtc $(objtree) +$(objtree)/lar: + $(MAKE) -C $(srctree)/util/lar + cp $(srctree)/util/lar/lar $(objtree) .PHONY: linuxbios.rom diff --git a/arch/x86/cache_as_ram.S b/arch/x86/cache_as_ram.S new file mode 100644 index 0000000000..01f9c301f8 --- /dev/null +++ b/arch/x86/cache_as_ram.S @@ -0,0 +1,259 @@ +/* Copyright (C) 2005 Eswar Nallusamy, LANL + * Copyright (C) 2005 Yinghai Lu, Tyan Corp. + * Copyright (C) 2007 Stefan Reinauer, coresystems GmbH + +/* We will use 4Kbytes only for cache as ram. This is + * enough to fit in our stack. + * + * disable HyperThreading is done by eswar + * the other is very similar to the AMD CAR, except remove amd specific msr + */ + +#define CacheSize 4096 +#define CacheBase (0xd0000 - CacheSize) + +#define ASSEMBLY +#include "mtrr.h" + + /* Save the BIST result */ + movl %eax, %ebp + +CacheAsRam: + /* Check whether the processor has HT capability */ + movl $01, %eax + cpuid + btl $28, %edx + jnc NotHtProcessor + bswapl %ebx + cmpb $01, %bh + jbe NotHtProcessor + + /* It is a HT processor; Send SIPI to the other logical processor + * within this processor so that the CAR related common system + * registers are programmed accordingly + */ + + /* Use some register that is common to both logical processors + * as semaphore. Refer Appendix B, Vol.3 + */ + + xorl %eax, %eax + xorl %edx, %edx + movl $0x250, %ecx + wrmsr + + /* Figure out the logical AP's APIC ID; the following logic will work + * only for processors with 2 threads. + * + * Refer to Vol 3. Table 7-1 for details about this logic + */ + movl $0xFEE00020, %esi + movl (%esi), %ebx + andl $0xFF000000, %ebx + bswapl %ebx + btl $0, %ebx + jnc LogicalAP0 + andb $0xFE, %bl + jmp SendSIPI +LogicalAP0: + orb $0x01, %bl +SendSIPI: + bswapl %ebx /* ebx - logical AP's APIC ID */ + + /* Fill up the IPI command registers in the Local APIC mapped to + * default address and issue SIPI to the other logical processor + * within this processor die. + */ + +RetrySIPI: + movl %ebx, %eax + movl $0xFEE00310, %esi + movl %eax, (%esi) + + /* SIPI vector - F900:0000 */ + movl $0x000006F9, %eax + movl $0xFEE00300, %esi + movl %eax, (%esi) + + movl $0x30, %ecx +SIPIDelay: + pause + decl %ecx + jnz SIPIDelay + + movl (%esi), %eax + andl $0x00001000, %eax + jnz RetrySIPI + + /* Wait for the Logical AP to complete initialization */ +LogicalAPSIPINotdone: + movl $0x250, %ecx + rdmsr + orl %eax, %eax + jz LogicalAPSIPINotdone + + + +NotHtProcessor: + /* Set the default memory type and enable fixed and variable MTRRs */ + movl $MTRRdefType_MSR, %ecx + xorl %edx, %edx + /* Enable Variable and Fixed MTRRs */ + movl $0x00000c00, %eax + wrmsr + + /*Clear all MTRRs */ + xorl %edx, %edx + movl $fixed_mtrr_msr, %esi +clear_fixed_var_mtrr: + lodsl (%esi), %eax + testl %eax, %eax + jz clear_fixed_var_mtrr_out + + movl %eax, %ecx + xorl %eax, %eax + wrmsr + + jmp clear_fixed_var_mtrr +clear_fixed_var_mtrr_out: + +#if CacheSize == 0x10000 + /* enable caching for 64K using fixed mtrr */ + movl $0x268, %ecx /* fix4k_c0000*/ + movl $0x06060606, %eax /* WB IO type */ + movl %eax, %edx + wrmsr + movl $0x269, %ecx + wrmsr +#endif + +#if CacheSize == 0x8000 + /* enable caching for 32K using fixed mtrr */ + movl $0x269, %ecx /* fix4k_c8000*/ + movl $0x06060606, %eax /* WB IO type */ + movl %eax, %edx + wrmsr +#endif + + /* enable caching for 16K/8K/4K using fixed mtrr */ + movl $0x269, %ecx /* fix4k_cc000*/ +#if CacheSize == 0x4000 + movl $0x06060606, %edx /* WB IO type */ +#endif +#if CacheSize == 0x2000 + movl $0x06060000, %edx /* WB IO type */ +#endif +#if CacheSize == 0x1000 + movl $0x06000000, %edx /* WB IO type */ +#endif + xorl %eax, %eax + wrmsr + +#if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE) + /* enable write base caching so we can do execute in place + * on the flash rom. + */ + movl $0x202, %ecx + xorl %edx, %edx + movl $(XIP_ROM_BASE | MTRR_TYPE_WRBACK), %eax + wrmsr + + movl $0x203, %ecx + movl $0x0000000f, %edx + movl $(~(XIP_ROM_SIZE - 1) | 0x800), %eax + wrmsr +#endif /* XIP_ROM_SIZE && XIP_ROM_BASE */ + + /* enable cache */ + movl %cr0, %eax + andl $0x9fffffff,%eax + movl %eax, %cr0 + + /* Read the range with lodsl*/ + movl $CacheBase, %esi + cld + movl $(CacheSize>>2), %ecx + rep lodsl + + /* Clear the range */ + movl $CacheBase, %edi + movl $(CacheSize>>2), %ecx + xorl %eax, %eax + rep stosl + + +#if 0 + /* check the cache as ram */ + movl $CacheBase, %esi + movl $(CacheSize>>2), %ecx +.xin1: + movl %esi, %eax + movl %eax, (%esi) + decl %ecx + je .xout1 + add $4, %esi + jmp .xin1 +.xout1: + + movl $CacheBase, %esi +// movl $(CacheSize>>2), %ecx + movl $4, %ecx +.xin1x: + movl %esi, %eax + + movl $0x4000, %edx + movb %ah, %al +.testx1: + outb %al, $0x80 + decl %edx + jnz .testx1 + + movl (%esi), %eax + cmpb 0xff, %al + je .xin2 /* dont show */ + + movl $0x4000, %edx +.testx2: + outb %al, $0x80 + decl %edx + jnz .testx2 + +.xin2: decl %ecx + je .xout1x + add $4, %esi + jmp .xin1x +.xout1x: + +#endif + + movl $(CacheBase+CacheSize-4), %eax + movl %eax, %esp + + /* Load a different set of data segments */ + movw $CACHE_RAM_DATA_SEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + +lout: + + /* Restore the BIST result */ + movl %ebp, %eax + /* We need to set ebp ? No need */ + movl %esp, %ebp + pushl %eax /* bist */ + call stage1_main + /* We will not go back */ + +fixed_mtrr_msr: + .long 0x250, 0x258, 0x259 + .long 0x268, 0x269, 0x26A + .long 0x26B, 0x26C, 0x26D + .long 0x26E, 0x26F +var_mtrr_msr: + .long 0x200, 0x201, 0x202, 0x203 + .long 0x204, 0x205, 0x206, 0x207 + .long 0x208, 0x209, 0x20A, 0x20B + .long 0x20C, 0x20D, 0x20E, 0x20F + .long 0x000 /* NULL, end of table */ + diff --git a/arch/x86/cachemain.c b/arch/x86/cachemain.c new file mode 100644 index 0000000000..c0c57cc70b --- /dev/null +++ b/arch/x86/cachemain.c @@ -0,0 +1,92 @@ +/* GPLv2. + * + * Copyright (C) 2007 Stefan Reinauer , coresystems GmbH + */ + +#include +#include +#include +#include +#include "config.h" + +static void post_code(u8 value) +{ + outb(value, 0x80); +} + +static void stop_ap(void) +{ + // nothing yet + post_code(0xf0); +} + +static void enable_superio(void) +{ + // nothing yet + post_code(0xf1); +} + +static void enable_rom(void) +{ + // nothing here yet + post_code(0xf2); +} + +void stage1_main(u32 bist) +{ + int ret; + struct mem_file archive, result; + + post_code(0x02); + + // before we do anything, we want to stop if we dont run + // on the bootstrap processor. + if (bist==0) { + // stop secondaries + stop_ap(); + } + + // We have cache as ram running and can start executing code in C. + // + + enable_superio(); + + // + uart_init(); // initialize serial port + console_init(); // print banner + + if (bist!=0) { + die("BIST FAILED: %08x", bist); + } + + // enable rom + enable_rom(); + + // location and size of image. + + // FIXME this should be defined in the VPD area + // but NOT IN THE CODE. + + archive.len=LINUXBIOS_ROMSIZE_KB*1024; + archive.start=(void *)(0UL-archive.len); + + // FIXME check integrity + + + // fixme: choose an initram image (normal/fallback) + // find first initram + ret=find_file(&archive, "normal/initram", &result); + if(!ret) { + void (*initram)(void); + initram=(result.start); + printk(BIOS_INFO, "Jumping to RAM init code at 0x%08x\n", + result.start); + initram(); + + } + + die ("FATAL: No initram module found\n"); + +} + + diff --git a/arch/x86/config.h b/arch/x86/config.h new file mode 100644 index 0000000000..a897e4eeaa --- /dev/null +++ b/arch/x86/config.h @@ -0,0 +1,8 @@ +/* This config file is a place holder and will be created dynamically soon */ + +#define LINUXBIOS_VERSION "3.0.0-wth" +#define LINUXBIOS_BUILD "Fri Jan 19 15:24:28 CET 2007" + +#define LINUXBIOS_ROMSIZE_KB 512 + +#define TTYS0_BASE 0x3f8 diff --git a/arch/x86/console.c b/arch/x86/console.c new file mode 100644 index 0000000000..ecfb660886 --- /dev/null +++ b/arch/x86/console.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include "config.h" + +// FIXME: we need this for varargs +#include + +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_DEBUG +#define debug(msg_level, fmt, arg...) printk(msg_level, fmt, ##arg) +#endif + +#ifndef LINUXBIOS_EXTRA_VERSION +#define LINUXBIOS_EXTRA_VERSION "" +#endif + +/* printk's without a loglevel use this.. */ +#define DEFAULT_MESSAGE_LOGLEVEL 4 /* BIOS_WARNING */ + +extern int vtxprintf(void (*)(unsigned char), const char *, va_list); +extern void uart8250_tx_byte(unsigned, unsigned char); + +int console_loglevel() +{ + return 8; +} + +void console_tx_byte(unsigned char byte) +{ + if (byte == '\n') + uart8250_tx_byte(TTYS0_BASE, '\r'); + uart8250_tx_byte(TTYS0_BASE, byte); +} + +int printk(int msg_level, const char *fmt, ...) +{ + va_list args; + int i; + + if (msg_level >= console_loglevel()) { + return 0; + } + + va_start(args, fmt); + i = vtxprintf(console_tx_byte, fmt, args); + va_end(args); + + return i; +} + +void console_init(void) +{ + static const char console_test[] = + "\n\nLinuxBIOS-" + LINUXBIOS_VERSION + LINUXBIOS_EXTRA_VERSION + " " + LINUXBIOS_BUILD + " starting...\n"; + + printk(BIOS_INFO, console_test); +} + +void die(const char *str) +{ + printk(BIOS_EMERG,str); + do { + hlt(); + } while(1); +} diff --git a/arch/x86/init.S b/arch/x86/init.S new file mode 100644 index 0000000000..2b46bcbcc8 --- /dev/null +++ b/arch/x86/init.S @@ -0,0 +1,148 @@ +# init code - switch cpu to pmode and enable cache as ram. +# +# Copyright (C) 2000 Ron Minnich, Advanced Computing Lab, LANL +# Copyright (C) 2007 Stefan Reinauer, 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 "macros.h" + +#define ROM_CODE_SEG 0x08 +#define ROM_DATA_SEG 0x10 + +#define CACHE_RAM_CODE_SEG 0x18 +#define CACHE_RAM_DATA_SEG 0x20 + + .code16 + .globl _start +_start: + cli + + /* save the BIST result */ + movl %eax, %ebp; + + /* thanks to kmliu@sis.tw.com for this TBL fix */ + /* IMMEDIATELY invalidate the translation lookaside buffer before + * executing any further code. Even though paging is disabled we + * could still get false address translations due to the TLB if we + * didn't invalidate it. + */ + + xorl %eax, %eax + movl %eax, %cr3 /* Invalidate TLB */ + + /* switch to protected mode */ + + movw %cs, %ax + shlw $4, %ax + movw $gdt16 + 0xe000, %bx + subw %ax, %bx + data32 lgdt %cs:(%bx) + + movl %cr0, %eax + andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */ + orl $0x60000001, %eax /* CD, NW, PE = 1 */ + movl %eax, %cr0 + + /* Restore BIST result */ + movl %ebp, %eax + + + // port80_post (0x23) /* post 0x01 */ + /* Now we are in protected mode. Jump to a 32 bit code segment. */ + //data32 ljmp $ROM_CODE_SEG, $__protected_start + data32 ljmp $ROM_CODE_SEG, $0xe058 + + .align 4 + .globl gdt16 +gdt16 = . - _start + .word gdt_end - gdt -1 /* compute the table limit */ + .long gdt /* we know the offset */ + + + /* From now on we are 32bit */ + + .code32 + + +/* This is the gdt for ROMCC/ASM part of LinuxBIOS. It + * is different from the gdt in GCC part of LinuxBIOS. + * + * That on was defined in c_start.S in LinuxBIOS v2. TODO + */ + + .align 4 + .globl gdtptr +gdt: +gdtptr: + .word gdt_end - gdt -1 /* compute the table limit */ + .long gdt /* we know the offset */ + .word 0 + + /* selgdt 0x08, flat code segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + + /* selgdt 0x10,flat data segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x93, 0xcf, 0x00 +gdt_end: + +/* + * When we come here we are in protected mode. We expand + * the stack and copies the data segment from ROM to the + * memory. + * + * After that, we call the chipset bootstrap routine that + * does what is left of the chipset initialization. + * + * NOTE aligned to 4 so that we are sure that the prefetch + * cache will be reloaded. + */ + + .align 4 +#if 0 + //This code was used by v2. TODO + .globl protected_start +protected_start: + + lgdt %cs:gdtptr + ljmp $ROM_CODE_SEG, $__protected_start +#endif + +.globl __protected_start +__protected_start: + /* Save the BIST value */ + movl %eax, %ebp + + port80_post (0x01) /* post 0x01 */ + + movw $ROM_DATA_SEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + + /* Restore the BIST value to %eax */ + movl %ebp, %eax + +#define CONFIG_CPUTYPE_INTEL 1 +#ifdef CONFIG_CPUTYPE_INTEL +#include "cache_as_ram.S" +#endif + +.align 4 diff --git a/arch/x86/init/Makefile b/arch/x86/init/Makefile deleted file mode 100644 index 1a9659ff58..0000000000 --- a/arch/x86/init/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -## -## This file is part of the LinuxBIOS project. -## -## Copyright (C) 2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -## - -head-y += init.o - diff --git a/arch/x86/init/init.S b/arch/x86/init/init.S deleted file mode 100644 index f809bd3524..0000000000 --- a/arch/x86/init/init.S +++ /dev/null @@ -1,436 +0,0 @@ -// mainboardinit cpu/x86/16bit/entry16.inc - -/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL - * rminnich@lanl.gov - */ - -/* Start code to put an i386 or later processor into 32-bit - * protected mode. - */ - -/* .section ".rom.text" */ -#include -.code16 -.globl _start -.type _start, @function - -_start: - cli - /* Save the BIST result */ - movl %eax, %ebp - - /* thanks to kmliu@sis.tw.com for this TBL fix ... */ - - /* IMMEDIATELY invalidate the translation lookaside buffer before executing*/ - /* any further code. Even though paging is disabled we could still get*/ - /*false address translations due to the TLB if we didn't invalidate it.*/ - - xorl %eax, %eax - movl %eax, %cr3 /* Invalidate TLB*/ - - /* Invalidating the cache here seems to be a bad idea on - * modern processors. Don't. - * If we are hyperthreaded or we have multiple cores it is bad, - * for SMP startup. On Opterons it causes a 5 second delay. - * Invalidating the cache was pure paranoia in any event. - * If you cpu needs it you can write a cpu dependent version of - * entry16.inc. - */ - - /* Note: gas handles memory addresses in 16 bit code very poorly. - * In particular it doesn't appear to have a directive allowing you - * associate a section or even an absolute offset with a segment register. - * - * This means that anything except cs:ip relative offsets are - * a real pain in 16 bit mode. And explains why it is almost - * imposible to get gas to do lgdt correctly. - * - * One way to work around this is to have the linker do the - * math instead of the assembler. This solves the very - * pratical problem of being able to write code that can - * be relocated. - * - * An lgdt call before we have memory enabled cannot be - * position independent, as we cannot execute a call - * instruction to get our current instruction pointer. - * So while this code is relocateable it isn't arbitrarily - * relocatable. - * - * The criteria for relocation have been relaxed to their - * utmost, so that we can use the same code for both - * our initial entry point and startup of the second cpu. - * The code assumes when executing at _start that: - * (((cs & 0xfff) == 0) and (ip == _start & 0xffff)) - * or - * ((cs == anything) and (ip == 0)). - * - * The restrictions in reset16.inc mean that _start initially - * must be loaded at or above 0xffff0000 or below 0x100000. - * - * The linker scripts computs gdtptr16_offset by simply returning - * the low 16 bits. This means that the intial segment used - * when start is called must be 64K aligned. This should not - * restrict the address as the ip address can be anything. - */ - - movw %cs, %ax - shlw $4, %ax - movw $gdtptr16_offset, %bx - subw %ax, %bx - data32 lgdt %cs:(%bx) - - movl %cr0, %eax - andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */ - orl $0x60000001, %eax /* CD, NW, PE = 1 */ - movl %eax, %cr0 - - /* Restore BIST to %eax */ - movl %ebp, %eax - - /* Now that we are in protected mode jump to a 32 bit code segment. */ - data32 ljmp $ROM_CODE_SEG, $__protected_start - - /** - * The gdt is defined in entry32.inc, it has a 4 Gb code segment - * at 0x08, and a 4 GB data segment at 0x10; - */ -.align 4 -.globl gdtptr16 -gdtptr16: - .word gdt_end - gdt -1 /* compute the table limit */ - .long gdt /* we know the offset */ - -.globl _estart -_estart: - .code32 - - -/* For starting linuxBIOS in protected mode */ - -#include - -/* .section ".rom.text" */ - .code32 - - .align 4 -.globl gdtptr - - /* This is the gdt for ROMCC/ASM part of LinuxBIOS. - * It is different from the gdt in GCC part of LinuxBIOS - * which is defined in c_start.S */ -gdt: -gdtptr: - .word gdt_end - gdt -1 /* compute the table limit */ - .long gdt /* we know the offset */ - .word 0 - - /* selgdt 0x08, flat code segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x9b, 0xcf, 0x00 - - /* selgdt 0x10,flat data segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x93, 0xcf, 0x00 - -gdt_end: - - - -// mainboardinit cpu/x86/32bit/entry32.inc - - - -/* - * When we come here we are in protected mode. We expand - * the stack and copies the data segment from ROM to the - * memory. - * - * After that, we call the chipset bootstrap routine that - * does what is left of the chipset initialization. - * - * NOTE aligned to 4 so that we are sure that the prefetch - * cache will be reloaded. - */ - .align 4 -.globl protected_start -protected_start: - - lgdt %cs:gdtptr - ljmp $ROM_CODE_SEG, $__protected_start - -__protected_start: - /* Save the BIST value */ - movl %eax, %ebp - - intel_chip_post_macro(0x10) /* post 10 */ - - movw $ROM_DATA_SEG, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw %ax, %fs - movw %ax, %gs - - /* Restore the BIST value to %eax */ - movl %ebp, %eax - - - - -// mainboardinit cpu/x86/16bit/reset16.inc - - - .section ".reset" - .code16 -.globl reset_vector -reset_vector: - .byte 0xe9 - .int _start - ( . + 2 ) - /* Note: The above jump is hand coded to work around bugs in binutils. - * 5 byte are used for a 3 byte instruction. This works because x86 - * is little endian and allows us to use supported 32bit relocations - * instead of the weird 16 bit relocations that binutils does not - * handle consistenly between versions because they are used so rarely. - */ - . = 0x8; - .code32 - jmp protected_start - .previous - - - - - - -// mainboardinit arch/i386/lib/cpu_reset.inc - -jmp cpu_reset_out - -__cpu_reset: - /* set the boot_complete flag */ - movl $0xffffffff, %ebp - jmp __main - -cpu_reset_out: - - -// mainboardinit arch/i386/lib/id.inc - - .section ".id", "a", @progbits - - .globl __id_start -__id_start: -vendor: - .asciz MAINBOARD_VENDOR -part: - .asciz MAINBOARD_PART_NUMBER -.long __id_end + 0x10 - vendor /* Reverse offset to the vendor id */ -.long __id_end + 0x10 - part /* Reverse offset to the part number */ -.long PAYLOAD_SIZE + ROM_IMAGE_SIZE /* Size of this romimage */ - .globl __id_end - -__id_end: -.previous - - -// mainboardinit ./failover.inc -// mainboardinit ./auto.inc -// - -/* by yhlu 6.2005 */ -/* yhlu 2005.12 make it support HDT Memory Debuggers with Disassmbly, please select the PCI Bus mem for Phys Type*/ -/* yhlu 2006.3 copy data from cache to ram and reserve 0x1000 for global variables */ -#define CacheSize DCACHE_RAM_SIZE -#define CacheBase (0xd0000 - CacheSize) -/* leave some space for global variable to pass to RAM stage */ -#define GlobalVarSize DCACHE_RAM_GLOBAL_VAR_SIZE - -#include -#include - - /* Save the BIST result */ - movl %eax, %ebp - - /*for normal part %ebx already contain cpu_init_detected from fallback call */ - -cache_as_ram_setup: - - /* hope we can skip the double set for normal part */ -#if ((HAVE_FAILOVER_BOOT==1) && (USE_FAILOVER_IMAGE==1)) || ((HAVE_FAILOVER_BOOT==0) && (USE_FALLBACK_IMAGE==1)) - /* check if cpu_init_detected */ - movl $MTRRdefType_MSR, %ecx - rdmsr - andl $0x00000800, %eax - movl %eax, %ebx /* We store the status */ - - /* Set MtrrFixDramModEn for clear fixed mtrr */ -enable_fixed_mtrr_dram_modify: - movl $SYSCFG_MSR, %ecx - rdmsr - andl $(~(SYSCFG_MSR_MtrrFixDramEn|SYSCFG_MSR_MtrrVarDramEn)), %eax - orl $SYSCFG_MSR_MtrrFixDramModEn, %eax - wrmsr - - /*Clear all MTRRs */ - - xorl %edx, %edx - movl $fixed_mtrr_msr, %esi -clear_fixed_var_mtrr: - lodsl (%esi), %eax - testl %eax, %eax - jz clear_fixed_var_mtrr_out - - movl %eax, %ecx - xorl %eax, %eax - wrmsr - - jmp clear_fixed_var_mtrr -clear_fixed_var_mtrr_out: - -#if CacheSize == 0x10000 - /* enable caching for 64K using fixed mtrr */ - movl $0x268, %ecx /* fix4k_c0000*/ - movl $0x06060606, %eax /* WB IO type */ - movl %eax, %edx - wrmsr - movl $0x269, %ecx - wrmsr -#endif - -#if CacheSize == 0xc000 - /* enable caching for 16K using fixed mtrr */ - movl $0x268, %ecx /* fix4k_c4000*/ - movl $0x06060606, %edx /* WB IO type */ - xorl %eax, %eax - wrmsr - /* enable caching for 32K using fixed mtrr */ - movl $0x269, %ecx /* fix4k_c8000*/ - movl $0x06060606, %eax /* WB IO type */ - movl %eax, %edx - wrmsr - -#endif - - -#if CacheSize == 0x8000 - /* enable caching for 32K using fixed mtrr */ - movl $0x269, %ecx /* fix4k_c8000*/ - movl $0x06060606, %eax /* WB IO type */ - movl %eax, %edx - wrmsr -#endif - -#if CacheSize < 0x8000 - /* enable caching for 16K/8K/4K using fixed mtrr */ - movl $0x269, %ecx /* fix4k_cc000*/ - #if CacheSize == 0x4000 - movl $0x06060606, %edx /* WB IO type */ - #endif - #if CacheSize == 0x2000 - movl $0x06060000, %edx /* WB IO type */ - #endif - #if CacheSize == 0x1000 - movl $0x06000000, %edx /* WB IO type */ - #endif - xorl %eax, %eax - wrmsr -#endif - - /* enable memory access for first MBs using top_mem */ - movl $TOP_MEM, %ecx - xorl %edx, %edx - movl $(((CONFIG_LB_MEM_TOPK << 10) + TOP_MEM_MASK) & ~TOP_MEM_MASK) , %eax - wrmsr -#endif /* USE_FAILOVER_IMAGE == 1*/ - - -#if ((HAVE_FAILOVER_BOOT==1) && (USE_FAILOVER_IMAGE == 0)) || ((HAVE_FAILOVER_BOOT==0) && (USE_FALLBACK_IMAGE==0)) - /* disable cache */ - movl %cr0, %eax - orl $(0x1<<30),%eax - movl %eax, %cr0 - -#endif - -#if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE) - /* enable write base caching so we can do execute in place - * on the flash rom. - */ - movl $0x202, %ecx - xorl %edx, %edx - movl $(XIP_ROM_BASE | MTRR_TYPE_WRBACK), %eax - wrmsr - - movl $0x203, %ecx - movl $((1<<(CPU_ADDR_BITS-32))-1), %edx /* AMD 40 bit */ - movl $(~(XIP_ROM_SIZE - 1) | 0x800), %eax - wrmsr -#endif /* XIP_ROM_SIZE && XIP_ROM_BASE */ - -#if ((HAVE_FAILOVER_BOOT==1) && (USE_FAILOVER_IMAGE==1)) || ((HAVE_FAILOVER_BOOT==0) && (USE_FALLBACK_IMAGE==1)) - /* Set the default memory type and enable fixed and variable MTRRs */ - movl $MTRRdefType_MSR, %ecx - xorl %edx, %edx - /* Enable Variable and Fixed MTRRs */ - movl $0x00000c00, %eax - wrmsr - - /* Enable the MTRRs and IORRs in SYSCFG */ - movl $SYSCFG_MSR, %ecx - rdmsr - orl $(SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn), %eax - wrmsr -#endif - - /* enable cache */ - movl %cr0, %eax - andl $0x9fffffff,%eax - movl %eax, %cr0 - -#if ((HAVE_FAILOVER_BOOT==1) && (USE_FAILOVER_IMAGE==1)) || ((HAVE_FAILOVER_BOOT==0) && (USE_FALLBACK_IMAGE==1)) - - /* Read the range with lodsl*/ - cld - movl $CacheBase, %esi - movl $(CacheSize>>2), %ecx - rep - lodsl - /* Clear the range */ - movl $CacheBase, %edi - movl $(CacheSize>>2), %ecx - xorl %eax, %eax - rep - stosl - -#endif /*USE_FAILOVER_IMAGE == 1*/ - - /* set up the stack pointer */ - movl $(CacheBase+CacheSize - GlobalVarSize), %eax - movl %eax, %esp - - /* Restore the BIST result */ - movl %ebp, %eax - /* We need to set ebp ? No need */ - movl %esp, %ebp - pushl %ebx /* init detected */ - pushl %eax /* bist */ - call cache_as_ram_main - /* We will not go back */ - -fixed_mtrr_msr: - .long 0x250, 0x258, 0x259 - .long 0x268, 0x269, 0x26A - .long 0x26B, 0x26C, 0x26D - .long 0x26E, 0x26F -var_mtrr_msr: - .long 0x200, 0x201, 0x202, 0x203 - .long 0x204, 0x205, 0x206, 0x207 - .long 0x208, 0x209, 0x20A, 0x20B - .long 0x20C, 0x20D, 0x20E, 0x20F -var_iorr_msr: - .long 0xC0010016, 0xC0010017, 0xC0010018, 0xC0010019 -mem_top: - .long 0xC001001A, 0xC001001D - .long 0x000 /* NULL, end of table */ -cache_as_ram_setup_out: - diff --git a/arch/x86/macros.h b/arch/x86/macros.h new file mode 100644 index 0000000000..48a0ef7a94 --- /dev/null +++ b/arch/x86/macros.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2000 Ron Minnich, Advanced Computing Lab, LANL + * Copyright (C) 2007 Stefan Reinauer, coresystems GmbH + */ + +#ifndef X86_MACROS_H +#define X86_MACROS_H 1 + + +#define port80_post(value) \ + movb $value, %al; \ + outb %al, $0x80 + +#endif diff --git a/arch/x86/mtrr.h b/arch/x86/mtrr.h new file mode 100644 index 0000000000..51c0b511c7 --- /dev/null +++ b/arch/x86/mtrr.h @@ -0,0 +1,45 @@ +#ifndef CPU_X86_MTRR_H +#define CPU_X86_MTRR_H + + +/* These are the region types */ +#define MTRR_TYPE_UNCACHEABLE 0 +#define MTRR_TYPE_WRCOMB 1 +/*#define MTRR_TYPE_ 2*/ +/*#define MTRR_TYPE_ 3*/ +#define MTRR_TYPE_WRTHROUGH 4 +#define MTRR_TYPE_WRPROT 5 +#define MTRR_TYPE_WRBACK 6 +#define MTRR_NUM_TYPES 7 + +#define MTRRcap_MSR 0x0fe +#define MTRRdefType_MSR 0x2ff + +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg)) +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) + +#define NUM_FIXED_RANGES 88 +#define MTRRfix64K_00000_MSR 0x250 +#define MTRRfix16K_80000_MSR 0x258 +#define MTRRfix16K_A0000_MSR 0x259 +#define MTRRfix4K_C0000_MSR 0x268 +#define MTRRfix4K_C8000_MSR 0x269 +#define MTRRfix4K_D0000_MSR 0x26a +#define MTRRfix4K_D8000_MSR 0x26b +#define MTRRfix4K_E0000_MSR 0x26c +#define MTRRfix4K_E8000_MSR 0x26d +#define MTRRfix4K_F0000_MSR 0x26e +#define MTRRfix4K_F8000_MSR 0x26f + + +#if !defined(__ROMCC__) && !defined (ASSEMBLY) + + +void x86_setup_var_mtrrs(unsigned address_bits); +void x86_setup_mtrrs(unsigned address_bits); +int x86_mtrr_check(void); + +#endif /* __ROMCC__ */ + + +#endif /* CPU_X86_MTRR_H */ diff --git a/arch/x86/reset.S b/arch/x86/reset.S new file mode 100644 index 0000000000..9a4f42c3af --- /dev/null +++ b/arch/x86/reset.S @@ -0,0 +1,26 @@ +# reset vector +# +# (C) 2007 coresystems GmbH + +# RVECTOR: size of reset vector, default is 0x10 +# RESRVED: size of vpd code, default is 0xf0 +# +# BOOTBLK: size of bootblock code, default is 0x1f00 (8k-256b) +# + +SEGMENT_SIZE = 0x10000 +RVECTOR = 0x00010 + + .code16 + .globl _start +_start: + jmp SEGMENT_SIZE-(BOOTBLK+RESRVED+RVECTOR) + +.byte 0 + +# date? idstring? we might want to put something else in here. +.ascii DATE + +# checksum +.word 0 + diff --git a/arch/x86/serial.c b/arch/x86/serial.c new file mode 100644 index 0000000000..2ad1b4f666 --- /dev/null +++ b/arch/x86/serial.c @@ -0,0 +1,110 @@ +#include +#include + +/* Base Address */ +#ifndef TTYS0_BASE +#define TTYS0_BASE 0x3f8 +#endif + +#ifndef TTYS0_BAUD +#define TTYS0_BAUD 115200 +#endif + +#if ((115200%TTYS0_BAUD) != 0) +#error Bad ttys0 baud rate +#endif + +#define TTYS0_DIV (115200/TTYS0_BAUD) + +/* Line Control Settings */ +#ifndef TTYS0_LCS +/* Set 8bit, 1 stop bit, no parity */ +#define TTYS0_LCS 0x3 +#endif + +#define UART_LCS TTYS0_LCS + + +#if CONFIG_USE_INIT == 0 + +/* Data */ +#define UART_RBR 0x00 +#define UART_TBR 0x00 + +/* Control */ +#define UART_IER 0x01 +#define UART_IIR 0x02 +#define UART_FCR 0x02 +#define UART_LCR 0x03 +#define UART_MCR 0x04 +#define UART_DLL 0x00 +#define UART_DLM 0x01 + +/* Status */ +#define UART_LSR 0x05 +#define UART_MSR 0x06 +#define UART_SCR 0x07 + +static int uart_can_tx_byte(void) +{ + return inb(TTYS0_BASE + UART_LSR) & 0x20; +} + +static void uart_wait_to_tx_byte(void) +{ + while(!uart_can_tx_byte()) + ; +} + +static void uart_wait_until_sent(void) +{ + while(!(inb(TTYS0_BASE + UART_LSR) & 0x40)) + ; +} + +static void uart_tx_byte(unsigned char data) +{ + uart_wait_to_tx_byte(); + outb(data, TTYS0_BASE + UART_TBR); + /* Make certain the data clears the fifos */ + uart_wait_until_sent(); +} + +void uart_init(void) +{ + /* disable interrupts */ + outb(0x0, TTYS0_BASE + UART_IER); + /* enable fifo's */ + outb(0x01, TTYS0_BASE + UART_FCR); + /* Set Baud Rate Divisor to 12 ==> 115200 Baud */ + outb(0x80 | UART_LCS, TTYS0_BASE + UART_LCR); +#if USE_OPTION_TABLE == 1 + static const unsigned char divisor[] = { 1,2,3,6,12,24,48,96 }; + unsigned ttys0_div, ttys0_index; + ttys0_index = read_option(CMOS_VSTART_baud_rate, CMOS_VLEN_baud_rate, 0); + ttys0_index &= 7; + ttys0_div = divisor[ttys0_index]; + outb(ttys0_div & 0xff, TTYS0_BASE + UART_DLL); + outb(0, TTYS0_BASE + UART_DLM); +#else + outb(TTYS0_DIV & 0xFF, TTYS0_BASE + UART_DLL); + outb((TTYS0_DIV >> 8) & 0xFF, TTYS0_BASE + UART_DLM); +#endif + outb(UART_LCS, TTYS0_BASE + UART_LCR); +} +#else +extern void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs); +void uart_init(void) +{ +#if USE_OPTION_TABLE == 1 + static const unsigned char divisor[] = { 1,2,3,6,12,24,48,96 }; + unsigned ttys0_div, ttys0_index; + ttys0_index = read_option(CMOS_VSTART_baud_rate, CMOS_VLEN_baud_rate, 0); + ttys0_index &= 7; + ttys0_div = divisor[ttys0_index]; + uart8250_init(TTYS0_BASE, ttys0_div, UART_LCS); +#else + uart8250_init(TTYS0_BASE, TTYS0_DIV, UART_LCS); +#endif +} +#endif diff --git a/console/vtxprintf.c b/console/vtxprintf.c new file mode 100644 index 0000000000..9ffc1f21dc --- /dev/null +++ b/console/vtxprintf.c @@ -0,0 +1,309 @@ +/* vtxprintf.c, from + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include + +#include + +/* haha, don't need ctype.c */ +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#define is_digit isdigit +#define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) + +static unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ + unsigned long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper(*cp) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +static long simple_strtol(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoul(cp+1,endp,base); + return simple_strtoul(cp,endp,base); +} + + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +static int number(void (*tx_byte)(unsigned char byte), + unsigned long long num, int base, int size, int precision, int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + int count = 0; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if ((signed long long)num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + tx_byte(' '), count++; + if (sign) + tx_byte(sign), count++; + if (type & SPECIAL) { + if (base==8) + tx_byte('0'), count++; + else if (base==16) { + tx_byte('0'), count++; + tx_byte(digits[33]), count++; + } + } + if (!(type & LEFT)) + while (size-- > 0) + tx_byte(c), count++; + while (i < precision--) + tx_byte('0'), count++; + while (i-- > 0) + tx_byte(tmp[i]), count++; + while (size-- > 0) + tx_byte(' '), count++; + return count; +} + + +int vtxprintf(void (*tx_byte)(unsigned char byte), const char *fmt, va_list args) +{ + int len; + unsigned long long num; + int i, base; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + int count; + + for (count=0; *fmt ; ++fmt) { + if (*fmt != '%') { + tx_byte(*fmt), count++; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + if (*fmt == 'l') { + qualifier = 'L'; + ++fmt; + } + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + tx_byte(' '), count++; + tx_byte((unsigned char) va_arg(args, int)), count++; + while (--field_width > 0) + tx_byte(' '), count++; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + tx_byte(' '), count++; + for (i = 0; i < len; ++i) + tx_byte(*s++), count++; + while (len < field_width--) + tx_byte(' '), count++; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + count += number(tx_byte, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'L') { + long long *ip = va_arg(args, long long *); + *ip = count; + } else if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = count; + } else { + int * ip = va_arg(args, int *); + *ip = count; + } + continue; + + case '%': + tx_byte('%'), count++; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + tx_byte('%'), count++; + if (*fmt) + tx_byte(*fmt), count++; + else + --fmt; + continue; + } + if (qualifier == 'L') { + num = va_arg(args, unsigned long long); + } else if (qualifier == 'l') { + num = va_arg(args, unsigned long); + } else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) { + num = va_arg(args, int); + } else { + num = va_arg(args, unsigned int); + } + count += number(tx_byte, num, base, field_width, precision, flags); + } + return count; +} + diff --git a/include/cpu/generic/x86/arch/hlt.h b/include/cpu/generic/x86/arch/hlt.h new file mode 100644 index 0000000000..f79c51f648 --- /dev/null +++ b/include/cpu/generic/x86/arch/hlt.h @@ -0,0 +1,9 @@ +#ifndef ARCH_HLT_H +#define ARCH_HLT_H + +static inline __attribute__((always_inline)) void hlt(void) +{ + asm("hlt"); +} + +#endif diff --git a/include/cpu/generic/x86/div64.h b/include/cpu/generic/x86/div64.h new file mode 100644 index 0000000000..28ed8b296a --- /dev/null +++ b/include/cpu/generic/x86/div64.h @@ -0,0 +1,48 @@ +#ifndef __I386_DIV64 +#define __I386_DIV64 + +/* + * do_div() is NOT a C function. It wants to return + * two values (the quotient and the remainder), but + * since that doesn't work very well in C, what it + * does is: + * + * - modifies the 64-bit dividend _in_place_ + * - returns the 32-bit remainder + * + * This ends up being the most efficient "calling + * convention" on x86. + */ +#define do_div(n,base) ({ \ + unsigned long __upper, __low, __high, __mod, __base; \ + __base = (base); \ + asm("":"=a" (__low), "=d" (__high):"A" (n)); \ + __upper = __high; \ + if (__high) { \ + __upper = __high % (__base); \ + __high = __high / (__base); \ + } \ + asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \ + asm("":"=A" (n):"a" (__low),"d" (__high)); \ + __mod; \ +}) + +/* + * (long)X = ((long long)divs) / (long)div + * (long)rem = ((long long)divs) % (long)div + * + * Warning, this will do an exception if X overflows. + */ +#define div_long_long_rem(a,b,c) div_ll_X_l_rem(a,b,c) + +extern inline long +div_ll_X_l_rem(long long divs, long div, long *rem) +{ + long dum2; + __asm__("divl %2":"=a"(dum2), "=d"(*rem) + : "rm"(div), "A"(divs)); + + return dum2; + +} +#endif diff --git a/include/fallback.h b/include/fallback.h new file mode 100644 index 0000000000..17db5c6d9f --- /dev/null +++ b/include/fallback.h @@ -0,0 +1,18 @@ +#ifndef PART_FALLBACK_BOOT_H +#define PART_FALLBACK_BOOT_H + +#ifndef ASSEMBLY + +#if HAVE_FALLBACK_BOOT == 1 +void set_boot_successful(void); +#else +#define set_boot_successful() +#endif + +void boot_successful(void); + +#endif /* ASSEMBLY */ + +#define RTC_BOOT_BYTE 48 + +#endif /* PART_FALLBACK_BOOT_H */ diff --git a/include/lar.h b/include/lar.h new file mode 100644 index 0000000000..af564d0ad5 --- /dev/null +++ b/include/lar.h @@ -0,0 +1,39 @@ +/* + * lar - LinuxBIOS archiver + * + * Copright (C) 2006 coresystems GmbH + * Written by Stefan Reinauer for 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 + * + * This file may be dual licensed with the new BSD license. + */ + +#include + +#define MAGIC "LARCHIVE" +#define MAX_PATHLEN 1024 + +struct lar_header { + char magic[8]; + u32 len; + u32 checksum; + u32 offset; +}; + +struct mem_file { + void *start; + int len; +}; + diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000000..3d056818cc --- /dev/null +++ b/include/string.h @@ -0,0 +1,130 @@ +#ifndef STRING_H +#define STRING_H + +#include +#include + +extern void *memcpy(void *dest, const void *src, size_t n); +extern void *memmove(void *dest, const void *src, size_t n); +extern void *memset(void *s, int c, size_t n); +extern int memcmp(const void *s1, const void *s2, size_t n); + +extern int sprintf(char * buf, const char *fmt, ...); + +// yes, linux has fancy ones. We don't care. This stuff gets used +// hardly at all. And the pain of including those files is just too high. + +//extern inline void strcpy(char *dst, char *src) {while (*src) *dst++ = *src++;} + +//extern inline int strlen(char *src) { int i = 0; while (*src++) i++; return i;} + +static inline size_t strnlen(const char *src, size_t max) +{ + size_t i = 0; + while((*src++) && (i < max)) { + i++; + } + return i; +} + +static inline size_t strlen(const char *src) +{ + size_t i = 0; + while(*src++) { + i++; + } + return i; +} + +static inline char *strchr(const char *s, int c) +{ + for (; *s; s++) { + if (*s == c) + return (char *) s; + } + return 0; +} + +static inline char *strdup(const char *s) +{ + size_t sz = strlen(s) + 1; + char *d = malloc(sz); + memcpy(d, s, sz); + return d; +} + +static inline char *strncpy(char *to, const char *from, int count) +{ + register char *ret = to; + + while (count > 0) { + count--; + if ((*to++ = *from++) == '\0') + break; + } + + while (count > 0) { + count--; + *to++ = '\0'; + } + return ret; +} + +static inline int strcmp(const char *s1, const char *s2) +{ + int r; + + while ((r = (*s1 - *s2)) == 0 && *s1) { + s1++; + s2++; + } + return r; +} + +static inline int isspace(int c) +{ + switch (c) { + case ' ': case '\f': case '\n': + case '\r': case '\t': case '\v': + return 1; + default: + return 0; + } +} + +static inline int isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} + +static inline int isxdigit(int c) +{ + return ((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F')); +} + +static inline int isupper(int c) +{ + return (c >= 'A' && c <= 'Z'); +} + +static inline int islower(int c) +{ + return (c >= 'a' && c <= 'z'); +} + +static inline int toupper(int c) +{ + if (islower(c)) + c -= 'a'-'A'; + return c; +} + +static inline int tolower(int c) +{ + if (isupper(c)) + c -= 'A'-'a'; + return c; +} +#endif /* STRING_H */ diff --git a/include/uart8250.h b/include/uart8250.h new file mode 100644 index 0000000000..dc09315dea --- /dev/null +++ b/include/uart8250.h @@ -0,0 +1,15 @@ +#ifndef UART8250_H +#define UART8250_H + +struct uart8250 { + unsigned int baud; + /* Do I need an lcs parameter here? */ +}; + +unsigned char uart8250_rx_byte(unsigned base_port); +int uart8250_can_rx_byte(unsigned base_port); +void uart8250_tx_byte(unsigned base_port, unsigned char data); +void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs); +void init_uart8250(unsigned base_port, struct uart8250 *uart); + +#endif /* UART8250_H */ diff --git a/lib/lar.c b/lib/lar.c new file mode 100644 index 0000000000..0b8c26803d --- /dev/null +++ b/lib/lar.c @@ -0,0 +1,63 @@ +/* + * lar - LinuxBIOS archiver + * + * Copright (C) 2006-2007 coresystems GmbH + * Written by Stefan Reinauer for 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 +#include +#include + +#ifndef CONFIG_BIG_ENDIAN +#define ntohl(x) ( ((x&0xff)<<24) | ((x&0xff00)<<8) | \ + ((x&0xff0000) >> 8) | ((x&0xff000000) >> 24) ) +#else +#define ntohl(x) (x) +#endif + +int find_file(struct mem_file *archive, char *filename, struct mem_file *result) +{ + char * walk, *fullname; + struct lar_header * header; + + for (walk = archive->start; walk < (char *)archive->start + + archive->len; walk+=16) { + + if(strcmp(walk, MAGIC)!=0) + continue; + + header=(struct lar_header *)walk; + fullname=walk+sizeof(struct lar_header); + + // FIXME: check checksum + + if(strcmp(fullname, filename)!=0) { + result->start=walk + ntohl(header->offset); + result->len=ntohl(header->len); + return 0; + } + + // skip file + walk += ( ntohl(header->offset) + ntohl(header->len) + + 15 ) & 0xfffffff0; + } + + return 1; +} + + diff --git a/lib/uart8250.c b/lib/uart8250.c new file mode 100644 index 0000000000..9eca833be2 --- /dev/null +++ b/lib/uart8250.c @@ -0,0 +1,91 @@ +/* Should support 8250, 16450, 16550, 16550A type uarts */ +#include +#include +#include "../arch/x86/config.h" // for ttyS0 base FIXME! + +/* Data */ +#define UART_RBR 0x00 +#define UART_TBR 0x00 + +/* Control */ +#define UART_IER 0x01 +#define UART_IIR 0x02 +#define UART_FCR 0x02 +#define UART_LCR 0x03 +#define UART_MCR 0x04 +#define UART_DLL 0x00 +#define UART_DLM 0x01 + +/* Status */ +#define UART_LSR 0x05 +#define UART_MSR 0x06 +#define UART_SCR 0x07 + +static inline int uart8250_can_tx_byte(unsigned base_port) +{ + return inb(base_port + UART_LSR) & 0x20; +} + +static inline void uart8250_wait_to_tx_byte(unsigned base_port) +{ + while(!uart8250_can_tx_byte(base_port)) + ; +} + +static inline void uart8250_wait_until_sent(unsigned base_port) +{ + while(!(inb(base_port + UART_LSR) & 0x40)) + ; +} + +void uart8250_tx_byte(unsigned base_port, unsigned char data) +{ + uart8250_wait_to_tx_byte(base_port); + outb(data, base_port + UART_TBR); + /* Make certain the data clears the fifos */ + uart8250_wait_until_sent(base_port); +} + +int uart8250_can_rx_byte(unsigned base_port) +{ + return inb(base_port + UART_LSR) & 0x01; +} + +unsigned char uart8250_rx_byte(unsigned base_port) +{ + while(!uart8250_can_rx_byte(base_port)) + ; + return inb(base_port + UART_RBR); +} + +void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs) +{ + lcs &= 0x7f; + /* disable interrupts */ + outb(0x0, base_port + UART_IER); + /* enable fifo's */ + outb(0x01, base_port + UART_FCR); + /* assert DTR and RTS so the other end is happy */ + outb(0x03, base_port + UART_MCR); + /* Set Baud Rate Divisor to 12 ==> 115200 Baud */ + outb(0x80 | lcs, base_port + UART_LCR); + outb(divisor & 0xFF, base_port + UART_DLL); + outb((divisor >> 8) & 0xFF, base_port + UART_DLM); + outb(lcs, base_port + UART_LCR); +} + +/* Initialize a generic uart */ +void init_uart8250(unsigned base_port, struct uart8250 *uart) +{ + int divisor; + int lcs; + divisor = 115200/(uart->baud ? uart->baud: 1); + lcs = 3; + if (base_port == TTYS0_BASE) { + /* Don't reinitialize the console serial port, + * This is espeically nasty in SMP. + */ + return; + } + uart8250_init(base_port, divisor, lcs); +} diff --git a/mainboard/emulation/qemu-i386/Makefile.target b/mainboard/emulation/qemu-i386/Makefile.target index 7f51adb739..f1651004f4 100644 --- a/mainboard/emulation/qemu-i386/Makefile.target +++ b/mainboard/emulation/qemu-i386/Makefile.target @@ -1,7 +1,28 @@ +## +## This file is part of the LinuxBIOS project. +## +## Copyright (C) 2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + # -# This is duplicate in arch/x86/ where it does not belong. -# How can we cross reference? +# VPD or SIP ROM or ... how does nvidia call it? +# Some space to cope with dirty southbridge tricks. +# Do we want to put our own stuff there, too? # linuxbios.vpd: @@ -10,3 +31,40 @@ linuxbios.vpd: $(Q)printf "ok.\n" +# +# this is going to be the enable car code, lar parser and such: +# + +INITCFLAGS=-I$(srctree)/include/cpu/generic/x86 -I$(srctree)/include -fno-builtin -Os -fPIC + +linuxbios.initram: + $(Q)echo Building linuxbios.initram + # + # main + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/mainboard/$(MAINBOARDDIR)/initram.c -o initram.o + # + # console lib + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/arch/x86/console.c -o console.o + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/arch/x86/serial.c -o serial.o + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/console/vtxprintf.c -o vtxprintf.o + $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/lib/uart8250.c -o uart8250.o + + $(Q)$(LD) -Ttext 0x00000000 -s --oformat binary initram.o console.o uart8250.o \ + serial.o vtxprintf.o -o $(objtree)/linuxbios.initram + + $(Q)chmod 644 $(objtree)/linuxbios.initram + + +# miscellaneous important targets. +$(objtree)/mainboard.o: $(objtree)/statictree.o + +$(objtree)/statictree.o: $(objtree)/statictree.c + $(CC) $(CFLAGS) $(LINUXBIOSINCLUDE) -c -o $(objtree)/statictree.o $(objtree)/statictree.c + +$(objtree)/statictree.c: mainboard/$(MAINBOARDDIR)/dts $(objtree)/dtc + $(objtree)/dtc -O lb mainboard/$(MAINBOARDDIR)/dts >$(objtree)/statictree.c + +$(objtree)/dtc: + $(MAKE) -C $(srctree)/util/dtc/ + cp $(srctree)/util/dtc/dtc $(objtree) + diff --git a/mainboard/emulation/qemu-i386/initram.c b/mainboard/emulation/qemu-i386/initram.c new file mode 100644 index 0000000000..14de5be04b --- /dev/null +++ b/mainboard/emulation/qemu-i386/initram.c @@ -0,0 +1,24 @@ +/* GPLv2. + * + * Copyright (C) 2007 Stefan Reinauer , coresystems GmbH + */ + +#include +#include +#include + +static void post_code(u8 value) +{ + outb(value, 0x80); +} + +int main(void) +{ + printk(BIOS_INFO, "RAM init code started\n"); + + die ("Nothing to do."); + + return 0; +} + + diff --git a/util/lar/list.c b/util/lar/list.c index 704da18d03..aa626613a8 100644 --- a/util/lar/list.c +++ b/util/lar/list.c @@ -90,7 +90,7 @@ int list_lar(int argc, char *argv[]) printf(" %s ", walk+sizeof(struct lar_header)); - printf("(%d bytes @0x%lx)\n", ntohl(header->len), + printf("(%d bytes @0x%x)\n", ntohl(header->len), (walk-inmap)+ntohl(header->offset)); } munmap(inmap, statbuf.st_size);