From c0f9056ee2a8c850019f715eccc5e5a9041b44cc Mon Sep 17 00:00:00 2001 From: Philippe Vachon Date: Sat, 10 Jan 2009 03:41:34 -0500 Subject: [PATCH] Add PowerPC support for the Cisco 1700 series. --- Makefile | 18 +- include/asm/ppc_asm.h | 680 ++++++++++++++++++++++++++++++++++ include/mach/c1700/platform.h | 16 + include/mach/c1700/platio.h | 24 ++ mach/c1700/Makefile | 18 + mach/c1700/platform.c | 75 ++++ mach/c1700/platio.c | 98 +++++ mach/c1700/promlib.c | 160 ++++++++ mach/c1700/start.S | 29 ++ 9 files changed, 1110 insertions(+), 8 deletions(-) create mode 100644 include/asm/ppc_asm.h create mode 100644 include/mach/c1700/platform.h create mode 100644 include/mach/c1700/platio.h create mode 100644 mach/c1700/Makefile create mode 100644 mach/c1700/platform.c create mode 100644 mach/c1700/platio.c create mode 100644 mach/c1700/promlib.c create mode 100644 mach/c1700/start.S diff --git a/Makefile b/Makefile index b14859d..c376c1d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -#Configuration for the Cisco 3620/3640 Routers +# Configuration for the Cisco 3620/3640 Routers TARGET=c3600 MACHCODE=0x1e TEXTADDR=0x80008000 @@ -15,15 +15,17 @@ LDFLAGS=-Ttext ${TEXTADDR} # ifndef CROSS_COMPILE # CROSS_COMPILE=mips-elf- # endif +# CFLAGS=-DDEBUG -mno-abicalls +# LDFLAGS=-Ttext ${TEXTADDR} # Configuration for the Cisco 1700 Series Routers -#TARGET=c1700 -#MACHCODE=0x33 -#TEXTADDR=0x80008000 -#ifndef CROSS_COMPILE -#CROSS_COMPILE=powerpc-elf- -#endif -#LDFLAGS=-Ttext=${TEXTADDR} +# TARGET=c1700 +# MACHCODE=0x33 +# TEXTADDR=0x80008000 +# ifndef CROSS_COMPILE +# CROSS_COMPILE=powerpc-elf- +# endif +# LDFLAGS=-Ttext=${TEXTADDR} # additional CFLAGS CFLAGS+= diff --git a/include/asm/ppc_asm.h b/include/asm/ppc_asm.h new file mode 100644 index 0000000..3b271e2 --- /dev/null +++ b/include/asm/ppc_asm.h @@ -0,0 +1,680 @@ +/* + * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. + */ +#ifndef _ASM_POWERPC_PPC_ASM_H +#define _ASM_POWERPC_PPC_ASM_H + +#define SZL (BITS_PER_LONG/8) + +/* + * Stuff for accurate CPU time accounting. + * These macros handle transitions between user and system state + * in exception entry and exit and accumulate time to the + * user_time and system_time fields in the paca. + */ + +#ifndef CONFIG_VIRT_CPU_ACCOUNTING +#define ACCOUNT_CPU_USER_ENTRY(ra, rb) +#define ACCOUNT_CPU_USER_EXIT(ra, rb) +#else +#define ACCOUNT_CPU_USER_ENTRY(ra, rb) \ + beq 2f; /* if from kernel mode */ \ +BEGIN_FTR_SECTION; \ + mfspr ra,SPRN_PURR; /* get processor util. reg */ \ +END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ +BEGIN_FTR_SECTION; \ + MFTB(ra); /* or get TB if no PURR */ \ +END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \ + ld rb,PACA_STARTPURR(r13); \ + std ra,PACA_STARTPURR(r13); \ + subf rb,rb,ra; /* subtract start value */ \ + ld ra,PACA_USER_TIME(r13); \ + add ra,ra,rb; /* add on to user time */ \ + std ra,PACA_USER_TIME(r13); \ +2: + +#define ACCOUNT_CPU_USER_EXIT(ra, rb) \ +BEGIN_FTR_SECTION; \ + mfspr ra,SPRN_PURR; /* get processor util. reg */ \ +END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ +BEGIN_FTR_SECTION; \ + MFTB(ra); /* or get TB if no PURR */ \ +END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \ + ld rb,PACA_STARTPURR(r13); \ + std ra,PACA_STARTPURR(r13); \ + subf rb,rb,ra; /* subtract start value */ \ + ld ra,PACA_SYSTEM_TIME(r13); \ + add ra,ra,rb; /* add on to user time */ \ + std ra,PACA_SYSTEM_TIME(r13); +#endif + +/* + * Macros for storing registers into and loading registers from + * exception frames. + */ +#ifdef __powerpc64__ +#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) +#define REST_GPR(n, base) ld n,GPR0+8*(n)(base) +#define SAVE_NVGPRS(base) SAVE_8GPRS(14, base); SAVE_10GPRS(22, base) +#define REST_NVGPRS(base) REST_8GPRS(14, base); REST_10GPRS(22, base) +#else +#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) +#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) +#define SAVE_NVGPRS(base) SAVE_GPR(13, base); SAVE_8GPRS(14, base); \ + SAVE_10GPRS(22, base) +#define REST_NVGPRS(base) REST_GPR(13, base); REST_8GPRS(14, base); \ + REST_10GPRS(22, base) +#endif + +/* + * Define what the VSX XX1 form instructions will look like, then add + * the 128 bit load store instructions based on that. + */ +#define VSX_XX1(xs, ra, rb) (((xs) & 0x1f) << 21 | ((ra) << 16) | \ + ((rb) << 11) | (((xs) >> 5))) + +#define STXVD2X(xs, ra, rb) .long (0x7c000798 | VSX_XX1((xs), (ra), (rb))) +#define LXVD2X(xs, ra, rb) .long (0x7c000698 | VSX_XX1((xs), (ra), (rb))) + +#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) + +#define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*TS_FPRWIDTH*(n)(base) +#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) +#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) +#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) +#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) +#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) +#define REST_FPR(n, base) lfd n,THREAD_FPR0+8*TS_FPRWIDTH*(n)(base) +#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) +#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) +#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) +#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) +#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) + +#define SAVE_VR(n,b,base) li b,THREAD_VR0+(16*(n)); stvx n,b,base +#define SAVE_2VRS(n,b,base) SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) +#define SAVE_4VRS(n,b,base) SAVE_2VRS(n,b,base); SAVE_2VRS(n+2,b,base) +#define SAVE_8VRS(n,b,base) SAVE_4VRS(n,b,base); SAVE_4VRS(n+4,b,base) +#define SAVE_16VRS(n,b,base) SAVE_8VRS(n,b,base); SAVE_8VRS(n+8,b,base) +#define SAVE_32VRS(n,b,base) SAVE_16VRS(n,b,base); SAVE_16VRS(n+16,b,base) +#define REST_VR(n,b,base) li b,THREAD_VR0+(16*(n)); lvx n,b,base +#define REST_2VRS(n,b,base) REST_VR(n,b,base); REST_VR(n+1,b,base) +#define REST_4VRS(n,b,base) REST_2VRS(n,b,base); REST_2VRS(n+2,b,base) +#define REST_8VRS(n,b,base) REST_4VRS(n,b,base); REST_4VRS(n+4,b,base) +#define REST_16VRS(n,b,base) REST_8VRS(n,b,base); REST_8VRS(n+8,b,base) +#define REST_32VRS(n,b,base) REST_16VRS(n,b,base); REST_16VRS(n+16,b,base) + +/* Save the lower 32 VSRs in the thread VSR region */ +#define SAVE_VSR(n,b,base) li b,THREAD_VSR0+(16*(n)); STXVD2X(n,b,base) +#define SAVE_2VSRS(n,b,base) SAVE_VSR(n,b,base); SAVE_VSR(n+1,b,base) +#define SAVE_4VSRS(n,b,base) SAVE_2VSRS(n,b,base); SAVE_2VSRS(n+2,b,base) +#define SAVE_8VSRS(n,b,base) SAVE_4VSRS(n,b,base); SAVE_4VSRS(n+4,b,base) +#define SAVE_16VSRS(n,b,base) SAVE_8VSRS(n,b,base); SAVE_8VSRS(n+8,b,base) +#define SAVE_32VSRS(n,b,base) SAVE_16VSRS(n,b,base); SAVE_16VSRS(n+16,b,base) +#define REST_VSR(n,b,base) li b,THREAD_VSR0+(16*(n)); LXVD2X(n,b,base) +#define REST_2VSRS(n,b,base) REST_VSR(n,b,base); REST_VSR(n+1,b,base) +#define REST_4VSRS(n,b,base) REST_2VSRS(n,b,base); REST_2VSRS(n+2,b,base) +#define REST_8VSRS(n,b,base) REST_4VSRS(n,b,base); REST_4VSRS(n+4,b,base) +#define REST_16VSRS(n,b,base) REST_8VSRS(n,b,base); REST_8VSRS(n+8,b,base) +#define REST_32VSRS(n,b,base) REST_16VSRS(n,b,base); REST_16VSRS(n+16,b,base) +/* Save the upper 32 VSRs (32-63) in the thread VSX region (0-31) */ +#define SAVE_VSRU(n,b,base) li b,THREAD_VR0+(16*(n)); STXVD2X(n+32,b,base) +#define SAVE_2VSRSU(n,b,base) SAVE_VSRU(n,b,base); SAVE_VSRU(n+1,b,base) +#define SAVE_4VSRSU(n,b,base) SAVE_2VSRSU(n,b,base); SAVE_2VSRSU(n+2,b,base) +#define SAVE_8VSRSU(n,b,base) SAVE_4VSRSU(n,b,base); SAVE_4VSRSU(n+4,b,base) +#define SAVE_16VSRSU(n,b,base) SAVE_8VSRSU(n,b,base); SAVE_8VSRSU(n+8,b,base) +#define SAVE_32VSRSU(n,b,base) SAVE_16VSRSU(n,b,base); SAVE_16VSRSU(n+16,b,base) +#define REST_VSRU(n,b,base) li b,THREAD_VR0+(16*(n)); LXVD2X(n+32,b,base) +#define REST_2VSRSU(n,b,base) REST_VSRU(n,b,base); REST_VSRU(n+1,b,base) +#define REST_4VSRSU(n,b,base) REST_2VSRSU(n,b,base); REST_2VSRSU(n+2,b,base) +#define REST_8VSRSU(n,b,base) REST_4VSRSU(n,b,base); REST_4VSRSU(n+4,b,base) +#define REST_16VSRSU(n,b,base) REST_8VSRSU(n,b,base); REST_8VSRSU(n+8,b,base) +#define REST_32VSRSU(n,b,base) REST_16VSRSU(n,b,base); REST_16VSRSU(n+16,b,base) + +#define SAVE_EVR(n,s,base) evmergehi s,s,n; stw s,THREAD_EVR0+4*(n)(base) +#define SAVE_2EVRS(n,s,base) SAVE_EVR(n,s,base); SAVE_EVR(n+1,s,base) +#define SAVE_4EVRS(n,s,base) SAVE_2EVRS(n,s,base); SAVE_2EVRS(n+2,s,base) +#define SAVE_8EVRS(n,s,base) SAVE_4EVRS(n,s,base); SAVE_4EVRS(n+4,s,base) +#define SAVE_16EVRS(n,s,base) SAVE_8EVRS(n,s,base); SAVE_8EVRS(n+8,s,base) +#define SAVE_32EVRS(n,s,base) SAVE_16EVRS(n,s,base); SAVE_16EVRS(n+16,s,base) +#define REST_EVR(n,s,base) lwz s,THREAD_EVR0+4*(n)(base); evmergelo n,s,n +#define REST_2EVRS(n,s,base) REST_EVR(n,s,base); REST_EVR(n+1,s,base) +#define REST_4EVRS(n,s,base) REST_2EVRS(n,s,base); REST_2EVRS(n+2,s,base) +#define REST_8EVRS(n,s,base) REST_4EVRS(n,s,base); REST_4EVRS(n+4,s,base) +#define REST_16EVRS(n,s,base) REST_8EVRS(n,s,base); REST_8EVRS(n+8,s,base) +#define REST_32EVRS(n,s,base) REST_16EVRS(n,s,base); REST_16EVRS(n+16,s,base) + +/* Macros to adjust thread priority for hardware multithreading */ +#define HMT_VERY_LOW or 31,31,31 # very low priority +#define HMT_LOW or 1,1,1 +#define HMT_MEDIUM_LOW or 6,6,6 # medium low priority +#define HMT_MEDIUM or 2,2,2 +#define HMT_MEDIUM_HIGH or 5,5,5 # medium high priority +#define HMT_HIGH or 3,3,3 + +/* handle instructions that older assemblers may not know */ +#define RFCI .long 0x4c000066 /* rfci instruction */ +#define RFDI .long 0x4c00004e /* rfdi instruction */ +#define RFMCI .long 0x4c00004c /* rfmci instruction */ + +#ifdef __KERNEL__ +#ifdef CONFIG_PPC64 + +#define XGLUE(a,b) a##b +#define GLUE(a,b) XGLUE(a,b) + +#define _GLOBAL(name) \ + .section ".text"; \ + .align 2 ; \ + .globl name; \ + .globl GLUE(.,name); \ + .section ".opd","aw"; \ +name: \ + .quad GLUE(.,name); \ + .quad .TOC.@tocbase; \ + .quad 0; \ + .previous; \ + .type GLUE(.,name),@function; \ +GLUE(.,name): + +#define _INIT_GLOBAL(name) \ + .section ".text.init.refok"; \ + .align 2 ; \ + .globl name; \ + .globl GLUE(.,name); \ + .section ".opd","aw"; \ +name: \ + .quad GLUE(.,name); \ + .quad .TOC.@tocbase; \ + .quad 0; \ + .previous; \ + .type GLUE(.,name),@function; \ +GLUE(.,name): + +#define _KPROBE(name) \ + .section ".kprobes.text","a"; \ + .align 2 ; \ + .globl name; \ + .globl GLUE(.,name); \ + .section ".opd","aw"; \ +name: \ + .quad GLUE(.,name); \ + .quad .TOC.@tocbase; \ + .quad 0; \ + .previous; \ + .type GLUE(.,name),@function; \ +GLUE(.,name): + +#define _STATIC(name) \ + .section ".text"; \ + .align 2 ; \ + .section ".opd","aw"; \ +name: \ + .quad GLUE(.,name); \ + .quad .TOC.@tocbase; \ + .quad 0; \ + .previous; \ + .type GLUE(.,name),@function; \ +GLUE(.,name): + +#define _INIT_STATIC(name) \ + .section ".text.init.refok"; \ + .align 2 ; \ + .section ".opd","aw"; \ +name: \ + .quad GLUE(.,name); \ + .quad .TOC.@tocbase; \ + .quad 0; \ + .previous; \ + .type GLUE(.,name),@function; \ +GLUE(.,name): + +#else /* 32-bit */ + +#define _ENTRY(n) \ + .globl n; \ +n: + +#define _GLOBAL(n) \ + .text; \ + .stabs __stringify(n:F-1),N_FUN,0,0,n;\ + .globl n; \ +n: + +#define _KPROBE(n) \ + .section ".kprobes.text","a"; \ + .globl n; \ +n: + +#endif + +/* + * LOAD_REG_IMMEDIATE(rn, expr) + * Loads the value of the constant expression 'expr' into register 'rn' + * using immediate instructions only. Use this when it's important not + * to reference other data (i.e. on ppc64 when the TOC pointer is not + * valid) and when 'expr' is a constant or absolute address. + * + * LOAD_REG_ADDR(rn, name) + * Loads the address of label 'name' into register 'rn'. Use this when + * you don't particularly need immediate instructions only, but you need + * the whole address in one register (e.g. it's a structure address and + * you want to access various offsets within it). On ppc32 this is + * identical to LOAD_REG_IMMEDIATE. + * + * LOAD_REG_ADDRBASE(rn, name) + * ADDROFF(name) + * LOAD_REG_ADDRBASE loads part of the address of label 'name' into + * register 'rn'. ADDROFF(name) returns the remainder of the address as + * a constant expression. ADDROFF(name) is a signed expression < 16 bits + * in size, so is suitable for use directly as an offset in load and store + * instructions. Use this when loading/storing a single word or less as: + * LOAD_REG_ADDRBASE(rX, name) + * ld rY,ADDROFF(name)(rX) + */ +#ifdef __powerpc64__ +#define LOAD_REG_IMMEDIATE(reg,expr) \ + lis (reg),(expr)@highest; \ + ori (reg),(reg),(expr)@higher; \ + rldicr (reg),(reg),32,31; \ + oris (reg),(reg),(expr)@h; \ + ori (reg),(reg),(expr)@l; + +#define LOAD_REG_ADDR(reg,name) \ + ld (reg),name@got(r2) + +#define LOAD_REG_ADDRBASE(reg,name) LOAD_REG_ADDR(reg,name) +#define ADDROFF(name) 0 + +/* offsets for stack frame layout */ +#define LRSAVE 16 + +#else /* 32-bit */ + +#define LOAD_REG_IMMEDIATE(reg,expr) \ + lis (reg),(expr)@ha; \ + addi (reg),(reg),(expr)@l; + +#define LOAD_REG_ADDR(reg,name) LOAD_REG_IMMEDIATE(reg, name) + +#define LOAD_REG_ADDRBASE(reg, name) lis (reg),name@ha +#define ADDROFF(name) name@l + +/* offsets for stack frame layout */ +#define LRSAVE 4 + +#endif + +/* various errata or part fixups */ +#ifdef CONFIG_PPC601_SYNC_FIX +#define SYNC \ +BEGIN_FTR_SECTION \ + sync; \ + isync; \ +END_FTR_SECTION_IFSET(CPU_FTR_601) +#define SYNC_601 \ +BEGIN_FTR_SECTION \ + sync; \ +END_FTR_SECTION_IFSET(CPU_FTR_601) +#define ISYNC_601 \ +BEGIN_FTR_SECTION \ + isync; \ +END_FTR_SECTION_IFSET(CPU_FTR_601) +#else +#define SYNC +#define SYNC_601 +#define ISYNC_601 +#endif + +#ifdef CONFIG_PPC_CELL +#define MFTB(dest) \ +90: mftb dest; \ +BEGIN_FTR_SECTION_NESTED(96); \ + cmpwi dest,0; \ + beq- 90b; \ +END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96) +#else +#define MFTB(dest) mftb dest +#endif + +#ifndef CONFIG_SMP +#define TLBSYNC +#else /* CONFIG_SMP */ +/* tlbsync is not implemented on 601 */ +#define TLBSYNC \ +BEGIN_FTR_SECTION \ + tlbsync; \ + sync; \ +END_FTR_SECTION_IFCLR(CPU_FTR_601) +#endif + + +/* + * This instruction is not implemented on the PPC 603 or 601; however, on + * the 403GCX and 405GP tlbia IS defined and tlbie is not. + * All of these instructions exist in the 8xx, they have magical powers, + * and they must be used. + */ + +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) +#define tlbia \ + li r4,1024; \ + mtctr r4; \ + lis r4,KERNELBASE@h; \ +0: tlbie r4; \ + addi r4,r4,0x1000; \ + bdnz 0b +#endif + + +#ifdef CONFIG_IBM440EP_ERR42 +#define PPC440EP_ERR42 isync +#else +#define PPC440EP_ERR42 +#endif + + +#if defined(CONFIG_BOOKE) +#define toreal(rd) +#define fromreal(rd) + +/* + * We use addis to ensure compatibility with the "classic" ppc versions of + * these macros, which use rs = 0 to get the tophys offset in rd, rather than + * converting the address in r0, and so this version has to do that too + * (i.e. set register rd to 0 when rs == 0). + */ +#define tophys(rd,rs) \ + addis rd,rs,0 + +#define tovirt(rd,rs) \ + addis rd,rs,0 + +#elif defined(CONFIG_PPC64) +#define toreal(rd) /* we can access c000... in real mode */ +#define fromreal(rd) + +#define tophys(rd,rs) \ + clrldi rd,rs,2 + +#define tovirt(rd,rs) \ + rotldi rd,rs,16; \ + ori rd,rd,((KERNELBASE>>48)&0xFFFF);\ + rotldi rd,rd,48 +#else +/* + * On APUS (Amiga PowerPC cpu upgrade board), we don't know the + * physical base address of RAM at compile time. + */ +#define toreal(rd) tophys(rd,rd) +#define fromreal(rd) tovirt(rd,rd) + +#define tophys(rd,rs) \ +0: addis rd,rs,-KERNELBASE@h; \ + .section ".vtop_fixup","aw"; \ + .align 1; \ + .long 0b; \ + .previous + +#define tovirt(rd,rs) \ +0: addis rd,rs,KERNELBASE@h; \ + .section ".ptov_fixup","aw"; \ + .align 1; \ + .long 0b; \ + .previous +#endif + +#ifdef CONFIG_PPC64 +#define RFI rfid +#define MTMSRD(r) mtmsrd r + +#else +#define FIX_SRR1(ra, rb) +#ifndef CONFIG_40x +#define RFI rfi +#else +#define RFI rfi; b . /* Prevent prefetch past rfi */ +#endif +#define MTMSRD(r) mtmsr r +#define CLR_TOP32(r) +#endif + +#endif /* __KERNEL__ */ + +/* The boring bits... */ + +/* Condition Register Bit Fields */ + +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 + + +/* General Purpose Registers (GPRs) */ + +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + + +/* Floating Point Registers (FPRs) */ + +#define fr0 0 +#define fr1 1 +#define fr2 2 +#define fr3 3 +#define fr4 4 +#define fr5 5 +#define fr6 6 +#define fr7 7 +#define fr8 8 +#define fr9 9 +#define fr10 10 +#define fr11 11 +#define fr12 12 +#define fr13 13 +#define fr14 14 +#define fr15 15 +#define fr16 16 +#define fr17 17 +#define fr18 18 +#define fr19 19 +#define fr20 20 +#define fr21 21 +#define fr22 22 +#define fr23 23 +#define fr24 24 +#define fr25 25 +#define fr26 26 +#define fr27 27 +#define fr28 28 +#define fr29 29 +#define fr30 30 +#define fr31 31 + +/* AltiVec Registers (VPRs) */ + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 + +/* VSX Registers (VSRs) */ + +#define vsr0 0 +#define vsr1 1 +#define vsr2 2 +#define vsr3 3 +#define vsr4 4 +#define vsr5 5 +#define vsr6 6 +#define vsr7 7 +#define vsr8 8 +#define vsr9 9 +#define vsr10 10 +#define vsr11 11 +#define vsr12 12 +#define vsr13 13 +#define vsr14 14 +#define vsr15 15 +#define vsr16 16 +#define vsr17 17 +#define vsr18 18 +#define vsr19 19 +#define vsr20 20 +#define vsr21 21 +#define vsr22 22 +#define vsr23 23 +#define vsr24 24 +#define vsr25 25 +#define vsr26 26 +#define vsr27 27 +#define vsr28 28 +#define vsr29 29 +#define vsr30 30 +#define vsr31 31 +#define vsr32 32 +#define vsr33 33 +#define vsr34 34 +#define vsr35 35 +#define vsr36 36 +#define vsr37 37 +#define vsr38 38 +#define vsr39 39 +#define vsr40 40 +#define vsr41 41 +#define vsr42 42 +#define vsr43 43 +#define vsr44 44 +#define vsr45 45 +#define vsr46 46 +#define vsr47 47 +#define vsr48 48 +#define vsr49 49 +#define vsr50 50 +#define vsr51 51 +#define vsr52 52 +#define vsr53 53 +#define vsr54 54 +#define vsr55 55 +#define vsr56 56 +#define vsr57 57 +#define vsr58 58 +#define vsr59 59 +#define vsr60 60 +#define vsr61 61 +#define vsr62 62 +#define vsr63 63 + +/* SPE Registers (EVPRs) */ + +#define evr0 0 +#define evr1 1 +#define evr2 2 +#define evr3 3 +#define evr4 4 +#define evr5 5 +#define evr6 6 +#define evr7 7 +#define evr8 8 +#define evr9 9 +#define evr10 10 +#define evr11 11 +#define evr12 12 +#define evr13 13 +#define evr14 14 +#define evr15 15 +#define evr16 16 +#define evr17 17 +#define evr18 18 +#define evr19 19 +#define evr20 20 +#define evr21 21 +#define evr22 22 +#define evr23 23 +#define evr24 24 +#define evr25 25 +#define evr26 26 +#define evr27 27 +#define evr28 28 +#define evr29 29 +#define evr30 30 +#define evr31 31 + +/* some stab codes */ +#define N_FUN 36 +#define N_RSYM 64 +#define N_SLINE 68 +#define N_SO 100 + + +#endif /* _ASM_POWERPC_PPC_ASM_H */ diff --git a/include/mach/c1700/platform.h b/include/mach/c1700/platform.h new file mode 100644 index 0000000..5efc53f --- /dev/null +++ b/include/mach/c1700/platform.h @@ -0,0 +1,16 @@ +#ifndef _INCLUDE_MACH_C1700_PLATFORM_H +#define _INCLUDE_MACH_C1700_PLATFORM_H + +#include + +#define FLASH_BASE 0x60000000 +#define MEMORY_BASE 0x80000000 + +void platform_init(); +uint32_t check_flash(); +void flash_directory(); +uint32_t locate_stage_two(); +void stage_two(uint32_t kern_off, uint32_t kern_entry, uint32_t kern_size, + uint32_t kern_loadpt); + +#endif /* _INCLUDE_MACH_C1700_PLATFORM_H */ diff --git a/include/mach/c1700/platio.h b/include/mach/c1700/platio.h new file mode 100644 index 0000000..a919f07 --- /dev/null +++ b/include/mach/c1700/platio.h @@ -0,0 +1,24 @@ +#ifndef _INCLUDE_MACH_C1700_PLATIO +#define _INCLUDE_MACH_C1700_PLATIO + +#include +#include + +/* a flash filesystem entry for the C1700 */ +struct fs_ent { + uint32_t magic; + uint32_t length; + /* todo: figure out exactly what these two fields contain */ + uint32_t crc32; + uint32_t date; + char filename[48]; +}; + +void platio_file_open(struct file *fp, const char *filename); +uint32_t platio_read(void *pbuf, uint32_t size, uint32_t nmemb, + struct file *fp); +uint8_t platio_find_file(const char *filename); + +#define FS_FILE_MAGIC 0xbad00b1e + +#endif /* _INCLUDE_MACH_C1700_PLATIO */ diff --git a/mach/c1700/Makefile b/mach/c1700/Makefile new file mode 100644 index 0000000..226cf8a --- /dev/null +++ b/mach/c1700/Makefile @@ -0,0 +1,18 @@ +ifndef CROSS_COMPILE +CROSS_COMPILE=powerpc-elf- +endif + +OBJECTS=start.o promlib.o platform.o platio.o + +INCLUDE=-I../../include + +all: ${OBJECTS} + +.c.o: + $(CC) ${CFLAGS} ${INCLUDE} -c $< + +.S.o: + $(CC) ${CFLAGS} ${INCLUDE} ${ASFLAGS} -c $< + +clean: + -rm -f *.o diff --git a/mach/c1700/platform.c b/mach/c1700/platform.c new file mode 100644 index 0000000..02fa2ec --- /dev/null +++ b/mach/c1700/platform.c @@ -0,0 +1,75 @@ +/* Platform-specific operations for the Cisco 1700 Series router + * (c) 2009 Philippe Vachon + * + * Licensed under the GNU General Public License v.2.0. See the COPYING + * file in the root directory of this source distribution for more info. + */ +#include +#include +#include +#include + +/** + * perform hardware-specifc initialization for this platform + */ +void platform_init() +{ +} + +/** + * Perform a sanity check on flash + * @returns 0 if no flash found, number of flash devices found otherwise + */ +uint32_t check_flash() +{ + uint32_t *ptr = (uint32_t *)FLASH_BASE; + + if (*ptr != FS_FILE_MAGIC) { + return 0; + } + + return 1; + /* TODO: add support for PCMCIA flash */ +} + +/** + * print a directory listing of the 'main' flash device in the system + */ + +void flash_directory() +{ + struct fs_ent *f = (struct fs_ent *)FLASH_BASE; + uint32_t offset = 0; + + /* Iterate over the files; f->magic is 0 if an invalid file is found. */ + while (f->magic == FS_FILE_MAGIC) { + printf("%s\n", f->filename); + offset += sizeof(struct fs_ent) + f->length; + f = (struct fs_ent *)(FLASH_BASE + offset); + } +} + +/** + * Locate the stage two loader for CiscoLoad for this particular platform + * returns 0 if not found, 1 if found + */ +uint32_t locate_stage_two() +{ + return platio_find_file("ciscoload.two"); +} + +/** + * Kick into the stage two loader. + */ +void stage_two(uint32_t kern_off, uint32_t kern_entry, uint32_t kern_size, + uint32_t kern_loadpt) +{ + uint32_t s2addr = ((uint32_t)find_file("ciscoload.two", FLASH_BASE)) + + sizeof(struct fs_ent); + + + ((void (*)(uint32_t data_offset, uint32_t data_length, uint32_t entry_pt, + uint32_t load_offset)) (s2addr)) + (kern_off, kern_size, kern_entry, kern_loadpt); + +} diff --git a/mach/c1700/platio.c b/mach/c1700/platio.c new file mode 100644 index 0000000..59f8382 --- /dev/null +++ b/mach/c1700/platio.c @@ -0,0 +1,98 @@ +/* Platform specific operations for I/O for the cisco 1700 Series + * (C) 2008 Philippe Vachon + * + * Licensed under the GNU General Public License v2. + */ +#include +#include +#include +#include + +#include + +/* find file in filesystem starting at base */ +struct fs_ent *find_file(const char *filename, uint32_t base) +{ + /* Actual file offset */ + uint32_t offset = 0; + + struct fs_ent *f = (struct fs_ent *)(base + offset); + + /* iterate over files in flash */ + while (f->magic == FS_FILE_MAGIC) { + if (!strncmp(f->filename, filename, 48)) { + return f; + } + + offset += sizeof(struct fs_ent) + f->length; + f = (struct fs_ent *)(base + offset); + } + + return NULL; +} + +/** + * Find a file within the platform-supported I/O devices + * @param filename the file + * @returns 0 on failure, device ID number on success + */ +uint8_t platio_find_file(const char *filename) +{ + if (find_file(filename, FLASH_BASE)) { + return 1; + } + /* todo: add support for PCMCIA devices */ + + return 0; +} + +/** + * Open a file. + * @param fp File structure to hold file information + * @param filename name of the file + */ +void platio_file_open(struct file *fp, const char *filename) +{ + struct fs_ent *ent = find_file(filename, FLASH_BASE); + + if (ent == NULL) { + fp->code = 0; + fp->private = NULL; + return; + } + + fp->dev = 1; /* TODO: add support for PCMCIA flash */ + + fp->private = (void *)ent; + + fp->file_len = ent->length; + fp->file_pos = 0; + + /* copy the filename */ + strncpy(fp->filename, ent->filename, 48); + + fp->code = 1; + +} + +/** + * Read data from a given file + * @param pbuf Buffer to read data into + * @param size size of entity to be read + * @param nmemb number of members to read + * @param fp file information structure to read from. + * @returns number of bytes read (should = size * nmemb for C3600) + */ +uint32_t platio_read(void *pbuf, uint32_t size, uint32_t nmemb, struct file *fp) +{ + /* calculate the effective offset of the data we want to read: */ + char *from = (char *)((uint32_t)(fp->private) + sizeof(struct fs_ent) + + fp->file_pos); + + memcpy(pbuf, from, size * nmemb); + + fp->file_pos += size * nmemb; + + return nmemb * size; + +} diff --git a/mach/c1700/promlib.c b/mach/c1700/promlib.c new file mode 100644 index 0000000..cd19b82 --- /dev/null +++ b/mach/c1700/promlib.c @@ -0,0 +1,160 @@ +/** + * low-level prom and I/O library for the Cisco 1700 series + * (C) 2008 Philippe Vachon + * ----------------------------------------------------------- + * Licensed under the GNU General Public License v2.0. See + * COPYING in the root directory of the source distribution for details. + */ + +#include +#include +#include + +#define UART_BASE 0x68050000 +#define UART_LSR 0x5 + + +/* putc + * output character c to console + * @param c ASCII number for character + */ +void c_putc(const char c) +{ + while (!(*((char *)(UART_BASE + UART_LSR)) & 0x20)); + ((char *)UART_BASE)[0] = c; +} + +/* puts - wrapper for putc + * output the string pointed to by s + * @param s String to be written to the console + */ +void c_puts(const char *s) +{ + while(*s != '\0') { + c_putc(*(s++)); + } +} + +/* putsn - put a string of length n on the console + * @param s string to be written + * @param n length + */ +void c_putsn(const char *s, int n) +{ + int i = 0; + while (*s != '\0' && i != n) { + c_putc(*(s++)); + i++; + } +} + + +/* getc - Syscall n + * get one character of input from the console + * @return ASCII code for character read from console + */ +char c_getc(void) +{ + char c; + while (!(*((uint8_t *)(UART_BASE + UART_LSR)) & 0x01)); + c = ((uint8_t *)UART_BASE)[0]; + return c; +} + +/* gets - wrapper for getc + * reads up to n characters into buffer b + * @param b Buffer to read characters into + * @param n size of buffer + * @return the number of characters read into b + */ +int c_gets(char *b, int n) +{ + int i = 0; + do { + b[i] = c_getc(); + c_putc(b[i]); + i++; + if (b[i - 1] == '\n' || b[i-1] == '\r') { + break; + } + else if (b[i - 1] == 0x8) { + i--; + } + } while (i < n); + + b[i - 1] = '\0'; + + return i; + +} + +/* c_version - get version string + * @return pointer to version string + */ +char *c_verstr(void) +{ + return "Cisco 1700 Series Router"; +} + +/* memsz - get total memory size (in bytes) + * @return the size of the memory installed in the router, in bytes + */ +int c_memsz(void) +{ + int m = 0; + + __asm__ ( + "li 3, 4\n" + "sc\n" + "mr %[memsz], 3\n" + : [memsz]"=r"(m) + : /* no inputs */ + : "r3","memory","cc" + ); + + + return m; +} + +/* timer - get number of ticks from timer + * @return the value in the timer + */ +long c_timer(void) +{ + return 0; +} + +/* String length with a maximum length allowed + * @param s pointer to string + * @param maxlen maximum length + */ +int c_strnlen(const char *s, int maxlen) +{ + int i = 0; + if (!s) return 0; + + while (*(s++) != '\0' && i != maxlen) { + i++; + } + + return i; +} + +/* baud - get console baud rate + * @return boot console baud rate + */ +int c_baud(void) +{ + int b = 115200; + + __asm__ ( + "li 3, 62\n" + "sc\n" + "mr %[baud], 3\n" + : [baud]"=r"(b) + : /* no returns */ + : "r3", "memory", "cc" + ); + + return b; +} diff --git a/mach/c1700/start.S b/mach/c1700/start.S new file mode 100644 index 0000000..ab99d94 --- /dev/null +++ b/mach/c1700/start.S @@ -0,0 +1,29 @@ +/* CILO entry point for the Cisco 1700 Series Routers + * (C) 2009 Philippe Vachon + * Licensed under the GNU General Public License v2.0 or later. See + * COPYING in the root of the source distribution for more details. + */ + +#include + + .text + .globl _start + +_start: + + /* put a letter C to show we are alive */ + lis r26, 0x6805 +putchar: + lbz r0, 5(r26) + andi. r0, r0, 0x20 + beq putchar + + /* put the C */ + li r3, 67 + stb r3, 0(r26) + + /* jump to the C code */ + bl start_bootloader + + .end _start + .size _start, .-_start