cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bootp.c (5702B)


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