Mercurial > sarpn
view ipl/loader.c @ 3:ec991c3809db
make the ipl code generic
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sat, 26 Feb 2011 12:28:22 -0500 |
parents | 5d9f272f4db6 |
children |
line wrap: on
line source
#ifndef BLOCK_SIZE #error missing BLOCK_SIZE #endif #define TEMP_BASE ((unsigned char*) 0x400000) /* 4MB */ typedef unsigned long u64; typedef signed long s64; typedef unsigned int u32; typedef signed int s32; typedef unsigned short u16; typedef signed short s16; typedef unsigned char u8; typedef signed char s8; #define EI_MAG0 0 #define EI_MAG1 1 #define EI_MAG2 2 #define EI_MAG3 3 #define EI_CLASS 4 #define EI_DATA 5 #define EI_VERSION 6 #define EI_OSABI 7 #define EI_ABIVERSION 8 #define EI_PAD 9 #define EI_NIDENT 16 #define ELFCLASS32 1 #define ELFCLASS64 2 #define ELFDATA2LSB 1 #define ELFDATA2MSB 2 #define EV_CURRENT 1 #define ET_NONE 0 #define ET_REL 1 #define ET_EXEC 2 #define ET_DYN 3 #define ET_CORE 4 #define ET_LOOS 0xfe00 #define ET_HIOS 0xfeff #define ET_LOPROC 0xff00 #define ET_HIPROC 0xffff #define SHT_NULL 0 #define SHT_PROGBITS 1 #define SHT_SYMTAB 2 #define SHT_STRTAB 3 #define SHT_RELA 4 #define SHT_HASH 5 #define SHT_DYNAMIC 6 #define SHT_NOTE 7 #define SHT_NOBITS 8 #define SHT_REL 9 #define SHT_SHLIB 10 #define SHT_DYNSYM 11 #define SHT_LOOS 0x60000000 #define SHT_HIOS 0x6fffffff #define SHT_LOPROC 0x70000000 #define SHT_HIPROC 0x7fffffff typedef u64 Elf64_Addr; typedef u64 Elf64_Off; typedef u16 Elf64_Half; typedef u32 Elf64_Word; typedef s32 Elf64_Sword; typedef u64 Elf64_Xword; typedef s64 Elf64_Sxword; /* * ELF file header */ typedef struct { unsigned char e_ident[EI_NIDENT]; /* ELF identification */ Elf64_Half e_type; /* Object file type */ Elf64_Half e_machine; /* Machine type */ Elf64_Word e_version; /* Object file version */ Elf64_Addr e_entry; /* Entry point address */ Elf64_Off e_phoff; /* Program header offset */ Elf64_Off e_shoff; /* Section header offset */ Elf64_Word e_flags; /* Processor-specific flags */ Elf64_Half e_ehsize; /* ELF header size */ Elf64_Half e_phentsize; /* Size of program header entry */ Elf64_Half e_phnum; /* Number of program header entries */ Elf64_Half e_shentsize; /* Size of section header entries */ Elf64_Half e_shnum; /* Number of section header entries */ Elf64_Half e_shstrndx; /* Section name string table index */ } Elf64_Ehdr; /* * ELF section header */ typedef struct { Elf64_Word sh_name; /* Section name */ Elf64_Word sh_type; /* Section type */ Elf64_Xword sh_flags; /* Section attributes */ Elf64_Addr sh_addr; /* Virtual address in memory */ Elf64_Off sh_offset; /* Offset in file */ Elf64_Xword sh_size; /* Size of section */ Elf64_Word sh_link; /* Link to other section */ Elf64_Word sh_info; /* Misc information */ Elf64_Xword sh_addralign; /* Address alignment boundary */ Elf64_Xword sh_entsize; /* Size of entries, if section has table */ } Elf64_Shdr; static unsigned char read_ccw[8] __attribute__ ((aligned (8))) = { /* * CCW2; read the entire system ELF */ 0x02, /* bits value name desc */ /* 0-7 2 Cmd Code read, no modifiers*/ 0xff, 0xff, 0xff, /* bits value name desc */ /* 8-31 addr Data Address dest of the read */ 0x20, /* bits value name desc */ /* 32 0 Chain-Data (CD) don't chain */ /* 33 0 Chain-Command (CC) don't chain */ /* 34 1 Sup.-Len.-Inditcation (SLI) suppress */ /* 35 0 Skip (SKP) issue read */ /* 36 0 Prog.-Contr.-Inter. (PCI) don't interrupt */ /* 37 0 Indir.-Data-Addr. (IDA) real addr */ /* 38 0 Suspend (S) don't suspend */ /* 39 0 Modified I.D.A. (MIDA) real addr */ 0x00, /* bits value name desc */ /* 40-47 0 <ignored> */ 0xff, 0xff, /* bits value name desc */ /* 48-63 len number of bytes to read */ }; unsigned char ORB[32] __attribute__ ((aligned (16))) = { /* Word 0 */ 0x12,0x34,0x56,0x78, /* bits value name desc */ /* 0-31 magic Interrupt Parameter */ /* Word 1 */ 0x00, /* bits value name desc */ /* 0-3 0 Subchannel Key */ /* 4 0 Suspend Control */ /* 5 0 Streaming-Mode Control */ /* 6 0 Modification Control */ /* 7 0 Synchronization Control */ 0x00, /* bits value name desc */ /* 8 0 Format Control format-0 CCWs */ /* 9 0 Prefetch Control */ /* 10 0 Initial-Status-Interruption Control */ /* 11 0 Address-Limit-Checking Control */ /* 12 0 Suppress-Suspended-Interruption Control */ /* 13 0 <zero> */ /* 14 0 Format-2-IDAW Control */ /* 15 0 2K-IDAW Control */ 0xff, /* bits value name desc */ /* 16-23 0xff Logical-Path Mask All paths */ 0x00, /* bits value name desc */ /* 24 0 Incorrect-Length-Suppression Mode */ /* 25 0 Modified-CCW-Indirect-Data-Addressing Control*/ /* 26-30 0 <zero> */ /* 31 0 ORB-Extension Control */ /* Word 2 */ 0xff,0xff,0xff,0xff, /* bits value name desc */ /* 0-31 addr Channel-Program Address */ /* Word 3 */ 0x00, /* bits value name desc */ /* 0-7 0 Channel-Subsystem Priority */ 0x00, /* bits value name desc */ /* 8-15 0 <zero/reserved> */ 0x00, /* bits value name desc */ /* 15-23 0 Control-Unit Priority */ 0x00, /* bits value name desc */ /* 24-31 0 <zero/reserved> */ /* Word 4 */ 0x00,0x00,0x00,0x00, /* bits value name desc */ /* 0-31 0 <zero/reserved> */ /* Word 5 */ 0x00,0x00,0x00,0x00, /* bits value name desc */ /* 0-31 0 <zero/reserved> */ /* Word 6 */ 0x00,0x00,0x00,0x00, /* bits value name desc */ /* 0-31 0 <zero/reserved> */ /* Word 7 */ 0x00,0x00,0x00,0x00, /* bits value name desc */ /* 0-31 0 <zero/reserved> */ }; #define memcpy(d,s,l) __builtin_memcpy((d), (s), (l)) #define memset(s,c,n) __builtin_memset((s),(c),(n)) /* * halt the cpu * * NOTE: we don't care about not clobbering registers as when this * code executes, the CPU will be stopped. */ static inline void die() { asm volatile( "SR %r1, %r1 # not used, but should be zero\n" "SR %r3, %r3 # CPU Address\n" "SIGP %r1, %r3, 0x05 # Signal, order 0x05\n" ); /* * Just in case SIGP fails */ for(;;); } /* * It is easier to write this thing in assembly... */ extern int __do_io(); extern void PGMHANDLER(); static u64 pgm_new_psw[2] = { 0x0000000180000000ULL, (u64) &PGMHANDLER, }; static u64 pgm_new_psw_real[2] = { 0x0002000180000000ULL, 0xfa11, }; /* * determine amount of storage */ static u64 sense_memsize() { u64 size; int cc; #define SKIP_SIZE (1024*1024ULL) /* set new PGM psw */ memcpy((void*)0x1d0, pgm_new_psw, 16); for(size = 0; size < ((u64)~SKIP_SIZE)-1; size += SKIP_SIZE) { asm volatile( "lg %%r1,%1\n" "tprot 0(%%r1),0\n" "ipm %0\n" "srl %0,28\n" : /* output */ "=d" (cc) : /* input */ "m" (size) : /* clobber */ "cc", "r1" ); /* * we cheat here a little...if we try to tprot a location * that isn't part of the configuration, a program exception * fires off, but our handler sets the CC to 3, and resumes * execution */ if (cc == 3) break; } /* invalidate new PGM psw */ memcpy((void*)0x1d0, pgm_new_psw_real, 16); return size; } /* * read the entire system into into TEMP_BASE */ static inline void readsystem() { register unsigned long base; /* * Read in BLOCK_SIZE chunks of system */ /* set the CCW address in the ORB */ *((u32 *) &ORB[8]) = (u32) (u64) read_ccw; read_ccw[6] = ((unsigned char) (BLOCK_SIZE >> 8) & 0xff); read_ccw[7] = ((unsigned char) (BLOCK_SIZE & 0xff)); base = (unsigned long) TEMP_BASE; for(;; base += BLOCK_SIZE) { read_ccw[1] = ((unsigned char) (base >> 16)); read_ccw[2] = ((unsigned char) (base >> 8) & 0xff); read_ccw[3] = ((unsigned char) (base & 0xff)); if (__do_io()) break; } } static inline void enable_bfp() { u64 cr0; asm volatile( "stctg 0,0,%0\n" "oi %1,0x04\n" "lctlg 0,0,%0\n" : /* output */ : /* input */ "m" (cr0), "m" (*(u64*) (((u8*)&cr0) + 5)) ); } void load_system(void) { /* * These are all stored in registers */ register int i; register Elf64_Ehdr *system_elf; register Elf64_Shdr *section; register void (*start_sym)(u64); /* * Read entire ELF to temporary location */ readsystem(); system_elf = (Elf64_Ehdr*) TEMP_BASE; /* * Check that this looks like a valid ELF */ if (system_elf->e_ident[0] != '\x7f' || system_elf->e_ident[1] != 'E' || system_elf->e_ident[2] != 'L' || system_elf->e_ident[3] != 'F' || system_elf->e_ident[EI_CLASS] != ELFCLASS64 || system_elf->e_ident[EI_DATA] != ELFDATA2MSB || system_elf->e_ident[EI_VERSION] != EV_CURRENT || system_elf->e_type != ET_EXEC || system_elf->e_machine != 0x16 || // FIXME: find the name for the #define system_elf->e_version != EV_CURRENT) die(); /* * Iterate through each section, and copy it to the final * destination as necessary */ for (i=0; i<system_elf->e_shnum; i++) { section = (Elf64_Shdr*) (TEMP_BASE + system_elf->e_shoff + system_elf->e_shentsize * i); switch (section->sh_type) { case SHT_PROGBITS: if (!section->sh_addr) break; /* * just copy the data from TEMP_BASE to * where it wants to be */ memcpy((void*) section->sh_addr, TEMP_BASE + section->sh_offset, section->sh_size); break; case SHT_NOBITS: /* * No action needed as there's no data to * copy, and we assume that the ELF sections * don't overlap */ memset((void*) section->sh_addr, 0, section->sh_size); break; default: /* Ignoring */ break; } } enable_bfp(); /* * Now, jump to the system entry point */ start_sym = (void*) system_elf->e_entry; start_sym(sense_memsize()); }