2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
5 #include <arch/sh4/vcpu.h>
6 #include <arch/sh4/vcpu_struct.h>
7 #include <boot/stage2.h>
11 #include <arch/sh4/sh4.h>
13 #define SAVE_CPU_STATE 0
15 #define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
19 extern vcpu_struct kernel_struct
;
21 extern unsigned int last_ex_cpu_state
[];
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();
42 ".globl _get_sr,_set_sr\n"
43 ".globl _get_vbr,_set_vbr\n"
83 static void dump_cpu_state()
87 unsigned int *stack_top
;
89 dprintf("dump_cpu_state entry\n");
91 dprintf("registers:\n");
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
);
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();
121 int reentrant_fault()
123 dprintf("bad reentrancy fault\n");
124 dprintf("spinning forever\n");
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");
140 int vcpu_init(kernel_args
*ka
)
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);
155 vbr
= (unsigned int)&vector_base
;
157 dprintf("vbr = 0x%x\n", get_vbr());
159 // disable exceptions
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);
178 ka
->arch_args
.vcpu
= &kernel_struct
;
181 vcpu_clear_all_itlb_entries();
182 vcpu_clear_all_utlb_entries();
184 *(int *)MMUCR
= 0x00000105;
189 static struct ptent
*get_ptent(struct pdent
*pd
, unsigned int fault_address
)
194 dprintf("get_ptent: fault_address 0x%x\n", fault_address
);
197 if((unsigned int)pd
< P1_PHYS_MEM_START
|| (unsigned int)pd
>= P1_PHYS_MEM_END
) {
199 dprintf("get_ptent: bad pdent 0x%x\n", pd
);
204 if(pd
[fault_address
>> 22].v
== 0) {
207 pt
= (struct ptent
*)PHYS_ADDR_TO_P1(pd
[fault_address
>> 22].ppn
<< 12);
209 dprintf("get_ptent: found ptent 0x%x\n", pt
);
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
)
218 struct utlb_data data
;
222 ptent
->tlb_ent
= tlb_ent
;
225 u
.data
.a
.asid
= asid
;
226 u
.data
.a
.vpn
= vpn
<< 2;
227 u
.data
.a
.dirty
= ptent
->d
;
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
;
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
)
252 unsigned int fault_addr
= *(unsigned int *)TEA
;
253 unsigned int shifted_fault_addr
;
257 dprintf("tlb_miss: excode 0x%x, pc 0x%x, sgr 0x%x, fault_address 0x%x\n", excode
, pc
, get_sgr(), fault_addr
);
260 // if(fault_addr == 0 || pc == 0 || get_sgr() == 0)
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;
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) {
276 return EXCEPTION_PAGE_FAULT_READ
;
278 return EXCEPTION_PAGE_FAULT_WRITE
;
282 dprintf("found entry. vaddr 0x%x maps to paddr 0x%x\n",
283 fault_addr
, ent
->ppn
<< 12);
288 // this is a tlb miss because of a write, so
289 // go ahead and mark it dirty
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
);
305 static int clear_all
= 0;
306 if(fault_addr
== 0x7ffffff8)
309 vcpu_clear_all_utlb_entries();
313 tlb_map(fault_addr
>> 12, ent
, next_utlb_ent
, asid
);
315 vcpu_dump_utlb_entry(next_utlb_ent
);
318 if(next_utlb_ent
>= UTLB_COUNT
)
322 dprintf("tlb_miss exit\n");
327 unsigned int tlb_initial_page_write(unsigned int excode
, unsigned int pc
)
331 unsigned int fault_addr
= *(unsigned int *)TEA
;
332 unsigned int shifted_fault_addr
;
336 dprintf("tlb_initial_page_write: excode 0x%x, pc 0x%x, fault_address 0x%x\n",
337 excode
, pc
, fault_addr
);
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;
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.
355 dprintf("tlb_ipw exception called but no page table ent exists!\n");
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
);
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()
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()
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()
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()
444 for(i
=0; i
<64; i
++) {
445 vcpu_dump_utlb_entry(i
);