fxBoot/src/hypervisor/kernel.S

190 lines
3.8 KiB
ArmAsm

/*
** 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