Replace iopl with either empty or full PIO bitmap.

This commit is contained in:
4lDO2
2024-03-17 14:33:29 +01:00
parent de137fe58d
commit d62aada7ad
7 changed files with 67 additions and 41 deletions
Generated
+1 -1
View File
@@ -225,7 +225,7 @@ checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7"
[[package]]
name = "redox_syscall"
version = "0.5.0"
version = "0.5.1"
dependencies = [
"bitflags 2.4.2",
]
+12 -5
View File
@@ -124,9 +124,11 @@ const BASE_GDT: [GdtEntry; 9] = [
pub struct ProcessorControlRegion {
pub self_ref: usize,
pub user_rsp_tmp: usize,
pub tss: TssWrapper,
pub gdt: [GdtEntry; 9],
percpu: crate::percpu::PercpuBlock,
pub tss: TssWrapper,
pub pio_bitmap: [u8; 8192],
pub all_ones: u8,
}
// NOTE: Despite not using #[repr(packed)], we do know that while there may be some padding
@@ -154,6 +156,9 @@ pub unsafe fn set_tss_stack(stack: usize) {
addr_of_mut!((*pcr()).tss.0.ss0).write((GDT_KERNEL_DATA << 3) as u16);
addr_of_mut!((*pcr()).tss.0.esp0).write(stack as u32);
}
pub unsafe fn set_userspace_io_allowed(allowed: bool) {
addr_of_mut!((*pcr()).tss.0.iobp_offset).write(if allowed { mem::size_of::<TaskStateSegment>() as u16 } else { 0xFFFF });
}
/// Initialize a minimal GDT without configuring percpu.
pub unsafe fn init() {
@@ -174,7 +179,7 @@ pub unsafe fn init() {
/// Initialize GDT and configure percpu.
pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
let pcr_frame = crate::memory::allocate_frames(1).expect("failed to allocate PCR frame");
let pcr_frame = crate::memory::allocate_frames(mem::size_of::<ProcessorControlRegion>().div_ceil(PAGE_SIZE)).expect("failed to allocate PCR frame");
let pcr =
&mut *(RmmA::phys_to_virt(pcr_frame.start_address()).data() as *mut ProcessorControlRegion);
@@ -188,10 +193,12 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
};
{
pcr.all_ones = 0xFF;
pcr.tss.0.iobp_offset = 0xFFFF;
let tss = &pcr.tss.0 as *const _ as usize as u32;
pcr.gdt[GDT_TSS].set_offset(tss);
pcr.gdt[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32);
pcr.gdt[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32 + 8192);
}
// Load the new GDT, which is correctly located in thread local storage.
@@ -203,8 +210,8 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
segmentation::load_es(SegmentSelector::new(GDT_USER_DATA as u16, Ring::Ring3));
segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0));
// TODO: Use FS for kernel TLS on i686?
segmentation::load_fs(SegmentSelector::new(GDT_USER_FS as u16, Ring::Ring3));
// TODO: Use FS for kernel percpu on i686?
segmentation::load_fs(SegmentSelector::new(GDT_USER_FS as u16, Ring::Ring0));
segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_PERCPU as u16, Ring::Ring0));
// Set the stack pointer to use when coming back from userspace.
+21 -8
View File
@@ -1,11 +1,11 @@
//! Global descriptor table
use core::{convert::TryInto, mem, cell::{Cell, RefCell}};
use core::{cell::{Cell, RefCell}, convert::TryInto, mem::{self, size_of}};
use core::sync::atomic::AtomicBool;
use crate::{
cpu_set::LogicalCpuId,
paging::{RmmA, RmmArch},
paging::{RmmA, RmmArch, PAGE_SIZE},
percpu::PercpuBlock,
};
@@ -43,6 +43,8 @@ pub const GDT_F_PAGE_SIZE: u8 = 1 << 7;
pub const GDT_F_PROTECTED_MODE: u8 = 1 << 6;
pub const GDT_F_LONG_MODE: u8 = 1 << 5;
const IOBITMAP_SIZE: u32 = 65536 / 8;
static mut INIT_GDT: [GdtEntry; 3] = [
// Null
GdtEntry::new(0, 0, 0, 0),
@@ -114,12 +116,13 @@ pub struct ProcessorControlRegion {
pub self_ref: usize,
pub user_rsp_tmp: usize,
// TODO: The I/O permissions bitmap can require more than 8192 bytes of space.
pub tss: TaskStateSegment,
// The GDT *must* be stored in the PCR! The paranoid interrupt handler, lacking a reliable way
// to correctly obtain GSBASE, uses SGDT to calculate the PCR offset.
pub gdt: [GdtEntry; 8],
pub percpu: PercpuBlock,
pub tss: TaskStateSegment,
pub iobitmap: [u8; IOBITMAP_SIZE as usize],
pub all_ones: u8,
}
const _: () = {
@@ -154,13 +157,22 @@ pub unsafe fn set_tss_stack(pcr: *mut ProcessorControlRegion, stack: usize) {
core::ptr::addr_of_mut!((*pcr).tss.rsp[0]).write_unaligned(stack as u64);
}
pub unsafe fn set_userspace_io_allowed(pcr: *mut ProcessorControlRegion, allowed: bool) {
let offset = if allowed {
u16::try_from(size_of::<TaskStateSegment>()).unwrap()
} else {
0xFFFF
};
core::ptr::addr_of_mut!((*pcr).tss.iomap_base).write(offset);
}
// Initialize startup GDT
#[cold]
pub unsafe fn init() {
// Before the kernel can remap itself, it needs to switch to a GDT it controls. Start with a
// minimal kernel-only GDT.
dtables::lgdt(&DescriptorTablePointer {
limit: (INIT_GDT.len() * mem::size_of::<GdtEntry>() - 1) as u16,
limit: (INIT_GDT.len() * size_of::<GdtEntry>() - 1) as u16,
base: INIT_GDT.as_ptr() as *const SegmentDescriptor,
});
@@ -183,7 +195,7 @@ unsafe fn load_segments() {
/// Initialize GDT and PCR.
#[cold]
pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
let pcr_frame = crate::memory::allocate_frames(1).expect("failed to allocate PCR");
let pcr_frame = crate::memory::allocate_frames(size_of::<ProcessorControlRegion>().div_ceil(PAGE_SIZE)).expect("failed to allocate PCR");
let pcr =
&mut *(RmmA::phys_to_virt(pcr_frame.start_address()).data() as *mut ProcessorControlRegion);
@@ -192,7 +204,7 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
// Setup the GDT.
pcr.gdt = BASE_GDT;
let limit = (pcr.gdt.len() * mem::size_of::<GdtEntry>() - 1)
let limit = (pcr.gdt.len() * size_of::<GdtEntry>() - 1)
.try_into()
.expect("main GDT way too large");
let base = pcr.gdt.as_ptr() as *const SegmentDescriptor;
@@ -201,13 +213,14 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
{
pcr.tss.iomap_base = 0xFFFF;
pcr.all_ones = 0xFF;
let tss = &mut pcr.tss as *mut TaskStateSegment as usize as u64;
let tss_lo = (tss & 0xFFFF_FFFF) as u32;
let tss_hi = (tss >> 32) as u32;
pcr.gdt[GDT_TSS].set_offset(tss_lo);
pcr.gdt[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32);
pcr.gdt[GDT_TSS].set_limit(size_of::<TaskStateSegment>() as u32 + IOBITMAP_SIZE);
(&mut pcr.gdt[GDT_TSS_HIGH] as *mut GdtEntry)
.cast::<u32>()
+12
View File
@@ -49,6 +49,7 @@ pub struct Context {
/// running. With fsgsbase, this is neither saved nor restored upon every syscall (there is no
/// need to!), and thus it must be re-read from the register before copying this struct.
pub(crate) gsbase: usize,
userspace_io_allowed: bool,
}
impl Context {
@@ -62,6 +63,7 @@ impl Context {
esp: 0,
fsbase: 0,
gsbase: 0,
userspace_io_allowed: false,
}
}
@@ -101,6 +103,15 @@ impl super::Context {
self.kfx.as_mut_ptr().cast::<FloatRegisters>().write(new);
}
}
pub fn set_userspace_io_allowed(&mut self, allowed: bool) {
self.arch.userspace_io_allowed = allowed;
if self.id == super::context_id() {
unsafe {
crate::gdt::set_userspace_io_allowed(allowed);
}
}
}
}
pub static EMPTY_CR3: Once<rmm::PhysicalAddress> = Once::new();
@@ -116,6 +127,7 @@ pub unsafe fn switch_to(prev: &mut super::Context, next: &mut super::Context) {
if let Some(ref stack) = next.kstack {
crate::gdt::set_tss_stack(stack.as_ptr() as usize + stack.len());
}
crate::gdt::set_userspace_io_allowed(next.arch.userspace_io_allowed);
core::arch::asm!("
fxsave [{prev_fx}]
+14 -1
View File
@@ -58,6 +58,7 @@ pub struct Context {
/// running. With fsgsbase, this is neither saved nor restored upon every syscall (there is no
/// need to!), and thus it must be re-read from the register before copying this struct.
pub(crate) gsbase: usize,
userspace_io_allowed: bool,
}
impl Context {
@@ -73,6 +74,7 @@ impl Context {
rsp: 0,
fsbase: 0,
gsbase: 0,
userspace_io_allowed: false,
}
}
@@ -112,6 +114,16 @@ impl super::Context {
self.kfx.as_mut_ptr().cast::<FloatRegisters>().write(new);
}
}
pub fn set_userspace_io_allowed(&mut self, allowed: bool) {
self.arch.userspace_io_allowed = allowed;
if self.id == super::context_id() {
unsafe {
crate::gdt::set_userspace_io_allowed(crate::gdt::pcr(), allowed);
}
}
}
}
pub static EMPTY_CR3: Once<rmm::PhysicalAddress> = Once::new();
@@ -129,6 +141,7 @@ pub unsafe fn switch_to(prev: &mut super::Context, next: &mut super::Context) {
if let Some(ref stack) = next.kstack {
crate::gdt::set_tss_stack(pcr, stack.as_ptr() as usize + stack.len());
}
crate::gdt::set_userspace_io_allowed(pcr, next.arch.userspace_io_allowed);
core::arch::asm!(
alternative2!(
@@ -204,7 +217,7 @@ pub unsafe fn switch_to(prev: &mut super::Context, next: &mut super::Context) {
);
}
PercpuBlock::current().new_addrsp_tmp.set(next.addr_space.clone());
(*pcr).percpu.new_addrsp_tmp.set(next.addr_space.clone());
switch_to_inner(&mut prev.arch, &mut next.arch)
}
+4 -22
View File
@@ -2,7 +2,6 @@ use alloc::sync::Arc;
use crate::{
context,
interrupt::InterruptStack,
paging::VirtualAddress,
syscall::error::{Error, Result, EFAULT, EINVAL, EPERM, ESRCH},
};
@@ -18,32 +17,15 @@ fn enforce_root() -> Result<()> {
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
pub fn iopl(level: usize, stack: &mut InterruptStack) -> Result<usize> {
pub fn iopl(level: usize) -> Result<usize> {
Err(Error::new(syscall::error::ENOSYS))
}
#[cfg(target_arch = "x86")]
pub fn iopl(level: usize, stack: &mut InterruptStack) -> Result<usize> {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn iopl(level: usize) -> Result<usize> {
enforce_root()?;
if level > 3 {
return Err(Error::new(EINVAL));
}
stack.iret.eflags = (stack.iret.eflags & !(3 << 12)) | ((level & 3) << 12);
Ok(0)
}
#[cfg(target_arch = "x86_64")]
pub fn iopl(level: usize, stack: &mut InterruptStack) -> Result<usize> {
enforce_root()?;
if level > 3 {
return Err(Error::new(EINVAL));
}
stack.iret.rflags = (stack.iret.rflags & !(3 << 12)) | ((level & 3) << 12);
context::current()?.write().set_userspace_io_allowed(level >= 3);
Ok(0)
}
+3 -4
View File
@@ -20,9 +20,9 @@ use self::{
usercopy::UserSlice,
};
use crate::interrupt::InterruptStack;
use crate::{
context::{memory::AddrSpace, ContextId},
interrupt::InterruptStack,
scheme::{memory::MemoryScheme, FileHandle, SchemeNamespace},
};
@@ -69,7 +69,6 @@ pub fn syscall(
d: usize,
e: usize,
f: usize,
stack: &mut InterruptStack,
) -> Result<usize> {
//SYS_* is declared in kernel/syscall/src/number.rs
match a & SYS_CLASS {
@@ -191,7 +190,7 @@ pub fn syscall(
WaitFlags::from_bits_truncate(d),
)
.map(ContextId::into),
SYS_IOPL => iopl(b, stack),
SYS_IOPL => iopl(b),
SYS_GETEGID => getegid(),
SYS_GETENS => getens(),
SYS_GETEUID => geteuid(),
@@ -283,7 +282,7 @@ pub fn syscall(
}
}
let result = inner(a, b, c, d, e, f, stack);
let result = inner(a, b, c, d, e, f);
{
let contexts = crate::context::contexts();