Add Cserve_Get_VM_Time
[qemu-palcode.git] / init.c
blob324bc911a0e37e4df623d7095d5ba47a7b08d8cf
1 /* Initialization of the system and the HWRPB.
3 Copyright (C) 2011 Richard Henderson
5 This file is part of QEMU PALcode.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the text
15 of the GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include <string.h>
22 #include <stddef.h>
23 #include "hwrpb.h"
24 #include "osf.h"
25 #include "ioport.h"
26 #include "uart.h"
27 #include "protos.h"
28 #include SYSTEM_H
30 #define PAGE_SHIFT 13
31 #define PAGE_SIZE (1ul << PAGE_SHIFT)
32 #define PAGE_OFFSET 0xfffffc0000000000UL
34 #define VPTPTR 0xfffffffe00000000UL
36 #define PA(VA) ((unsigned long)(VA) & 0xfffffffffful)
37 #define VA(PA) ((void *)(PA) + PAGE_OFFSET)
39 #define HZ 1024
41 struct hwrpb_combine {
42 struct hwrpb_struct hwrpb;
43 struct percpu_struct processor;
44 struct memdesc_struct md;
45 struct memclust_struct mc[2];
46 struct crb_struct crb;
47 struct procdesc_struct proc_dispatch;
48 struct procdesc_struct proc_fixup;
51 extern char stack[PAGE_SIZE] __attribute__((section(".sbss")));
52 extern char _end[] __attribute__((visibility("hidden"), nocommon));
54 struct pcb_struct pcb __attribute__((section(".sbss")));
56 static unsigned long page_dir[1024]
57 __attribute__((aligned(PAGE_SIZE), section(".bss.page_dir")));
59 /* The HWRPB must be aligned because it is exported at INIT_HWRPB. */
60 struct hwrpb_combine hwrpb __attribute__((aligned(PAGE_SIZE)));
62 void *last_alloc;
63 bool have_vga;
65 static void *
66 alloc (unsigned long size, unsigned long align)
68 void *p = (void *)(((unsigned long)last_alloc + align - 1) & ~(align - 1));
69 last_alloc = p + size;
70 return memset (p, 0, size);
73 static inline unsigned long
74 pt_index(unsigned long addr, int level)
76 return (addr >> (PAGE_SHIFT + (10 * level))) & 0x3ff;
79 static inline unsigned long
80 build_pte (void *page)
82 unsigned long bits;
84 bits = PA((unsigned long)page) << (32 - PAGE_SHIFT);
85 bits += _PAGE_VALID | _PAGE_KRE | _PAGE_KWE;
87 return bits;
90 static inline void *
91 pte_page (unsigned long pte)
93 return VA(pte >> 32 << PAGE_SHIFT);
96 static void
97 set_pte (unsigned long addr, void *page)
99 unsigned long *pt = page_dir;
100 unsigned long index;
102 index = pt_index(addr, 2);
103 if (pt[index] != 0)
104 pt = pte_page (pt[index]);
105 else
107 unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE);
108 pt[index] = build_pte (npt);
109 pt = npt;
112 index = pt_index(addr, 1);
113 if (pt[index] != 0)
114 pt = pte_page (pt[index]);
115 else
117 unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE);
118 pt[index] = build_pte (npt);
119 pt = npt;
122 index = pt_index(addr, 0);
123 pt[index] = build_pte (page);
126 static void
127 init_page_table(void)
129 /* Install the self-reference for the virtual page table base register. */
130 page_dir[pt_index(VPTPTR, 2)] = build_pte(page_dir);
132 set_pte ((unsigned long)INIT_HWRPB, &hwrpb);
134 /* ??? SRM maps some amount of memory at 0x20000000 for use by programs
135 started from the console prompt. Including the bootloader. While
136 we're emulating MILO, don't bother as we jump straight to the kernel
137 loaded into KSEG. */
140 static void
141 init_hwrpb (unsigned long memsize)
143 unsigned long pal_pages;
144 unsigned long amask;
146 hwrpb.hwrpb.phys_addr = PA(&hwrpb);
148 /* Yes, the 'HWRPB' magic is in big-endian byte ordering. */
149 hwrpb.hwrpb.id = ( (long)'H' << 56
150 | (long)'W' << 48
151 | (long)'R' << 40
152 | (long)'P' << 32
153 | (long)'B' << 24);
155 hwrpb.hwrpb.size = sizeof(struct hwrpb_struct);
157 ((int *)hwrpb.hwrpb.ssn)[0] = ( 'Q' << 0
158 | 'E' << 8
159 | 'M' << 16
160 | 'U' << 24);
162 amask = ~__builtin_alpha_amask(-1);
163 switch (__builtin_alpha_implver())
165 case 0: /* EV4 */
166 hwrpb.hwrpb.cpuid = EV4_CPU;
167 hwrpb.hwrpb.max_asn = 63;
168 break;
170 case 1: /* EV5 */
171 hwrpb.hwrpb.cpuid
172 = ((amask & 0x101) == 0x101 ? PCA56_CPU /* MAX+BWX */
173 : amask & 1 ? EV56_CPU /* BWX */
174 : EV5_CPU);
175 hwrpb.hwrpb.max_asn = 127;
176 break;
178 case 2: /* EV6 */
179 hwrpb.hwrpb.cpuid = (amask & 4 ? EV67_CPU : EV6_CPU); /* CIX */
180 hwrpb.hwrpb.max_asn = 255;
181 break;
184 hwrpb.hwrpb.pagesize = PAGE_SIZE;
185 hwrpb.hwrpb.pa_bits = 40;
186 hwrpb.hwrpb.sys_type = SYS_TYPE;
187 hwrpb.hwrpb.sys_variation = SYS_VARIATION;
188 hwrpb.hwrpb.sys_revision = SYS_REVISION;
189 hwrpb.processor.type = hwrpb.hwrpb.cpuid;
191 hwrpb.hwrpb.intr_freq = HZ * 4096;
192 hwrpb.hwrpb.cycle_freq = 250000000; /* QEMU architects 250MHz. */
194 hwrpb.hwrpb.vptb = VPTPTR;
196 hwrpb.hwrpb.nr_processors = 1;
197 hwrpb.hwrpb.processor_size = sizeof(struct percpu_struct);
198 hwrpb.hwrpb.processor_offset = offsetof(struct hwrpb_combine, processor);
200 hwrpb.hwrpb.mddt_offset = offsetof(struct hwrpb_combine, md);
201 hwrpb.md.numclusters = 2;
203 pal_pages = (PA(last_alloc) + PAGE_SIZE - 1) >> PAGE_SHIFT;
205 hwrpb.mc[0].numpages = pal_pages;
206 hwrpb.mc[0].usage = 1;
207 hwrpb.mc[1].start_pfn = pal_pages;
208 hwrpb.mc[1].numpages = (memsize >> PAGE_SHIFT) - pal_pages;
210 hwrpb.hwrpb.crb_offset = offsetof(struct hwrpb_combine, crb);
211 hwrpb.crb.dispatch_va = &hwrpb.proc_dispatch;
212 hwrpb.crb.dispatch_pa = PA(&hwrpb.proc_dispatch);
213 hwrpb.crb.fixup_va = &hwrpb.proc_fixup;
214 hwrpb.crb.fixup_pa = PA(&hwrpb.proc_fixup);
215 hwrpb.crb.map_entries = 1;
216 hwrpb.crb.map_pages = 1;
217 hwrpb.crb.map[0].va = &hwrpb;
218 hwrpb.crb.map[0].pa = PA(&hwrpb);
219 hwrpb.crb.map[0].count = 1;
221 /* See crb.c for how we match the VMS calling conventions to Unix. */
222 hwrpb.proc_dispatch.address = (unsigned long)crb_dispatch;
223 hwrpb.proc_fixup.address = (unsigned long)crb_fixup;
225 hwrpb_update_checksum(&hwrpb.hwrpb);
228 static void
229 init_pcb (void)
231 pcb.ksp = (unsigned long)stack + sizeof(stack);
232 pcb.ptbr = PA(page_dir) >> PAGE_SHIFT;
233 pcb.flags = 1; /* FEN */
236 static void
237 init_i8259 (void)
239 /* ??? MILO initializes the PIC as edge triggered; I do not know how SRM
240 initializes them. However, Linux seems to expect that these are level
241 triggered. That may be a kernel bug, but level triggers are more
242 reliable anyway so lets go with that. */
244 /* Initialize the slave PIC. */
245 outb(0x11, PORT_PIC2_CMD); /* ICW1: edge trigger, cascade, ICW4 req */
246 outb(0x08, PORT_PIC2_DATA); /* ICW2: irq offset = 8 */
247 outb(0x02, PORT_PIC2_DATA); /* ICW3: slave ID 2 */
248 outb(0x01, PORT_PIC2_DATA); /* ICW4: not special nested, normal eoi */
250 /* Initialize the master PIC. */
251 outb(0x11, PORT_PIC1_CMD); /* ICW1 */
252 outb(0x00, PORT_PIC1_DATA); /* ICW2: irq offset = 0 */
253 outb(0x04, PORT_PIC1_DATA); /* ICW3: slave control INTC2 */
254 outb(0x01, PORT_PIC1_DATA); /* ICW4 */
256 /* Initialize level triggers. The CY82C693UB that's on real alpha
257 hardware doesn't have this; this is a PIIX extension. However,
258 QEMU doesn't implement regular level triggers. */
259 outb(0xff, PORT_PIC2_ELCR);
260 outb(0xff, PORT_PIC1_ELCR);
262 /* Disable all interrupts. */
263 outb(0xff, PORT_PIC2_DATA);
264 outb(0xff, PORT_PIC1_DATA);
266 /* Non-specific EOI, clearing anything the might be pending. */
267 outb(0x20, PORT_PIC2_CMD);
268 outb(0x20, PORT_PIC1_CMD);
271 void
272 do_start(unsigned long memsize, void (*kernel_entry)(void), long cpus)
274 last_alloc = _end;
276 init_page_table();
277 init_hwrpb(memsize);
278 init_pcb();
279 init_i8259();
280 uart_init();
281 ps2port_setup();
282 pci_setup();
283 vgahw_init();
286 register int variant __asm__("$16") = 2; /* OSF/1 PALcode */
287 register void (*pc)(void) __asm__("$17");
288 register unsigned long pa_pcb __asm__("$18");
289 register unsigned long vptptr __asm__("$19");
291 pc = (kernel_entry ? kernel_entry : do_console);
292 pa_pcb = PA(&pcb);
293 vptptr = VPTPTR;
294 asm("call_pal 0x0a" : : "r"(variant), "r"(pc), "r"(pa_pcb), "r"(vptptr));
296 __builtin_unreachable ();
299 void
300 do_start_wait(void)
302 while (1)
304 // WtInt with interrupts off. Rely on the fact that QEMU will
305 // un-halt the CPU when an interrupt arrives.
306 asm("lda $16,-1\n\tcall_pal 0x3e" : : : "$0", "$16");
308 // FIXME do something with the IPI.