Я реализую переключение контекста для своей первой ОС, и у меня возникла небольшая проблема, которую я не могу решить: восстановление состояния процессора после сохранения его из структуры. Поскольку все регистры должны быть сохранены, я не могу использовать временный регистр. вот моя структура:
#[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))
}
}
}
Как это решить?
я понятия не имею, как взглянуть на методы Linux, tysm для напоминания о повторе, я думаю, что это ключ, я также рассмотрю возможность использования чистого asm или global_asm! вместо этого спасибо!
Отдельные файлы сборки @TimRoberts не так легко использовать в приложениях Rust, как встроенные сборки Rust. global_asm
— хороший способ в данном конкретном случае
исправлено с помощью инструкции 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); }
Почему бы вам не сделать это в файлах ассемблера
.s
, где у вас есть полный контроль? Вы смотрели на методы, которые Linux использует для этого? Кстати, в восстановлении лучше нажать обратный адрес и сделатьret
.