xref: /OK3568_Linux_fs/kernel/arch/alpha/boot/main.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * arch/alpha/boot/main.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 1994, 1995 Linus Torvalds
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This file is the bootloader for the Linux/AXP kernel
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/string.h>
12*4882a593Smuzhiyun #include <generated/utsrelease.h>
13*4882a593Smuzhiyun #include <linux/mm.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <asm/console.h>
16*4882a593Smuzhiyun #include <asm/hwrpb.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <stdarg.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "ksize.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun extern unsigned long switch_to_osf_pal(unsigned long nr,
23*4882a593Smuzhiyun 	struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
24*4882a593Smuzhiyun 	unsigned long *vptb);
25*4882a593Smuzhiyun struct hwrpb_struct *hwrpb = INIT_HWRPB;
26*4882a593Smuzhiyun static struct pcb_struct pcb_va[1];
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun  * Find a physical address of a virtual object..
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * This is easy using the virtual page table address.
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun static inline void *
find_pa(unsigned long * vptb,void * ptr)35*4882a593Smuzhiyun find_pa(unsigned long *vptb, void *ptr)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	unsigned long address = (unsigned long) ptr;
38*4882a593Smuzhiyun 	unsigned long result;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	result = vptb[address >> 13];
41*4882a593Smuzhiyun 	result >>= 32;
42*4882a593Smuzhiyun 	result <<= 13;
43*4882a593Smuzhiyun 	result |= address & 0x1fff;
44*4882a593Smuzhiyun 	return (void *) result;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /*
48*4882a593Smuzhiyun  * This function moves into OSF/1 pal-code, and has a temporary
49*4882a593Smuzhiyun  * PCB for that. The kernel proper should replace this PCB with
50*4882a593Smuzhiyun  * the real one as soon as possible.
51*4882a593Smuzhiyun  *
52*4882a593Smuzhiyun  * The page table muckery in here depends on the fact that the boot
53*4882a593Smuzhiyun  * code has the L1 page table identity-map itself in the second PTE
54*4882a593Smuzhiyun  * in the L1 page table. Thus the L1-page is virtually addressable
55*4882a593Smuzhiyun  * itself (through three levels) at virtual address 0x200802000.
56*4882a593Smuzhiyun  */
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define VPTB	((unsigned long *) 0x200000000)
59*4882a593Smuzhiyun #define L1	((unsigned long *) 0x200802000)
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun void
pal_init(void)62*4882a593Smuzhiyun pal_init(void)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	unsigned long i, rev;
65*4882a593Smuzhiyun 	struct percpu_struct * percpu;
66*4882a593Smuzhiyun 	struct pcb_struct * pcb_pa;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	/* Create the dummy PCB.  */
69*4882a593Smuzhiyun 	pcb_va->ksp = 0;
70*4882a593Smuzhiyun 	pcb_va->usp = 0;
71*4882a593Smuzhiyun 	pcb_va->ptbr = L1[1] >> 32;
72*4882a593Smuzhiyun 	pcb_va->asn = 0;
73*4882a593Smuzhiyun 	pcb_va->pcc = 0;
74*4882a593Smuzhiyun 	pcb_va->unique = 0;
75*4882a593Smuzhiyun 	pcb_va->flags = 1;
76*4882a593Smuzhiyun 	pcb_va->res1 = 0;
77*4882a593Smuzhiyun 	pcb_va->res2 = 0;
78*4882a593Smuzhiyun 	pcb_pa = find_pa(VPTB, pcb_va);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	/*
81*4882a593Smuzhiyun 	 * a0 = 2 (OSF)
82*4882a593Smuzhiyun 	 * a1 = return address, but we give the asm the vaddr of the PCB
83*4882a593Smuzhiyun 	 * a2 = physical addr of PCB
84*4882a593Smuzhiyun 	 * a3 = new virtual page table pointer
85*4882a593Smuzhiyun 	 * a4 = KSP (but the asm sets it)
86*4882a593Smuzhiyun 	 */
87*4882a593Smuzhiyun 	srm_printk("Switching to OSF PAL-code .. ");
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
90*4882a593Smuzhiyun 	if (i) {
91*4882a593Smuzhiyun 		srm_printk("failed, code %ld\n", i);
92*4882a593Smuzhiyun 		__halt();
93*4882a593Smuzhiyun 	}
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	percpu = (struct percpu_struct *)
96*4882a593Smuzhiyun 		(INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
97*4882a593Smuzhiyun 	rev = percpu->pal_revision = percpu->palcode_avail[2];
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	srm_printk("Ok (rev %lx)\n", rev);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	tbia(); /* do it directly in case we are SMP */
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
openboot(void)104*4882a593Smuzhiyun static inline long openboot(void)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	char bootdev[256];
107*4882a593Smuzhiyun 	long result;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	result = callback_getenv(ENV_BOOTED_DEV, bootdev, 255);
110*4882a593Smuzhiyun 	if (result < 0)
111*4882a593Smuzhiyun 		return result;
112*4882a593Smuzhiyun 	return callback_open(bootdev, result & 255);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
close(long dev)115*4882a593Smuzhiyun static inline long close(long dev)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	return callback_close(dev);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
load(long dev,unsigned long addr,unsigned long count)120*4882a593Smuzhiyun static inline long load(long dev, unsigned long addr, unsigned long count)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	char bootfile[256];
123*4882a593Smuzhiyun 	extern char _end;
124*4882a593Smuzhiyun 	long result, boot_size = &_end - (char *) BOOT_ADDR;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	result = callback_getenv(ENV_BOOTED_FILE, bootfile, 255);
127*4882a593Smuzhiyun 	if (result < 0)
128*4882a593Smuzhiyun 		return result;
129*4882a593Smuzhiyun 	result &= 255;
130*4882a593Smuzhiyun 	bootfile[result] = '\0';
131*4882a593Smuzhiyun 	if (result)
132*4882a593Smuzhiyun 		srm_printk("Boot file specification (%s) not implemented\n",
133*4882a593Smuzhiyun 		       bootfile);
134*4882a593Smuzhiyun 	return callback_read(dev, count, (void *)addr, boot_size/512 + 1);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun /*
138*4882a593Smuzhiyun  * Start the kernel.
139*4882a593Smuzhiyun  */
runkernel(void)140*4882a593Smuzhiyun static void runkernel(void)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	__asm__ __volatile__(
143*4882a593Smuzhiyun 		"bis %1,%1,$30\n\t"
144*4882a593Smuzhiyun 		"bis %0,%0,$26\n\t"
145*4882a593Smuzhiyun 		"ret ($26)"
146*4882a593Smuzhiyun 		: /* no outputs: it doesn't even return */
147*4882a593Smuzhiyun 		: "r" (START_ADDR),
148*4882a593Smuzhiyun 		  "r" (PAGE_SIZE + INIT_STACK));
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
start_kernel(void)151*4882a593Smuzhiyun void start_kernel(void)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	long i;
154*4882a593Smuzhiyun 	long dev;
155*4882a593Smuzhiyun 	int nbytes;
156*4882a593Smuzhiyun 	char envval[256];
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	srm_printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n");
159*4882a593Smuzhiyun 	if (INIT_HWRPB->pagesize != 8192) {
160*4882a593Smuzhiyun 		srm_printk("Expected 8kB pages, got %ldkB\n", INIT_HWRPB->pagesize >> 10);
161*4882a593Smuzhiyun 		return;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 	pal_init();
164*4882a593Smuzhiyun 	dev = openboot();
165*4882a593Smuzhiyun 	if (dev < 0) {
166*4882a593Smuzhiyun 		srm_printk("Unable to open boot device: %016lx\n", dev);
167*4882a593Smuzhiyun 		return;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 	dev &= 0xffffffff;
170*4882a593Smuzhiyun 	srm_printk("Loading vmlinux ...");
171*4882a593Smuzhiyun 	i = load(dev, START_ADDR, KERNEL_SIZE);
172*4882a593Smuzhiyun 	close(dev);
173*4882a593Smuzhiyun 	if (i != KERNEL_SIZE) {
174*4882a593Smuzhiyun 		srm_printk("Failed (%lx)\n", i);
175*4882a593Smuzhiyun 		return;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
179*4882a593Smuzhiyun 	if (nbytes < 0) {
180*4882a593Smuzhiyun 		nbytes = 0;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 	envval[nbytes] = '\0';
183*4882a593Smuzhiyun 	strcpy((char*)ZERO_PGE, envval);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	srm_printk(" Ok\nNow booting the kernel\n");
186*4882a593Smuzhiyun 	runkernel();
187*4882a593Smuzhiyun 	for (i = 0 ; i < 0x100000000 ; i++)
188*4882a593Smuzhiyun 		/* nothing */;
189*4882a593Smuzhiyun 	__halt();
190*4882a593Smuzhiyun }
191