Fix bootmaker for amd64
[newos.git] / boot / sh4 / vcpu_c.c
blob312ddd01cf77b8f6c9f528f6d26521f04b101758
1 /*
2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
4 */
5 #include <arch/sh4/vcpu.h>
6 #include <arch/sh4/vcpu_struct.h>
7 #include <boot/stage2.h>
8 #include "serial.h"
9 #include <string.h>
10 #include <arch/cpu.h>
11 #include <arch/sh4/sh4.h>
13 #define SAVE_CPU_STATE 0
15 #define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
17 #define CHATTY_TLB 0
19 extern vcpu_struct kernel_struct;
20 #if SAVE_CPU_STATE
21 extern unsigned int last_ex_cpu_state[];
22 #endif
23 unsigned int next_utlb_ent = 0;
25 unsigned int vector_base();
26 unsigned int boot_stack[256] = { 0, };
28 void vcpu_clear_all_itlb_entries();
29 void vcpu_clear_all_utlb_entries();
30 void vcpu_dump_utlb_entry(int ent);
31 void vcpu_dump_all_itlb_entries();
32 void vcpu_dump_all_utlb_entries();
34 unsigned int get_sr();
35 void set_sr(unsigned int sr);
36 unsigned int get_vbr();
37 void set_vbr(unsigned int vbr);
38 unsigned int get_sgr();
39 unsigned int get_ssr();
40 unsigned int get_spc();
41 asm(
42 ".globl _get_sr,_set_sr\n"
43 ".globl _get_vbr,_set_vbr\n"
44 ".globl _get_sgr\n"
46 "_get_sr:\n"
47 " stc sr,r0\n"
48 " rts\n"
49 " nop\n"
51 "_set_sr:\n"
52 " ldc r4,sr\n"
53 " rts\n"
54 " nop\n"
56 "_get_vbr:\n"
57 " stc vbr,r0\n"
58 " rts\n"
59 " nop\n"
61 "_set_vbr:\n"
62 " ldc r4,vbr\n"
63 " rts\n"
64 " nop\n"
66 "_get_sgr:\n"
67 " stc sgr,r0\n"
68 " rts\n"
69 " nop\n"
71 "_get_ssr:\n"
72 " stc ssr,r0\n"
73 " rts\n"
74 " nop\n"
76 "_get_spc:\n"
77 " stc spc,r0\n"
78 " rts\n"
79 " nop\n"
82 #if SAVE_CPU_STATE
83 static void dump_cpu_state()
85 int i;
86 unsigned int *stack;
87 unsigned int *stack_top;
89 dprintf("dump_cpu_state entry\n");
91 dprintf("registers:\n");
92 for(i=0; i<16; i++) {
93 dprintf("r%d 0x%x\n", i, last_ex_cpu_state[i]);
95 dprintf("gbr 0x%x\n", last_ex_cpu_state[16]);
96 dprintf("mach 0x%x\n", last_ex_cpu_state[17]);
97 dprintf("macl 0x%x\n", last_ex_cpu_state[18]);
98 dprintf("pr 0x%x\n", last_ex_cpu_state[19]);
99 dprintf("spc 0x%x\n", last_ex_cpu_state[20]);
100 dprintf("sgr 0x%x\n", last_ex_cpu_state[21]);
101 dprintf("ssr 0x%x\n", last_ex_cpu_state[22]);
102 dprintf("fpul 0x%x\n", last_ex_cpu_state[23]);
103 dprintf("fpscr 0x%x\n", last_ex_cpu_state[24]);
105 stack = (unsigned int *)(get_sgr() - 0x200);
106 stack_top = (unsigned int *)ROUNDUP((unsigned int)stack, PAGE_SIZE);
107 dprintf("stack at 0x%x to 0x%x\n", stack, stack_top);
108 // dump the stack
109 for(;stack < stack_top; stack++)
110 dprintf("0x%x\n", *stack);
112 dprintf("utlb entries:\n");
113 vcpu_dump_all_utlb_entries();
114 dprintf("itlb entries:\n");
115 vcpu_dump_all_itlb_entries();
118 for(;;);
120 #endif
121 int reentrant_fault()
123 dprintf("bad reentrancy fault\n");
124 dprintf("spinning forever\n");
125 for(;;);
126 return 0;
129 static int default_vector(void *_frame)
131 struct iframe *frame = (struct iframe *)_frame;
133 dprintf("default_vector: ex_code 0x%x, pc 0x%x\n", frame->excode, frame->spc);
134 dprintf("sgr = 0x%x\n", frame->sgr);
135 dprintf("spinning forever\n");
136 for(;;);
137 return 0;
140 int vcpu_init(kernel_args *ka)
142 int i;
143 unsigned int sr;
144 unsigned int vbr;
146 dprintf("vcpu_init: entry\n");
148 memset(&kernel_struct, 0, sizeof(kernel_struct));
149 for(i=0; i<256; i++) {
150 kernel_struct.vt[i].func = &default_vector;
152 kernel_struct.kstack = (unsigned int *)((int)boot_stack + sizeof(boot_stack) - 4);
154 // set the vbr
155 vbr = (unsigned int)&vector_base;
156 set_vbr(vbr);
157 dprintf("vbr = 0x%x\n", get_vbr());
159 // disable exceptions
160 sr = get_sr();
161 sr |= 0x10000000;
162 set_sr(sr);
164 if((sr & 0x20000000) != 0) {
165 // we're using register bank 1 now
166 dprintf("using bank 1, switching register banks\n");
167 // this switches in the bottom 8 registers.
168 // dont have to do anything more, since the bottom 8 are
169 // not saved in the call.
170 set_sr(sr & 0xdfffffff);
173 // enable exceptions
174 sr = get_sr();
175 sr &= 0xefffffff;
176 set_sr(sr);
178 ka->arch_args.vcpu = &kernel_struct;
180 // enable the mmu
181 vcpu_clear_all_itlb_entries();
182 vcpu_clear_all_utlb_entries();
183 *(int *)PTEH = 0;
184 *(int *)MMUCR = 0x00000105;
186 return 0;
189 static struct ptent *get_ptent(struct pdent *pd, unsigned int fault_address)
191 struct ptent *pt;
193 #if CHATTY_TLB
194 dprintf("get_ptent: fault_address 0x%x\n", fault_address);
195 #endif
197 if((unsigned int)pd < P1_PHYS_MEM_START || (unsigned int)pd >= P1_PHYS_MEM_END) {
198 #if CHATTY_TLB
199 dprintf("get_ptent: bad pdent 0x%x\n", pd);
200 #endif
201 return 0;
204 if(pd[fault_address >> 22].v == 0) {
205 return 0;
207 pt = (struct ptent *)PHYS_ADDR_TO_P1(pd[fault_address >> 22].ppn << 12);
208 #if CHATTY_TLB
209 dprintf("get_ptent: found ptent 0x%x\n", pt);
210 #endif
212 return &pt[(fault_address >> 12) & 0x000003ff];
215 static void tlb_map(unsigned int vpn, struct ptent *ptent, unsigned int tlb_ent, unsigned int asid)
217 union {
218 struct utlb_data data;
219 unsigned int n[3];
220 } u;
222 ptent->tlb_ent = tlb_ent;
224 u.n[0] = 0;
225 u.data.a.asid = asid;
226 u.data.a.vpn = vpn << 2;
227 u.data.a.dirty = ptent->d;
228 u.data.a.valid = 1;
230 u.n[1] = 0;
231 u.data.da1.ppn = ptent->ppn << 2;
232 u.data.da1.valid = 1;
233 u.data.da1.psize1 = (ptent->sz & 0x2) ? 1 : 0;
234 u.data.da1.prot_key = ptent->pr;
235 u.data.da1.psize0 = ptent->sz & 0x1;
236 u.data.da1.cacheability = ptent->c;
237 u.data.da1.dirty = ptent->d;
238 u.data.da1.sh = ptent->sh;
239 u.data.da1.wt = ptent->wt;
241 u.n[2] = 0;
243 *((unsigned int *)(UTLB | (next_utlb_ent << UTLB_ADDR_SHIFT))) = u.n[0];
244 *((unsigned int *)(UTLB1 | (next_utlb_ent << UTLB_ADDR_SHIFT))) = u.n[1];
245 *((unsigned int *)(UTLB2 | (next_utlb_ent << UTLB_ADDR_SHIFT))) = u.n[2];
248 unsigned int tlb_miss(unsigned int excode, unsigned int pc)
250 struct pdent *pd;
251 struct ptent *ent;
252 unsigned int fault_addr = *(unsigned int *)TEA;
253 unsigned int shifted_fault_addr;
254 unsigned int asid;
256 #if CHATTY_TLB
257 dprintf("tlb_miss: excode 0x%x, pc 0x%x, sgr 0x%x, fault_address 0x%x\n", excode, pc, get_sgr(), fault_addr);
258 #endif
260 // if(fault_addr == 0 || pc == 0 || get_sgr() == 0)
261 // dump_cpu_state();
263 if(fault_addr >= P1_AREA) {
264 pd = (struct pdent *)kernel_struct.kernel_pgdir;
265 asid = kernel_struct.kernel_asid;
266 shifted_fault_addr = fault_addr & 0x7fffffff;
267 } else {
268 pd = (struct pdent *)kernel_struct.user_pgdir;
269 asid = kernel_struct.user_asid;
270 shifted_fault_addr = fault_addr;
273 ent = get_ptent(pd, shifted_fault_addr);
274 if(ent == NULL || ent->v == 0) {
275 if(excode == 0x2)
276 return EXCEPTION_PAGE_FAULT_READ;
277 else
278 return EXCEPTION_PAGE_FAULT_WRITE;
281 #if CHATTY_TLB
282 dprintf("found entry. vaddr 0x%x maps to paddr 0x%x\n",
283 fault_addr, ent->ppn << 12);
284 #endif
287 if(excode == 0x3) {
288 // this is a tlb miss because of a write, so
289 // go ahead and mark it dirty
290 ent->d = 1;
293 #if 0
294 // XXX hack!
295 if(fault_addr == 0x7ffffff8) {
296 dprintf("sr = 0x%x\n", get_sr());
297 dprintf("ssr = 0x%x sgr = 0x%x spc = 0x%x\n", get_ssr(), get_sgr(), get_spc());
298 dprintf("kernel_struct: kpgdir 0x%x upgdir 0x%x kasid 0x%x uasid 0x%x kstack 0x%x\n",
299 kernel_struct.kernel_pgdir, kernel_struct.user_pgdir, kernel_struct.kernel_asid,
300 kernel_struct.user_asid, kernel_struct.kstack);
302 #endif
303 #if 0
305 static int clear_all = 0;
306 if(fault_addr == 0x7ffffff8)
307 clear_all = 1;
308 if(clear_all)
309 vcpu_clear_all_utlb_entries();
311 #endif
313 tlb_map(fault_addr >> 12, ent, next_utlb_ent, asid);
314 #if CHATTY_TLB
315 vcpu_dump_utlb_entry(next_utlb_ent);
316 #endif
317 next_utlb_ent++;
318 if(next_utlb_ent >= UTLB_COUNT)
319 next_utlb_ent = 0;
321 #if CHATTY_TLB
322 dprintf("tlb_miss exit\n");
323 #endif
324 return excode;
327 unsigned int tlb_initial_page_write(unsigned int excode, unsigned int pc)
329 struct pdent *pd;
330 struct ptent *ent;
331 unsigned int fault_addr = *(unsigned int *)TEA;
332 unsigned int shifted_fault_addr;
333 unsigned int asid;
335 #if CHATTY_TLB
336 dprintf("tlb_initial_page_write: excode 0x%x, pc 0x%x, fault_address 0x%x\n",
337 excode, pc, fault_addr);
338 #endif
340 if(fault_addr >= P1_AREA) {
341 pd = (struct pdent *)kernel_struct.kernel_pgdir;
342 asid = kernel_struct.kernel_asid;
343 shifted_fault_addr = fault_addr & 0x7fffffff;
344 } else {
345 pd = (struct pdent *)kernel_struct.user_pgdir;
346 asid = kernel_struct.user_asid;
347 shifted_fault_addr = fault_addr;
350 ent = get_ptent(pd, shifted_fault_addr);
351 if(ent == NULL || ent->v == 0) {
352 // if we're here, the page table is
353 // out of sync with the tlb cache.
354 // time to die.
355 dprintf("tlb_ipw exception called but no page table ent exists!\n");
356 for(;;);
360 struct utlb_addr_array *a;
361 struct utlb_data_array_1 *da1;
363 a = (struct utlb_addr_array *)(UTLB | (ent->tlb_ent << UTLB_ADDR_SHIFT));
364 da1 = (struct utlb_data_array_1 *)(UTLB1 | (ent->tlb_ent << UTLB_ADDR_SHIFT));
366 // inspect this tlb entry to make sure it's the right one
367 if(asid != a->asid || (ent->ppn << 2) != da1->ppn || ((fault_addr >> 12) << 2) != a->vpn) {
368 dprintf("tlb_ipw exception found that the page table out of sync with tlb\n");
369 dprintf("page_table entry: 0x%x\n", *(unsigned int *)ent);
370 vcpu_dump_utlb_entry(ent->tlb_ent);
371 for(;;);
373 a->dirty = 1;
374 ent->d = 1;
377 return excode;
380 void vcpu_dump_itlb_entry(int ent)
382 struct itlb_data data;
384 *(int *)&data.a = *((int *)(ITLB | (ent << ITLB_ADDR_SHIFT)));
385 *(int *)&data.da1 = *((int *)(ITLB1 | (ent << ITLB_ADDR_SHIFT)));
386 *(int *)&data.da2 = *((int *)(ITLB2 | (ent << ITLB_ADDR_SHIFT)));
388 dprintf("itlb[%d] = \n", ent);
389 dprintf(" asid = %d\n", data.a.asid);
390 dprintf(" valid = %d\n", data.a.valid);
391 dprintf(" vpn = 0x%x\n", data.a.vpn << 10);
392 dprintf(" ppn = 0x%x\n", data.da1.ppn << 10);
395 void vcpu_clear_all_itlb_entries()
397 int i;
398 for(i=0; i<4; i++) {
399 *((int *)(ITLB | (i << ITLB_ADDR_SHIFT))) = 0;
400 *((int *)(ITLB1 | (i << ITLB_ADDR_SHIFT))) = 0;
401 *((int *)(ITLB2 | (i << ITLB_ADDR_SHIFT))) = 0;
405 void vcpu_dump_all_itlb_entries()
407 int i;
409 for(i=0; i<4; i++) {
410 vcpu_dump_itlb_entry(i);
414 void vcpu_dump_utlb_entry(int ent)
416 struct utlb_data data;
418 *(int *)&data.a = *((int *)(UTLB | (ent << UTLB_ADDR_SHIFT)));
419 *(int *)&data.da1 = *((int *)(UTLB1 | (ent << UTLB_ADDR_SHIFT)));
420 *(int *)&data.da2 = *((int *)(UTLB2 | (ent << UTLB_ADDR_SHIFT)));
422 dprintf("utlb[%d] = \n", ent);
423 dprintf(" asid = %d\n", data.a.asid);
424 dprintf(" valid = %d\n", data.a.valid);
425 dprintf(" dirty = %d\n", data.a.dirty);
426 dprintf(" vpn = 0x%x\n", data.a.vpn << 10);
427 dprintf(" ppn = 0x%x\n", data.da1.ppn << 10);
430 void vcpu_clear_all_utlb_entries()
432 int i;
433 for(i=0; i<64; i++) {
434 *((int *)(UTLB | (i << UTLB_ADDR_SHIFT))) = 0;
435 *((int *)(UTLB1 | (i << UTLB_ADDR_SHIFT))) = 0;
436 *((int *)(UTLB2 | (i << UTLB_ADDR_SHIFT))) = 0;
440 void vcpu_dump_all_utlb_entries()
442 int i;
444 for(i=0; i<64; i++) {
445 vcpu_dump_utlb_entry(i);