Support proc partially with aarch64
This commit is contained in:
@@ -165,6 +165,48 @@ impl InterruptStack {
|
||||
all.x1 = self.scratch.x1;
|
||||
all.x0 = self.scratch.x0;
|
||||
}
|
||||
|
||||
/// Loads all registers from a struct used by the proc:
|
||||
/// scheme to read/write registers.
|
||||
pub fn load(&mut self, all: &IntRegisters) {
|
||||
self.iret.elr_el1 = all.elr_el1;
|
||||
self.iret.tpidr_el0 = all.tpidr_el0;
|
||||
self.iret.tpidrro_el0 = all.tpidrro_el0;
|
||||
self.iret.spsr_el1 = all.spsr_el1;
|
||||
self.iret.esr_el1 = all.esr_el1;
|
||||
self.iret.sp_el0 = all.sp_el0;
|
||||
self.preserved.x30 = all.x30;
|
||||
self.preserved.x29 = all.x29;
|
||||
self.preserved.x28 = all.x28;
|
||||
self.preserved.x27 = all.x27;
|
||||
self.preserved.x26 = all.x26;
|
||||
self.preserved.x25 = all.x25;
|
||||
self.preserved.x24 = all.x24;
|
||||
self.preserved.x23 = all.x23;
|
||||
self.preserved.x22 = all.x22;
|
||||
self.preserved.x21 = all.x21;
|
||||
self.preserved.x20 = all.x20;
|
||||
self.preserved.x19 = all.x19;
|
||||
self.scratch.x18 = all.x18;
|
||||
self.scratch.x17 = all.x17;
|
||||
self.scratch.x16 = all.x16;
|
||||
self.scratch.x15 = all.x15;
|
||||
self.scratch.x14 = all.x14;
|
||||
self.scratch.x13 = all.x13;
|
||||
self.scratch.x12 = all.x12;
|
||||
self.scratch.x11 = all.x11;
|
||||
self.scratch.x10 = all.x10;
|
||||
self.scratch.x9 = all.x9;
|
||||
self.scratch.x8 = all.x8;
|
||||
self.scratch.x7 = all.x7;
|
||||
self.scratch.x6 = all.x6;
|
||||
self.scratch.x5 = all.x5;
|
||||
self.scratch.x4 = all.x4;
|
||||
self.scratch.x3 = all.x3;
|
||||
self.scratch.x2 = all.x2;
|
||||
self.scratch.x1 = all.x1;
|
||||
self.scratch.x0 = all.x0;
|
||||
}
|
||||
|
||||
//TODO
|
||||
pub fn is_singlestep(&self) -> bool { false }
|
||||
|
||||
@@ -208,6 +208,16 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Context {
|
||||
pub fn get_fx_regs(&self) -> FloatRegisters {
|
||||
self.arch.get_fx_regs().expect("TODO: make get_fx_regs always valid")
|
||||
}
|
||||
|
||||
pub fn set_fx_regs(&mut self, mut new: FloatRegisters) {
|
||||
assert!(self.arch.set_fx_regs(new), "TODO: make set_fx_regs always valid")
|
||||
}
|
||||
}
|
||||
|
||||
pub static EMPTY_CR3: Once<rmm::PhysicalAddress> = Once::new();
|
||||
|
||||
// SAFETY: EMPTY_CR3 must be initialized.
|
||||
|
||||
@@ -397,6 +397,93 @@ impl ProcScheme {
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
fn read_env_regs(&self) -> Result<EnvRegisters> {
|
||||
//TODO: Support other archs
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn read_env_regs(&self) -> Result<EnvRegisters> {
|
||||
let (fsbase, gsbase) = if info.pid == context::context_id() {
|
||||
#[cfg(not(feature = "x86_fsgsbase"))]
|
||||
unsafe {
|
||||
(
|
||||
x86::msr::rdmsr(x86::msr::IA32_FS_BASE),
|
||||
x86::msr::rdmsr(x86::msr::IA32_KERNEL_GSBASE),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "x86_fsgsbase")]
|
||||
unsafe {
|
||||
use x86::bits64::segmentation::*;
|
||||
|
||||
(
|
||||
rdfsbase(),
|
||||
{
|
||||
swapgs();
|
||||
let gsbase = rdgsbase();
|
||||
swapgs();
|
||||
gsbase
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
try_stop_context(info.pid, |context| {
|
||||
Ok((context.arch.fsbase as u64, context.arch.gsbase as u64))
|
||||
})?
|
||||
};
|
||||
Ok(EnvRegisters { fsbase: fsbase as _, gsbase: gsbase as _ })
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
fn write_env_regs(&self, regs: EnvRegisters) -> Result<()> {
|
||||
//TODO: Support other archs
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn write_env_regs(&self, regs: EnvRegisters) -> Result<()> {
|
||||
if !(RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize)) && RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize))) {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
if info.pid == context::context_id() {
|
||||
#[cfg(not(feature = "x86_fsgsbase"))]
|
||||
unsafe {
|
||||
x86::msr::wrmsr(x86::msr::IA32_FS_BASE, regs.fsbase as u64);
|
||||
// We have to write to KERNEL_GSBASE, because when the kernel returns to
|
||||
// userspace, it will have executed SWAPGS first.
|
||||
x86::msr::wrmsr(x86::msr::IA32_KERNEL_GSBASE, regs.gsbase as u64);
|
||||
|
||||
match context::contexts().current().ok_or(Error::new(ESRCH))?.write().arch {
|
||||
ref mut arch => {
|
||||
arch.fsbase = regs.fsbase as usize;
|
||||
arch.gsbase = regs.gsbase as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "x86_fsgsbase")]
|
||||
unsafe {
|
||||
use x86::bits64::segmentation::*;
|
||||
|
||||
wrfsbase(regs.fsbase);
|
||||
swapgs();
|
||||
wrgsbase(regs.gsbase);
|
||||
swapgs();
|
||||
|
||||
// No need to update the current context; with fsgsbase enabled, these
|
||||
// registers are automatically saved and restored.
|
||||
}
|
||||
} else {
|
||||
try_stop_context(info.pid, |context| {
|
||||
context.arch.fsbase = regs.fsbase as usize;
|
||||
context.arch.gsbase = regs.gsbase as usize;
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for ProcScheme {
|
||||
@@ -497,13 +584,6 @@ impl Scheme for ProcScheme {
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
//TODO: support other archs
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// Don't hold a global lock during the context switch later on
|
||||
let info = {
|
||||
@@ -598,34 +678,7 @@ impl Scheme for ProcScheme {
|
||||
}
|
||||
})?,
|
||||
RegsKind::Env => {
|
||||
let (fsbase, gsbase) = if info.pid == context::context_id() {
|
||||
#[cfg(not(feature = "x86_fsgsbase"))]
|
||||
unsafe {
|
||||
(
|
||||
x86::msr::rdmsr(x86::msr::IA32_FS_BASE),
|
||||
x86::msr::rdmsr(x86::msr::IA32_KERNEL_GSBASE),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "x86_fsgsbase")]
|
||||
unsafe {
|
||||
use x86::bits64::segmentation::*;
|
||||
|
||||
(
|
||||
rdfsbase(),
|
||||
{
|
||||
swapgs();
|
||||
let gsbase = rdgsbase();
|
||||
swapgs();
|
||||
gsbase
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
try_stop_context(info.pid, |context| {
|
||||
Ok((context.arch.fsbase as u64, context.arch.gsbase as u64))
|
||||
})?
|
||||
};
|
||||
(Output { env: EnvRegisters { fsbase: fsbase as _, gsbase: gsbase as _ }}, mem::size_of::<EnvRegisters>())
|
||||
(Output { env: self.read_env_regs()? }, mem::size_of::<EnvRegisters>())
|
||||
}
|
||||
};
|
||||
|
||||
@@ -709,13 +762,6 @@ impl Scheme for ProcScheme {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
|
||||
//TODO: support other archs
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
|
||||
// Don't hold a global lock during the context switch later on
|
||||
let info = {
|
||||
@@ -843,44 +889,7 @@ impl Scheme for ProcScheme {
|
||||
let regs = unsafe {
|
||||
*(buf as *const _ as *const EnvRegisters)
|
||||
};
|
||||
if !(RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize)) && RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize))) {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
if info.pid == context::context_id() {
|
||||
#[cfg(not(feature = "x86_fsgsbase"))]
|
||||
unsafe {
|
||||
x86::msr::wrmsr(x86::msr::IA32_FS_BASE, regs.fsbase as u64);
|
||||
// We have to write to KERNEL_GSBASE, because when the kernel returns to
|
||||
// userspace, it will have executed SWAPGS first.
|
||||
x86::msr::wrmsr(x86::msr::IA32_KERNEL_GSBASE, regs.gsbase as u64);
|
||||
|
||||
match context::contexts().current().ok_or(Error::new(ESRCH))?.write().arch {
|
||||
ref mut arch => {
|
||||
arch.fsbase = regs.fsbase as usize;
|
||||
arch.gsbase = regs.gsbase as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "x86_fsgsbase")]
|
||||
unsafe {
|
||||
use x86::bits64::segmentation::*;
|
||||
|
||||
wrfsbase(regs.fsbase);
|
||||
swapgs();
|
||||
wrgsbase(regs.gsbase);
|
||||
swapgs();
|
||||
|
||||
// No need to update the current context; with fsgsbase enabled, these
|
||||
// registers are automatically saved and restored.
|
||||
}
|
||||
} else {
|
||||
try_stop_context(info.pid, |context| {
|
||||
context.arch.fsbase = regs.fsbase as usize;
|
||||
context.arch.gsbase = regs.gsbase as usize;
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
self.write_env_regs(regs)?;
|
||||
Ok(mem::size_of::<EnvRegisters>())
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user