summaryrefslogtreecommitdiffstats
path: root/arch/alpha/boot
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /arch/alpha/boot
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'arch/alpha/boot')
-rw-r--r--arch/alpha/boot/Makefile53
-rw-r--r--arch/alpha/boot/head.S76
-rw-r--r--arch/alpha/boot/main.c217
-rw-r--r--arch/alpha/boot/tools/build.c173
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;
+}