sylveos

Toy Operating System
Log | Files | Refs

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 }