Replace iopl with either empty or full PIO bitmap.
This commit is contained in:
Generated
+1
-1
@@ -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
@@ -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
@@ -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>()
|
||||
|
||||
@@ -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}]
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user