diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
commit | e7c2a72e2680827d6a733931273a93461c0d8d1b (patch) | |
tree | c9abeda78ef7504062bb2e816bcf3e3c9d680112 /arch/alpha/boot | |
parent | ec6044459060a8c9ce7f64405c465d141898548c (diff) |
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'arch/alpha/boot')
-rw-r--r-- | arch/alpha/boot/Makefile | 53 | ||||
-rw-r--r-- | arch/alpha/boot/head.S | 76 | ||||
-rw-r--r-- | arch/alpha/boot/main.c | 217 | ||||
-rw-r--r-- | arch/alpha/boot/tools/build.c | 173 |
4 files changed, 491 insertions, 28 deletions
diff --git a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile new file mode 100644 index 000000000..b05047c2a --- /dev/null +++ b/arch/alpha/boot/Makefile @@ -0,0 +1,53 @@ +# +# arch/alpha/boot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1994 by Linus Torvalds +# + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.S.s: + $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< +.S.o: + $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + +OBJECTS = head.o main.o + +all: tools/lxboot tools/bootlx vmlinux + @echo run mkfloppy on machine with floppy drive + +msb: tools/lxboot tools/bootlx vmlinux + ( cat tools/lxboot tools/bootlx vmlinux ) > /dev/rz0a + disklabel -rw rz0 'linux' tools/lxboot tools/bootlx + +vmlinux: tools/build $(TOPDIR)/vmlinux + tools/build -v $(TOPDIR)/vmlinux > vmlinux + +tools/lxboot: tools/build + tools/build > tools/lxboot + +tools/bootlx: bootloader tools/build + tools/build -vb bootloader > tools/bootlx + +tools/build: tools/build.c + $(HOSTCC) tools/build.c -o tools/build + +bootloader: $(OBJECTS) + $(LD) -non_shared -T 0x20000000 -N \ + $(OBJECTS) \ + $(LIBS) \ + -o bootloader || \ + (rm -f bootloader && exit 1) + +clean: + rm -f vmlinux bootloader tools/build tools/bootlx tools/lxboot + +dep: diff --git a/arch/alpha/boot/head.S b/arch/alpha/boot/head.S index 03a2a9010..efca165e6 100644 --- a/arch/alpha/boot/head.S +++ b/arch/alpha/boot/head.S @@ -1,44 +1,23 @@ /* - * alpha/head.S + * arch/alpha/boot/head.S * - * initial boot stuff.. + * initial bootloader stuff.. */ #include <asm/system.h> #define halt .long PAL_halt -/* - * NOTE! The console bootstrap will load us at 0x20000000, but this image - * is linked to run at START_ADDR, so the first thing we do is to move - * ourself up to the right address.. We'd better be position-independent - * at that stage :-) - */ .set noreorder .globl __start .ent __start __start: bis $31,$31,$31 - br $1,$200 - .long START_ADDR, START_ADDR >> 32 /* strange bug in the assembler.. duh */ - .long START_SIZE, START_SIZE >> 32 -$200: ldq $30,0($1) /* new stack - below this */ - lda $2,-8($1) /* __start */ - bis $30,$30,$3 /* new address */ - subq $3,$2,$6 /* difference */ - ldq $4,8($1) /* size */ -$201: subq $4,8,$4 - ldq $5,0($2) - addq $2,8,$2 - stq $5,0($3) - addq $3,8,$3 - bne $4,$201 - br $1,$202 -$202: addq $1,$6,$1 - addq $1,12,$1 /* $203 in the new address space */ - jmp $31,($1),$203 -$203: br $27,$100 -$100: ldgp $29,0($27) + br 1f + /* room for the initial PCB, which comes here */ + .quad 0,0,0,0,0,0,0,0 +1: br $27,2f +2: ldgp $29,0($27) lda $27,start_kernel jsr $26,($27),start_kernel halt @@ -109,3 +88,44 @@ switch_to_osf_pal: __do_swppal: .long PAL_swppal .end switch_to_osf_pal + +.globl dispatch +.ent dispatch +dispatch: + subq $30,80,$30 + stq $26,0($30) + stq $29,8($30) + + stq $8,16($30) + stq $9,24($30) + stq $10,32($30) + stq $11,40($30) + stq $12,48($30) + stq $13,56($30) + stq $14,64($30) + stq $15,72($30) + + lda $1,0x10000000 /* hwrpb */ + ldq $2,0xc0($1) /* crb offset */ + addq $2,$1,$2 /* crb */ + ldq $27,0($2) /* dispatch procedure value */ + + ldq $2,8($27) /* dispatch call address */ + jsr $26,($2) /* call it (weird VMS call seq) */ + + ldq $26,0($30) + ldq $29,8($30) + + ldq $8,16($30) + ldq $9,24($30) + ldq $10,32($30) + ldq $11,40($30) + ldq $12,48($30) + ldq $13,56($30) + ldq $14,64($30) + ldq $15,72($30) + + addq $30,80,$30 + ret $31,($26) +.end dispatch + diff --git a/arch/alpha/boot/main.c b/arch/alpha/boot/main.c new file mode 100644 index 000000000..d122eb6f6 --- /dev/null +++ b/arch/alpha/boot/main.c @@ -0,0 +1,217 @@ +/* + * arch/alpha/boot/main.c + * + * Copyright (C) 1994, 1995 Linus Torvalds + * + * This file is the bootloader for the Linux/AXP kernel + */ +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/version.h> +#include <linux/mm.h> + +#include <asm/system.h> +#include <asm/console.h> +#include <asm/hwrpb.h> + +#include <stdarg.h> + +extern int vsprintf(char *, const char *, va_list); +extern unsigned long switch_to_osf_pal(unsigned long nr, + struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, + unsigned long vptb, unsigned long *kstk); + +int printk(const char * fmt, ...) +{ + va_list args; + int i; + static char buf[1024]; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + puts(buf,i); + return i; +} + +#define hwrpb (*INIT_HWRPB) + +/* + * Find a physical address of a virtual object.. + * + * This is easy using the virtual page table address. + */ +struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb) +{ + unsigned long address = (unsigned long) pcb; + unsigned long result; + + result = vptb[address >> 13]; + result >>= 32; + result <<= 13; + result |= address & 0x1fff; + return (struct pcb_struct *) result; +} + +/* + * This function moves into OSF/1 pal-code, and has a temporary + * PCB for that. The kernel proper should replace this PCB with + * the real one as soon as possible. + * + * The page table muckery in here depends on the fact that the boot + * code has the L1 page table identity-map itself in the second PTE + * in the L1 page table. Thus the L1-page is virtually addressable + * itself (through three levels) at virtual address 0x200802000. + * + * As we don't want it there anyway, we also move the L1 self-map + * up as high as we can, so that the last entry in the L1 page table + * maps the page tables. + * + * As a result, the OSF/1 pal-code will instead use a virtual page table + * map located at 0xffffffe00000000. + */ +#define pcb_va ((struct pcb_struct *) 0x20000000) +#define old_vptb (0x0000000200000000UL) +#define new_vptb (0xfffffffe00000000UL) +void pal_init(void) +{ + unsigned long i, rev, sum; + unsigned long *L1, *l; + struct percpu_struct * percpu; + struct pcb_struct * pcb_pa; + + /* Find the level 1 page table and duplicate it in high memory */ + L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */ + L1[1023] = L1[1]; + + percpu = (struct percpu_struct *) (hwrpb.processor_offset + (unsigned long) &hwrpb), + + pcb_va->ksp = 0; + pcb_va->usp = 0; + pcb_va->ptbr = L1[1] >> 32; + pcb_va->asn = 0; + pcb_va->pcc = 0; + pcb_va->unique = 0; + pcb_va->flags = 1; + pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va); + printk("Switching to OSF PAL-code .. "); + /* + * a0 = 2 (OSF) + * a1 = return address, but we give the asm the virtual addr of the PCB + * a2 = physical addr of PCB + * a3 = new virtual page table pointer + * a4 = KSP (but we give it 0, asm sets it) + */ + i = switch_to_osf_pal( + 2, + pcb_va, + pcb_pa, + new_vptb, + 0); + if (i) { + printk("failed, code %ld\n", i); + halt(); + } + rev = percpu->pal_revision = percpu->palcode_avail[2]; + + hwrpb.vptb = new_vptb; + + /* update checksum: */ + sum = 0; + for (l = (unsigned long *) &hwrpb; l < (unsigned long *) &hwrpb.chksum; ++l) + sum += *l; + hwrpb.chksum = sum; + + printk("Ok (rev %lx)\n", rev); + /* remove the old virtual page-table mapping */ + L1[1] = 0; + invalidate_all(); +} + +extern int _end; + +static inline long openboot(void) +{ + char bootdev[256]; + long result; + + result = dispatch(CCB_GET_ENV, ENV_BOOTED_DEV, bootdev, 255); + if (result < 0) + return result; + return dispatch(CCB_OPEN, bootdev, result & 255); +} + +static inline long close(long dev) +{ + return dispatch(CCB_CLOSE, dev); +} + +static inline long load(long dev, unsigned long addr, unsigned long count) +{ + char bootfile[256]; + long result; + + result = dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255); + if (result < 0) + return result; + result &= 255; + bootfile[result] = '\0'; + if (result) + printk("Boot file specification (%s) not implemented\n", bootfile); + return dispatch(CCB_READ, dev, count, addr, BOOT_SIZE/512 + 1); +} + +/* + * Start the kernel. + */ +static void runkernel(void) +{ + __asm__ __volatile__( + "bis %1,%1,$30\n\t" + "bis %0,%0,$26\n\t" + "ret ($26)" + : /* no outputs: it doesn't even return */ + : "r" (START_ADDR), + "r" (PAGE_SIZE + INIT_STACK)); +} + +void start_kernel(void) +{ + long i; + long dev; + int nbytes; + char envval[256]; + + printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n"); + if (hwrpb.pagesize != 8192) { + printk("Expected 8kB pages, got %ldkB\n", hwrpb.pagesize >> 10); + return; + } + pal_init(); + dev = openboot(); + if (dev < 0) { + printk("Unable to open boot device: %016lx\n", dev); + return; + } + dev &= 0xffffffff; + printk("Loading vmlinux ..."); + i = load(dev, START_ADDR, START_SIZE); + close(dev); + if (i != START_SIZE) { + printk("Failed (%lx)\n", i); + return; + } + + nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, + envval, sizeof(envval)); + if (nbytes > 0) { + envval[nbytes] = '\0'; + strcpy((char*)ZERO_PGE, envval); + } + + printk(" Ok\nNow booting the kernel\n"); + runkernel(); + for (i = 0 ; i < 0x100000000 ; i++) + /* nothing */; + halt(); +} diff --git a/arch/alpha/boot/tools/build.c b/arch/alpha/boot/tools/build.c new file mode 100644 index 000000000..040655a54 --- /dev/null +++ b/arch/alpha/boot/tools/build.c @@ -0,0 +1,173 @@ +/* + * arch/alpha/boot/tools/build.c + * + * Build a bootable image from the vmlinux binary + */ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> + +#include <a.out.h> + +#include <asm/system.h> + +#define MAXSECT 10 +#define MAXBUF 8192 + +int verbose = 0; +int pad = 0; +char * program = "tools/build"; +char buffer[MAXBUF]; +unsigned long bootblock[64]; +struct filehdr fhdr; +struct aouthdr ahdr; +struct scnhdr shdr[MAXSECT]; + +char * usage = "'build [-b] system > secondary' or 'build > primary'"; + +static void die(char * str) +{ + fprintf(stderr,"%s: %s\n", program, str); + exit(1); +} + +static int comp(struct scnhdr * a, struct scnhdr * b) +{ + return a->s_vaddr - b->s_vaddr; +} + +int main(int argc, char ** argv) +{ + int fd, i; + unsigned long tmp, start; + unsigned long system_start, system_size; + char * infile = NULL; + + system_start = START_ADDR; + system_size = START_SIZE; + if (argc) { + program = *(argv++); + argc--; + } + while (argc > 0) { + if (**argv == '-') { + while (*++*argv) { + switch (**argv) { + case 'b': + system_start = BOOT_ADDR; + system_size = BOOT_SIZE; + pad = 1; + break; + case 'v': + verbose++; + break; + default: + die(usage); + } + } + } else if (infile) + die(usage); + else + infile = *argv; + argv++; + argc--; + } + if (!infile) { + memcpy(bootblock, "Linux Test", 10); + bootblock[60] = BOOT_SIZE / 512; /* count */ + bootblock[61] = 1; /* starting LBM */ + bootblock[62] = 0; /* flags */ + tmp = 0; + for (i = 0 ; i < 63 ; i++) + tmp += bootblock[i]; + bootblock[63] = tmp; + if (write(1, (char *) bootblock, 512) != 512) { + perror("bbwrite"); + exit(1); + } + return 0; + } + fd = open(infile, O_RDONLY); + if (fd < 0) { + perror(infile); + exit(1); + } + if (read(fd, &fhdr, sizeof(struct filehdr)) != sizeof(struct filehdr)) + die("unable to read file header"); + if (fhdr.f_nscns > MAXSECT) + die("Too many sections"); + if (fhdr.f_opthdr != AOUTHSZ) + die("optional header doesn't look like a.out"); + if (read(fd, &ahdr, sizeof(struct aouthdr)) != sizeof(struct aouthdr)) + die("unable to read a.out header"); + for (i = 0 ; i < fhdr.f_nscns ; i++) { + if (read(fd, i+shdr, sizeof(struct scnhdr)) != sizeof(struct scnhdr)) + die("unable to read section header"); + if (shdr[i].s_paddr != shdr[i].s_vaddr) + die("unable to handle different phys/virt addresses"); + if (shdr[i].s_relptr) + die("Unable to handle relocation info"); + if (verbose) { + fprintf(stderr, "section %d (%.8s):\t%lx - %lx (at %x)\n", + i, shdr[i].s_name, + shdr[i].s_vaddr, + shdr[i].s_vaddr + shdr[i].s_size, + shdr[i].s_scnptr); + } + } + qsort(shdr, fhdr.f_nscns, sizeof(shdr[1]), comp); + start = system_start; + for (i = 0 ; i < fhdr.f_nscns ; i++) { + unsigned long size, offset; + memset(buffer, 0, MAXBUF); + if (!strcmp(shdr[i].s_name, ".comment")) + continue; + if (shdr[i].s_vaddr != start) + die("Unordered or badly placed segments"); + size = shdr[i].s_size; + start += size; + offset = shdr[i].s_scnptr; + if (lseek(fd, offset, SEEK_SET) != offset) + die("Unable to seek in in-file"); + while (size > 0) { + unsigned long num = size; + if (num > MAXBUF) + num = MAXBUF; + if (offset) + if (read(fd, buffer, num) != num) + die("partial read"); + if (write(1, buffer, num) != num) + die("partial write"); + size -= num; + } + if (verbose) { + fprintf(stderr, "section %d (%.8s):\t%lx - %lx (at %x)\n", + i, shdr[i].s_name, + shdr[i].s_vaddr, + shdr[i].s_vaddr + shdr[i].s_size, + shdr[i].s_scnptr); + } + } + if (start > system_start + system_size) { + fprintf(stderr, "Boot image too large\n"); + exit(1); + } + if (pad) { + unsigned long count = (system_start + system_size) - start; + memset(buffer, 0, MAXBUF); + while (count > 0) { + int i = MAXBUF; + if (i > count) + i = count; + i = write(1, buffer, i); + if (i <= 0) { + perror("pad write"); + exit(1); + } + count -= i; + } + } + + return 0; +} |