18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/alpha/boot/main.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1994, 1995 Linus Torvalds 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file is the bootloader for the Linux/AXP kernel 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/string.h> 128c2ecf20Sopenharmony_ci#include <generated/utsrelease.h> 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/console.h> 168c2ecf20Sopenharmony_ci#include <asm/hwrpb.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <stdarg.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "ksize.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ciextern unsigned long switch_to_osf_pal(unsigned long nr, 238c2ecf20Sopenharmony_ci struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, 248c2ecf20Sopenharmony_ci unsigned long *vptb); 258c2ecf20Sopenharmony_cistruct hwrpb_struct *hwrpb = INIT_HWRPB; 268c2ecf20Sopenharmony_cistatic struct pcb_struct pcb_va[1]; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Find a physical address of a virtual object.. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * This is easy using the virtual page table address. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic inline void * 358c2ecf20Sopenharmony_cifind_pa(unsigned long *vptb, void *ptr) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci unsigned long address = (unsigned long) ptr; 388c2ecf20Sopenharmony_ci unsigned long result; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci result = vptb[address >> 13]; 418c2ecf20Sopenharmony_ci result >>= 32; 428c2ecf20Sopenharmony_ci result <<= 13; 438c2ecf20Sopenharmony_ci result |= address & 0x1fff; 448c2ecf20Sopenharmony_ci return (void *) result; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * This function moves into OSF/1 pal-code, and has a temporary 498c2ecf20Sopenharmony_ci * PCB for that. The kernel proper should replace this PCB with 508c2ecf20Sopenharmony_ci * the real one as soon as possible. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * The page table muckery in here depends on the fact that the boot 538c2ecf20Sopenharmony_ci * code has the L1 page table identity-map itself in the second PTE 548c2ecf20Sopenharmony_ci * in the L1 page table. Thus the L1-page is virtually addressable 558c2ecf20Sopenharmony_ci * itself (through three levels) at virtual address 0x200802000. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define VPTB ((unsigned long *) 0x200000000) 598c2ecf20Sopenharmony_ci#define L1 ((unsigned long *) 0x200802000) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_civoid 628c2ecf20Sopenharmony_cipal_init(void) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci unsigned long i, rev; 658c2ecf20Sopenharmony_ci struct percpu_struct * percpu; 668c2ecf20Sopenharmony_ci struct pcb_struct * pcb_pa; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Create the dummy PCB. */ 698c2ecf20Sopenharmony_ci pcb_va->ksp = 0; 708c2ecf20Sopenharmony_ci pcb_va->usp = 0; 718c2ecf20Sopenharmony_ci pcb_va->ptbr = L1[1] >> 32; 728c2ecf20Sopenharmony_ci pcb_va->asn = 0; 738c2ecf20Sopenharmony_ci pcb_va->pcc = 0; 748c2ecf20Sopenharmony_ci pcb_va->unique = 0; 758c2ecf20Sopenharmony_ci pcb_va->flags = 1; 768c2ecf20Sopenharmony_ci pcb_va->res1 = 0; 778c2ecf20Sopenharmony_ci pcb_va->res2 = 0; 788c2ecf20Sopenharmony_ci pcb_pa = find_pa(VPTB, pcb_va); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* 818c2ecf20Sopenharmony_ci * a0 = 2 (OSF) 828c2ecf20Sopenharmony_ci * a1 = return address, but we give the asm the vaddr of the PCB 838c2ecf20Sopenharmony_ci * a2 = physical addr of PCB 848c2ecf20Sopenharmony_ci * a3 = new virtual page table pointer 858c2ecf20Sopenharmony_ci * a4 = KSP (but the asm sets it) 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci srm_printk("Switching to OSF PAL-code .. "); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB); 908c2ecf20Sopenharmony_ci if (i) { 918c2ecf20Sopenharmony_ci srm_printk("failed, code %ld\n", i); 928c2ecf20Sopenharmony_ci __halt(); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci percpu = (struct percpu_struct *) 968c2ecf20Sopenharmony_ci (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB); 978c2ecf20Sopenharmony_ci rev = percpu->pal_revision = percpu->palcode_avail[2]; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci srm_printk("Ok (rev %lx)\n", rev); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci tbia(); /* do it directly in case we are SMP */ 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic inline long openboot(void) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci char bootdev[256]; 1078c2ecf20Sopenharmony_ci long result; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci result = callback_getenv(ENV_BOOTED_DEV, bootdev, 255); 1108c2ecf20Sopenharmony_ci if (result < 0) 1118c2ecf20Sopenharmony_ci return result; 1128c2ecf20Sopenharmony_ci return callback_open(bootdev, result & 255); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic inline long close(long dev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci return callback_close(dev); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic inline long load(long dev, unsigned long addr, unsigned long count) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci char bootfile[256]; 1238c2ecf20Sopenharmony_ci extern char _end; 1248c2ecf20Sopenharmony_ci long result, boot_size = &_end - (char *) BOOT_ADDR; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci result = callback_getenv(ENV_BOOTED_FILE, bootfile, 255); 1278c2ecf20Sopenharmony_ci if (result < 0) 1288c2ecf20Sopenharmony_ci return result; 1298c2ecf20Sopenharmony_ci result &= 255; 1308c2ecf20Sopenharmony_ci bootfile[result] = '\0'; 1318c2ecf20Sopenharmony_ci if (result) 1328c2ecf20Sopenharmony_ci srm_printk("Boot file specification (%s) not implemented\n", 1338c2ecf20Sopenharmony_ci bootfile); 1348c2ecf20Sopenharmony_ci return callback_read(dev, count, (void *)addr, boot_size/512 + 1); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* 1388c2ecf20Sopenharmony_ci * Start the kernel. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_cistatic void runkernel(void) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci __asm__ __volatile__( 1438c2ecf20Sopenharmony_ci "bis %1,%1,$30\n\t" 1448c2ecf20Sopenharmony_ci "bis %0,%0,$26\n\t" 1458c2ecf20Sopenharmony_ci "ret ($26)" 1468c2ecf20Sopenharmony_ci : /* no outputs: it doesn't even return */ 1478c2ecf20Sopenharmony_ci : "r" (START_ADDR), 1488c2ecf20Sopenharmony_ci "r" (PAGE_SIZE + INIT_STACK)); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_civoid start_kernel(void) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci long i; 1548c2ecf20Sopenharmony_ci long dev; 1558c2ecf20Sopenharmony_ci int nbytes; 1568c2ecf20Sopenharmony_ci char envval[256]; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci srm_printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n"); 1598c2ecf20Sopenharmony_ci if (INIT_HWRPB->pagesize != 8192) { 1608c2ecf20Sopenharmony_ci srm_printk("Expected 8kB pages, got %ldkB\n", INIT_HWRPB->pagesize >> 10); 1618c2ecf20Sopenharmony_ci return; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci pal_init(); 1648c2ecf20Sopenharmony_ci dev = openboot(); 1658c2ecf20Sopenharmony_ci if (dev < 0) { 1668c2ecf20Sopenharmony_ci srm_printk("Unable to open boot device: %016lx\n", dev); 1678c2ecf20Sopenharmony_ci return; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci dev &= 0xffffffff; 1708c2ecf20Sopenharmony_ci srm_printk("Loading vmlinux ..."); 1718c2ecf20Sopenharmony_ci i = load(dev, START_ADDR, KERNEL_SIZE); 1728c2ecf20Sopenharmony_ci close(dev); 1738c2ecf20Sopenharmony_ci if (i != KERNEL_SIZE) { 1748c2ecf20Sopenharmony_ci srm_printk("Failed (%lx)\n", i); 1758c2ecf20Sopenharmony_ci return; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); 1798c2ecf20Sopenharmony_ci if (nbytes < 0) { 1808c2ecf20Sopenharmony_ci nbytes = 0; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci envval[nbytes] = '\0'; 1838c2ecf20Sopenharmony_ci strcpy((char*)ZERO_PGE, envval); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci srm_printk(" Ok\nNow booting the kernel\n"); 1868c2ecf20Sopenharmony_ci runkernel(); 1878c2ecf20Sopenharmony_ci for (i = 0 ; i < 0x100000000 ; i++) 1888c2ecf20Sopenharmony_ci /* nothing */; 1898c2ecf20Sopenharmony_ci __halt(); 1908c2ecf20Sopenharmony_ci} 191