Как восстановить состояние процессора? (восстановление регистров процессора x86_64)

Я реализую переключение контекста для своей первой ОС, и у меня возникла небольшая проблема, которую я не могу решить: восстановление состояния процессора после сохранения его из структуры. Поскольку все регистры должны быть сохранены, я не могу использовать временный регистр. вот моя структура:

#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct CPUStatus {    
    pub rsp: u64,
    pub rflags: u64,
    pub ss: u64,
    pub cs: u64,

    pub rip: u64,
    
    r15: u64,
    r14: u64,
    r13: u64,
    r12: u64,
    r11: u64,
    r10: u64,
    r9: u64,
    r8: u64,

    rbp: u64,
    rdi: u64,
    rsi: u64,

    rdx: u64, 
    rcx: u64,
    rbx: u64,
    rax: u64,
}

мой код сохранения:

    pub extern "C" fn save_inner(self) -> Self {
        self
    }

    pub extern "C" fn save() -> Self {
        unsafe {        
            asm!("
            push rax
            push rbx
            push rcx
            push rdx
            
            push rsi
            push rdi
            push rbp
            
            push r8
            push r9
            push r10
            push r11
            push r12
            push r13
            push r14
            push r15

            push 0
            push 0x8
            push 0x10
            pushfq 
            push 0 // rsp
            call {}
            add rsp, {}
            ret
            ", sym Self::save_inner, const core::mem::size_of::<CPUStatus>() + 8, options(noreturn))
        }
    }

Я попробовал это, очевидно, это дает слишком много регистров, используемых во встроенной ошибке сборки:

pub extern "C" fn restore(self) -> ! {
        unsafe {
            asm!("
            mov rax, {}
            mov rbx, {}
            mov rcx, {}
            mov rdx, {}

            mov rsi, {}
            mov rdi, {}
            mov rbp, {}

            mov r8, {}
            mov r9, {}
            mov r10, {}
            mov r11, {}
            mov r12, {}
            mov r13, {}
            mov r14, {}
            mov r15, {}
            
            mov rsp, {}
            push {}
            popfq
            jmp {}
            ", 
            in(reg) self.rax, 
            in(reg) self.rbx,
            in(reg) self.rcx,
            in(reg) self.rdx,

            in(reg) self.rsi,
            in(reg) self.rdi,
            in(reg) self.rbp,

            in(reg) self.r8,
            in(reg) self.r9,
            in(reg) self.r10,
            in(reg) self.r11,
            in(reg) self.r12,
            in(reg) self.r13,
            in(reg) self.r14,
            in(reg) self.r15,

            in(reg) self.rsp,
            in(reg) self.rflags,            
            in(reg) self.rip, options(noreturn))
        }
 }
}

Как это решить?

Почему бы вам не сделать это в файлах ассемблера .s, где у вас есть полный контроль? Вы смотрели на методы, которые Linux использует для этого? Кстати, в восстановлении лучше нажать обратный адрес и сделать ret.

Tim Roberts 10.08.2024 19:49

я понятия не имею, как взглянуть на методы Linux, tysm для напоминания о повторе, я думаю, что это ключ, я также рассмотрю возможность использования чистого asm или global_asm! вместо этого спасибо!

Roxve 10.08.2024 20:00

Отдельные файлы сборки @TimRoberts не так легко использовать в приложениях Rust, как встроенные сборки Rust. global_asm — хороший способ в данном конкретном случае

Andrey Turkin 11.08.2024 08:23
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
3
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

исправлено с помощью инструкции iretq и global_asm!

global_asm!("
.global restore_cpu_status
restore_cpu_status:
    // push the iretq frame
    push [rdi + 16]     // push ss
    push [rdi]          // push rsp
    push [rdi + 8]      // push rflags
    push [rdi + 24]     // push cs
    push [rdi + 32]     // push rip

    
    mov r15, [rdi + 40]    
    mov r14, [rdi + 48]    
    mov r13, [rdi + 56]    
    mov r12, [rdi + 64]    
    mov r11, [rdi + 72]    
    mov r10, [rdi + 80]    
    mov r9, [rdi + 88]    
    mov r8, [rdi + 96]    

    mov rbp, [rdi + 104]

    mov rsi, [rdi + 120]

    mov rdx, [rdi + 128]
    mov rcx, [rdi + 136]
    mov rbx, [rdi + 144]
    mov rax, [rdi + 152]

    mov rdi, [rdi + 112]

    iretq
");

вот определение функции

extern "C" { pub fn restore_cpu_status(status: &CPUStatus); }

Другие вопросы по теме