diff --git a/src/arch/alpha/boot/Config b/src/arch/alpha/boot/Config new file mode 100644 index 0000000000..178df54605 --- /dev/null +++ b/src/arch/alpha/boot/Config @@ -0,0 +1 @@ +object boot.o diff --git a/src/arch/alpha/boot/boot.c b/src/arch/alpha/boot/boot.c new file mode 100644 index 0000000000..367fe6bc75 --- /dev/null +++ b/src/arch/alpha/boot/boot.c @@ -0,0 +1,197 @@ +#include +#include +#include + +/* FIXME remove the hardcodes + * MAX_ASM, CMD_LINE, SYSNAME, CYCLE_FREQ, CPU, SYS_VARIATION, SYS_TYPE + */ + +#ifndef CMD_LINE +#define CMD_LINE "" +#endif + +/* Magic values. + * Hard code these for the DS10 for now. + */ +#define HWRPB_SIGNATURE 0x4857525042000000 +#define HWRPB_SYS_TYPE ST_DEC_TSUNAMI +#define HWRPB_SYS_VARIATION (7 << 10) +#define HWRPB_CPU EV6_CPU +#define HWRPB_CYCLE_FREQ 462962962 +#define HWRPB_INTR_FREQ (4096*1024) +#define HWRPB_SYSNAME "linuxBIOS DS10" +#define HWRPB_COMMAND_LINE CMD_LINE +#define HWRPB_MAX_ASN 255 + +#define OFFSET(x, y) ((unsigned long)(((char *)&(x)) - ((char *)&(y)))) +#define ELEMENTS(x) (sizeof(x)/sizeof((x)[0])) +#define ADDR(x) ((unsigned long)&(x)) + +struct sysname_struct { + unsigned long length; + unsigned char name[30]; +}; + +static struct boot_data { + struct hwrpb_struct hwrpb; + struct dsr_struct dsr; + struct sysname_struct sysname; + struct percpu_struct cpu[1]; + struct memdesc_struct mem; + struct memclust_struct mem_cluster[2]; +} boot_data = +{ + .hwrpb = { + .phys_addr = ADDR(boot_data.hwrpb), + .id = HWRPB_SIGNATURE, + .revision = 6, + .size = sizeof(boot_data.hwrpb), + .cpuid = 0, + .pagesize = 8192, + .pa_bits = 13, + .max_asn = HWRPB_MAX_ASN, + .ssn = "MILO-LinuxBIOS", + .sys_type = HWRPB_SYS_TYPE, + .sys_variation = HWRPB_SYS_VARIATION, + .sys_revision = 0, + .intr_freq = HWRPB_INTR_FREQ, + .cycle_freq = HWRPB_CYCLE_FREQ, + .vptb = 0, + .res1 = 0, + .tbhb_offset = 0, + .nr_processors = ELEMENTS(boot_data.cpu), + .processor_size = sizeof(boot_data.cpu[0]), + .processor_offset = OFFSET(boot_data.cpu, boot_data.hwrpb), + .ctb_nr = 0, + .ctb_size = 0, + .ctbt_offset = 0, + .mddt_offset = OFFSET(boot_data.mem, boot_data.hwrpb), + .cdb_offset = 0, + .frut_offset = 0, + .save_terminal = 0, + .save_terminal_data = 0, + .restore_terminal = 0, + .restore_terminal_data = 0, + .CPU_restart = 0, + .CPU_restart_data = 0, + .res2 = 0, + .res3 = 0, + .chksum = 0, + .rxrdy = 0, + .txrdy = 0, + .dsr_offset = OFFSET(boot_data.dsr, boot_data.hwrpb), + }, + .dsr = { + .smm = 0, + .lurt_off = 0, + .sysname_off = OFFSET(boot_data.sysname, boot_data.dsr), + }, + .sysname = { + .length = sizeof(HWRPB_SYSNAME) -1, + .name = HWRPB_SYSNAME, + }, + + .cpu = { + { + .serial_no = { + 0x73695f78756e694c, + 0x002174616572475f, + }, + .type = HWRPB_CPU, + } + }, + .mem = { + .chksum = 0, + .optional_pa = ADDR(boot_data.mem), + .numclusters = ELEMENTS(boot_data.mem_cluster), + }, + .mem_cluster = { + { + .start_pfn = 0, + .numpages = 128, + .numtested = 0, + .bitmap_va = 0, + .bitmap_pa = 0, + .bitmap_chksum = 0, + .usage = 1, /* console/PALcode reserved */ + }, + { + .start_pfn = 128, + .numpages = 0, + .numtested = 0, + .bitmap_va = 0, + .bitmap_pa = 0, + .bitmap_chksum = 0, + .usage = 0, + }, + }, +}; + + +static struct { + struct uniform_boot_header header; + struct { + struct ube_hwrpb hwrpb; + } env; + unsigned char command_line[1024]; +} ube_all = { + .header = { + .header_bytes = sizeof(ube_all.header), + .header_checksum = 0, + .arg = (unsigned long)&ube_all.command_line, + .arg_bytes = sizeof(ube_all.command_line), + .env = (unsigned long)&ube_all.env, + .env_bytes = sizeof(ube_all.env), + }, + .env = { + .hwrpb = { + .tag = UBE_TAG_HWRPB, + .size = sizeof(ube_all.env.hwrpb), + .hwrpb = (unsigned long)&boot_data.hwrpb, + }, + }, + .command_line = HWRPB_COMMAND_LINE, +}; + +static unsigned long hwrpb_compute_checksum(struct hwrpb_struct *hwrpb) +{ + unsigned long sum = 0, *l; + for (l = (unsigned long *)hwrpb; l <= (unsigned long *) &hwrpb->chksum; ++l) + sum += *l; + return sum; + +} + + +void *get_ube_pointer(unsigned long totalram) +{ + /* Set the amount of RAM I have */ + boot_data.mem_cluster[1].numpages = (totalram >> 3) - + boot_data.mem_cluster[1].start_pfn; + boot_data.hwrpb.chksum = 0; + boot_data.hwrpb.chksum = hwrpb_compute_checksum(&boot_data.hwrpb); + ube_all.header.header_checksum = 0; + ube_all.header.header_checksum = + uniform_boot_compute_header_checksum(&ube_all.header); + return &ube_all; +} + + +int elf_check_arch(Elf_ehdr *ehdr) +{ + return ( + (ehdr->e_machine == EM_ALPHA) && + (ehdr->e_ident[EI_CLASS] == ELFCLASS64) && + (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + ); +} + +void jmp_to_elf_entry(void *entry, void *ptr) +{ + void (*kernel_entry)(void *ptr); + kernel_entry = entry; + + /* Jump to kernel */ + kernel_entry(ptr); +} + diff --git a/src/arch/alpha/lib/Config b/src/arch/alpha/lib/Config new file mode 100644 index 0000000000..02e6d884cd --- /dev/null +++ b/src/arch/alpha/lib/Config @@ -0,0 +1,9 @@ +object hardwaremain.o + +makedefine OBJECTS+= __divqu.o __remqu.o __divlu.o __remlu.o + +makerule __divqu.o: $(TOP)/src/arch/alpha/lib/divide.S; $(CC) $(CFLAGS) -DDIV -c -o __divqu.o $< +makerule __remqu.o: $(TOP)/src/arch/alpha/lib/divide.S; $(CC) $(CFLAGS) -DREM -c -o __remqu.o $< +makerule __divlu.o: $(TOP)/src/arch/alpha/lib/divide.S; $(CC) $(CFLAGS) -DDIV -DINTSIZE -c -o __divlu.o $< +makerule __remlu.o: $(TOP)/src/arch/alpha/lib/divide.S; $(CC) $(CFLAGS) -DREM -DINTSIZE -c -o __remlu.o $< + diff --git a/src/arch/alpha/lib/divide.S b/src/arch/alpha/lib/divide.S new file mode 100644 index 0000000000..a4bc1f751e --- /dev/null +++ b/src/arch/alpha/lib/divide.S @@ -0,0 +1,195 @@ +/* + * cpu/ev6/divide.S + * + * (C) 1995 Linus Torvalds + * + * Alpha division.. + */ + +/* + * The alpha chip doesn't provide hardware division, so we have to do it + * by hand. The compiler expects the functions + * + * __divqu: 64-bit unsigned long divide + * __remqu: 64-bit unsigned long remainder + * __divqs/__remqs: signed 64-bit + * __divlu/__remlu: unsigned 32-bit + * __divls/__remls: signed 32-bit + * + * These are not normal C functions: instead of the normal + * calling sequence, these expect their arguments in registers + * $24 and $25, and return the result in $27. Register $28 may + * be clobbered (assembly temporary), anything else must be saved. + * + * In short: painful. + * + * This is a rather simple bit-at-a-time algorithm: it's very good + * at dividing random 64-bit numbers, but the more usual case where + * the divisor is small is handled better by the DEC algorithm + * using lookup tables. This uses much less memory, though, and is + * nicer on the cache.. Besides, I don't know the copyright status + * of the DEC code. + */ + +/* + * My temporaries: + * $0 - current bit + * $1 - shifted divisor + * $2 - modulus/quotient + * + * $23 - return address + * $24 - dividend + * $25 - divisor + * + * $27 - quotient/modulus + * $28 - compare status + */ + +#define halt .long 0 + +/* + * Select function type and registers + */ +#define mask $0 +#define divisor $1 +#define compare $28 +#define tmp1 $3 +#define tmp2 $4 + +#ifdef DIV +#define DIV_ONLY(x,y...) x,##y +#define MOD_ONLY(x,y...) +#define func(x) __div##x +#define modulus $2 +#define quotient $27 +#define GETSIGN(x) xor $24,$25,x +#define STACK 48 +#else +#define DIV_ONLY(x,y...) +#define MOD_ONLY(x,y...) x,##y +#define func(x) __rem##x +#define modulus $27 +#define quotient $2 +#define GETSIGN(x) bis $24,$24,x +#define STACK 32 +#endif + +/* + * For 32-bit operations, we need to extend to 64-bit + */ +#ifdef INTSIZE +#define ufunction func(lu) +#define sfunction func(l) +#define LONGIFY(x) zapnot x,15,x +#define SLONGIFY(x) addl x,0,x +#else +#define ufunction func(qu) +#define sfunction func(q) +#define LONGIFY(x) +#define SLONGIFY(x) +#endif + +.set noat +.align 3 +.globl ufunction +.ent ufunction +ufunction: + subq $30,STACK,$30 + .frame $30,STACK,$23 + .prologue 0 + +7: stq $1, 0($30) + bis $25,$25,divisor + stq $2, 8($30) + bis $24,$24,modulus + stq $0,16($30) + bis $31,$31,quotient + LONGIFY(divisor) + stq tmp1,24($30) + LONGIFY(modulus) + bis $31,1,mask + DIV_ONLY(stq tmp2,32($30)) + beq divisor, 9f /* div by zero */ + +#ifdef INTSIZE + /* + * shift divisor left, using 3-bit shifts for + * 32-bit divides as we can't overflow. Three-bit + * shifts will result in looping three times less + * here, but can result in two loops more later. + * Thus using a large shift isn't worth it (and + * s8add pairs better than a sll..) + */ +1: cmpult divisor,modulus,compare + s8addq divisor,$31,divisor + s8addq mask,$31,mask + bne compare,1b +#else +1: cmpult divisor,modulus,compare + blt divisor, 2f + addq divisor,divisor,divisor + addq mask,mask,mask + bne compare,1b + unop +#endif + + /* ok, start to go right again.. */ +2: DIV_ONLY(addq quotient,mask,tmp2) + srl mask,1,mask + cmpule divisor,modulus,compare + subq modulus,divisor,tmp1 + DIV_ONLY(cmovne compare,tmp2,quotient) + srl divisor,1,divisor + cmovne compare,tmp1,modulus + bne mask,2b + +9: ldq $1, 0($30) + ldq $2, 8($30) + ldq $0,16($30) + ldq tmp1,24($30) + DIV_ONLY(ldq tmp2,32($30)) + addq $30,STACK,$30 + ret $31,($23),1 + .end ufunction + +/* + * Uhh.. Ugly signed division. I'd rather not have it at all, but + * it's needed in some circumstances. There are different ways to + * handle this, really. This does: + * -a / b = a / -b = -(a / b) + * -a % b = -(a % b) + * a % -b = a % b + * which is probably not the best solution, but at least should + * have the property that (x/y)*y + (x%y) = x. + */ +.align 3 +.globl sfunction +.ent sfunction +sfunction: + subq $30,STACK,$30 + .frame $30,STACK,$23 + .prologue 0 + bis $24,$25,$28 + SLONGIFY($28) + bge $28,7b + stq $24,0($30) + subq $31,$24,$28 + stq $25,8($30) + cmovlt $24,$28,$24 /* abs($24) */ + stq $23,16($30) + subq $31,$25,$28 + stq tmp1,24($30) + cmovlt $25,$28,$25 /* abs($25) */ + unop + bsr $23,ufunction + ldq $24,0($30) + ldq $25,8($30) + GETSIGN($28) + subq $31,$27,tmp1 + SLONGIFY($28) + ldq $23,16($30) + cmovlt $28,tmp1,$27 + ldq tmp1,24($30) + addq $30,STACK,$30 + ret $31,($23),1 + .end sfunction diff --git a/src/arch/alpha/lib/hardwaremain.c b/src/arch/alpha/lib/hardwaremain.c new file mode 100644 index 0000000000..aaf634911f --- /dev/null +++ b/src/arch/alpha/lib/hardwaremain.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +void hardwaremain(unsigned long signature, unsigned long memsize, + unsigned long cpu_speed) +{ + early_mainboard_init(); + displayinit(); + + printk("\n\nsignature=0x%016lx memsize=0x%016lx cpu_speed=0x%016lx\n", + signature, memsize, cpu_speed); + elfboot(memsize >> 10 /* In kilobytes */); + printk("\n after elfboot\n"); +} + +void fatal_error(unsigned long exception_handler, unsigned long exception_at, + unsigned long return_address) +{ + /* Just in case we are totally messed up */ + early_mainboard_init(); + displayinit(); + printk("\n\nFault: 0x%0lx\n", exception_handler); + printk("PC: 0x%0lx\n", exception_at); + printk("RA: 0x%0lx\n", return_address); + /* Now spin forever */ + while(1) {;} +}