^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * arch/alpha/boot/bootp.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 1997 Jay Estabrook
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This file is used for creating a bootp file for the Linux/AXP kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * based significantly on the arch/alpha/boot/main.c of Linus Torvalds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <generated/utsrelease.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/hwrpb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <stdarg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "ksize.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) extern unsigned long switch_to_osf_pal(unsigned long nr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) unsigned long *vptb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) extern void move_stack(unsigned long new_stack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct hwrpb_struct *hwrpb = INIT_HWRPB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static struct pcb_struct pcb_va[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Find a physical address of a virtual object..
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * This is easy using the virtual page table address.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static inline void *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) find_pa(unsigned long *vptb, void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned long address = (unsigned long) ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned long result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) result = vptb[address >> 13];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) result >>= 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) result <<= 13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) result |= address & 0x1fff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return (void *) result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * This function moves into OSF/1 pal-code, and has a temporary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * PCB for that. The kernel proper should replace this PCB with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * the real one as soon as possible.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * The page table muckery in here depends on the fact that the boot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * code has the L1 page table identity-map itself in the second PTE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * in the L1 page table. Thus the L1-page is virtually addressable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * itself (through three levels) at virtual address 0x200802000.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define VPTB ((unsigned long *) 0x200000000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define L1 ((unsigned long *) 0x200802000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) pal_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) unsigned long i, rev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct percpu_struct * percpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct pcb_struct * pcb_pa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* Create the dummy PCB. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) pcb_va->ksp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) pcb_va->usp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) pcb_va->ptbr = L1[1] >> 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) pcb_va->asn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) pcb_va->pcc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) pcb_va->unique = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) pcb_va->flags = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) pcb_va->res1 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) pcb_va->res2 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) pcb_pa = find_pa(VPTB, pcb_va);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * a0 = 2 (OSF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * a1 = return address, but we give the asm the vaddr of the PCB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * a2 = physical addr of PCB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * a3 = new virtual page table pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * a4 = KSP (but the asm sets it)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) srm_printk("Switching to OSF PAL-code .. ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) srm_printk("failed, code %ld\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) __halt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) percpu = (struct percpu_struct *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) rev = percpu->pal_revision = percpu->palcode_avail[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) srm_printk("Ok (rev %lx)\n", rev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) tbia(); /* do it directly in case we are SMP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) load(unsigned long dst, unsigned long src, unsigned long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) memcpy((void *)dst, (void *)src, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * Start the kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) runkernel(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) __asm__ __volatile__(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) "bis %0,%0,$27\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) "jmp ($27)"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) : /* no outputs: it doesn't even return */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) : "r" (START_ADDR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) extern char _end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #define KERNEL_ORIGIN \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ((((unsigned long)&_end) + 511) & ~511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) start_kernel(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * Note that this crufty stuff with static and envval
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * and envbuf is because:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * 1. Frequently, the stack is short, and we don't want to overrun;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * 2. Frequently the stack is where we are going to copy the kernel to;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * 3. A certain SRM console required the GET_ENV output to stack.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * ??? A comment in the aboot sources indicates that the GET_ENV
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * destination must be quadword aligned. Might this explain the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * behaviour, rather than requiring output to the stack, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * seems rather far-fetched.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static long nbytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static char envval[256] __attribute__((aligned(8)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static unsigned long initrd_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) srm_printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (INIT_HWRPB->pagesize != 8192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) srm_printk("Expected 8kB pages, got %ldkB\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) INIT_HWRPB->pagesize >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (INIT_HWRPB->vptb != (unsigned long) VPTB) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) srm_printk("Expected vptb at %p, got %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) VPTB, (void *)INIT_HWRPB->vptb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) pal_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* The initrd must be page-aligned. See below for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) cause of the magic number 5. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) initrd_start = ((START_ADDR + 5*KERNEL_SIZE + PAGE_SIZE) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) (PAGE_SIZE-1)) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #ifdef INITRD_IMAGE_SIZE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) srm_printk("Initrd positioned at %#lx\n", initrd_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * Move the stack to a safe place to ensure it won't be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * overwritten by kernel image.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) move_stack(initrd_start - PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (nbytes < 0 || nbytes >= sizeof(envval)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) nbytes = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) envval[nbytes] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) srm_printk("Loading the kernel...'%s'\n", envval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /* NOTE: *no* callbacks or printouts from here on out!!! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* This is a hack, as some consoles seem to get virtual 20000000 (ie
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * where the SRM console puts the kernel bootp image) memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * overlapping physical memory where the kernel wants to be put,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * which causes real problems when attempting to copy the former to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * the latter... :-(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * So, we first move the kernel virtual-to-physical way above where
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * we physically want the kernel to end up, then copy it from there
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * to its final resting place... ;-}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * Sigh... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) #ifdef INITRD_IMAGE_SIZE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) load(initrd_start, KERNEL_ORIGIN+KERNEL_SIZE, INITRD_IMAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) memset((char*)ZERO_PGE, 0, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) strcpy((char*)ZERO_PGE, envval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) #ifdef INITRD_IMAGE_SIZE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) ((long *)(ZERO_PGE+256))[0] = initrd_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) ((long *)(ZERO_PGE+256))[1] = INITRD_IMAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) runkernel();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }