diff options
author | imp <imp@FreeBSD.org> | 2006-04-19 17:16:49 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2006-04-19 17:16:49 +0000 |
commit | f65e9cd48e102c804c39d5fc6e1ef308cead6c92 (patch) | |
tree | a98ee56083fbc0be6ef7ccbffa5fd23a06ac797c | |
parent | b8c014aae747b676e781aecf74fb3c52bf0b9fa6 (diff) | |
download | FreeBSD-src-f65e9cd48e102c804c39d5fc6e1ef308cead6c92.zip FreeBSD-src-f65e9cd48e102c804c39d5fc6e1ef308cead6c92.tar.gz |
MFp4 (checkpoint of work in progress):
o Use a directory layout that is more akin to the i386 boot layout.
o Create a libat91 for library routines that are used by one or more
of the boot loaders.
o Create bootiic for booting from an iic part.
o Create bootspi for booting from an spi part.
o Optimize the size of many of these routines (especially emac.c). Except
for the emac.c optimizations, all these have been tested.
o eliminate the inc directory, libat91 superceeds it.
o Move linker.cfg up a layer to allow it to be shared.
34 files changed, 2979 insertions, 48 deletions
diff --git a/sys/boot/arm/at91/Makefile b/sys/boot/arm/at91/Makefile new file mode 100644 index 0000000..9c9b84f --- /dev/null +++ b/sys/boot/arm/at91/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= libat91 boot0 bootiic bootspi + +.include <bsd.subdir.mk> diff --git a/sys/boot/arm/at91/Makefile.inc b/sys/boot/arm/at91/Makefile.inc new file mode 100644 index 0000000..528d145 --- /dev/null +++ b/sys/boot/arm/at91/Makefile.inc @@ -0,0 +1,23 @@ +# $FreeBSD$ + +CFLAGS=-O2 -mcpu=arm9 -ffreestanding \ + -I${.CURDIR}/../libat91 \ + -Wall -Waggregate-return -Wcast-align \ + -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ + -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ + -Werror + +CFLAGS+=-DBOOT_TSC +#CFLAGS+=-DBOOT_KB920X + +LIBAT91=${.OBJDIR}/../libat91/libat91.a + +.if defined(P) +${P}: ${P}.out + objcopy -S -O binary ${P}.out ${.TARGET} + +${P}.out: ${OBJS} + ld ${LDFLAGS} -o ${.TARGET} ${OBJS} ${LIBAT91} + +CLEANFILES+= ${P} ${P}.out +.endif diff --git a/sys/boot/arm/at91/boot0/Makefile b/sys/boot/arm/at91/boot0/Makefile index 595cd14..cb586a2 100644 --- a/sys/boot/arm/at91/boot0/Makefile +++ b/sys/boot/arm/at91/boot0/Makefile @@ -1,22 +1,11 @@ # $FreeBSD$ -PROG=boot0 -SRCS=arm_init.s at91rm9200_lowlevel.c lib.c main.c xmodem.c +P=boot0 +FILES=${P} +SRCS=arm_init.s main.c NO_MAN= LDFLAGS=-e 0 -T linker.cfg -CFLAGS=-O2 -mcpu=arm9 -ffreestanding -I${.CURDIR}/../inc -CFLAGS+=-DBOOT0_KB9202 -#CFLAGS+=-DBOOT0_TSC OBJS+= ${SRCS:N*.h:R:S/$/.o/g} -CLEANFILES=${OBJS} ${PROG} ${PROG}.out -all: ${PROG} +.include <bsd.prog.mk> -${PROG}: ${PROG}.out ${OBJS} - objcopy -S -O binary ${PROG}.out ${PROG} - -${PROG}.out: ${OBJS} - ld ${LDFLAGS} -o ${PROG}.out ${OBJS} - -clean: - rm -f ${CLEANFILES} diff --git a/sys/boot/arm/at91/boot0/main.c b/sys/boot/arm/at91/boot0/main.c index bc29b2f..00073d1 100644 --- a/sys/boot/arm/at91/boot0/main.c +++ b/sys/boot/arm/at91/boot0/main.c @@ -24,7 +24,7 @@ * $FreeBSD$ */ -#include "AT91RM9200.h" +#include "at91rm9200.h" #include "lib.h" #include "at91rm9200_lowlevel.h" @@ -34,7 +34,7 @@ int main(void) { char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */ - fn_t *fn = (fn_t *)addr; + fn_t *fn = (fn_t *)(SDRAM_BASE + (1 << 20)); /* Load to base + 1MB */ while (xmodem_rx(addr) == -1) continue; diff --git a/sys/boot/arm/at91/bootiic/Makefile b/sys/boot/arm/at91/bootiic/Makefile new file mode 100644 index 0000000..deb30f8 --- /dev/null +++ b/sys/boot/arm/at91/bootiic/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +P=bootiic +FILES=${P} +SRCS=arm_init.s main.c +NO_MAN= +LDFLAGS=-e 0 -T ${.CURDIR}/../linker.cfg +OBJS+= ${SRCS:N*.h:R:S/$/.o/g} + +.include <bsd.prog.mk> diff --git a/sys/boot/arm/at91/bootiic/README b/sys/boot/arm/at91/bootiic/README new file mode 100644 index 0000000..1489d7c --- /dev/null +++ b/sys/boot/arm/at91/bootiic/README @@ -0,0 +1,35 @@ +$FreeBSD$ + +This image is intended to be programmed into boot EEPROM. The image is nearly +0x4000 so it will not fit in KB9200's 0x2000. It is intended for KB9201 or +later. Alternatively, the KB9200 can be upgraded with larger EEPROM. +It performs basic functions prior to executing an image at a +specified address. The pre-boot functions can be modified and saved back into +EEPROM. +The MAC address is set with 0.0.0.0.0.0 by default. This is an invalid address +and must be changed to a valid value in order to use the ethernet interface. + +Memory usage: + +EEPROM = 0x4000 +SDRAM = + run stack = 0x21800000 + variables = 0x21200000 + ethernet = 0x21000000 (buffers and descriptors) + + +Functions supported: + + c - copy + d - display auto command table (in RAM) + e - execute image + ? - help + ip - set local ip + m - set mac + server_ip - set server ip + s - set auto command entry + t - create linux boot tag list + tftp - download image via tftp + w - update auto command table + x - download image via xmodem + diff --git a/sys/boot/arm/at91/bootiic/arm_init.s b/sys/boot/arm/at91/bootiic/arm_init.s new file mode 100644 index 0000000..e405f89 --- /dev/null +++ b/sys/boot/arm/at91/bootiic/arm_init.s @@ -0,0 +1,122 @@ +/******************************************************************************* + * + * Filename: arm_init.s + * + * Initialization for C-environment and basic operation. Adapted from + * ATMEL cstartup.s. + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * 12JAN2005 kb_admin updated for 16KB eeprom + * Atmel stack prevents loading full size at once + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + ******************************************************************************/ + + .equ TWI_EEPROM_SIZE, 0x2000 + .equ ARM_MODE_USER, 0x10 + .equ ARM_MODE_FIQ, 0x11 + .equ ARM_MODE_IRQ, 0x12 + .equ ARM_MODE_SVC, 0x13 + .equ ARM_MODE_ABORT, 0x17 + .equ ARM_MODE_UNDEF, 0x1B + .equ ARM_MODE_SYS, 0x1F + + .equ I_BIT, 0x80 + .equ F_BIT, 0x40 + .equ T_BIT, 0x20 + +/* + * Stack definitions + * + * Start near top of internal RAM. + */ + + .equ END_INT_SRAM, 0x4000 + .equ SVC_STACK_START, (END_INT_SRAM - 0x4) + .equ SVC_STACK_USE, 0x21800000 + +start: + +/* vectors - must reside at address 0 */ +/* the format of this table is defined in the datasheet */ + B InitReset @; reset +undefvec: + B undefvec @; Undefined Instruction +swivec: + B swivec @; Software Interrupt +pabtvec: + B pabtvec @; Prefetch Abort +dabtvec: + B dabtvec @; Data Abort +rsvdvec: + .long (TWI_EEPROM_SIZE >> 9) +irqvec: + ldr pc, [pc,#-0xF20] @; IRQ : read the AIC +fiqvec: + B fiqvec @; FIQ + + +InitReset: + +/* Set stack and init for SVC */ + ldr r1, = SVC_STACK_START + mov sp, r1 @; Init stack SYS + + msr cpsr_c, #(ARM_MODE_SVC | I_BIT | F_BIT) + mov sp, r1 @ ; Init stack SYS + +/* Perform system initialization */ + + .extern _init + + bl _init + + ldr r1, = SVC_STACK_USE + mov sp, r1 @ ; Move the stack to SDRAM + +/* Copy the rest of the load image from EEPROM */ + .extern InitEEPROM + + bl InitEEPROM + + .extern ReadEEPROM + + mov r0, #8192 + mov r1, #8192 + mov r2, #8192 + bl ReadEEPROM + +/* Start execution at main */ + + .extern main +_main: +__main: + bl main + +/* main should not return. If it does, spin forever */ + +infiniteLoop: + b infiniteLoop + +/* the following section is used to store boot commands in */ +/* non-volatile memory. */ + + .global BootCommandSection +BootCommandSection: + .string "Bootloader for KB9202 Evaluation Board." + .string "c 0x20210000 0x10100000 0x80000 " + .string "m 0 0 0 0 0 0 " + .string "t 0x20000100 console=ttyS0,115200 root=/dev/ram rw initrd=0x20210000,654933" + .string "e 0x10000000 " + .string " " diff --git a/sys/boot/arm/at91/bootiic/main.c b/sys/boot/arm/at91/bootiic/main.c new file mode 100644 index 0000000..2642b10 --- /dev/null +++ b/sys/boot/arm/at91/bootiic/main.c @@ -0,0 +1,57 @@ +/******************************************************************************* + * + * Filename: main.c + * + * Basic entry points for top-level functions + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * 12JAN2005 kb_admin cosmetic changes + * 29APR2005 kb_admin modified boot delay + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + ******************************************************************************/ + +#include "env_vars.h" +#include "at91rm9200_lowlevel.h" +#include "loader_prompt.h" +#include "emac.h" +#include "lib.h" + +/* + * .KB_C_FN_DEFINITION_START + * int main(void) + * This global function waits at least one second, but not more than two + * seconds, for input from the serial port. If no response is recognized, + * it acts according to the parameters specified by the environment. For + * example, the function might boot an operating system. Do not return + * from this function. + * .KB_C_FN_DEFINITION_END + */ +int +main(void) +{ + + EMAC_Init(); + + LoadBootCommands(); + + printf("\n\rKB9202(www.kwikbyte.com)\n\rAuto boot..\n\r"); + + if (getc(1) == -1) + ExecuteEnvironmentFunctions(); + + Bootloader(0); + + return (1); +} diff --git a/sys/boot/arm/at91/bootspi/Makefile b/sys/boot/arm/at91/bootspi/Makefile new file mode 100644 index 0000000..203d8a1 --- /dev/null +++ b/sys/boot/arm/at91/bootspi/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +P=bootspi +FILES=${P} +SRCS=arm_init.s main.c +NO_MAN= +LDFLAGS=-e 0 -T ${.CURDIR}/../linker.cfg +OBJS+= ${SRCS:N*.h:R:S/$/.o/g} + +.include <bsd.prog.mk> diff --git a/sys/boot/arm/at91/bootspi/README b/sys/boot/arm/at91/bootspi/README new file mode 100644 index 0000000..9a4ffa8 --- /dev/null +++ b/sys/boot/arm/at91/bootspi/README @@ -0,0 +1,34 @@ +$FreeBSD$ + +This image is intended to be programmed into boot EEPROM. The image is nearly +0x4000 so it will not fit in KB9200's 0x2000. It is intended for KB9201 or +later. Alternatively, the KB9200 can be upgraded with larger EEPROM. +It performs basic functions prior to executing an image at a +specified address. The pre-boot functions can be modified and saved back into +EEPROM. +The MAC address is set with 0.0.0.0.0.0 by default. This is an invalid address +and must be changed to a valid value in order to use the ethernet interface. + +Memory usage: + +EEPROM = 0x4000 +SDRAM = + run stack = 0x21800000 + variables = 0x21200000 + ethernet = 0x21000000 (buffers and descriptors) + + +Functions supported: + + c - copy + d - display auto command table (in RAM) + e - execute image + ? - help + ip - set local ip + m - set mac + server_ip - set server ip + s - set auto command entry + t - create linux boot tag list + tftp - download image via tftp + w - update auto command table + x - download image via xmodem diff --git a/sys/boot/arm/at91/bootspi/arm_init.s b/sys/boot/arm/at91/bootspi/arm_init.s new file mode 100644 index 0000000..f9e6655 --- /dev/null +++ b/sys/boot/arm/at91/bootspi/arm_init.s @@ -0,0 +1,110 @@ +/******************************************************************************* + * + * Filename: arm_init.s + * + * Initialization for C-environment and basic operation. Adapted from + * ATMEL cstartup.s. + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * 12JAN2005 kb_admin updated for 16KB eeprom + * Atmel stack prevents loading full size at once + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + ******************************************************************************/ + + .equ TWI_EEPROM_SIZE, 0x2000 + .equ ARM_MODE_USER, 0x10 + .equ ARM_MODE_FIQ, 0x11 + .equ ARM_MODE_IRQ, 0x12 + .equ ARM_MODE_SVC, 0x13 + .equ ARM_MODE_ABORT, 0x17 + .equ ARM_MODE_UNDEF, 0x1B + .equ ARM_MODE_SYS, 0x1F + + .equ I_BIT, 0x80 + .equ F_BIT, 0x40 + .equ T_BIT, 0x20 + +/* + * Stack definitions + * + * Start near top of internal RAM. + */ + + .equ END_INT_SRAM, 0x4000 + .equ SVC_STACK_START, (END_INT_SRAM - 0x4) + .equ SVC_STACK_USE, 0x21800000 + +start: + +/* vectors - must reside at address 0 */ +/* the format of this table is defined in the datasheet */ + B InitReset @; reset +undefvec: + B undefvec @; Undefined Instruction +swivec: + B swivec @; Software Interrupt +pabtvec: + B pabtvec @; Prefetch Abort +dabtvec: + B dabtvec @; Data Abort +rsvdvec: + .long (TWI_EEPROM_SIZE >> 9) +irqvec: + ldr pc, [pc,#-0xF20] @; IRQ : read the AIC +fiqvec: + B fiqvec @; FIQ + + +InitReset: + +/* Set stack and init for SVC */ + ldr r1, = SVC_STACK_START + mov sp, r1 @; Init stack SYS + + msr cpsr_c, #(ARM_MODE_SVC | I_BIT | F_BIT) + mov sp, r1 @ ; Init stack SYS + +/* Perform system initialization */ + + .extern _init + + bl _init + + ldr r1, = SVC_STACK_USE + mov sp, r1 @ ; Move the stack to SDRAM + +/* Start execution at main */ + + .extern main +_main: +__main: + bl main + +/* main should not return. If it does, spin forever */ + +infiniteLoop: + b infiniteLoop + +/* the following section is used to store boot commands in */ +/* non-volatile memory. */ + + .global BootCommandSection +BootCommandSection: + .string "Bootloader for KB9202 Evaluation Board." + .string "c 0x20210000 0x10100000 0x80000 " + .string "m 0 0 0 0 0 0 " + .string "t 0x20000100 console=ttyS0,115200 root=/dev/ram rw initrd=0x20210000,654933" + .string "e 0x10000000 " + .string " " diff --git a/sys/boot/arm/at91/bootspi/main.c b/sys/boot/arm/at91/bootspi/main.c new file mode 100644 index 0000000..a187eb4b --- /dev/null +++ b/sys/boot/arm/at91/bootspi/main.c @@ -0,0 +1,57 @@ +/******************************************************************************* + * + * Filename: main.c + * + * Basic entry points for top-level functions + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * 12JAN2005 kb_admin cosmetic changes + * 29APR2005 kb_admin modified boot delay + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + ******************************************************************************/ + +#include "env_vars.h" +#include "at91rm9200_lowlevel.h" +#include "loader_prompt.h" +#include "emac.h" +#include "lib.h" + +/* + * .KB_C_FN_DEFINITION_START + * int main(void) + * This global function waits at least one second, but not more than two + * seconds, for input from the serial port. If no response is recognized, + * it acts according to the parameters specified by the environment. For + * example, the function might boot an operating system. Do not return + * from this function. + * .KB_C_FN_DEFINITION_END + */ +int +main(void) +{ + + EMAC_Init(); + + LoadBootCommands(); + + printf("\r\nSPI Boot loader.\r\nAutoboot...\r\n"); + + if (getc(1) == -1) + ExecuteEnvironmentFunctions(); + + Bootloader(0); + + return (1); +} diff --git a/sys/boot/arm/at91/libat91/Makefile b/sys/boot/arm/at91/libat91/Makefile new file mode 100644 index 0000000..e85fef5 --- /dev/null +++ b/sys/boot/arm/at91/libat91/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +LIB= at91 +INTERNALLIB= +SRCS=at91rm9200_lowlevel.c eeprom.c emac.c env_vars.c getc.c loader_prompt.c \ + p_string.c putchar.c printf.c xmodem.c +NO_MAN= + +.include <bsd.lib.mk> diff --git a/sys/boot/arm/at91/inc/AT91RM9200.h b/sys/boot/arm/at91/libat91/at91rm9200.h index 6fe7d07..6fe7d07 100644 --- a/sys/boot/arm/at91/inc/AT91RM9200.h +++ b/sys/boot/arm/at91/libat91/at91rm9200.h diff --git a/sys/boot/arm/at91/boot0/at91rm9200_lowlevel.c b/sys/boot/arm/at91/libat91/at91rm9200_lowlevel.c index d0f10a1..cd10d25 100644 --- a/sys/boot/arm/at91/boot0/at91rm9200_lowlevel.c +++ b/sys/boot/arm/at91/libat91/at91rm9200_lowlevel.c @@ -27,7 +27,7 @@ * $FreeBSD$ */ -#include "AT91RM9200.h" +#include "at91rm9200.h" #include "at91rm9200_lowlevel.h" #define BAUD 115200 @@ -46,10 +46,9 @@ _init(void) AT91PS_PDC pPDC = (AT91PS_PDC)&(pUSART->US_RPR); register unsigned value; - int i; volatile sdram_size_t *p = (sdram_size_t *)SDRAM_BASE; -#ifdef BOOT0_TSC +#ifdef BOOT_TSC // For the TSC board, we turn ON the one LED we have while // early in boot. AT91C_BASE_PIOC->PIO_PER = AT91C_PIO_PC10; diff --git a/sys/boot/arm/at91/boot0/at91rm9200_lowlevel.h b/sys/boot/arm/at91/libat91/at91rm9200_lowlevel.h index 8445e16..0129a91 100644 --- a/sys/boot/arm/at91/boot0/at91rm9200_lowlevel.h +++ b/sys/boot/arm/at91/libat91/at91rm9200_lowlevel.h @@ -31,7 +31,7 @@ #define SDRAM_BASE 0x20000000 -#ifdef BOOT0_KB9202 +#ifdef BOOT_KB9202 /* The following divisor sets PLLA frequency: e.g. 10/5 * 90 = 180MHz */ #define OSC_MAIN_FREQ_DIV 5 /* for 10MHz osc */ #define SDRAM_WIDTH AT91C_SDRC_DBW_16_BITS @@ -39,7 +39,7 @@ typedef unsigned short sdram_size_t; #define OSC_MAIN_MULT 90 #endif -#ifdef BOOT0_TSC +#ifdef BOOT_TSC /* The following divisor sets PLLA frequency: e.g. 16/4 * 45 = 180MHz */ #define OSC_MAIN_FREQ_DIV 4 /* for 16MHz osc */ #define SDRAM_WIDTH AT91C_SDRC_DBW_16_BITS @@ -52,6 +52,6 @@ typedef unsigned int sdram_size_t; #define GetSeconds() (AT91C_BASE_RTC->RTC_TIMR & AT91C_RTC_SEC) -extern void DefaultSystemInit(void); +extern void _init(void); #endif /* _AT91RM9200_LOWLEVEL_H_ */ diff --git a/sys/boot/arm/at91/libat91/eeprom.c b/sys/boot/arm/at91/libat91/eeprom.c new file mode 100644 index 0000000..7c9e2ae --- /dev/null +++ b/sys/boot/arm/at91/libat91/eeprom.c @@ -0,0 +1,181 @@ +/****************************************************************************** + * + * Filename: eeprom.c + * + * Instantiation of eeprom routines + * + * Revision information: + * + * 28AUG2004 kb_admin initial creation - adapted from Atmel sources + * 12JAN2005 kb_admin fixed clock generation, write polling, init + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +#include "at91rm9200_lowlevel.h" +#include "at91rm9200.h" +#include "lib.h" + +/******************************* GLOBALS *************************************/ + + +/*********************** PRIVATE FUNCTIONS/DATA ******************************/ + + +/* Use a macro to calculate the TWI clock generator value to save code space. */ +#define AT91C_TWSI_CLOCK 100000 +#define TWSI_EEPROM_ADDRESS 0x50 + +#define TWI_CLK_BASE_DIV ((AT91C_MASTER_CLOCK/(4*AT91C_TWSI_CLOCK)) - 2) +#define SET_TWI_CLOCK ((0x00010000) | (TWI_CLK_BASE_DIV) | (TWI_CLK_BASE_DIV << 8)) + + +/*************************** GLOBAL FUNCTIONS ********************************/ + + +/* + * .KB_C_FN_DEFINITION_START + * void InitEEPROM(void) + * This global function initializes the EEPROM interface (TWI). Intended + * to be called a single time. + * .KB_C_FN_DEFINITION_END + */ +void +InitEEPROM(void) +{ + + AT91PS_TWI twiPtr = (AT91PS_TWI)AT91C_BASE_TWI; + + AT91PS_PIO pPio = (AT91PS_PIO)AT91C_BASE_PIOA; + AT91PS_PMC pPMC = (AT91PS_PMC)AT91C_BASE_PMC; + + pPio->PIO_ASR = AT91C_PA25_TWD | AT91C_PA26_TWCK; + pPio->PIO_PDR = AT91C_PA25_TWD | AT91C_PA26_TWCK; + + pPio->PIO_MDDR = ~AT91C_PA25_TWD; + pPio->PIO_MDER = AT91C_PA25_TWD; + + pPMC->PMC_PCER = 1u << AT91C_ID_TWI; + + twiPtr->TWI_IDR = 0xffffffffu; + twiPtr->TWI_CR = AT91C_TWI_SWRST; + twiPtr->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS; + + twiPtr->TWI_CWGR = SET_TWI_CLOCK; +} + + +/* + * .KB_C_FN_DEFINITION_START + * void ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size) + * This global function reads data from the eeprom at ee_addr storing data + * to data_addr for size bytes. Assume the TWI has been initialized. + * This function does not utilize the page read mode to simplify the code. + * .KB_C_FN_DEFINITION_END + */ +void +ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size) +{ + const AT91PS_TWI twiPtr = AT91C_BASE_TWI; + unsigned int status; + + status = twiPtr->TWI_SR; + status = twiPtr->TWI_RHR; + + // Set the TWI Master Mode Register + twiPtr->TWI_MMR = (TWSI_EEPROM_ADDRESS << 16) | + AT91C_TWI_IADRSZ_2_BYTE | AT91C_TWI_MREAD; + + // Set TWI Internal Address Register + twiPtr->TWI_IADR = ee_addr; + + // Start transfer + twiPtr->TWI_CR = AT91C_TWI_START; + + status = twiPtr->TWI_SR; + + while (size-- > 1){ + + // Wait RHR Holding register is full + while (!(twiPtr->TWI_SR & AT91C_TWI_RXRDY)) + continue; + + // Read byte + *(data_addr++) = twiPtr->TWI_RHR; + } + + twiPtr->TWI_CR = AT91C_TWI_STOP; + + status = twiPtr->TWI_SR; + + // Wait transfer is finished + while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP)) + continue; + + // Read last byte + *data_addr = twiPtr->TWI_RHR; +} + + +/* + * .KB_C_FN_DEFINITION_START + * void WriteEEPROM(unsigned ee_addr, char *data_addr, unsigned size) + * This global function writes data to the eeprom at ee_addr using data + * from data_addr for size bytes. Assume the TWI has been initialized. + * This function does not utilize the page write mode as the write time is + * much greater than the time required to access the device for byte-write + * functionality. This allows the function to be much simpler. + * .KB_C_FN_DEFINITION_END + */ +void +WriteEEPROM(unsigned ee_addr, char *data_addr, unsigned size) +{ + const AT91PS_TWI twiPtr = AT91C_BASE_TWI; + unsigned status; + char test_data; + + while (size--) { + if (!(ee_addr & 0x3f)) + putchar('.'); + + // Set the TWI Master Mode Register + twiPtr->TWI_MMR = ((TWSI_EEPROM_ADDRESS << 16) | + AT91C_TWI_IADRSZ_2_BYTE) & ~AT91C_TWI_MREAD; + + // Set TWI Internal Address Register + twiPtr->TWI_IADR = ee_addr++; + + status = twiPtr->TWI_SR; + + twiPtr->TWI_THR = *(data_addr++); + + twiPtr->TWI_CR = AT91C_TWI_START; + + // Wait transfer is finished + while (!(twiPtr->TWI_SR & AT91C_TWI_TXRDY)) + continue; + + twiPtr->TWI_CR = AT91C_TWI_STOP; + + status = twiPtr->TWI_SR; + + // Wait transfer is finished + while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP)) + continue; + + // wait for write operation to complete + ReadEEPROM(ee_addr, &test_data, 1); + } + + putchar('\r'); + putchar('\n'); +} diff --git a/sys/boot/arm/at91/libat91/eeprom.h b/sys/boot/arm/at91/libat91/eeprom.h new file mode 100644 index 0000000..9f41ac4 --- /dev/null +++ b/sys/boot/arm/at91/libat91/eeprom.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * + * Filename: eeprom.h + * + * Definition of eeprom routines + * + * Revision information: + * + * 28AUG2004 kb_admin initial creation - adapted from Atmel sources + * 12JAN2005 kb_admin add init + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + ******************************************************************************/ + +#ifndef _EEPROM_H_ +#define _EEPROM_H_ + +#endif /* _EEPROM_H_ */ diff --git a/sys/boot/arm/at91/libat91/emac.c b/sys/boot/arm/at91/libat91/emac.c new file mode 100644 index 0000000..15913b4 --- /dev/null +++ b/sys/boot/arm/at91/libat91/emac.c @@ -0,0 +1,665 @@ +/****************************************************************************** + * + * Filename: emac.c + * + * Instantiation of routines for MAC/ethernet functions supporting tftp. + * + * Revision information: + * + * 28AUG2004 kb_admin initial creation + * 08JAN2005 kb_admin added tftp download + * also adapted from external sources + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +#include "at91rm9200.h" +#include "emac.h" +#include "p_string.h" +#include "at91rm9200_lowlevel.h" +#include "lib.h" + +/******************************* GLOBALS *************************************/ + +/*********************** PRIVATE FUNCTIONS/DATA ******************************/ + +static unsigned localMACSet, serverMACSet, MAC_init; +static unsigned char localMACAddr[6], serverMACAddr[6]; +static unsigned localIPAddr, serverIPAddr; +static unsigned short serverPort, localPort; +static int ackBlock; + +static unsigned lastAddress, lastSize; +static char *dlAddress; + +static unsigned transmitBuffer[1024 / sizeof(unsigned)]; +static unsigned tftpSendPacket[256 / sizeof(unsigned)]; + +receive_descriptor_t *p_rxBD; + + +/* + * .KB_C_FN_DEFINITION_START + * unsigned short IP_checksum(unsigned short *p, int len) + * This private function calculates the IP checksum for various headers. + * .KB_C_FN_DEFINITION_END + */ +static unsigned short +IP_checksum(void *cp, int len) +{ + unsigned i, t; + unsigned short *p = (unsigned short *)cp; + + len &= ~1; + for (i=0,t=0; i<len; i+=2, ++p) + t += SWAP16(*p); + t = (t & 0xffff) + (t >> 16); + return (~t); +} + + +/* + * .KB_C_FN_DEFINITION_START + * void GetServerAddress(void) + * This private function sends an ARP request to determine the server MAC. + * .KB_C_FN_DEFINITION_END + */ +static void +GetServerAddress(void) +{ + arp_header_t *p_ARP; + + p_ARP = (arp_header_t*)transmitBuffer; + p_memset((char*)p_ARP->dest_mac, 0xFF, 6); + p_memcpy((char*)p_ARP->src_mac, (char*)localMACAddr, 6); + + p_ARP->frame_type = SWAP16(PROTOCOL_ARP); + p_ARP->hard_type = SWAP16(1); + p_ARP->prot_type = SWAP16(PROTOCOL_IP); + p_ARP->hard_size = 6; + p_ARP->prot_size = 4; + p_ARP->operation = SWAP16(ARP_REQUEST); + + p_memcpy((char*)p_ARP->sender_mac, (char*)localMACAddr, 6); + p_memcpy((char*)p_ARP->sender_ip, (char*)localIPAddr, 4); + p_memset((char*)p_ARP->target_mac, 0, 6); + p_memcpy((char*)p_ARP->target_ip, (char*)serverIPAddr, 4); + + // wait until transmit is available + while (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ)) ; + + *AT91C_EMAC_TSR |= AT91C_EMAC_COMP; + *AT91C_EMAC_TAR = (unsigned)transmitBuffer; + *AT91C_EMAC_TCR = 0x40; +} + + +/* + * .KB_C_FN_DEFINITION_START + * void Send_TFTP_Packet(char *tftpData, unsigned tftpLength) + * This private function initializes and send a TFTP packet. + * .KB_C_FN_DEFINITION_END + */ +static void +Send_TFTP_Packet(char *tftpData, unsigned tftpLength) +{ + transmit_header_t *macHdr = (transmit_header_t*)tftpSendPacket; + ip_header_t *ipHdr; + udp_header_t *udpHdr; + unsigned t_checksum; + + p_memcpy((char*)macHdr->dest_mac, (char*)serverMACAddr, 6); + p_memcpy((char*)macHdr->src_mac, (char*)localMACAddr, 6); + + macHdr->proto_mac = SWAP16(PROTOCOL_IP); + + ipHdr = &macHdr->iphdr; + + ipHdr->ip_v_hl = 0x45; + ipHdr->ip_tos = 0; + ipHdr->ip_len = SWAP16(28 + tftpLength); + ipHdr->ip_id = 0; + ipHdr->ip_off = SWAP16(0x4000); + ipHdr->ip_ttl = 64; + ipHdr->ip_p = PROTOCOL_UDP; + ipHdr->ip_sum = 0; + + p_memcpy((char*)ipHdr->ip_src, (char*)localIPAddr, 4); + p_memcpy((char*)ipHdr->ip_dst, (char*)serverIPAddr, 4); + + ipHdr->ip_sum = SWAP16(IP_checksum(ipHdr, 20)); + + udpHdr = (udp_header_t*)(ipHdr + 1); + + udpHdr->src_port = localPort; + udpHdr->dst_port = serverPort; + udpHdr->udp_len = SWAP16(8 + tftpLength); + udpHdr->udp_cksum = 0; + + p_memcpy((char*)udpHdr+8, tftpData, tftpLength); + + t_checksum = IP_checksum((char *)ipHdr + 12, (16 + tftpLength)); + + t_checksum = (~t_checksum) & 0xFFFF; + t_checksum += 25 + tftpLength; + + t_checksum = (t_checksum & 0xffff) + (t_checksum >> 16); + t_checksum = (~t_checksum) & 0xFFFF; + + udpHdr->udp_cksum = SWAP16(t_checksum); + + while (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ)) ; + + *AT91C_EMAC_TSR |= AT91C_EMAC_COMP; + *AT91C_EMAC_TAR = (unsigned)tftpSendPacket; + *AT91C_EMAC_TCR = 42 + tftpLength; +} + + +/* + * .KB_C_FN_DEFINITION_START + * void TFTP_RequestFile(char *filename) + * This private function sends a RRQ packet to the server. + * .KB_C_FN_DEFINITION_END + */ +static void +TFTP_RequestFile(char *filename) +{ + tftp_header_t tftpHeader; + char *cPtr, *ePtr, *mPtr; + unsigned length; + + tftpHeader.opcode = SWAP16(TFTP_RRQ_OPCODE); + + cPtr = (char*)&(tftpHeader.block_num); + + ePtr = p_strcpy(cPtr, filename); + mPtr = p_strcpy(ePtr, "octet"); + + length = mPtr - cPtr; + length += 2; + + Send_TFTP_Packet((char*)&tftpHeader, length); +} + + +/* + * .KB_C_FN_DEFINITION_START + * void TFTP_ACK_Data(char *data, unsigned short block_num, unsigned short len) + * This private function sends an ACK packet to the server. + * .KB_C_FN_DEFINITION_END + */ +static void +TFTP_ACK_Data(char *data, unsigned short block_num, unsigned short len) +{ + tftp_header_t tftpHeader; + + if (block_num == SWAP16(ackBlock + 1)) { + ++ackBlock; + p_memcpy(dlAddress, data, len); + dlAddress += len; + lastSize += len; + } + + tftpHeader.opcode = SWAP16(TFTP_ACK_OPCODE); + tftpHeader.block_num = block_num; + Send_TFTP_Packet((char*)&tftpHeader, 4); + + if (len < 512) + ackBlock = -2; +} + + +/* + * .KB_C_FN_DEFINITION_START + * void CheckForNewPacket(ip_header_t *pHeader) + * This private function polls for received ethernet packets and handles + * any here. + * .KB_C_FN_DEFINITION_END + */ +static void +CheckForNewPacket(void) +{ + unsigned short *pFrameType; + unsigned i; + char *pData; + ip_header_t *pIpHeader; + arp_header_t *p_ARP; + int process = 0; + + process = 0; + for (i = 0; i < MAX_RX_PACKETS; ++i) { + if(p_rxBD[i].address & 0x1) { + process = 1; + (*AT91C_EMAC_RSR) |= (*AT91C_EMAC_RSR); + break; + } + } + + if (!process) + return ; + + process = i; + + pFrameType = (unsigned short *) ((p_rxBD[i].address & 0xFFFFFFFC) + 12); + pData = (char *)(p_rxBD[i].address & 0xFFFFFFFC); + + switch (SWAP16(*pFrameType)) { + + case PROTOCOL_ARP: + p_ARP = (arp_header_t*)pData; + + i = SWAP16(p_ARP->operation); + if (i == ARP_REPLY) { + + // check if new server info is available + if ((!serverMACSet) && + (!(p_memcmp((char*)p_ARP->sender_ip, + (char*)serverIPAddr, 4)))) { + + serverMACSet = 1; + + p_memcpy((char*)serverMACAddr, + (char*)p_ARP->sender_mac, 6); + } + } else if (i == ARP_REQUEST) { + + // ARP REPLY operation + p_ARP->operation = SWAP16(ARP_REPLY); + + // Swap the src/dst MAC addr + p_memcpy(p_ARP->dest_mac, p_ARP->src_mac, 6); + p_memcpy(p_ARP->src_mac, localMACAddr, 6); + + // Do IP and MAC addr at same time. + p_memcpy(p_ARP->target_mac, p_ARP->sender_mac, 10); + p_memcpy(p_ARP->sender_mac, localMACAddr, 6); + p_memcpy(p_ARP->sender_ip, (char *)&localIPAddr, 4); + + if (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ)) + break; + + *AT91C_EMAC_TSR |= AT91C_EMAC_COMP; + *AT91C_EMAC_TAR = (unsigned)pData; + *AT91C_EMAC_TCR = 0x40; + } + break; + + case PROTOCOL_IP: + pIpHeader = (ip_header_t*)(pData + 14); + switch(pIpHeader->ip_p) { + case PROTOCOL_UDP: + { + udp_header_t *udpHdr; + tftp_header_t *tftpHdr; + + udpHdr = (udp_header_t*)((char*)pIpHeader+20); + tftpHdr = (tftp_header_t*)((char*)udpHdr + 8); + + if (udpHdr->dst_port != localPort) + break; + + if (tftpHdr->opcode != SWAP16(TFTP_DATA_OPCODE)) + break; + + if (ackBlock == -1) { + if (tftpHdr->block_num != SWAP16(1)) + break; + serverPort = udpHdr->src_port; + ackBlock = 0; + } + + if (serverPort != udpHdr->src_port) + break; + + TFTP_ACK_Data(tftpHdr->data, + tftpHdr->block_num, + SWAP16(udpHdr->udp_len) - 12); + } + break; + + default: + break; + } + break; + + default: + break; + } + p_rxBD[process].address &= ~0x01; +} + + +/* + * .KB_C_FN_DEFINITION_START + * unsigned short AT91F_MII_ReadPhy (AT91PS_EMAC pEmac, unsigned char addr) + * This private function reads the PHY device. + * .KB_C_FN_DEFINITION_END + */ +static unsigned short +AT91F_MII_ReadPhy (AT91PS_EMAC pEmac, unsigned char addr) +{ + unsigned value = 0x60020000 | (addr << 18); + + pEmac->EMAC_CTL |= AT91C_EMAC_MPE; + pEmac->EMAC_MAN = value; + while(!((pEmac->EMAC_SR) & AT91C_EMAC_IDLE)); + pEmac->EMAC_CTL &= ~AT91C_EMAC_MPE; + return (pEmac->EMAC_MAN & 0x0000ffff); +} + + +/* + * .KB_C_FN_DEFINITION_START + * void MII_GetLinkSpeed(AT91PS_EMAC pEmac) + * This private function determines the link speed set by the PHY. + * .KB_C_FN_DEFINITION_END + */ +static void +MII_GetLinkSpeed(AT91PS_EMAC pEmac) +{ + unsigned short stat2; + unsigned update = 0; + + stat2 = AT91F_MII_ReadPhy(pEmac, MII_STS2_REG); + + if (!(stat2 & 0x400)) { + return ; + + } else if (stat2 & 0x4000) { + + update |= AT91C_EMAC_SPD; + + if (stat2 & 0x200) { + update |= AT91C_EMAC_FD; + } + + } else if (stat2 & 0x200) { + update |= AT91C_EMAC_FD; + } + + pEmac->EMAC_CFG = + (pEmac->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD)) | update; +} + + +/* + * .KB_C_FN_DEFINITION_START + * void AT91F_EmacEntry(void) + * This private function initializes the EMAC on the chip. + * .KB_C_FN_DEFINITION_END + */ +static void +AT91F_EmacEntry(void) +{ + unsigned i; + char *pRxPacket = (char*)RX_DATA_START; + AT91PS_EMAC pEmac = AT91C_BASE_EMAC; + + for (i = 0; i < MAX_RX_PACKETS; ++i) { + p_rxBD[i].address = (unsigned)pRxPacket; + p_rxBD[i].size = 0; + pRxPacket += RX_PACKET_SIZE; + } + + // Set the WRAP bit at the end of the list descriptor + p_rxBD[MAX_RX_PACKETS-1].address |= 0x02; + + pEmac->EMAC_CTL = 0; + + if(!(pEmac->EMAC_SR & AT91C_EMAC_LINK)) + MII_GetLinkSpeed(pEmac); + + // the sequence write EMAC_SA1L and write EMAC_SA1H must be respected + pEmac->EMAC_SA1L = ((unsigned)localMACAddr[2] << 24) | + ((unsigned)localMACAddr[3] << 16) | ((int)localMACAddr[4] << 8) | + localMACAddr[5]; + pEmac->EMAC_SA1H = ((unsigned)localMACAddr[0] << 8) | localMACAddr[1]; + + pEmac->EMAC_RBQP = (unsigned) p_rxBD; + pEmac->EMAC_RSR |= (AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA); + pEmac->EMAC_CFG |= AT91C_EMAC_CAF; + pEmac->EMAC_CFG = (pEmac->EMAC_CFG & ~(AT91C_EMAC_CLK)) | + AT91C_EMAC_CLK_HCLK_32; + pEmac->EMAC_CTL |= (AT91C_EMAC_TE | AT91C_EMAC_RE); + + pEmac->EMAC_TAR = (unsigned)transmitBuffer; +} + + +/* ************************** GLOBAL FUNCTIONS ********************************/ + + +/* + * .KB_C_FN_DEFINITION_START + * void SetMACAddress(unsigned low_address, unsigned high_address) + * This global function sets the MAC address. low_address is the first + * four bytes while high_address is the last 2 bytes of the 48-bit value. + * .KB_C_FN_DEFINITION_END + */ +void +SetMACAddress(unsigned low_address, unsigned high_address) +{ + + AT91PS_EMAC pEmac = AT91C_BASE_EMAC; + AT91PS_PMC pPMC = AT91C_BASE_PMC; + + /* enable the peripheral clock before using EMAC */ + pPMC->PMC_PCER = ((unsigned) 1 << AT91C_ID_EMAC); + + pEmac->EMAC_SA1L = low_address; + pEmac->EMAC_SA1H = (high_address & 0x0000ffff); + + localMACAddr[0] = (low_address >> 0) & 0xFF; + localMACAddr[1] = (low_address >> 8) & 0xFF; + localMACAddr[2] = (low_address >> 16) & 0xFF; + localMACAddr[3] = (low_address >> 24) & 0xFF; + localMACAddr[4] = (high_address >> 0) & 0xFF; + localMACAddr[5] = (high_address >> 8) & 0xFF; + + localMACSet = 1; + + // low_address & 0x000000ff = first byte in address + // low_address & 0x0000ff00 = next + // low_address & 0x00ff0000 = next + // low_address & 0xff000000 = next + // high_address & 0x000000ff = next + // high_address & 0x0000ff00 = last byte in address +} + + +/* + * .KB_C_FN_DEFINITION_START + * void SetServerIPAddress(unsigned address) + * This global function sets the IP of the TFTP download server. + * .KB_C_FN_DEFINITION_END + */ +void +SetServerIPAddress(unsigned address) +{ + // force update in case the IP has changed + serverMACSet = 0; + serverIPAddr = address; +} + + +/* + * .KB_C_FN_DEFINITION_START + * void SetLocalIPAddress(unsigned address) + * This global function sets the IP of this module. + * .KB_C_FN_DEFINITION_END + */ +void +SetLocalIPAddress(unsigned address) +{ + // force update in case the IP has changed + serverMACSet = 0; + localIPAddr = address; +} + + +/* + * .KB_C_FN_DEFINITION_START + * void TFTP_Download(unsigned address, char *filename) + * This global function initiates and processes a tftp download request. + * The server IP, local IP, local MAC must be set before this function is + * executed. + * .KB_C_FN_DEFINITION_END + */ +void +TFTP_Download(unsigned address, char *filename) +{ + unsigned thisSeconds, running, state; + int timeout, tickUpdate; + + if (!address) { + // report last transfer information + printf("Last tftp transfer info --\r\n" + "address: 0x%x\r\n" + " size: 0x%x\r\n", lastAddress, lastSize); + return ; + } + + if ((!localMACSet) || (!localIPAddr) || (!serverIPAddr)) + return ; + + if (!MAC_init) { + AT91C_BASE_PMC->PMC_PCER = 1u << AT91C_ID_EMAC; + + AT91C_BASE_PIOA->PIO_ASR = + AT91C_PA14_ERXER | + AT91C_PA12_ERX0 | + AT91C_PA13_ERX1 | + AT91C_PA8_ETXEN | + AT91C_PA16_EMDIO | + AT91C_PA9_ETX0 | + AT91C_PA10_ETX1 | + AT91C_PA11_ECRS_ECRSDV | + AT91C_PA15_EMDC | + AT91C_PA7_ETXCK_EREFCK; + AT91C_BASE_PIOA->PIO_BSR = 0; + AT91C_BASE_PIOA->PIO_PDR = + AT91C_PA14_ERXER | + AT91C_PA12_ERX0 | + AT91C_PA13_ERX1 | + AT91C_PA8_ETXEN | + AT91C_PA16_EMDIO | + AT91C_PA9_ETX0 | + AT91C_PA10_ETX1 | + AT91C_PA11_ECRS_ECRSDV | + AT91C_PA15_EMDC | + AT91C_PA7_ETXCK_EREFCK; + AT91C_BASE_PIOB->PIO_ASR = 0; + AT91C_BASE_PIOB->PIO_BSR = + AT91C_PB12_ETX2 | + AT91C_PB13_ETX3 | + AT91C_PB14_ETXER | + AT91C_PB15_ERX2 | + AT91C_PB16_ERX3 | + AT91C_PB17_ERXDV | + AT91C_PB18_ECOL | + AT91C_PB19_ERXCK; + AT91C_BASE_PIOB->PIO_PDR = + AT91C_PB12_ETX2 | + AT91C_PB13_ETX3 | + AT91C_PB14_ETXER | + AT91C_PB15_ERX2 | + AT91C_PB16_ERX3 | + AT91C_PB17_ERXDV | + AT91C_PB18_ECOL | + AT91C_PB19_ERXCK; + MAC_init = 1; + } + + AT91F_EmacEntry(); + + GetServerAddress(); + lastAddress = address; + dlAddress = (char*)address; + lastSize = 0; + running = 1; + state = TFTP_WAITING_SERVER_MAC; + timeout = 10; + thisSeconds = GetSeconds(); + serverPort = SWAP16(69); + localPort++; /* In network byte order, but who cares */ + ackBlock = -1; + + while (running && timeout) { + + CheckForNewPacket(); + + tickUpdate = 0; + + if (thisSeconds != GetSeconds()) { + tickUpdate = 1; + --timeout; + thisSeconds = GetSeconds(); + } + + switch (state) { + + case TFTP_WAITING_SERVER_MAC: + if (serverMACSet) { + state = TFTP_SEND_REQUEST; + break; + } + + if (tickUpdate) + GetServerAddress(); + break; + + case TFTP_SEND_REQUEST: + // send request for file + if (ackBlock != -1) { + state = TFTP_GET_DATA; + break; + } + + if (tickUpdate) + TFTP_RequestFile(filename); + break; + + case TFTP_GET_DATA: + // receiving data + if (ackBlock == -2) { + state = TFTP_COMPLETE; + break; + } + break; + + case TFTP_COMPLETE: + default: + running = 0; + break; + } + } +} + + +/* + * .KB_C_FN_DEFINITION_START + * void EMAC_Init(void) + * This global function initializes variables used in tftp transfers. + * .KB_C_FN_DEFINITION_END + */ +void +EMAC_Init(void) +{ + p_rxBD = (receive_descriptor_t*)RX_BUFFER_START; + localMACSet = 0; + serverMACSet = 0; + localPort = SWAP16(0x8002); + lastAddress = 0; + lastSize = 0; + MAC_init = 0; +} diff --git a/sys/boot/arm/at91/libat91/emac.h b/sys/boot/arm/at91/libat91/emac.h new file mode 100644 index 0000000..ca5862a --- /dev/null +++ b/sys/boot/arm/at91/libat91/emac.h @@ -0,0 +1,122 @@ +/****************************************************************************** + * + * Filename: emac.h + * + * Definition of routine to set the MAC address. + * + * Revision information: + * + * 28AUG2004 kb_admin initial creation + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + + +#ifndef _EMAC_H_ +#define _EMAC_H_ + +extern void SetMACAddress(unsigned low_address, unsigned high_address); +extern void SetServerIPAddress(unsigned address); +extern void SetLocalIPAddress(unsigned address); +extern void EMAC_Init(void); +extern void TFTP_Download(unsigned address, char *filename); + +#define MAX_RX_PACKETS 8 +#define RX_PACKET_SIZE 1536 +#define RX_BUFFER_START 0x21000000 +#define RX_DATA_START (RX_BUFFER_START + (8 * MAX_RX_PACKETS)) + +#define ARP_REQUEST 0x0001 +#define ARP_REPLY 0x0002 +#define PROTOCOL_ARP 0x0806 +#define PROTOCOL_IP 0x0800 +#define PROTOCOL_UDP 0x11 + +#define SWAP16(x) ((((x) & 0xff) << 8) | ((x) >> 8)) + +typedef struct { + unsigned address; + unsigned size; +} receive_descriptor_t; + +typedef struct { + + unsigned char dest_mac[6]; + + unsigned char src_mac[6]; + + unsigned short frame_type; + unsigned short hard_type; + unsigned short prot_type; + unsigned char hard_size; + unsigned char prot_size; + + unsigned short operation; + + unsigned char sender_mac[6]; + unsigned char sender_ip[4]; + + unsigned char target_mac[6]; + unsigned char target_ip[4]; + +} __attribute__((__packed__)) arp_header_t; + +typedef struct { + unsigned char ip_v_hl; + unsigned char ip_tos; + unsigned short ip_len; + unsigned short ip_id; + unsigned short ip_off; + unsigned char ip_ttl; + unsigned char ip_p; + unsigned short ip_sum; + unsigned char ip_src[4]; + unsigned char ip_dst[4]; +} __attribute__((__packed__)) ip_header_t; + +typedef struct { + unsigned char dest_mac[6]; + unsigned char src_mac[6]; + unsigned short proto_mac; + unsigned short packet_length; + ip_header_t iphdr; +} __attribute__((__packed__)) transmit_header_t; + +typedef struct { + unsigned short src_port; + unsigned short dst_port; + unsigned short udp_len; + unsigned short udp_cksum; +} __attribute__((__packed__)) udp_header_t; + +typedef struct { + unsigned short opcode; + unsigned short block_num; + unsigned char data[512]; +} __attribute__((__packed__)) tftp_header_t; + +#define TFTP_RRQ_OPCODE 1 +#define TFTP_WRQ_OPCODE 2 +#define TFTP_DATA_OPCODE 3 +#define TFTP_ACK_OPCODE 4 +#define TFTP_ERROR_OPCODE 5 + +#define TFTP_WAITING_SERVER_MAC 1 +#define TFTP_SEND_REQUEST 2 +#define TFTP_GET_DATA 3 +#define TFTP_COMPLETE 4 + +/* MII registers definition */ +#define MII_STS_REG 0x01 +#define MII_STS2_REG 0x11 + +#endif /* _EMAC_H_ */ diff --git a/sys/boot/arm/at91/libat91/env_vars.c b/sys/boot/arm/at91/libat91/env_vars.c new file mode 100644 index 0000000..4c08fd8 --- /dev/null +++ b/sys/boot/arm/at91/libat91/env_vars.c @@ -0,0 +1,207 @@ +/****************************************************************************** + * + * Filename: env_vars.c + * + * Instantiation of environment variables, structures, and other globals. + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +#include "env_vars.h" +#include "loader_prompt.h" +#include "p_string.h" +#include "eeprom.h" +#include "lib.h" + +/******************************* GLOBALS *************************************/ +char boot_commands[MAX_BOOT_COMMANDS][MAX_INPUT_SIZE]; + +char env_table[MAX_ENV_SIZE_BYTES]; + +extern char BootCommandSection; + +/************************** PRIVATE FUNCTIONS ********************************/ + + +static int currentIndex; +static int currentOffset; + + +/* + * .KB_C_FN_DEFINITION_START + * int ReadCharFromEnvironment(char *) + * This private function reads characters from the enviroment variables + * to service the command prompt during auto-boot or just to setup the + * default environment. Returns positive value if valid character was + * set in the pointer. Returns negative value to signal input stream + * terminated. Returns 0 to indicate _wait_ condition. + * .KB_C_FN_DEFINITION_END + */ +static int +ReadCharFromEnvironment(int timeout) +{ + int ch; + + if (currentIndex < MAX_BOOT_COMMANDS) { + ch = boot_commands[currentIndex][currentOffset++]; + if (ch == '\0' || (currentOffset >= MAX_INPUT_SIZE)) { + currentOffset = 0; + ++currentIndex; + } + return (ch); + } + + return (-1); +} + + +/*************************** GLOBAL FUNCTIONS ********************************/ + + +/* + * .KB_C_FN_DEFINITION_START + * void WriteCommandTable(void) + * This global function write the current command table to the non-volatile + * memory. + * .KB_C_FN_DEFINITION_END + */ +void +WriteCommandTable(void) +{ + int i, size = MAX_ENV_SIZE_BYTES, copySize; + char *cPtr = env_table; + + p_memset(env_table, 0, sizeof(env_table)); + + for (i = 0; i < MAX_BOOT_COMMANDS; ++i) { + + copySize = p_strlen(boot_commands[i]); + size -= copySize + 1; + + if (size < 0) { + continue; + } + p_memcpy(cPtr, boot_commands[i], copySize); + cPtr += copySize; + *cPtr++ = 0; + } + + WriteEEPROM((unsigned)&BootCommandSection, env_table, + sizeof(env_table)); +} + + +/* + * .KB_C_FN_DEFINITION_START + * void SetBootCommand(int index, char *command) + * This global function replaces the specified index with the string residing + * at command. Execute this function with a NULL string to clear the + * associated command index. + * .KB_C_FN_DEFINITION_END + */ +void +SetBootCommand(int index, char *command) +{ + int i; + + if ((unsigned)index < MAX_BOOT_COMMANDS) { + + p_memset(boot_commands[index], 0, MAX_INPUT_SIZE); + + if (!command) + return ; + + for (i = 0; i < MAX_INPUT_SIZE; ++i) { + boot_commands[index][i] = command[i]; + if (!(boot_commands[index][i])) + return; + } + } +} + + +/* + * .KB_C_FN_DEFINITION_START + * void DumpBootCommands(void) + * This global function displays the current boot commands. + * .KB_C_FN_DEFINITION_END + */ +void +DumpBootCommands(void) +{ + int i, j; + + for (i = 0; i < MAX_BOOT_COMMANDS; ++i) { + printf("0x%x : ", i); + for (j = 0; j < MAX_INPUT_SIZE; ++j) { + putchar(boot_commands[i][j]); + if (!(boot_commands[i][j])) + break; + } + printf("[E]\n\r"); + } +} + + +/* + * .KB_C_FN_DEFINITION_START + * void LoadBootCommands(void) + * This global function loads the existing boot commands from raw format and + * coverts it to the standard, command-index format. Notice, the processed + * boot command table has much more space allocated than the actual table + * stored in non-volatile memory. This is because the processed table + * exists in RAM which is larger than the non-volatile space. + * .KB_C_FN_DEFINITION_END + */ +void +LoadBootCommands(void) +{ + int index, j, size; + char *cPtr; + + p_memset((char*)boot_commands, 0, sizeof(boot_commands)); + + cPtr = &BootCommandSection; + + size = MAX_ENV_SIZE_BYTES; + + for (index = 0; (index < MAX_BOOT_COMMANDS) && size; ++index) { + for (j = 0; (j < MAX_INPUT_SIZE) && size; ++j) { + size--; + boot_commands[index][j] = *cPtr++; + if (!(boot_commands[index][j])) { + break; + } + } + } +} + + +/* + * .KB_C_FN_DEFINITION_START + * void ExecuteEnvironmentFunctions(void) + * This global function executes applicable entries in the environment. + * .KB_C_FN_DEFINITION_END + */ +void +ExecuteEnvironmentFunctions(void) +{ + currentIndex = 0; + currentOffset = 0; + + DumpBootCommands(); + Bootloader(ReadCharFromEnvironment); +} diff --git a/sys/boot/arm/at91/libat91/env_vars.h b/sys/boot/arm/at91/libat91/env_vars.h new file mode 100644 index 0000000..c6e46b4 --- /dev/null +++ b/sys/boot/arm/at91/libat91/env_vars.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Filename: env_vars.h + * + * Definition of environment variables, structures, and other globals. + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +#ifndef _ENV_VARS_H_ +#define _ENV_VARS_H_ + +/* each environment variable is a string following the standard command */ +/* definition used by the interactive loader in the following format: */ +/* <command> <parm1> <parm2> ... */ +/* all environment variables (or commands) are stored in a string */ +/* format: NULL-terminated. */ +/* this implies that commands can never utilize 0-values: actual 0, not */ +/* the string '0'. this is not an issue as the string '0' is handled */ +/* by the command parse routine. */ + +/* the following defines the maximum size of the environment for */ +/* including variables. */ +/* this value must match that declared in the low-level file that */ +/* actually reserves the space for the non-volatile environment. */ +#define MAX_ENV_SIZE_BYTES 0x100 + +#define MAX_BOOT_COMMANDS 10 + +/* C-style reference section */ +#ifndef __ASSEMBLY__ + +extern void WriteCommandTable(void); +extern void SetBootCommand(int index, char *command); +extern void DumpBootCommands(void); +extern void LoadBootCommands(void); +extern void ExecuteEnvironmentFunctions(void); + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ENV_VARS_H_ */ diff --git a/sys/boot/arm/at91/boot0/lib.c b/sys/boot/arm/at91/libat91/getc.c index 1f3e6e6..c86183b 100644 --- a/sys/boot/arm/at91/boot0/lib.c +++ b/sys/boot/arm/at91/libat91/getc.c @@ -34,23 +34,9 @@ * $FreeBSD$ */ -#include "AT91RM9200.h" +#include "at91rm9200.h" #include "at91rm9200_lowlevel.h" - -/* - * void putc(int ch) - * Writes a character to the DBGU port. It assumes that DBGU has - * already been initialized. - */ -void -putc(int ch) -{ - AT91PS_USART pUSART = (AT91PS_USART)AT91C_BASE_DBGU; - - while (!(pUSART->US_CSR & AT91C_US_TXRDY)) - continue; - pUSART->US_THR = (ch & 0xFF); -} +#include "lib.h" /* * int getc(int seconds) diff --git a/sys/boot/arm/at91/boot0/lib.h b/sys/boot/arm/at91/libat91/lib.h index 535b719..73a1f47 100644 --- a/sys/boot/arm/at91/boot0/lib.h +++ b/sys/boot/arm/at91/libat91/lib.h @@ -28,6 +28,16 @@ #define ARM_BOOT_LIB_H int getc(int); -void putc(int); +void putchar(int); +void printf(const char *fmt,...); + +/* The following function write eeprom at ee_addr using data */ +/* from data_add for size bytes. */ +void ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size); +void WriteEEPROM(unsigned ee_addr, char *data_addr, unsigned size); +void InitEEPROM(void); + +/* XMODEM protocol */ +int xmodem_rx(char *dst); #endif diff --git a/sys/boot/arm/at91/libat91/loader_prompt.c b/sys/boot/arm/at91/libat91/loader_prompt.c new file mode 100644 index 0000000..264765a --- /dev/null +++ b/sys/boot/arm/at91/libat91/loader_prompt.c @@ -0,0 +1,426 @@ +/****************************************************************************** + * + * Filename: loader_prompt.c + * + * Instantiation of the interactive loader functions. + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * 12JAN2005 kb_admin massive changes for tftp, strings, and more + * 05JUL2005 kb_admin save tag address, and set registers on boot + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +#include "at91rm9200_lowlevel.h" +#include "p_string.h" +#include "eeprom.h" +#ifdef SUPPORT_TAG_LIST +#include "tag_list.h" +#endif +#include "emac.h" +#include "loader_prompt.h" +#include "env_vars.h" +#include "lib.h" + + +/******************************* GLOBALS *************************************/ + + +/*********************** PRIVATE FUNCTIONS/DATA ******************************/ + +static char inputBuffer[MAX_INPUT_SIZE]; +static int buffCount; + +// argv pointer are either NULL or point to locations in inputBuffer +static char *argv[MAX_COMMAND_PARAMS]; + +static char backspaceString[] = {0x8, ' ', 0x8, 0}; + +static command_entry_t CommandTable[] = { + {COMMAND_COPY, "c"}, + {COMMAND_DUMP, "d"}, + {COMMAND_EXEC, "e"}, + {COMMAND_HELP, "?"}, + {COMMAND_LOCAL_IP, "ip"}, + {COMMAND_MAC, "m"}, + {COMMAND_SERVER_IP, "server_ip"}, + {COMMAND_SET, "s"}, +#ifdef SUPPORT_TAG_LIST + {COMMAND_TAG, "t"}, +#endif + {COMMAND_TFTP, "tftp"}, + {COMMAND_WRITE, "w"}, + {COMMAND_XMODEM, "x"}, + {COMMAND_FINAL_FLAG, 0} +}; + +static unsigned tagAddress; + +/* + * .KB_C_FN_DEFINITION_START + * unsigned BuildIP(void) + * This private function packs the test IP info to an unsigned value. + * .KB_C_FN_DEFINITION_END + */ +static unsigned +BuildIP(void) +{ + return ((p_ASCIIToDec(argv[1]) << 24) | + (p_ASCIIToDec(argv[2]) << 16) | + (p_ASCIIToDec(argv[3]) << 8) | + p_ASCIIToDec(argv[4])); +} + + +/* + * .KB_C_FN_DEFINITION_START + * int StringToCommand(char *cPtr) + * This private function converts a command string to a command code. + * .KB_C_FN_DEFINITION_END + */ +static int +StringToCommand(char *cPtr) +{ + int i; + + for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i) + if (!p_strcmp(CommandTable[i].c_string, cPtr)) + return (CommandTable[i].command); + + return (COMMAND_INVALID); +} + + +/* + * .KB_C_FN_DEFINITION_START + * void RestoreSpace(int) + * This private function restores NULL characters to spaces in order to + * process the remaining args as a string. The number passed is the argc + * of the first entry to begin restoring space in the inputBuffer. + * .KB_C_FN_DEFINITION_END + */ +static void +RestoreSpace(int startArgc) +{ + char *cPtr; + + for (startArgc++; startArgc < MAX_COMMAND_PARAMS; startArgc++) { + if ((cPtr = argv[startArgc])) + *(cPtr - 1) = ' '; + } +} + + +/* + * .KB_C_FN_DEFINITION_START + * int BreakCommand(char *) + * This private function splits the buffer into separate strings as pointed + * by argv and returns the number of parameters (< 0 on failure). + * .KB_C_FN_DEFINITION_END + */ +static int +BreakCommand(char *buffer) +{ + int pCount, cCount, state; + + state = pCount = 0; + p_memset((char*)argv, 0, sizeof(argv)); + + for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) { + + if (!state) { + /* look for next command */ + if (!p_IsWhiteSpace(buffer[cCount])) { + argv[pCount++] = &buffer[cCount]; + state = 1; + } else { + buffer[cCount] = 0; + } + } else { + /* in command, find next white space */ + if (p_IsWhiteSpace(buffer[cCount])) { + buffer[cCount] = 0; + state = 0; + } + } + + if (pCount >= MAX_COMMAND_PARAMS) { + return (-1); + } + } + + return (pCount); +} + + +/* + * .KB_C_FN_DEFINITION_START + * void ParseCommand(char *) + * This private function executes matching functions. + * .KB_C_FN_DEFINITION_END + */ +static void +ParseCommand(char *buffer) +{ + int argc; + + if ((argc = BreakCommand(buffer)) < 1) { + return ; + } + + switch (StringToCommand(argv[0])) { + + case COMMAND_COPY: + { + // "c <to> <from> <size in bytes>" + // copy memory + + char *to, *from; + unsigned size; + + if (argc > 3) { + to = (char *)p_ASCIIToHex(argv[1]); + from = (char *)p_ASCIIToHex(argv[2]); + size = p_ASCIIToHex(argv[3]); + p_memcpy(to, from, size); + } + + } + break; + + case COMMAND_DUMP: + // display boot commands + DumpBootCommands(); + break; + + case COMMAND_EXEC: + { + // "e <address>" + // execute at address + + void (*execAddr)(unsigned, unsigned, unsigned); + + if (argc > 1) { + /* in future, include machtypes (MACH_KB9200 = 612) */ + execAddr = (void (*)(unsigned, unsigned, unsigned)) + p_ASCIIToHex(argv[1]); + (*execAddr)(0, 612, tagAddress); + } + + } + break; + + case COMMAND_TFTP: + { + // "tftp <local_dest_addr filename>" + // tftp download + + unsigned address = 0; + + if (argc > 2) + address = p_ASCIIToHex(argv[1]); + + TFTP_Download(address, argv[2]); + + } + break; + + case COMMAND_SERVER_IP: + // "server_ip <server IP 192 200 1 20>" + // set download server address + + if (argc > 4) + SetServerIPAddress(BuildIP()); + break; + + case COMMAND_HELP: + // dump command info + printf("Commands:\r\n" + "\tc\r\n" + "\td\r\n" + "\te\r\n" + "\tip\r\n" + "\tserver_ip\r\n" + "\tm\r\n" + "\ttftp\r\n" + "\ts\r\n" +#ifdef SUPPORT_TAG_LIST + "\tt\r\n" +#endif + "\tw\r\n" + "\tx\r\n"); + break; + + case COMMAND_LOCAL_IP: + // "local_ip <local IP 192 200 1 21> + // set ip of this module + + if (argc > 4) + SetLocalIPAddress(BuildIP()); + break; + + case COMMAND_MAC: + { + // "m <mac address 12 34 56 78 9a bc> + // set mac address using 6 byte values + + unsigned low_addr, high_addr; + + if (argc > 6) { + + low_addr = (p_ASCIIToHex(argv[4]) << 24) | + (p_ASCIIToHex(argv[3]) << 16) | + (p_ASCIIToHex(argv[2]) << 8) | + p_ASCIIToHex(argv[1]); + high_addr = + (p_ASCIIToHex(argv[6]) << 8) | + p_ASCIIToHex(argv[5]); + SetMACAddress(low_addr, high_addr); + } + + } + break; + + case COMMAND_SET: + { + // s <index> <new boot command> + // set the boot command at index (0-based) + + unsigned index; + + if (argc > 1) { + RestoreSpace(2); + index = p_ASCIIToHex(argv[1]); + SetBootCommand(index, argv[2]); + } + + } + break; + +#ifdef SUPPORT_TAG_LIST + case COMMAND_TAG: + { + // t <address> <boot command line> + // create tag-list for linux boot + + if (argc > 2) { + RestoreSpace(2); + tagAddress = p_ASCIIToHex(argv[1]); + InitTagList(argv[2], (void*)tagAddress); + } + + } + break; +#endif + + case COMMAND_WRITE: + // write the command table to non-volatile + + WriteCommandTable(); + break; + + case COMMAND_XMODEM: + { + // "x <address>" + // download X-modem record at address + + char *destAddr = 0; + + if (argc > 1) { + destAddr = (char *)p_ASCIIToHex(argv[1]); + xmodem_rx(destAddr); + } + } + break; + + default: + break; + } + + printf("\r\n"); +} + + +/* + * .KB_C_FN_DEFINITION_START + * void ServicePrompt(char) + * This private function process each character checking for valid commands. + * This function is only executed if the character is considered valid. + * Each command is terminated with NULL (0) or '\r'. + * .KB_C_FN_DEFINITION_END + */ +static void ServicePrompt(char p_char) { + + if (p_char == '\r') { + p_char = 0; + + } + + if (p_char != 0x8) { + if (buffCount < MAX_INPUT_SIZE-1) { + + inputBuffer[buffCount] = p_char; + ++buffCount; + putchar(p_char); + } + + } else if (buffCount) { + + /* handle backspace BS */ + --buffCount; + inputBuffer[buffCount] = 0; + printf(backspaceString); + return ; + } + + if (!p_char) { + printf("\r\n"); + ParseCommand(inputBuffer); + p_memset(inputBuffer, 0, MAX_INPUT_SIZE); + buffCount = 0; + printf("\r\n>"); + } +} + + +/* ************************** GLOBAL FUNCTIONS ********************************/ + + +/* + * .KB_C_FN_DEFINITION_START + * void Bootloader(void *inputFunction) + * This global function is the entry point for the bootloader. If the + * inputFunction pointer is NULL, the loader input will be serviced from + * the uart. Otherwise, inputFunction is called to get characters which + * the loader will parse. + * .KB_C_FN_DEFINITION_END + */ +void +Bootloader(int(*inputFunction)(int)) +{ + int ch = 0; + + p_memset((void*)inputBuffer, 0, sizeof(inputBuffer)); + + buffCount = 0; + if (!inputFunction) { + inputFunction = getc; + } + + printf("\r\n>"); + + while (ch >= 0) + if ((ch = ((*inputFunction)(0))) > 0) + ServicePrompt(ch); +} diff --git a/sys/boot/arm/at91/libat91/loader_prompt.h b/sys/boot/arm/at91/libat91/loader_prompt.h new file mode 100644 index 0000000..0223340 --- /dev/null +++ b/sys/boot/arm/at91/libat91/loader_prompt.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * + * Filename: loader_prompt.h + * + * Definition of the interactive loader functions. + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +#ifndef _LOADER_PROMPT_H_ +#define _LOADER_PROMPT_H_ + +#define MAX_INPUT_SIZE 256 +#define MAX_COMMAND_PARAMS 10 + +enum { + COMMAND_INVALID = 0, + COMMAND_COPY, + COMMAND_DUMP, + COMMAND_EXEC, + COMMAND_HELP, + COMMAND_LOCAL_IP, + COMMAND_MAC, + COMMAND_SERVER_IP, + COMMAND_SET, + COMMAND_TAG, + COMMAND_TFTP, + COMMAND_WRITE, + COMMAND_XMODEM, + COMMAND_FINAL_FLAG +} e_cmd_t; + + +typedef struct { + int command; + const char *c_string; +} command_entry_t; + +void EnterInteractiveBootloader(int(*inputFunction)(int)); +void Bootloader(int(*inputFunction)(int)); + +#endif /* _LOADER_PROMPT_H_ */ diff --git a/sys/boot/arm/at91/libat91/p_string.c b/sys/boot/arm/at91/libat91/p_string.c new file mode 100644 index 0000000..743b011 --- /dev/null +++ b/sys/boot/arm/at91/libat91/p_string.c @@ -0,0 +1,210 @@ +/****************************************************************************** + * + * Filename: p_string.c + * + * Instantiation of basic string operations to prevent inclusion of full + * string library. These are simple implementations not necessarily optimized + * for speed, but rather to show intent. + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * 12JAN2005 kb_admin minor updates + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +#include "p_string.h" + +/* + * .KB_C_FN_DEFINITION_START + * int p_IsWhiteSpace(char) + * This global function returns true if the character is not considered + * a non-space character. + * .KB_C_FN_DEFINITION_END + */ +int +p_IsWhiteSpace(char cValue) +{ + return ((cValue == ' ') || + (cValue == '\t') || + (cValue == 0) || + (cValue == '\r') || + (cValue == '\n')); +} + + +/* + * .KB_C_FN_DEFINITION_START + * unsigned p_HexCharValue(char) + * This global function returns the decimal value of the validated hex char. + * .KB_C_FN_DEFINITION_END + */ +unsigned +p_HexCharValue(char cValue) +{ + if (cValue < ('9' + 1)) + return (cValue - '0'); + if (cValue < ('F' + 1)) + return (cValue - 'A' + 10); + return (cValue - 'a' + 10); +} + + +/* + * .KB_C_FN_DEFINITION_START + * void p_memset(char *buffer, char value, int size) + * This global function sets memory at the pointer for the specified + * number of bytes to value. + * .KB_C_FN_DEFINITION_END + */ +void +p_memset(char *buffer, char value, int size) +{ + while (size--) + *buffer++ = value; +} + + +/* + * .KB_C_FN_DEFINITION_START + * int p_strlen(char *) + * This global function returns the number of bytes starting at the pointer + * before (not including) the string termination character ('/0'). + * .KB_C_FN_DEFINITION_END + */ +int +p_strlen(const char *buffer) +{ + int len = 0; + if (buffer) + while (buffer[len]) + len++; + return (len); +} + + +/* + * .KB_C_FN_DEFINITION_START + * char *p_strcpy(char *to, char *from) + * This global function returns a pointer to the end of the destination string + * after the copy operation (after the '/0'). + * .KB_C_FN_DEFINITION_END + */ +char * +p_strcpy(char *to, const char *from) +{ + while (*from) + *to++ = *from++; + *to++ = '\0'; + return (to); +} + + +/* + * .KB_C_FN_DEFINITION_START + * unsigned p_ASCIIToHex(char *) + * This global function set the unsigned value equal to the converted + * hex number passed as a string. No error checking is performed; the + * string must be valid hex value, point at the start of string, and be + * NULL-terminated. + * .KB_C_FN_DEFINITION_END + */ +unsigned +p_ASCIIToHex(const char *buf) +{ + unsigned lValue = 0; + + if ((*buf == '0') && ((buf[1] == 'x') || (buf[1] == 'X'))) + buf += 2; + + while (*buf) { + lValue <<= 4; + lValue += p_HexCharValue(*buf++); + } + return (lValue); +} + + +/* + * .KB_C_FN_DEFINITION_START + * unsigned p_ASCIIToDec(char *) + * This global function set the unsigned value equal to the converted + * decimal number passed as a string. No error checking is performed; the + * string must be valid decimal value, point at the start of string, and be + * NULL-terminated. + * .KB_C_FN_DEFINITION_END + */ +unsigned +p_ASCIIToDec(const char *buf) +{ + unsigned v = 0; + + while (*buf) { + v *= 10; + v += (*buf++) - '0'; + } + return (v); +} + + +/* + * .KB_C_FN_DEFINITION_START + * void p_memcpy(char *, char *, unsigned) + * This global function copies data from the first pointer to the second + * pointer for the specified number of bytes. + * .KB_C_FN_DEFINITION_END + */ +void +p_memcpy(char *to, const char *from, unsigned size) +{ + while (size--) + *to++ = *from++; +} + + +/* + * .KB_C_FN_DEFINITION_START + * int p_memcmp(char *to, char *from, unsigned size) + * This global function compares data at to against data at from for + * size bytes. Returns 0 if the locations are equal. size must be + * greater than 0. + * .KB_C_FN_DEFINITION_END + */ +int +p_memcmp(const char *to, const char *from, unsigned size) +{ + while ((--size) && (*to++ == *from++)) + continue; + + return (*to != *from); +} + + +/* + * .KB_C_FN_DEFINITION_START + * int p_strcmp(char *to, char *from) + * This global function compares string at to against string at from. + * Returns 0 if the locations are equal. + * .KB_C_FN_DEFINITION_END + */ +int +p_strcmp(const char *to, const char *from) +{ + + while (*to && *from && (*to == *from)) { + ++to; + ++from; + } + + return (!((!*to) && (*to == *from))); +} diff --git a/sys/boot/arm/at91/libat91/p_string.h b/sys/boot/arm/at91/libat91/p_string.h new file mode 100644 index 0000000..d4461b3 --- /dev/null +++ b/sys/boot/arm/at91/libat91/p_string.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Filename: p_string.h + * + * Definition of basic, private, string operations to prevent inclusion of full + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +#ifndef _P_STRING_H_ +#define _P_STRING_H_ + +#define ToASCII(x) ((x > 9) ? (x + 'A' - 0xa) : (x + '0')) + +int p_IsWhiteSpace(char cValue); +unsigned p_HexCharValue(char cValue); +void p_memset(char *buffer, char value, int size); +int p_strlen(const char *buffer); +char *p_strcpy(char *to, const char *from); +unsigned p_ASCIIToHex(const char *buf); +unsigned p_ASCIIToDec(const char *buf); +void p_memcpy(char *to, const char *from, unsigned size); +int p_memcmp(const char *to, const char *from, unsigned size); +int p_strcmp(const char *to, const char *from); + +#endif /* _P_STRING_H_ */ diff --git a/sys/boot/arm/at91/libat91/printf.c b/sys/boot/arm/at91/libat91/printf.c new file mode 100644 index 0000000..81b48c5 --- /dev/null +++ b/sys/boot/arm/at91/libat91/printf.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * Copyright (c) 2006 M. Warner Losh + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD$ + */ + +#include <stdarg.h> +#include "lib.h" + +void +printf(const char *fmt,...) +{ + va_list ap; + const char *hex = "0123456789abcdef"; + char buf[10]; + char *s; + unsigned u; + int c; + + va_start(ap, fmt); + while ((c = *fmt++)) { + if (c == '%') { + c = *fmt++; + switch (c) { + case 'c': + putchar(va_arg(ap, int)); + continue; + case 's': + for (s = va_arg(ap, char *); *s; s++) + putchar(*s); + continue; + case 'u': + u = va_arg(ap, unsigned); + s = buf; + do + *s++ = '0' + u % 10U; + while (u /= 10U); + dumpbuf:; + while (--s >= buf) + putchar(*s); + continue; + case 'x': + u = va_arg(ap, unsigned); + s = buf; + do + *s++ = hex[u & 0xfu]; + while (u >>= 4); + goto dumpbuf; + } + } + putchar(c); + } + va_end(ap); + + return; +} diff --git a/sys/boot/arm/at91/boot0/xmodem.h b/sys/boot/arm/at91/libat91/putchar.c index bcc156c..137c2e3 100644 --- a/sys/boot/arm/at91/boot0/xmodem.h +++ b/sys/boot/arm/at91/libat91/putchar.c @@ -21,12 +21,34 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * This software is derived from software provided by kwikbyte without + * copyright as follows: + * + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * * $FreeBSD$ */ -#ifndef BOOT_ARM_XMODEM_H -#define BOOT_ARM_XMODEM_H +#include "at91rm9200.h" +#include "at91rm9200_lowlevel.h" +#include "lib.h" -int xmodem_rx(char *dst); +/* + * void putchar(int ch) + * Writes a character to the DBGU port. It assumes that DBGU has + * already been initialized. + */ +void +putchar(int ch) +{ + AT91PS_USART pUSART = (AT91PS_USART)AT91C_BASE_DBGU; -#endif /* BOOT_ARM_XMODEM_H */ + while (!(pUSART->US_CSR & AT91C_US_TXRDY)) + continue; + pUSART->US_THR = (ch & 0xFF); +} diff --git a/sys/boot/arm/at91/libat91/tag_list.c b/sys/boot/arm/at91/libat91/tag_list.c new file mode 100644 index 0000000..41b150c --- /dev/null +++ b/sys/boot/arm/at91/libat91/tag_list.c @@ -0,0 +1,79 @@ +/****************************************************************************** + * + * Filename: tag_list.c + * + * Instantiation of basic routines that create linux-boot tag list. + * + * Revision information: + * + * 22AUG2004 kb_admin initial creation + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +/******************************* GLOBALS *************************************/ + +/********************** PRIVATE FUNCTIONS/DATA/DEFINES ***********************/ + +#define u32 unsigned +#define u16 unsigned short +#define u8 unsigned char + +#include "/usr/src/arm/linux/include/asm/setup.h" + +#define PAGE_SIZE 0x1000 +#define MEM_SIZE 0x2000000 +#define PHYS_OFFSET 0x20000000 + +/*************************** GLOBAL FUNCTIONS ********************************/ + +/* + * .KB_C_FN_DEFINITION_START + * void InitTagList(char*, void *) + * This global function populates a linux-boot style tag list from the + * string passed in the pointer at the location specified. + * .KB_C_FN_DEFINITION_END + */ +void InitTagList(char *parms, void *output) { + + char *src, *dst; + struct tag *tagList = (struct tag*)output; + + tagList->hdr.size = tag_size(tag_core); + tagList->hdr.tag = ATAG_CORE; + tagList->u.core.flags = 1; + tagList->u.core.pagesize = PAGE_SIZE; + tagList->u.core.rootdev = 0xff; + tagList = tag_next(tagList); + + tagList->hdr.size = tag_size(tag_mem32); + tagList->hdr.tag = ATAG_MEM; + tagList->u.mem.size = MEM_SIZE; + tagList->u.mem.start = PHYS_OFFSET; + tagList = tag_next(tagList); + + tagList->hdr.size = tag_size(tag_cmdline); + tagList->hdr.tag = ATAG_CMDLINE; + + src = parms; + dst = tagList->u.cmdline.cmdline; + while (*src) { + *dst++ = *src++; + } + *dst = 0; + + tagList->hdr.size += ((unsigned)(src - parms) + 1) / sizeof(unsigned); + tagList = tag_next(tagList); + + tagList->hdr.size = 0; + tagList->hdr.tag = ATAG_NONE; +} diff --git a/sys/boot/arm/at91/libat91/tag_list.h b/sys/boot/arm/at91/libat91/tag_list.h new file mode 100644 index 0000000..6fa4ea9 --- /dev/null +++ b/sys/boot/arm/at91/libat91/tag_list.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * + * Filename: tag_list.h + * + * Definition of basic routines that create linux-boot tag list. + * + * Revision information: + * + * 22AUG2004 kb_admin initial creation + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + *****************************************************************************/ + +#ifndef _TAG_LIST_H_ +#define _TAG_LIST_H_ + +extern void InitTagList(char *parms, void*); + +#endif /* _TAG_LIST_H_ */ diff --git a/sys/boot/arm/at91/boot0/xmodem.c b/sys/boot/arm/at91/libat91/xmodem.c index 8781187..c3903aa 100644 --- a/sys/boot/arm/at91/boot0/xmodem.c +++ b/sys/boot/arm/at91/libat91/xmodem.c @@ -81,11 +81,11 @@ GetRecord(char blocknum, char *dest) goto err; if (((ch = getc(1)) == -1) || ((ch & 0xff) != (chk & 0xFF))) goto err; - putc(ACK); + putchar(ACK); return (1); err:; - putc(CAN); + putchar(CAN); // We should allow for resend, but we don't. return (0); } @@ -107,11 +107,11 @@ xmodem_rx(char *dest) while (1) { if (starting) - putc('C'); + putchar('C'); if (((ch = getc(1)) == -1) || (ch != SOH && ch != EOT)) continue; if (ch == EOT) { - putc(ACK); + putchar(ACK); return (dest - startAddress); } starting = 0; diff --git a/sys/boot/arm/at91/linker.cfg b/sys/boot/arm/at91/linker.cfg new file mode 100644 index 0000000..40ae7bf --- /dev/null +++ b/sys/boot/arm/at91/linker.cfg @@ -0,0 +1,291 @@ +/******************************************************************************* + * + * Filename: linker.cfg + * + * linker config file used for internal RAM or eeprom images at address 0. + * + * Revision information: + * + * 20AUG2004 kb_admin initial creation + * 12JAN2005 kb_admin move data to SDRAM + * + * BEGIN_KBDD_BLOCK + * No warranty, expressed or implied, is included with this software. It is + * provided "AS IS" and no warranty of any kind including statutory or aspects + * relating to merchantability or fitness for any purpose is provided. All + * intellectual property rights of others is maintained with the respective + * owners. This software is not copyrighted and is intended for reference + * only. + * END_BLOCK + * + * $FreeBSD$ + ******************************************************************************/ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", + "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(start) + SEARCH_DIR(/usr/local/arm/2.95.3/arm-linux/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + .text : + { + *(.text) + *(.text.*) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t.*) + *(.glue_7t) *(.glue_7) + } + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : + { + *(.rel.text) + *(.rel.text.*) + *(.rel.gnu.linkonce.t.*) + } + .rela.text : + { + *(.rela.text) + *(.rela.text.*) + *(.rela.gnu.linkonce.t.*) + } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : + { + *(.rel.rodata) + *(.rel.rodata.*) + *(.rel.gnu.linkonce.r.*) + } + .rela.rodata : + { + *(.rela.rodata) + *(.rela.rodata.*) + *(.rela.gnu.linkonce.r.*) + } + .rel.data : + { + *(.rel.data) + *(.rel.data.*) + *(.rel.gnu.linkonce.d.*) + } + .rela.data : + { + *(.rela.data) + *(.rela.data.*) + *(.rela.gnu.linkonce.d.*) + } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : + { + *(.rel.sdata) + *(.rel.sdata.*) + *(.rel.gnu.linkonce.s.*) + } + .rela.sdata : + { + *(.rela.sdata) + *(.rela.sdata.*) + *(.rela.gnu.linkonce.s.*) + } + .rel.sbss : + { + *(.rel.sbss) + *(.rel.sbss.*) + *(.rel.gnu.linkonce.sb.*) + } + .rela.sbss : + { + *(.rela.sbss) + *(.rela.sbss.*) + *(.rel.gnu.linkonce.sb.*) + } + .rel.sdata2 : + { + *(.rel.sdata2) + *(.rel.sdata2.*) + *(.rel.gnu.linkonce.s2.*) + } + .rela.sdata2 : + { + *(.rela.sdata2) + *(.rela.sdata2.*) + *(.rela.gnu.linkonce.s2.*) + } + .rel.sbss2 : + { + *(.rel.sbss2) + *(.rel.sbss2.*) + *(.rel.gnu.linkonce.sb2.*) + } + .rela.sbss2 : + { + *(.rela.sbss2) + *(.rela.sbss2.*) + *(.rela.gnu.linkonce.sb2.*) + } + .rel.bss : + { + *(.rel.bss) + *(.rel.bss.*) + *(.rel.gnu.linkonce.b.*) + } + .rela.bss : + { + *(.rela.bss) + *(.rela.bss.*) + *(.rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0 + .plt : { *(.plt) } + .fini : + { + KEEP (*(.fini)) + } =0 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) } + .data : + { + __data_start = . ; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + . = 0x21200000; + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + __bss_start__ = .; + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .bss : + { + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + _bss_end__ = . ; __bss_end__ = . ; __end__ = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} |