switching.zig (3132B)
1 // Heavenly Guide, 2 // 3 // We come before you with a prayer for luck and success in our switching journey. 4 // Grant us the opportunities and experiences that foster our spiritual and 5 // emotional development. 6 // 7 // May we embrace challenges as opportunities for growth and self-improvement. 8 // Lead us on a path of self-discovery and fulfillment, knowing that true success 9 // lies in becoming the best versions of ourselves. 10 // 11 // In your guidance, we find switching. 12 // 13 // Amen. 14 // TODO; write this in Holy C 15 const interrupts = @import("./interrupts.zig"); 16 17 // TODO; maybe this should also generate the extern? 18 pub fn mk_fn(name: []const u8, body: []const u8) []const u8 { 19 return "" ++ 20 ".global " ++ name ++ "\n" ++ 21 ".type " ++ name ++ ", %function\n" ++ 22 name ++ ":\n" ++ body; 23 } 24 25 comptime { 26 // r0 - current registers 27 // r1 - new registers 28 // r2 - function 29 // 30 // Store current registers/PSR 31 // Call function 32 // Find God and Pray 33 // We modify PC to the return statement to 34 // allow returning back as if nothing happened 35 asm (mk_fn("switch_state_inner", 36 \\ stm r0, {r0-r14} 37 \\ str lr, [r0, #60] 38 \\ mrs r3, cpsr 39 \\ str r3, [r0, #64] 40 \\ // ldr r3, [r1, #64] 41 \\ // msr cpsr_cxsf, r3 42 \\ mov r0, r1 43 \\ blx r2 44 )); 45 46 // Just restore state, don't preserve current 47 // Treat the new registers as the stack 48 // Copy "stack" into registers (user) 49 // Collapse stack 50 // Treat as exception return 51 asm (mk_fn("restore_state_user", 52 \\ mov sp, r0 53 \\ ldm sp, {r0-r14}^ 54 \\ add sp, sp, #60 55 \\ rfeia sp 56 )); 57 58 // Restore the PSR 59 // Flush prefetch 60 // Load all registers (including PC) 61 asm (mk_fn("restore_state_privileged", 62 \\ ldr r1, [r0, #64] 63 \\ msr cpsr_cxsf, r1 64 \\ mov r2, #0 65 \\ mcr p15, 0, r2, c7, c5, 4 66 \\ ldm r0, {r0-r15} 67 )); 68 69 // Jump to lr and put sp 70 // r0 - lr 71 // r1 - sp 72 // r2 - r0 73 asm (mk_fn("jump", 74 \\ mov sp, r1 75 \\ mov lr, r0 76 \\ mov r0, r2 77 \\ bx lr 78 )); 79 } 80 81 extern fn switch_state_inner(old: *interrupts.Registers, new: *const interrupts.Registers, *const fn (*interrupts.Registers) callconv(.c) void) void; 82 pub extern fn restore_state_user(state: *const interrupts.Registers) noreturn; 83 pub extern fn restore_state_privileged(state: *const interrupts.Registers) noreturn; 84 pub extern fn jump(lr: u32, sp: u32, r0: u32) noreturn; 85 86 pub inline fn switch_state(old: *interrupts.Registers, new: *const interrupts.Registers) void { 87 if (new.psr.mode == .User) { 88 switch_state_inner(old, new, restore_state_user); 89 } else { 90 switch_state_inner(old, new, restore_state_privileged); 91 } 92 } 93 94 pub inline fn restore_state(state: *const interrupts.Registers) void { 95 if (state.psr.mode == .User) { 96 restore_state_user(state); 97 } else { 98 restore_state_privileged(state); 99 } 100 }