How can I set cpu state by saving cpu registers values?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
gamingjam60
Posts: 20
Joined: Sat Aug 24, 2024 10:06 pm
Libera.chat IRC: gamingjam60
Location: India
GitHub: https://github.com/baponkar
Contact:

How can I set cpu state by saving cpu registers values?

Post by gamingjam60 »

Here my plan is changing cpu state by some process so I have written following assembly code ,

Code: Select all

global restore_cpu_state

restore_cpu_state:
    mov r15, rdi           ; Save original rdi in r15

    mov rax, [r15 + 8*0]   ; Load gs
    mov gs, ax
    mov rax, [r15 + 8*1]   ; Load fs
    mov fs, ax
    mov rax, [r15 + 8*2]   ; Load es
    mov es, ax
    mov rax, [r15 + 8*3]   ; Load ds
    mov ds, ax

    ; Restore general-purpose registers
    mov rax, [r15 + 8*4]   ; Restore rax
    mov rbx, [r15 + 8*5]   ; Restore rbx
    mov rcx, [r15 + 8*6]   ; Restore rcx
    mov rdx, [r15 + 8*7]   ; Restore rdx
    mov rbp, [r15 + 8*8]   ; Restore rbp
    mov rdi, [r15 + 8*9]   ; Restore rdi
    mov rsi, [r15 + 8*10]  ; Restore rsi
    mov r8,  [r15 + 8*11]  ; Restore r8
    mov r9,  [r15 + 8*12]  ; Restore r9
    mov r10, [r15 + 8*13]  ; Restore r10
    mov r11, [r15 + 8*14]  ; Restore r11
    mov r12, [r15 + 8*15]  ; Restore r12
    mov r13, [r15 + 8*16]  ; Restore r13
    mov r14, [r15 + 8*17]  ; Restore r14
    mov r15, [r15 + 8*18]  ; Restore r15 (AFTER using it to hold rdi)

    ; Skip int_no (8*19) and err_code (8*20)
    add rdi, 8*21          ; Use rdi again safely

    ; Restore the stack frame for iretq
    mov rax, [rdi + 8*0]   ; Load iret_rip
    mov rcx, [rdi + 8*1]   ; Load iret_cs
    mov rdx, [rdi + 8*2]   ; Load iret_rflags
    mov rbx, [rdi + 8*3]   ; Load iret_rsp
    mov rbp, [rdi + 8*4]   ; Load iret_ss

    ; Push onto stack for iretq
    push rbp
    push rbx
    push rdx
    push rcx
    push rax

    iretq   ; Restore full CPU state and return
As registers_t have rdi value so First I am taking original rdi into r15 temporarily which is containing whole registers_t structure into rdi then storing all other registers value from there including new rdi value. It is some foggy to me as iret_rip, iret_cs, iret_rflags, iret_rsp and iret_ss as those values is storing in reference of new rdi value although the registers_t structure also have those registers_t values. Is it good or I need to change it with registers_t values of corresponding registers and after that I have permission to update r15 by mov r15, [r15 + 8*18] ; .

where registers_t structure is define follwoing way

Code: Select all

struct registers { // Total 26*8 = 208 bytes, 16 bytes aligned
    // Segment registers
    uint64_t gs;            // Offset 8*0
    uint64_t fs;            // Offset 8*1
    uint64_t es;            // Offset 8*2
    uint64_t ds;            // Offset 8*3

    // General purpose registers
    uint64_t rax;           // Offset 8*4
    uint64_t rbx;           // Offset 8*5
    uint64_t rcx;           // Offset 8*6
    uint64_t rdx;           // Offset 8*7
    uint64_t rbp;           // Offset 8*8
    uint64_t rdi;           // Offset 8*9
    uint64_t rsi;           // Offset 8*10
    uint64_t r8;            // Offset 8*11
    uint64_t r9;            // Offset 8*12
    uint64_t r10;           // Offset 8*13
    uint64_t r11;           // Offset 8*14
    uint64_t r12;           // Offset 8*15
    uint64_t r13;           // Offset 8*16
    uint64_t r14;           // Offset 8*17
    uint64_t r15;           // Offset 8*18

    uint64_t int_no;        // Offset 8*19
    uint64_t err_code;      // Offset 8*20

    // Interrupt return CPU state registers value
    uint64_t iret_rip;      // Offset 8*21
    uint64_t iret_cs;       // Offset 8*22
    uint64_t iret_rflags;   // Offset 8*23
    uint64_t iret_rsp;      // Offset 8*24
    uint64_t iret_ss;       // Offset 8*25
    
} __attribute__((packed));
typedef struct registers registers_t;

but when I am trying to use the restore_cpu_state(new_regs); is causing General Protection fault by following output

Code: Select all

recieved interrupt: 13
General protection fault (pushes an error code)
Error Code: 0xA5E4
CS: 0x8, RIP : 0xFFFFFFFF80006CF9
Stack Contents:
  [0xFFFF80007FF4FE70] = 0x0
  [0xFFFF80007FF4FE78] = 0xFFFFFFFF8000A5E6
  [0xFFFF80007FF4FE80] = 0x8
  [0xFFFF80007FF4FE88] = 0x2
  [0xFFFF80007FF4FE90] = 0xFFFF80007FF4FEA8
  [0xFFFF80007FF4FE98] = 0x10
  [0xFFFF80007FF4FEA0] = 0xFFFF80007FF4FED0
  [0xFFFF80007FF4FEA8] = 0xFFFFFFFF80009587
  [0xFFFF80007FF4FEB0] = 0x3000000010
  [0xFFFF80007FF4FEB8] = 0xFFFF80007FF4FF10
  [0xFFFF80007FF4FEC0] = 0x3000000030
  [0xFFFF80007FF4FEC8] = 0xFFFFFFFF80329000
  [0xFFFF80007FF4FED0] = 0xFFFF80007FF4FF00
  [0xFFFF80007FF4FED8] = 0xFFFFFFFF800065C2
  [0xFFFF80007FF4FEE0] = 0xFFFFFFFF8000D28F
  [0xFFFF80007FF4FEE8] = 0xFFFF80007FF4FF10
  [0xFFFF80007FF4FEF0] = 0x3
  [0xFFFF80007FF4FEF8] = 0xFFFFFFFF8000951A
  [0xFFFF80007FF4FF00] = 0xFFFF80007FF4FFE0
  [0xFFFF80007FF4FF08] = 0xFFFFFFFF800073D1
  [0xFFFF80007FF4FF10] = 0x10
  [0xFFFF80007FF4FF18] = 0x10
  [0xFFFF80007FF4FF20] = 0xFFFFFFFF80320010
  [0xFFFF80007FF4FF28] = 0xFFFFFFFF80320010
  [0xFFFF80007FF4FF30] = 0xFFFFFFFF8032E000
  [0xFFFF80007FF4FF38] = 0x0
System Halted!
Full code is in https://github.com/baponkar/KeblaOS/blo ... _state.asm

It will be very helpful to get any suggestion to fix the problem. Thankyou. =D>
Octocontrabass
Member
Member
Posts: 5671
Joined: Mon Mar 25, 2013 7:01 pm

Re: How can I set cpu state by saving cpu registers values?

Post by Octocontrabass »

A typical OS has one kernel stack per thread. To switch tasks, you switch kernel stacks. There's a pretty good example on the wiki.
Post Reply