diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/alpha/boot/bootp.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/alpha/boot/bootp.c')
-rw-r--r-- | arch/alpha/boot/bootp.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/arch/alpha/boot/bootp.c b/arch/alpha/boot/bootp.c new file mode 100644 index 000000000000..ec53c28e33de --- /dev/null +++ b/arch/alpha/boot/bootp.c | |||
@@ -0,0 +1,214 @@ | |||
1 | /* | ||
2 | * arch/alpha/boot/bootp.c | ||
3 | * | ||
4 | * Copyright (C) 1997 Jay Estabrook | ||
5 | * | ||
6 | * This file is used for creating a bootp file for the Linux/AXP kernel | ||
7 | * | ||
8 | * based significantly on the arch/alpha/boot/main.c of Linus Torvalds | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/version.h> | ||
13 | #include <linux/mm.h> | ||
14 | |||
15 | #include <asm/system.h> | ||
16 | #include <asm/console.h> | ||
17 | #include <asm/hwrpb.h> | ||
18 | #include <asm/pgtable.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | #include <stdarg.h> | ||
22 | |||
23 | #include "ksize.h" | ||
24 | |||
25 | extern 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 | |||
29 | extern void move_stack(unsigned long new_stack); | ||
30 | |||
31 | struct hwrpb_struct *hwrpb = INIT_HWRPB; | ||
32 | static 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 | |||
40 | static inline void * | ||
41 | find_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 | |||
67 | void | ||
68 | pal_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 | |||
110 | static inline void | ||
111 | load(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 | */ | ||
119 | static inline void | ||
120 | runkernel(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 | |||
129 | extern char _end; | ||
130 | #define KERNEL_ORIGIN \ | ||
131 | ((((unsigned long)&_end) + 511) & ~511) | ||
132 | |||
133 | void | ||
134 | start_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 | } | ||