|
|
1.1 root 1: /* Initialization of the system and the HWRPB.
2:
3: Copyright (C) 2011 Richard Henderson
4:
5: This file is part of QEMU PALcode.
6:
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.
11:
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.
16:
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/>. */
20:
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
29:
30: #define PAGE_SHIFT 13
31: #define PAGE_SIZE (1ul << PAGE_SHIFT)
32: #define PAGE_OFFSET 0xfffffc0000000000UL
33:
34: #define VPTPTR 0xfffffffe00000000UL
35:
36: #define PA(VA) ((unsigned long)(VA) & 0xfffffffffful)
37: #define VA(PA) ((void *)(PA) + PAGE_OFFSET)
38:
39: #define HZ 1024
40:
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;
49: };
50:
51: extern char stack[PAGE_SIZE] __attribute__((section(".sbss")));
52: extern char _end[] __attribute__((visibility("hidden"), nocommon));
53:
54: struct pcb_struct pcb __attribute__((section(".sbss")));
55:
56: static unsigned long page_dir[1024] __attribute__((aligned(PAGE_SIZE)));
57:
58: /* The HWRPB must be aligned because it is exported at INIT_HWRPB. */
59: struct hwrpb_combine hwrpb __attribute__((aligned(PAGE_SIZE)));
60:
61: void *last_alloc;
62: bool have_vga;
63:
64: static void *
65: alloc (unsigned long size, unsigned long align)
66: {
67: void *p = (void *)(((unsigned long)last_alloc + align - 1) & ~(align - 1));
68: last_alloc = p + size;
69: return memset (p, 0, size);
70: }
71:
72: static inline unsigned long
73: pt_index(unsigned long addr, int level)
74: {
75: return (addr >> (PAGE_SHIFT + (10 * level))) & 0x3ff;
76: }
77:
78: static inline unsigned long
79: build_pte (void *page)
80: {
81: unsigned long bits;
82:
83: bits = PA((unsigned long)page) << (32 - PAGE_SHIFT);
84: bits += _PAGE_VALID | _PAGE_KRE | _PAGE_KWE;
85:
86: return bits;
87: }
88:
89: static inline void *
90: pte_page (unsigned long pte)
91: {
92: return VA(pte >> 32 << PAGE_SHIFT);
93: }
94:
95: static void
96: set_pte (unsigned long addr, void *page)
97: {
98: unsigned long *pt = page_dir;
99: unsigned long index;
100:
101: index = pt_index(addr, 2);
102: if (pt[index] != 0)
103: pt = pte_page (pt[index]);
104: else
105: {
106: unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE);
107: pt[index] = build_pte (npt);
108: pt = npt;
109: }
110:
111: index = pt_index(addr, 1);
112: if (pt[index] != 0)
113: pt = pte_page (pt[index]);
114: else
115: {
116: unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE);
117: pt[index] = build_pte (npt);
118: pt = npt;
119: }
120:
121: index = pt_index(addr, 0);
122: pt[index] = build_pte (page);
123: }
124:
125: static void
126: init_page_table(void)
127: {
128: /* Install the self-reference for the virtual page table base register. */
129: page_dir[pt_index(VPTPTR, 2)] = build_pte(page_dir);
130:
131: set_pte ((unsigned long)INIT_HWRPB, &hwrpb);
132:
133: /* ??? SRM maps some amount of memory at 0x20000000 for use by programs
134: started from the console prompt. Including the bootloader. While
135: we're emulating MILO, don't bother as we jump straight to the kernel
136: loaded into KSEG. */
137: }
138:
139: static void
140: init_hwrpb (unsigned long memsize)
141: {
142: unsigned long pal_pages;
143: unsigned long amask;
144:
145: hwrpb.hwrpb.phys_addr = PA(&hwrpb);
146:
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);
153:
154: hwrpb.hwrpb.size = sizeof(struct hwrpb_struct);
155:
156: ((int *)hwrpb.hwrpb.ssn)[0] = ( 'Q' << 0
157: | 'E' << 8
158: | 'M' << 16
159: | 'U' << 24);
160:
161: amask = ~__builtin_alpha_amask(-1);
162: switch (__builtin_alpha_implver())
163: {
164: case 0: /* EV4 */
165: hwrpb.hwrpb.cpuid = EV4_CPU;
166: hwrpb.hwrpb.max_asn = 63;
167: break;
168:
169: case 1: /* EV5 */
170: hwrpb.hwrpb.cpuid
171: = ((amask & 0x101) == 0x101 ? PCA56_CPU /* MAX+BWX */
172: : amask & 1 ? EV56_CPU /* BWX */
173: : EV5_CPU);
174: hwrpb.hwrpb.max_asn = 127;
175: break;
176:
177: case 2: /* EV6 */
178: hwrpb.hwrpb.cpuid = (amask & 4 ? EV67_CPU : EV6_CPU); /* CIX */
179: hwrpb.hwrpb.max_asn = 255;
180: break;
181: }
182:
183: hwrpb.hwrpb.pagesize = PAGE_SIZE;
184: hwrpb.hwrpb.pa_bits = 40;
185: hwrpb.hwrpb.sys_type = SYS_TYPE;
186: hwrpb.hwrpb.sys_variation = SYS_VARIATION;
187: hwrpb.hwrpb.sys_revision = SYS_REVISION;
188: hwrpb.processor.type = hwrpb.hwrpb.cpuid;
189:
190: hwrpb.hwrpb.intr_freq = HZ * 4096;
191: hwrpb.hwrpb.cycle_freq = 250000000; /* QEMU architects 250MHz. */
192:
193: hwrpb.hwrpb.vptb = VPTPTR;
194:
195: hwrpb.hwrpb.nr_processors = 1;
196: hwrpb.hwrpb.processor_size = sizeof(struct percpu_struct);
197: hwrpb.hwrpb.processor_offset = offsetof(struct hwrpb_combine, processor);
198:
199: hwrpb.hwrpb.mddt_offset = offsetof(struct hwrpb_combine, md);
200: hwrpb.md.numclusters = 2;
201:
202: pal_pages = (PA(last_alloc) + PAGE_SIZE - 1) >> PAGE_SHIFT;
203:
204: hwrpb.mc[0].numpages = pal_pages;
205: hwrpb.mc[0].usage = 1;
206: hwrpb.mc[1].start_pfn = pal_pages;
207: hwrpb.mc[1].numpages = (memsize >> PAGE_SHIFT) - pal_pages;
208:
209: hwrpb.hwrpb.crb_offset = offsetof(struct hwrpb_combine, crb);
210: hwrpb.crb.dispatch_va = &hwrpb.proc_dispatch;
211: hwrpb.crb.dispatch_pa = PA(&hwrpb.proc_dispatch);
212: hwrpb.crb.fixup_va = &hwrpb.proc_fixup;
213: hwrpb.crb.fixup_pa = PA(&hwrpb.proc_fixup);
214: hwrpb.crb.map_entries = 1;
215: hwrpb.crb.map_pages = 1;
216: hwrpb.crb.map[0].va = &hwrpb;
217: hwrpb.crb.map[0].pa = PA(&hwrpb);
218: hwrpb.crb.map[0].count = 1;
219:
220: /* See crb.c for how we match the VMS calling conventions to Unix. */
221: hwrpb.proc_dispatch.address = (unsigned long)crb_dispatch;
222: hwrpb.proc_fixup.address = (unsigned long)crb_fixup;
223:
224: hwrpb_update_checksum(&hwrpb.hwrpb);
225: }
226:
227: static void
228: init_pcb (void)
229: {
230: pcb.ksp = (unsigned long)stack + sizeof(stack);
231: pcb.ptbr = PA(page_dir) >> PAGE_SHIFT;
232: pcb.flags = 1; /* FEN */
233: }
234:
235: static void
236: init_i8259 (void)
237: {
238: /* ??? MILO initializes the PIC as edge triggered; I do not know how SRM
239: initializes them. However, Linux seems to expect that these are level
240: triggered. That may be a kernel bug, but level triggers are more
241: reliable anyway so lets go with that. */
242:
243: /* Initialize the slave PIC. */
244: outb(0x11, PORT_PIC2_CMD); /* ICW1: edge trigger, cascade, ICW4 req */
245: outb(0x08, PORT_PIC2_DATA); /* ICW2: irq offset = 8 */
246: outb(0x02, PORT_PIC2_DATA); /* ICW3: slave ID 2 */
247: outb(0x01, PORT_PIC2_DATA); /* ICW4: not special nested, normal eoi */
248:
249: /* Initialize the master PIC. */
250: outb(0x11, PORT_PIC1_CMD); /* ICW1 */
251: outb(0x00, PORT_PIC1_DATA); /* ICW2: irq offset = 0 */
252: outb(0x04, PORT_PIC1_DATA); /* ICW3: slave control INTC2 */
253: outb(0x01, PORT_PIC1_DATA); /* ICW4 */
254:
255: /* Initialize level triggers. The CY82C693UB that's on real alpha
256: hardware doesn't have this; this is a PIIX extension. However,
257: QEMU doesn't implement regular level triggers. */
258: outb(0xff, PORT_PIC2_ELCR);
259: outb(0xff, PORT_PIC1_ELCR);
260:
261: /* Disable all interrupts. */
262: outb(0xff, PORT_PIC2_DATA);
263: outb(0xff, PORT_PIC1_DATA);
264:
265: /* Non-specific EOI, clearing anything the might be pending. */
266: outb(0x20, PORT_PIC2_CMD);
267: outb(0x20, PORT_PIC1_CMD);
268: }
269:
270: void
271: do_start(unsigned long memsize, void (*kernel_entry)(void), long cpus)
272: {
273: last_alloc = _end;
274:
275: init_page_table();
276: init_hwrpb(memsize);
277: init_pcb();
278: init_i8259();
279: uart_init();
280: ps2port_setup();
281: pci_setup();
282: vgahw_init();
283:
284: {
285: register int variant __asm__("$16") = 2; /* OSF/1 PALcode */
286: register void (*pc)(void) __asm__("$17");
287: register unsigned long pa_pcb __asm__("$18");
288: register unsigned long vptptr __asm__("$19");
289:
290: pc = (kernel_entry ? kernel_entry : do_console);
291: pa_pcb = PA(&pcb);
292: vptptr = VPTPTR;
293: asm("call_pal 0x0a" : : "r"(variant), "r"(pc), "r"(pa_pcb), "r"(vptptr));
294: }
295: __builtin_unreachable ();
296: }
297:
298: void
299: do_start_wait(void)
300: {
301: while (1)
302: {
303: // WtInt with interrupts off. Rely on the fact that QEMU will
304: // un-halt the CPU when an interrupt arrives.
305: asm("lda $16,-1\n\tcall_pal 0x3e" : : : "$0", "$16");
306:
307: // FIXME do something with the IPI.
308: }
309: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.