PCBB.PTBR contains a page frame number, not a physical address.
[qemu-palcode.git] / init.c
blobcb900c5a2780dc51ed385f41ffd91eff3bbb0d29
1 #include <string.h>
2 #include <stddef.h>
3 #include "hwrpb.h"
4 #include "osf.h"
5 #include "uart.h"
7 #define PAGE_SHIFT 13
8 #define PAGE_SIZE (1ul << PAGE_SHIFT)
9 #define PAGE_OFFSET 0xfffffc0000000000UL
11 #define VPTPTR 0xfffffffe00000000UL
13 #define PA(VA) ((unsigned long)(VA) & 0xfffffffffful)
14 #define VA(PA) ((void *)(PA) + PAGE_OFFSET)
16 #define HZ 1024
18 struct hwrpb_combine {
19 struct hwrpb_struct hwrpb;
20 struct percpu_struct processor;
21 struct memdesc_struct md;
22 struct memclust_struct mc[2];
25 extern char stack[PAGE_SIZE] __attribute__((section(".sbss")));
26 extern char _end[] __attribute__((visibility("hidden"), nocommon));
28 struct pcb_struct pcb __attribute__((section(".sbss")));
30 static unsigned long page_dir[1024] __attribute__((aligned(PAGE_SIZE)));
32 /* The HWRPB must be aligned because it is exported at INIT_HWRPB. */
33 struct hwrpb_combine hwrpb __attribute__((aligned(PAGE_SIZE)));
35 static void *last_alloc;
37 static void *
38 alloc (unsigned long size, unsigned long align)
40 void *p = (void *)(((unsigned long)last_alloc + align - 1) & ~(align - 1));
41 last_alloc = p + size;
42 return memset (p, 0, size);
45 static inline unsigned long
46 pt_index(unsigned long addr, int level)
48 return (addr >> (PAGE_SHIFT + (10 * level))) & 0x3ff;
51 static inline unsigned long
52 build_pte (void *page)
54 unsigned long bits;
56 bits = PA((unsigned long)page) << (32 - PAGE_SHIFT);
57 bits += _PAGE_VALID | _PAGE_KRE | _PAGE_KWE;
59 return bits;
62 static inline void *
63 pte_page (unsigned long pte)
65 return VA(pte >> 32 << PAGE_SHIFT);
68 static void
69 set_pte (unsigned long addr, void *page)
71 unsigned long *pt = page_dir;
72 unsigned long index;
74 index = pt_index(addr, 2);
75 if (pt[index] != 0)
76 pt = pte_page (pt[index]);
77 else
79 unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE);
80 pt[index] = build_pte (npt);
81 pt = npt;
84 index = pt_index(addr, 1);
85 if (pt[index] != 0)
86 pt = pte_page (pt[index]);
87 else
89 unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE);
90 pt[index] = build_pte (npt);
91 pt = npt;
94 index = pt_index(addr, 0);
95 pt[index] = build_pte (page);
98 static void
99 init_page_table(void)
101 /* Install the self-reference for the virtual page table base register. */
102 page_dir[pt_index(VPTPTR, 2)] = build_pte(page_dir);
104 set_pte ((unsigned long)INIT_HWRPB, &hwrpb);
106 /* ??? SRM maps some amount of memory at 0x20000000 for use by programs
107 started from the console prompt. Including the bootloader. While
108 we're emulating MILO, don't bother as we jump straight to the kernel
109 loaded into KSEG. */
112 static inline unsigned long
113 init_cpuid (void)
115 unsigned long implver, amask;
117 implver = __builtin_alpha_implver();
118 amask = ~__builtin_alpha_amask(-1);
120 switch (implver)
122 case 0: /* EV4 */
123 return EV4_CPU;
125 case 1: /* EV5 */
126 if ((amask & 0x101) == 0x101) /* MAX + BWX */
127 return PCA56_CPU;
128 if (amask & 1) /* BWX */
129 return EV56_CPU;
130 return EV5_CPU;
132 case 2: /* EV6 */
133 if (amask & 4) /* CIX */
134 return EV67_CPU;
135 return EV6_CPU;
137 return 0;
140 static void
141 init_hwrpb (unsigned long memsize)
143 unsigned long pal_pages;
145 hwrpb.hwrpb.phys_addr = PA(&hwrpb);
147 /* Yes, the 'HWRPB' magic is in big-endian byte ordering. */
148 hwrpb.hwrpb.id = ( (long)'H' << 56
149 | (long)'W' << 48
150 | (long)'R' << 40
151 | (long)'P' << 32
152 | (long)'B' << 24);
154 hwrpb.hwrpb.size = sizeof(struct hwrpb_struct);
156 /* The inclusion of MILO here tells the Linux kernel that we do
157 not (yet) support any of the extended console support routines
158 that are in SRM. */
159 ((int *)hwrpb.hwrpb.ssn)[0] = ( 'M' << 0
160 | 'I' << 8
161 | 'L' << 16
162 | 'O' << 24);
163 ((int *)hwrpb.hwrpb.ssn)[1] = ( ' ' << 0
164 | 'Q' << 8
165 | 'E' << 16
166 | 'M' << 24);
167 ((int *)hwrpb.hwrpb.ssn)[2] = ( 'U' << 0);
169 /* For now, hard-code emulation of sx164. */
170 hwrpb.hwrpb.cpuid = PCA56_CPU;
171 hwrpb.hwrpb.pagesize = PAGE_SIZE;
172 hwrpb.hwrpb.pa_bits = 40;
173 hwrpb.hwrpb.max_asn = 127;
174 hwrpb.hwrpb.sys_type = ST_DEC_EB164;
175 hwrpb.hwrpb.sys_variation = 15 << 10;
176 hwrpb.hwrpb.sys_revision = 0;
177 hwrpb.processor.type = PCA56_CPU;
179 hwrpb.hwrpb.intr_freq = HZ * 4096;
181 /* ??? What the hell should we put here. Measure like the kernel will? */
182 hwrpb.hwrpb.cycle_freq = 400000000;
184 hwrpb.hwrpb.vptb = VPTPTR;
186 hwrpb.hwrpb.nr_processors = 1;
187 hwrpb.hwrpb.processor_size = sizeof(struct percpu_struct);
188 hwrpb.hwrpb.processor_offset = offsetof(struct hwrpb_combine, processor);
190 hwrpb.hwrpb.mddt_offset = offsetof(struct hwrpb_combine, md);
191 hwrpb.md.numclusters = 2;
193 pal_pages = (PA(last_alloc) + PAGE_SIZE - 1) >> PAGE_SHIFT;
195 hwrpb.mc[0].numpages = pal_pages;
196 hwrpb.mc[0].usage = 1;
197 hwrpb.mc[1].start_pfn = pal_pages;
198 hwrpb.mc[1].numpages = (memsize >> PAGE_SHIFT) - pal_pages;
201 unsigned long sum = 0, *l;
202 for (l = (unsigned long *) &hwrpb.hwrpb; l < &hwrpb.hwrpb.chksum; ++l)
203 sum += *l;
204 hwrpb.hwrpb.chksum = sum;
208 static void
209 init_pcb (void)
211 pcb.ksp = (unsigned long)stack + sizeof(stack);
212 pcb.ptbr = PA(page_dir) >> PAGE_SHIFT;
213 pcb.flags = 1; /* FEN */
216 void
217 do_hello(void)
219 uart_puts(COM1, "Hello, World!\n");
220 asm ("halt");
221 __builtin_unreachable ();
224 void
225 do_start(unsigned long memsize, void (*kernel_entry)(void))
227 last_alloc = _end;
229 init_page_table();
230 init_hwrpb(memsize);
231 init_pcb();
232 uart_init();
235 register int variant __asm__("$16") = 2; /* OSF/1 PALcode */
236 register void (*pc)(void) __asm__("$17");
237 register unsigned long pa_pcb __asm__("$18");
238 register unsigned long vptptr __asm__("$19");
240 pc = (kernel_entry ? kernel_entry : do_hello);
241 pa_pcb = PA(&pcb);
242 vptptr = VPTPTR;
243 asm("call_pal 0x0a" : : "r"(variant), "r"(pc), "r"(pa_pcb), "r"(vptptr));
245 __builtin_unreachable ();