Support proc partially with aarch64

This commit is contained in:
Jeremy Soller
2022-08-20 14:45:45 -06:00
parent 9b8abfc5d7
commit 9dd069c8ca
3 changed files with 141 additions and 80 deletions

View File

@@ -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 }

View File

@@ -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.

View File

@@ -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>())
}
},