patch-2.1.79 linux/arch/alpha/boot/bootp.c
Next file: linux/arch/alpha/config.in
Previous file: linux/arch/alpha/boot/Makefile
Back to the patch index
Back to the overall index
- Lines: 223
- Date:
Mon Jan 12 14:51:14 1998
- Orig file:
v2.1.78/linux/arch/alpha/boot/bootp.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.78/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c
@@ -0,0 +1,222 @@
+/*
+ * arch/alpha/boot/bootp.c
+ *
+ * Copyright (C) 1997 Jay Estabrook
+ *
+ * This file is used for creating a bootp file for the Linux/AXP kernel
+ *
+ * based significantly on the arch/alpha/boot/main.c of Linus Torvalds
+ */
+#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 <asm/pgtable.h>
+
+#include <stdarg.h>
+
+#include "ksize.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, j, written, remaining, num_nl;
+ static char buf[1024];
+ char * str;
+
+ va_start(args, fmt);
+ i = vsprintf(buf, fmt, args);
+ va_end(args);
+
+ /* expand \n into \r\n: */
+
+ num_nl = 0;
+ for (j = 0; j < i; ++j) {
+ if (buf[j] == '\n')
+ ++num_nl;
+ }
+ remaining = i + num_nl;
+ for (j = i - 1; j >= 0; --j) {
+ buf[j + num_nl] = buf[j];
+ if (buf[j] == '\n') {
+ --num_nl;
+ buf[j + num_nl] = '\r';
+ }
+ }
+
+ str = buf;
+ do {
+ written = puts(str, remaining);
+ remaining -= written;
+ str += written;
+ } while (remaining > 0);
+ 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 vaddr 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;
+ flush_tlb_all();
+}
+
+static inline long load(unsigned long dst,
+ unsigned long src,
+ unsigned long count)
+{
+ extern void * memcpy(void *, const void *, size_t);
+
+ memcpy((void *)dst, (void *)src, count);
+ return count;
+}
+
+/*
+ * Start the kernel.
+ */
+static void runkernel(void)
+{
+ __asm__ __volatile__(
+ "bis %1,%1,$30\n\t"
+ "bis %0,%0,$27\n\t"
+ "jmp ($27)"
+ : /* no outputs: it doesn't even return */
+ : "r" (START_ADDR),
+ "r" (PAGE_SIZE + INIT_STACK));
+}
+
+extern char _end;
+#define KERNEL_ORIGIN \
+ ((((unsigned long)&_end) + 511) & ~511)
+
+void start_kernel(void)
+{
+ long i;
+ int nbytes;
+ char envval[256];
+
+ printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n");
+ if (hwrpb.pagesize != 8192) {
+ printk("Expected 8kB pages, got %ldkB\n", hwrpb.pagesize >> 10);
+ return;
+ }
+ pal_init();
+
+ nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS,
+ envval, sizeof(envval));
+ if (nbytes < 0) {
+ nbytes = 0;
+ }
+ envval[nbytes] = '\0';
+ strcpy((char*)ZERO_PAGE, envval);
+
+ printk("Loading the kernel ...\n");
+
+ /* NOTE: *no* callbacks or printouts from here on out!!! */
+
+ i = load(START_ADDR, KERNEL_ORIGIN, KERNEL_SIZE);
+
+ runkernel();
+
+ for (i = 0 ; i < 0x100000000 ; i++)
+ /* nothing */;
+ halt();
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov