/* ** hypervisor:kernel - low level world manipulation */ .section .gint.mapped, "ax" .align 2 .global _hypervisor_kernel_abi .global _hypervisor_kernel_world_switch /* hypervisor_kernel_abi(): Kernel ABI entry */ _hypervisor_kernel_abi: /* check trapa validity */ mov.l abi_trapa_reg, r1 mov.l @r1, r1 shlr2 r1 mov #1, r2 cmp/hi r1, r2 bf abi_error /* involve syscall if possible */ shll2 r1 mova abi_syscall_table, r0 mov.l @(r0, r1), r3 tst r3, r3 bt abi_error jmp @r3 nop /* error handling */ abi_error: mov #-1, r0 ldc r0, R0_BANK rte nop .align 4 abi_trapa_reg: .long 0xff000020 abi_syscall_table: .long _hypervisor_kernel_world_switch .long 0x00000000 ! _hypervisor_kernel_schedule /* hypervisor world_switch(struct hworld *world): Performs a world switch This hypervisor call will check the world validity then it will save the current world environment information, install the new world then perform an world switch. */ _hypervisor_kernel_world_switch: /* enable exception but block all interruption */ mov.l sr_ws_config, r0 stc sr, r1 or r0, r1 ldc r1, sr /* check potential error */ stc R4_BANK, r4 tst r4, r4 bt kernel_world_error mov.l hypervisor_world_current, r5 mov.l @r5, r5 tst r5, r5 bt kernel_world_error /* switch stack (user -> kernel) */ mov.l r15, @r5 mov.l @(4, r5), r15 /* save the current context */ sts.l pr, @-r15 mov.l r4, @-r15 mov.l r5, @-r15 mov.l drivers_context_save, r0 jsr @r0 mov.l @(8, r5), r4 mov.l @r15+, r5 mov.l @r15+, r4 lds.l @r15+, pr /* switch stack (kernel -> user) */ mov.l r15, @(4, r5) mov.l @r5, r15 /* save cpu context */ add #100, r5 sts.l pr, @-r5 stc.l spc, @-r5 stc.l ssr, @-r5 sts.l mach, @-r5 sts.l macl, @-r5 stc.l gbr, @-r5 mov.l r15, @-r5 mov.l r14, @-r5 mov.l r13, @-r5 mov.l r12, @-r5 mov.l r11, @-r5 mov.l r10, @-r5 mov.l r9, @-r5 mov.l r8, @-r5 stc.l R7_BANK, @-r5 stc.l R6_BANK, @-r5 stc.l R5_BANK, @-r5 stc.l R4_BANK, @-r5 stc.l R3_BANK, @-r5 stc.l R2_BANK, @-r5 stc.l R1_BANK, @-r5 stc.l R0_BANK, @-r5 /* restore cpu context */ add #12, r4 ldc.l @r4+, R0_BANK ldc.l @r4+, R1_BANK ldc.l @r4+, R2_BANK ldc.l @r4+, R3_BANK ldc.l @r4+, R4_BANK ldc.l @r4+, R5_BANK ldc.l @r4+, R6_BANK ldc.l @r4+, R7_BANK mov.l @r4+, r8 mov.l @r4+, r9 mov.l @r4+, r10 mov.l @r4+, r11 mov.l @r4+, r12 mov.l @r4+, r13 mov.l @r4+, r14 mov.l @r4+, r15 ldc.l @r4+, gbr lds.l @r4+, macl lds.l @r4+, mach ldc.l @r4+, ssr ldc.l @r4+, spc lds.l @r4+, pr /* switch stack (user -> kernel) */ add #-100, r4 mov.l r15, @r4 mov.l @(4, r4), r15 /* indicate that the world has changed */ mov.l hypervisor_world_current, r0 mov.l r4, @r0 /* save the current context Note that the SR register can be restored. So, interruption / exceptions can occur during this lack of time between JSR and the resotoration of the SR register. */ stc.l ssr, @-r15 stc.l spc, @-r15 sts.l pr, @-r15 mov.l r4, @-r15 stc.l sr, @-r15 mov.l drivers_context_restore, r0 jsr @r0 mov.l @(8, r4), r4 ldc.l @r15+, sr mov.l @r15+, r4 lds.l @r15+, pr ldc.l @r15+, spc ldc.l @r15+, ssr /* switch stack (kernel -> user) */ mov.l r15, @(4, r4) mov.l @r4, r15 /* force hypervisor VBR re-installation, because it possible that the VBR has been changed during the handler */ mov.l hypervisor_vbr_redirect, r0 mov.l hypervisor_vbr, r1 stc vbr, r2 mov.l r2, @r0 ldc.l @r1+, vbr /* perform the world switch */ rte nop kernel_world_error: rts mov #-2, r0 .align 4 sr_ws_config: .long 0x600000f0 !wswitch_debug: .long _wswitch_debug hypervisor_vbr: .long _hypervisor_vbr hypervisor_vbr_redirect: .long _hypervisor_vbr_redirect hypervisor_world_current: .long _hypervisor_world_current drivers_context_save: .long _drivers_save drivers_context_restore: .long _drivers_restore