mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 13:26:48 +00:00
Implement cpu_local with GS and ensure GS points to TSS
This commit is contained in:
parent
52bde1721e
commit
c2f7a10b84
42
Cargo.lock
generated
42
Cargo.lock
generated
@ -852,7 +852,7 @@ dependencies = [
|
|||||||
"uart_16550",
|
"uart_16550",
|
||||||
"uefi",
|
"uefi",
|
||||||
"uefi-services",
|
"uefi-services",
|
||||||
"x86_64 0.14.11",
|
"x86_64",
|
||||||
"xmas-elf 0.8.0",
|
"xmas-elf 0.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1090,11 +1090,10 @@ dependencies = [
|
|||||||
"spin 0.9.8",
|
"spin 0.9.8",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"tdx-guest",
|
"tdx-guest",
|
||||||
"trapframe",
|
|
||||||
"unwinding",
|
"unwinding",
|
||||||
"volatile",
|
"volatile",
|
||||||
"x86",
|
"x86",
|
||||||
"x86_64 0.14.11",
|
"x86_64",
|
||||||
"xarray",
|
"xarray",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1267,15 +1266,6 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "raw-cpuid"
|
|
||||||
version = "11.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.6.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rle-decode-fast"
|
name = "rle-decode-fast"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@ -1437,8 +1427,8 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"iced-x86",
|
"iced-x86",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"raw-cpuid 10.7.0",
|
"raw-cpuid",
|
||||||
"x86_64 0.14.11",
|
"x86_64",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1512,16 +1502,6 @@ dependencies = [
|
|||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "trapframe"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "105000258ba41c463b63403c9341c55a298f35f6137b1cca08c10f0409ef8d3a"
|
|
||||||
dependencies = [
|
|
||||||
"raw-cpuid 11.0.2",
|
|
||||||
"x86_64 0.15.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typeflags"
|
name = "typeflags"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1714,7 +1694,7 @@ checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"raw-cpuid 10.7.0",
|
"raw-cpuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1729,18 +1709,6 @@ dependencies = [
|
|||||||
"volatile",
|
"volatile",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "x86_64"
|
|
||||||
version = "0.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4bc79523af8abf92fb1a970c3e086c5a343f6bcc1a0eb890f575cbb3b45743df"
|
|
||||||
dependencies = [
|
|
||||||
"bit_field",
|
|
||||||
"bitflags 2.6.0",
|
|
||||||
"rustversion",
|
|
||||||
"volatile",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xarray"
|
name = "xarray"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use ostd::cpu::UserContext;
|
use ostd::cpu::UserContext;
|
||||||
|
|
||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
use crate::{cpu::LinuxAbi, prelude::*};
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[repr(u64)]
|
#[repr(u64)]
|
||||||
@ -18,7 +18,7 @@ pub enum ArchPrctlCode {
|
|||||||
pub fn sys_arch_prctl(
|
pub fn sys_arch_prctl(
|
||||||
code: u64,
|
code: u64,
|
||||||
addr: u64,
|
addr: u64,
|
||||||
_ctx: &Context,
|
ctx: &Context,
|
||||||
user_ctx: &mut UserContext,
|
user_ctx: &mut UserContext,
|
||||||
) -> Result<SyscallReturn> {
|
) -> Result<SyscallReturn> {
|
||||||
let arch_prctl_code = ArchPrctlCode::try_from(code)?;
|
let arch_prctl_code = ArchPrctlCode::try_from(code)?;
|
||||||
@ -26,17 +26,24 @@ pub fn sys_arch_prctl(
|
|||||||
"arch_prctl_code: {:?}, addr = 0x{:x}",
|
"arch_prctl_code: {:?}, addr = 0x{:x}",
|
||||||
arch_prctl_code, addr
|
arch_prctl_code, addr
|
||||||
);
|
);
|
||||||
let res = do_arch_prctl(arch_prctl_code, addr, user_ctx).unwrap();
|
let res = do_arch_prctl(arch_prctl_code, addr, ctx, user_ctx).unwrap();
|
||||||
Ok(SyscallReturn::Return(res as _))
|
Ok(SyscallReturn::Return(res as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_arch_prctl(code: ArchPrctlCode, addr: u64, ctx: &mut UserContext) -> Result<u64> {
|
pub fn do_arch_prctl(
|
||||||
|
code: ArchPrctlCode,
|
||||||
|
addr: u64,
|
||||||
|
ctx: &Context,
|
||||||
|
user_ctx: &mut UserContext,
|
||||||
|
) -> Result<u64> {
|
||||||
match code {
|
match code {
|
||||||
ArchPrctlCode::ARCH_SET_FS => {
|
ArchPrctlCode::ARCH_SET_FS => {
|
||||||
ctx.set_tls_pointer(addr as usize);
|
ctx.task.set_tls_pointer(addr as usize);
|
||||||
|
user_ctx.set_tls_pointer(addr as usize);
|
||||||
|
user_ctx.activate_tls_pointer();
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
ArchPrctlCode::ARCH_GET_FS => Ok(ctx.tls_pointer() as u64),
|
ArchPrctlCode::ARCH_GET_FS => Ok(user_ctx.tls_pointer() as u64),
|
||||||
ArchPrctlCode::ARCH_GET_GS | ArchPrctlCode::ARCH_SET_GS => {
|
ArchPrctlCode::ARCH_GET_GS | ArchPrctlCode::ARCH_SET_GS => {
|
||||||
return_errno_with_message!(Errno::EINVAL, "GS cannot be accessed from the user space")
|
return_errno_with_message!(Errno::EINVAL, "GS cannot be accessed from the user space")
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ use ostd::{cpu::UserContext, user::UserContextApi};
|
|||||||
|
|
||||||
use super::{constants::*, SyscallReturn};
|
use super::{constants::*, SyscallReturn};
|
||||||
use crate::{
|
use crate::{
|
||||||
cpu::LinuxAbi,
|
|
||||||
fs::{
|
fs::{
|
||||||
file_table::FileDesc,
|
file_table::FileDesc,
|
||||||
fs_resolver::{FsPath, AT_FDCWD},
|
fs_resolver::{FsPath, AT_FDCWD},
|
||||||
|
@ -117,11 +117,17 @@ SECTIONS
|
|||||||
# processor, while it would be copied to other dynamically allocated memory
|
# processor, while it would be copied to other dynamically allocated memory
|
||||||
# areas for the application processors.
|
# areas for the application processors.
|
||||||
. = ALIGN(4096);
|
. = ALIGN(4096);
|
||||||
.cpu_local : AT(ADDR(.cpu_local) - KERNEL_VMA) {
|
|
||||||
__cpu_local_start = .;
|
__cpu_local_start = .;
|
||||||
KEEP(*(SORT(.cpu_local)))
|
# Make sure that cpu_local_tss is right at the beginning of CPU local area,
|
||||||
__cpu_local_end = .;
|
# which stores the task state segment in x86_64 architecture, so that
|
||||||
|
# when trap from ring3 to ring0, CPU can switch stack correctly.
|
||||||
|
.cpu_local_tss : AT(ADDR(.cpu_local_tss) - KERNEL_VMA) {
|
||||||
|
*(.cpu_local_tss)
|
||||||
}
|
}
|
||||||
|
.cpu_local : AT(ADDR(.cpu_local) - KERNEL_VMA) {
|
||||||
|
KEEP(*(SORT(.cpu_local)))
|
||||||
|
}
|
||||||
|
__cpu_local_end = .;
|
||||||
|
|
||||||
.bss : AT(ADDR(.bss) - KERNEL_VMA) {
|
.bss : AT(ADDR(.bss) - KERNEL_VMA) {
|
||||||
__bss = .;
|
__bss = .;
|
||||||
|
@ -39,7 +39,6 @@ owo-colors = { version = "3", optional = true }
|
|||||||
ostd-pod = { git = "https://github.com/asterinas/ostd-pod", rev = "c4644be", version = "0.1.1" }
|
ostd-pod = { git = "https://github.com/asterinas/ostd-pod", rev = "c4644be", version = "0.1.1" }
|
||||||
spin = "0.9.4"
|
spin = "0.9.4"
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
trapframe = "0.10.0"
|
|
||||||
unwinding = { version = "0.2.2", default-features = false, features = ["fde-gnu-eh-frame-hdr", "hide-trace", "panic", "personality", "unwinder"] }
|
unwinding = { version = "0.2.2", default-features = false, features = ["fde-gnu-eh-frame-hdr", "hide-trace", "panic", "personality", "unwinder"] }
|
||||||
volatile = { version = "0.4.5", features = ["unstable"] }
|
volatile = { version = "0.4.5", features = ["unstable"] }
|
||||||
xarray = { git = "https://github.com/asterinas/xarray", version = "0.1.0" }
|
xarray = { git = "https://github.com/asterinas/xarray", version = "0.1.0" }
|
||||||
|
@ -2,25 +2,25 @@
|
|||||||
|
|
||||||
//! Architecture dependent CPU-local information utilities.
|
//! Architecture dependent CPU-local information utilities.
|
||||||
|
|
||||||
use x86_64::registers::segmentation::{Segment64, FS};
|
use x86_64::registers::segmentation::{Segment64, GS};
|
||||||
|
|
||||||
/// Sets the base address for the CPU local storage by writing to the FS base model-specific register.
|
/// Sets the base address for the CPU local storage by writing to the GS base model-specific register.
|
||||||
/// This operation is marked as `unsafe` because it directly interfaces with low-level CPU registers.
|
/// This operation is marked as `unsafe` because it directly interfaces with low-level CPU registers.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// - This function is safe to call provided that the FS register is dedicated entirely for CPU local storage
|
/// - This function is safe to call provided that the GS register is dedicated entirely for CPU local storage
|
||||||
/// and is not concurrently accessed for other purposes.
|
/// and is not concurrently accessed for other purposes.
|
||||||
/// - The caller must ensure that `addr` is a valid address and properly aligned, as required by the CPU.
|
/// - The caller must ensure that `addr` is a valid address and properly aligned, as required by the CPU.
|
||||||
/// - This function should only be called in contexts where the CPU is in a state to accept such changes,
|
/// - This function should only be called in contexts where the CPU is in a state to accept such changes,
|
||||||
/// such as during processor initialization.
|
/// such as during processor initialization.
|
||||||
pub(crate) unsafe fn set_base(addr: u64) {
|
pub(crate) unsafe fn set_base(addr: u64) {
|
||||||
FS::write_base(x86_64::addr::VirtAddr::new(addr));
|
GS::write_base(x86_64::addr::VirtAddr::new(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the base address for the CPU local storage by reading the FS base model-specific register.
|
/// Gets the base address for the CPU local storage by reading the GS base model-specific register.
|
||||||
pub(crate) fn get_base() -> u64 {
|
pub(crate) fn get_base() -> u64 {
|
||||||
FS::read_base().as_u64()
|
GS::read_base().as_u64()
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::cpu::local::single_instr::{
|
use crate::cpu::local::single_instr::{
|
||||||
@ -29,7 +29,7 @@ use crate::cpu::local::single_instr::{
|
|||||||
SingleInstructionSubAssign,
|
SingleInstructionSubAssign,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The GDT ensures that the FS segment is initialized to zero on boot.
|
/// The GDT ensures that the GS segment is initialized to zero on boot.
|
||||||
/// This assertion checks that the base address has been set.
|
/// This assertion checks that the base address has been set.
|
||||||
macro_rules! debug_assert_initialized {
|
macro_rules! debug_assert_initialized {
|
||||||
() => {
|
() => {
|
||||||
@ -49,7 +49,7 @@ macro_rules! impl_numeric_single_instruction_for {
|
|||||||
debug_assert_initialized!();
|
debug_assert_initialized!();
|
||||||
|
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
concat!("add fs:[{0}], {1", $register_format, "}"),
|
concat!("add gs:[{0}], {1", $register_format, "}"),
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
in($inout_type) val,
|
in($inout_type) val,
|
||||||
options(nostack),
|
options(nostack),
|
||||||
@ -62,7 +62,7 @@ macro_rules! impl_numeric_single_instruction_for {
|
|||||||
debug_assert_initialized!();
|
debug_assert_initialized!();
|
||||||
|
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
concat!("sub fs:[{0}], {1", $register_format, "}"),
|
concat!("sub gs:[{0}], {1", $register_format, "}"),
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
in($inout_type) val,
|
in($inout_type) val,
|
||||||
options(nostack),
|
options(nostack),
|
||||||
@ -75,7 +75,7 @@ macro_rules! impl_numeric_single_instruction_for {
|
|||||||
debug_assert_initialized!();
|
debug_assert_initialized!();
|
||||||
|
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
concat!("and fs:[{0}], {1", $register_format, "}"),
|
concat!("and gs:[{0}], {1", $register_format, "}"),
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
in($inout_type) val,
|
in($inout_type) val,
|
||||||
options(nostack),
|
options(nostack),
|
||||||
@ -88,7 +88,7 @@ macro_rules! impl_numeric_single_instruction_for {
|
|||||||
debug_assert_initialized!();
|
debug_assert_initialized!();
|
||||||
|
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
concat!("or fs:[{0}], {1", $register_format, "}"),
|
concat!("or gs:[{0}], {1", $register_format, "}"),
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
in($inout_type) val,
|
in($inout_type) val,
|
||||||
options(nostack),
|
options(nostack),
|
||||||
@ -101,7 +101,7 @@ macro_rules! impl_numeric_single_instruction_for {
|
|||||||
debug_assert_initialized!();
|
debug_assert_initialized!();
|
||||||
|
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
concat!("xor fs:[{0}], {1", $register_format, "}"),
|
concat!("xor gs:[{0}], {1", $register_format, "}"),
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
in($inout_type) val,
|
in($inout_type) val,
|
||||||
options(nostack),
|
options(nostack),
|
||||||
@ -115,7 +115,7 @@ macro_rules! impl_numeric_single_instruction_for {
|
|||||||
|
|
||||||
let val: Self;
|
let val: Self;
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
concat!("mov {0", $register_format, "}, fs:[{1}]"),
|
concat!("mov {0", $register_format, "}, gs:[{1}]"),
|
||||||
out($inout_type) val,
|
out($inout_type) val,
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
options(nostack, readonly),
|
options(nostack, readonly),
|
||||||
@ -129,7 +129,7 @@ macro_rules! impl_numeric_single_instruction_for {
|
|||||||
debug_assert_initialized!();
|
debug_assert_initialized!();
|
||||||
|
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
concat!("mov fs:[{0}], {1", $register_format, "}"),
|
concat!("mov gs:[{0}], {1", $register_format, "}"),
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
in($inout_type) val,
|
in($inout_type) val,
|
||||||
options(nostack),
|
options(nostack),
|
||||||
@ -162,7 +162,7 @@ macro_rules! impl_generic_single_instruction_for {
|
|||||||
|
|
||||||
let val: Self;
|
let val: Self;
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
concat!("mov {0}, fs:[{1}]"),
|
concat!("mov {0}, gs:[{1}]"),
|
||||||
out(reg) val,
|
out(reg) val,
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
options(nostack, readonly),
|
options(nostack, readonly),
|
||||||
@ -176,7 +176,7 @@ macro_rules! impl_generic_single_instruction_for {
|
|||||||
debug_assert_initialized!();
|
debug_assert_initialized!();
|
||||||
|
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
concat!("mov fs:[{0}], {1}"),
|
concat!("mov gs:[{0}], {1}"),
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
in(reg) val,
|
in(reg) val,
|
||||||
options(nostack),
|
options(nostack),
|
||||||
@ -202,7 +202,7 @@ impl SingleInstructionLoad for bool {
|
|||||||
|
|
||||||
let val: u8;
|
let val: u8;
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
"mov {0}, fs:[{1}]",
|
"mov {0}, gs:[{1}]",
|
||||||
out(reg_byte) val,
|
out(reg_byte) val,
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
options(nostack, readonly),
|
options(nostack, readonly),
|
||||||
@ -218,7 +218,7 @@ impl SingleInstructionStore for bool {
|
|||||||
|
|
||||||
let val: u8 = if val { 1 } else { 0 };
|
let val: u8 = if val { 1 } else { 0 };
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
"mov fs:[{0}], {1}",
|
"mov gs:[{0}], {1}",
|
||||||
in(reg) offset,
|
in(reg) offset,
|
||||||
in(reg_byte) val,
|
in(reg_byte) val,
|
||||||
options(nostack),
|
options(nostack),
|
||||||
|
@ -12,10 +12,11 @@ use core::{
|
|||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
pub use trapframe::GeneralRegs as RawGeneralRegs;
|
use x86::bits64::segmentation::wrfsbase;
|
||||||
use trapframe::UserContext as RawUserContext;
|
|
||||||
use x86_64::registers::rflags::RFlags;
|
use x86_64::registers::rflags::RFlags;
|
||||||
|
|
||||||
|
pub use super::trap::GeneralRegs as RawGeneralRegs;
|
||||||
|
use super::trap::{TrapFrame, UserContext as RawUserContext};
|
||||||
use crate::{
|
use crate::{
|
||||||
task::scheduler,
|
task::scheduler,
|
||||||
trap::call_irq_callback_functions,
|
trap::call_irq_callback_functions,
|
||||||
@ -76,6 +77,27 @@ impl UserContext {
|
|||||||
pub fn fp_regs_mut(&mut self) -> &mut FpRegs {
|
pub fn fp_regs_mut(&mut self) -> &mut FpRegs {
|
||||||
&mut self.fp_regs
|
&mut self.fp_regs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets thread-local storage pointer.
|
||||||
|
pub fn set_tls_pointer(&mut self, tls: usize) {
|
||||||
|
self.set_fsbase(tls)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets thread-local storage pointer.
|
||||||
|
pub fn tls_pointer(&self) -> usize {
|
||||||
|
self.fsbase()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Activates thread-local storage pointer on the current CPU.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The method by itself is safe because the value of the TLS register won't affect kernel code.
|
||||||
|
/// But if the user relies on the TLS pointer, make sure that the pointer is correctly set when
|
||||||
|
/// entering the user space.
|
||||||
|
pub fn activate_tls_pointer(&self) {
|
||||||
|
unsafe { wrfsbase(self.fsbase() as u64) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserContextApiInternal for UserContext {
|
impl UserContextApiInternal for UserContext {
|
||||||
@ -135,8 +157,8 @@ impl UserContextApiInternal for UserContext {
|
|||||||
return_reason
|
return_reason
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_trap_frame(&self) -> trapframe::TrapFrame {
|
fn as_trap_frame(&self) -> TrapFrame {
|
||||||
trapframe::TrapFrame {
|
TrapFrame {
|
||||||
rax: self.user_context.general.rax,
|
rax: self.user_context.general.rax,
|
||||||
rbx: self.user_context.general.rbx,
|
rbx: self.user_context.general.rbx,
|
||||||
rcx: self.user_context.general.rcx,
|
rcx: self.user_context.general.rcx,
|
||||||
|
@ -9,11 +9,13 @@ use core::fmt::Debug;
|
|||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use log::info;
|
use log::info;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
use trapframe::TrapFrame;
|
|
||||||
use volatile::{access::ReadWrite, Volatile};
|
use volatile::{access::ReadWrite, Volatile};
|
||||||
|
|
||||||
use super::registers::Capability;
|
use super::registers::Capability;
|
||||||
use crate::{mm::Vaddr, trap::IrqLine};
|
use crate::{
|
||||||
|
mm::Vaddr,
|
||||||
|
trap::{IrqLine, TrapFrame},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FaultEventRegisters {
|
pub struct FaultEventRegisters {
|
||||||
|
@ -8,10 +8,12 @@ use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec::Vec};
|
|||||||
|
|
||||||
use id_alloc::IdAlloc;
|
use id_alloc::IdAlloc;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
use trapframe::TrapFrame;
|
|
||||||
use x86_64::registers::rflags::{self, RFlags};
|
use x86_64::registers::rflags::{self, RFlags};
|
||||||
|
|
||||||
use crate::sync::{Mutex, PreemptDisabled, SpinLock, SpinLockGuard};
|
use crate::{
|
||||||
|
sync::{Mutex, PreemptDisabled, SpinLock, SpinLockGuard},
|
||||||
|
trap::TrapFrame,
|
||||||
|
};
|
||||||
|
|
||||||
/// The global allocator for software defined IRQ lines.
|
/// The global allocator for software defined IRQ lines.
|
||||||
pub(crate) static IRQ_ALLOCATOR: Once<SpinLock<IdAlloc>> = Once::new();
|
pub(crate) static IRQ_ALLOCATOR: Once<SpinLock<IdAlloc>> = Once::new();
|
||||||
|
@ -8,7 +8,6 @@ use core::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use trapframe::TrapFrame;
|
|
||||||
use x86::cpuid::cpuid;
|
use x86::cpuid::cpuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -16,7 +15,7 @@ use crate::{
|
|||||||
pit::{self, OperatingMode},
|
pit::{self, OperatingMode},
|
||||||
TIMER_FREQ,
|
TIMER_FREQ,
|
||||||
},
|
},
|
||||||
trap::IrqLine,
|
trap::{IrqLine, TrapFrame},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The frequency of TSC(Hz)
|
/// The frequency of TSC(Hz)
|
||||||
|
@ -60,6 +60,10 @@ pub(crate) fn check_tdx_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn init_on_bsp() {
|
pub(crate) fn init_on_bsp() {
|
||||||
|
// SAFETY: this function is only called once on BSP.
|
||||||
|
unsafe {
|
||||||
|
crate::arch::trap::init(true);
|
||||||
|
}
|
||||||
irq::init();
|
irq::init();
|
||||||
kernel::acpi::init();
|
kernel::acpi::init();
|
||||||
|
|
||||||
|
@ -10,10 +10,12 @@ use core::fmt::Write;
|
|||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
use trapframe::TrapFrame;
|
|
||||||
|
|
||||||
use super::{device::serial::SerialPort, kernel::IO_APIC};
|
use super::{device::serial::SerialPort, kernel::IO_APIC};
|
||||||
use crate::{sync::SpinLock, trap::IrqLine};
|
use crate::{
|
||||||
|
sync::SpinLock,
|
||||||
|
trap::{IrqLine, TrapFrame},
|
||||||
|
};
|
||||||
|
|
||||||
/// Prints the formatted arguments to the standard output using the serial port.
|
/// Prints the formatted arguments to the standard output using the serial port.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -11,6 +11,7 @@ core::arch::global_asm!(include_str!("switch.S"));
|
|||||||
pub(crate) struct TaskContext {
|
pub(crate) struct TaskContext {
|
||||||
pub regs: CalleeRegs,
|
pub regs: CalleeRegs,
|
||||||
pub rip: usize,
|
pub rip: usize,
|
||||||
|
pub fsbase: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskContext {
|
impl TaskContext {
|
||||||
@ -18,8 +19,19 @@ impl TaskContext {
|
|||||||
Self {
|
Self {
|
||||||
regs: CalleeRegs::new(),
|
regs: CalleeRegs::new(),
|
||||||
rip: 0,
|
rip: 0,
|
||||||
|
fsbase: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets thread-local storage pointer.
|
||||||
|
pub fn set_tls_pointer(&mut self, tls: usize) {
|
||||||
|
self.fsbase = tls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets thread-local storage pointer.
|
||||||
|
pub fn tls_pointer(&self) -> usize {
|
||||||
|
self.fsbase
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Callee-saved registers.
|
/// Callee-saved registers.
|
||||||
|
@ -14,7 +14,11 @@ context_switch: # (cur: *mut TaskContext, nxt: *TaskContext)
|
|||||||
mov [rdi + 32], r13
|
mov [rdi + 32], r13
|
||||||
mov [rdi + 40], r14
|
mov [rdi + 40], r14
|
||||||
mov [rdi + 48], r15
|
mov [rdi + 48], r15
|
||||||
|
rdfsbase r15
|
||||||
|
mov [rdi + 64], r15
|
||||||
# Restore nxt's registers
|
# Restore nxt's registers
|
||||||
|
mov r15, [rsi + 64]
|
||||||
|
wrfsbase r15
|
||||||
mov rsp, [rsi + 0]
|
mov rsp, [rsi + 0]
|
||||||
mov rbx, [rsi + 8]
|
mov rbx, [rsi + 8]
|
||||||
mov rbp, [rsi + 16]
|
mov rbp, [rsi + 16]
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use tdx_guest::{tdcall::accept_page, tdvmcall::map_gpa, TdxTrapFrame};
|
use tdx_guest::{tdcall::accept_page, tdvmcall::map_gpa, TdxTrapFrame};
|
||||||
use trapframe::TrapFrame;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mm::{
|
mm::{
|
||||||
@ -13,6 +12,7 @@ use crate::{
|
|||||||
PAGE_SIZE,
|
PAGE_SIZE,
|
||||||
},
|
},
|
||||||
prelude::Paddr,
|
prelude::Paddr,
|
||||||
|
trap::TrapFrame,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SHARED_BIT: u8 = 51;
|
const SHARED_BIT: u8 = 51;
|
||||||
|
@ -10,7 +10,6 @@ use core::{
|
|||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
use trapframe::TrapFrame;
|
|
||||||
use x86::{
|
use x86::{
|
||||||
cpuid::cpuid,
|
cpuid::cpuid,
|
||||||
msr::{wrmsr, IA32_TSC_DEADLINE},
|
msr::{wrmsr, IA32_TSC_DEADLINE},
|
||||||
@ -26,7 +25,7 @@ use crate::{
|
|||||||
tsc::TSC_FREQ,
|
tsc::TSC_FREQ,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
trap::IrqLine,
|
trap::{IrqLine, TrapFrame},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Initializes APIC with tsc deadline mode or periodic mode.
|
/// Initializes APIC with tsc deadline mode or periodic mode.
|
||||||
|
@ -12,13 +12,12 @@ use core::{cell::RefCell, sync::atomic::Ordering};
|
|||||||
|
|
||||||
pub use jiffies::Jiffies;
|
pub use jiffies::Jiffies;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
use trapframe::TrapFrame;
|
|
||||||
|
|
||||||
use self::apic::APIC_TIMER_CALLBACK;
|
use self::apic::APIC_TIMER_CALLBACK;
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::x86::kernel,
|
arch::x86::kernel,
|
||||||
cpu_local,
|
cpu_local,
|
||||||
trap::{self, IrqLine},
|
trap::{self, IrqLine, TrapFrame},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The timer frequency (Hz). Here we choose 1000Hz since 1000Hz is easier for unit conversion and
|
/// The timer frequency (Hz). Here we choose 1000Hz since 1000Hz is easier for unit conversion and
|
||||||
|
120
ostd/src/arch/x86/trap/gdt.rs
Normal file
120
ostd/src/arch/x86/trap/gdt.rs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0 OR MIT
|
||||||
|
//
|
||||||
|
// The original source code is from [trapframe-rs](https://github.com/rcore-os/trapframe-rs),
|
||||||
|
// which is released under the following license:
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 - 2024 Runji Wang
|
||||||
|
//
|
||||||
|
// We make the following new changes:
|
||||||
|
// * Link TaskStateSegment to .cpu_local area.
|
||||||
|
// * Init TaskStateSegment on bsp/ap respectively.
|
||||||
|
//
|
||||||
|
// These changes are released under the following license:
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Configure Global Descriptor Table (GDT).
|
||||||
|
|
||||||
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
|
use core::cell::SyncUnsafeCell;
|
||||||
|
|
||||||
|
use x86_64::{
|
||||||
|
instructions::tables::{lgdt, load_tss, sgdt},
|
||||||
|
registers::{
|
||||||
|
model_specific::Star,
|
||||||
|
segmentation::{Segment64, GS},
|
||||||
|
},
|
||||||
|
structures::{
|
||||||
|
gdt::{Descriptor, SegmentSelector},
|
||||||
|
tss::TaskStateSegment,
|
||||||
|
DescriptorTablePointer,
|
||||||
|
},
|
||||||
|
PrivilegeLevel, VirtAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Init TSS & GDT.
|
||||||
|
pub unsafe fn init(on_bsp: bool) {
|
||||||
|
// Allocate stack for trap from user, set the stack top to TSS,
|
||||||
|
// so that when trap from ring3 to ring0, CPU can switch stack correctly.
|
||||||
|
let tss = if on_bsp {
|
||||||
|
init_local_tss_on_bsp()
|
||||||
|
} else {
|
||||||
|
init_local_tss_on_ap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (tss0, tss1) = match Descriptor::tss_segment(tss) {
|
||||||
|
Descriptor::SystemSegment(tss0, tss1) => (tss0, tss1),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
// FIXME: the segment limit assumed by x86_64 does not include the I/O port bitmap.
|
||||||
|
|
||||||
|
// Get current GDT.
|
||||||
|
let gdtp = sgdt();
|
||||||
|
let entry_count = (gdtp.limit + 1) as usize / size_of::<u64>();
|
||||||
|
let old_gdt = core::slice::from_raw_parts(gdtp.base.as_ptr::<u64>(), entry_count);
|
||||||
|
|
||||||
|
// Allocate new GDT with 7 more entries.
|
||||||
|
//
|
||||||
|
// NOTICE: for fast syscall:
|
||||||
|
// STAR[47:32] = K_CS = K_SS - 8
|
||||||
|
// STAR[63:48] = U_CS32 = U_SS32 - 8 = U_CS - 16
|
||||||
|
let mut gdt = Vec::from(old_gdt);
|
||||||
|
gdt.extend([tss0, tss1, KCODE64, KDATA64, UCODE32, UDATA32, UCODE64].iter());
|
||||||
|
let gdt = Vec::leak(gdt);
|
||||||
|
|
||||||
|
// Load new GDT and TSS.
|
||||||
|
lgdt(&DescriptorTablePointer {
|
||||||
|
limit: gdt.len() as u16 * 8 - 1,
|
||||||
|
base: VirtAddr::new(gdt.as_ptr() as _),
|
||||||
|
});
|
||||||
|
load_tss(SegmentSelector::new(
|
||||||
|
entry_count as u16,
|
||||||
|
PrivilegeLevel::Ring0,
|
||||||
|
));
|
||||||
|
|
||||||
|
let sysret = SegmentSelector::new(entry_count as u16 + 4, PrivilegeLevel::Ring3).0;
|
||||||
|
let syscall = SegmentSelector::new(entry_count as u16 + 2, PrivilegeLevel::Ring0).0;
|
||||||
|
Star::write_raw(sysret, syscall);
|
||||||
|
|
||||||
|
USER_SS = sysret + 8;
|
||||||
|
USER_CS = sysret + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The linker script ensure that cpu_local_tss section is right
|
||||||
|
// at the beginning of cpu_local area, so that gsbase (offset zero)
|
||||||
|
// points to LOCAL_TSS.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[link_section = ".cpu_local_tss"]
|
||||||
|
static LOCAL_TSS: SyncUnsafeCell<TaskStateSegment> = SyncUnsafeCell::new(TaskStateSegment::new());
|
||||||
|
|
||||||
|
unsafe fn init_local_tss_on_bsp() -> &'static TaskStateSegment {
|
||||||
|
let tss_ptr = LOCAL_TSS.get();
|
||||||
|
|
||||||
|
let trap_stack_top = Box::leak(Box::new([0u8; 0x1000])).as_ptr() as u64 + 0x1000;
|
||||||
|
(*tss_ptr).privilege_stack_table[0] = VirtAddr::new(trap_stack_top);
|
||||||
|
&*tss_ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn init_local_tss_on_ap() -> &'static TaskStateSegment {
|
||||||
|
let gs_base = GS::read_base().as_u64();
|
||||||
|
let tss_ptr = gs_base as *mut TaskStateSegment;
|
||||||
|
|
||||||
|
let trap_stack_top = Box::leak(Box::new([0u8; 0x1000])).as_ptr() as u64 + 0x1000;
|
||||||
|
(*tss_ptr).privilege_stack_table[0] = VirtAddr::new(trap_stack_top);
|
||||||
|
&*tss_ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
static mut USER_SS: u16 = 0;
|
||||||
|
#[no_mangle]
|
||||||
|
static mut USER_CS: u16 = 0;
|
||||||
|
|
||||||
|
const KCODE64: u64 = 0x00209800_00000000; // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE
|
||||||
|
const UCODE64: u64 = 0x0020F800_00000000; // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE
|
||||||
|
const KDATA64: u64 = 0x00009200_00000000; // DATA_WRITABLE | USER_SEGMENT | PRESENT
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const UDATA64: u64 = 0x0000F200_00000000; // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT
|
||||||
|
const UCODE32: u64 = 0x00cffa00_0000ffff; // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT
|
||||||
|
const UDATA32: u64 = 0x00cff200_0000ffff; // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT
|
47
ostd/src/arch/x86/trap/idt.rs
Normal file
47
ostd/src/arch/x86/trap/idt.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0 OR MIT
|
||||||
|
//
|
||||||
|
// The original source code is from [trapframe-rs](https://github.com/rcore-os/trapframe-rs),
|
||||||
|
// which is released under the following license:
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 - 2024 Runji Wang
|
||||||
|
//
|
||||||
|
// We make the following new changes:
|
||||||
|
// * Include `trap.S` in this file and remove unused function `sidt`.
|
||||||
|
// * Link `VECTORS` to `trap_handler_table` defined in `trap.S`.
|
||||||
|
//
|
||||||
|
// These changes are released under the following license:
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Configure Interrupt Descriptor Table (GDT).
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use core::arch::global_asm;
|
||||||
|
|
||||||
|
use x86_64::{
|
||||||
|
structures::idt::{Entry, HandlerFunc, InterruptDescriptorTable},
|
||||||
|
PrivilegeLevel,
|
||||||
|
};
|
||||||
|
|
||||||
|
global_asm!(include_str!("trap.S"));
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
extern "C" {
|
||||||
|
#[link_name = "trap_handler_table"]
|
||||||
|
static VECTORS: [HandlerFunc; 256];
|
||||||
|
}
|
||||||
|
|
||||||
|
let idt = Box::leak(Box::new(InterruptDescriptorTable::new()));
|
||||||
|
let entries: &'static mut [Entry<HandlerFunc>; 256] =
|
||||||
|
unsafe { core::mem::transmute_copy(&idt) };
|
||||||
|
for i in 0..256 {
|
||||||
|
let opt = unsafe { entries[i].set_handler_fn(VECTORS[i]) };
|
||||||
|
// Enable user space `int3` and `into`.
|
||||||
|
if i == 3 || i == 4 {
|
||||||
|
opt.set_privilege_level(PrivilegeLevel::Ring3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idt.load();
|
||||||
|
}
|
@ -1,11 +1,28 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0 OR MIT
|
||||||
|
//
|
||||||
|
// The original source code is from [trapframe-rs](https://github.com/rcore-os/trapframe-rs),
|
||||||
|
// which is released under the following license:
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 - 2024 Runji Wang
|
||||||
|
//
|
||||||
|
// We make the following new changes:
|
||||||
|
// * Implement the `trap_handler` of Asterinas.
|
||||||
|
//
|
||||||
|
// These changes are released under the following license:
|
||||||
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
//! Handles trap.
|
//! Handles trap.
|
||||||
|
|
||||||
|
mod gdt;
|
||||||
|
mod idt;
|
||||||
|
mod syscall;
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use trapframe::TrapFrame;
|
|
||||||
|
|
||||||
use super::ex_table::ExTable;
|
use super::ex_table::ExTable;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -31,6 +48,168 @@ cpu_local_cell! {
|
|||||||
static IS_KERNEL_INTERRUPTED: bool = false;
|
static IS_KERNEL_INTERRUPTED: bool = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trap frame of kernel interrupt
|
||||||
|
///
|
||||||
|
/// # Trap handler
|
||||||
|
///
|
||||||
|
/// You need to define a handler function like this:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #[no_mangle]
|
||||||
|
/// extern "sysv64" fn trap_handler(tf: &mut TrapFrame) {
|
||||||
|
/// match tf.trap_num {
|
||||||
|
/// 3 => {
|
||||||
|
/// println!("TRAP: BreakPoint");
|
||||||
|
/// tf.rip += 1;
|
||||||
|
/// }
|
||||||
|
/// _ => panic!("TRAP: {:#x?}", tf),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub struct TrapFrame {
|
||||||
|
// Pushed by 'trap.S'
|
||||||
|
pub rax: usize,
|
||||||
|
pub rbx: usize,
|
||||||
|
pub rcx: usize,
|
||||||
|
pub rdx: usize,
|
||||||
|
pub rsi: usize,
|
||||||
|
pub rdi: usize,
|
||||||
|
pub rbp: usize,
|
||||||
|
pub rsp: usize,
|
||||||
|
pub r8: usize,
|
||||||
|
pub r9: usize,
|
||||||
|
pub r10: usize,
|
||||||
|
pub r11: usize,
|
||||||
|
pub r12: usize,
|
||||||
|
pub r13: usize,
|
||||||
|
pub r14: usize,
|
||||||
|
pub r15: usize,
|
||||||
|
pub _pad: usize,
|
||||||
|
|
||||||
|
pub trap_num: usize,
|
||||||
|
pub error_code: usize,
|
||||||
|
|
||||||
|
// Pushed by CPU
|
||||||
|
pub rip: usize,
|
||||||
|
pub cs: usize,
|
||||||
|
pub rflags: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize interrupt handling on x86_64.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function will:
|
||||||
|
///
|
||||||
|
/// - Disable interrupt.
|
||||||
|
/// - Switch to a new [GDT], extend 7 more entries from the current one.
|
||||||
|
/// - Switch to a new [TSS], `GSBASE` pointer to its base address.
|
||||||
|
/// - Switch to a new [IDT], override the current one.
|
||||||
|
/// - Enable [`syscall`] instruction.
|
||||||
|
/// - set `EFER::SYSTEM_CALL_EXTENSIONS`
|
||||||
|
///
|
||||||
|
/// [GDT]: https://wiki.osdev.org/GDT
|
||||||
|
/// [IDT]: https://wiki.osdev.org/IDT
|
||||||
|
/// [TSS]: https://wiki.osdev.org/Task_State_Segment
|
||||||
|
/// [`syscall`]: https://www.felixcloutier.com/x86/syscall
|
||||||
|
///
|
||||||
|
#[cfg(any(target_os = "none", target_os = "uefi"))]
|
||||||
|
pub unsafe fn init(on_bsp: bool) {
|
||||||
|
x86_64::instructions::interrupts::disable();
|
||||||
|
gdt::init(on_bsp);
|
||||||
|
idt::init();
|
||||||
|
syscall::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User space context.
|
||||||
|
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub struct UserContext {
|
||||||
|
pub general: GeneralRegs,
|
||||||
|
pub trap_num: usize,
|
||||||
|
pub error_code: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// General registers.
|
||||||
|
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub struct GeneralRegs {
|
||||||
|
pub rax: usize,
|
||||||
|
pub rbx: usize,
|
||||||
|
pub rcx: usize,
|
||||||
|
pub rdx: usize,
|
||||||
|
pub rsi: usize,
|
||||||
|
pub rdi: usize,
|
||||||
|
pub rbp: usize,
|
||||||
|
pub rsp: usize,
|
||||||
|
pub r8: usize,
|
||||||
|
pub r9: usize,
|
||||||
|
pub r10: usize,
|
||||||
|
pub r11: usize,
|
||||||
|
pub r12: usize,
|
||||||
|
pub r13: usize,
|
||||||
|
pub r14: usize,
|
||||||
|
pub r15: usize,
|
||||||
|
pub rip: usize,
|
||||||
|
pub rflags: usize,
|
||||||
|
pub fsbase: usize,
|
||||||
|
pub gsbase: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserContext {
|
||||||
|
/// Get number of syscall.
|
||||||
|
pub fn get_syscall_num(&self) -> usize {
|
||||||
|
self.general.rax
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get return value of syscall.
|
||||||
|
pub fn get_syscall_ret(&self) -> usize {
|
||||||
|
self.general.rax
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set return value of syscall.
|
||||||
|
pub fn set_syscall_ret(&mut self, ret: usize) {
|
||||||
|
self.general.rax = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get syscall args.
|
||||||
|
pub fn get_syscall_args(&self) -> [usize; 6] {
|
||||||
|
[
|
||||||
|
self.general.rdi,
|
||||||
|
self.general.rsi,
|
||||||
|
self.general.rdx,
|
||||||
|
self.general.r10,
|
||||||
|
self.general.r8,
|
||||||
|
self.general.r9,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set instruction pointer.
|
||||||
|
pub fn set_ip(&mut self, ip: usize) {
|
||||||
|
self.general.rip = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set stack pointer.
|
||||||
|
pub fn set_sp(&mut self, sp: usize) {
|
||||||
|
self.general.rsp = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get stack pointer.
|
||||||
|
pub fn get_sp(&self) -> usize {
|
||||||
|
self.general.rsp
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set thread-local storage pointer.
|
||||||
|
pub fn set_tls(&mut self, tls: usize) {
|
||||||
|
self.general.fsbase = tls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if this function is called within the context of an IRQ handler
|
/// Returns true if this function is called within the context of an IRQ handler
|
||||||
/// and the IRQ occurs while the CPU is executing in the kernel mode.
|
/// and the IRQ occurs while the CPU is executing in the kernel mode.
|
||||||
/// Otherwise, it returns false.
|
/// Otherwise, it returns false.
|
||||||
@ -38,7 +217,7 @@ pub fn is_kernel_interrupted() -> bool {
|
|||||||
IS_KERNEL_INTERRUPTED.load()
|
IS_KERNEL_INTERRUPTED.load()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only from kernel
|
/// Handle traps (only from kernel).
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "sysv64" fn trap_handler(f: &mut TrapFrame) {
|
extern "sysv64" fn trap_handler(f: &mut TrapFrame) {
|
||||||
if CpuException::is_cpu_exception(f.trap_num as u16) {
|
if CpuException::is_cpu_exception(f.trap_num as u16) {
|
140
ostd/src/arch/x86/trap/syscall.S
Normal file
140
ostd/src/arch/x86/trap/syscall.S
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/* SPDX-License-Identifier: MPL-2.0 OR MIT
|
||||||
|
*
|
||||||
|
* The original source code is from [trapframe-rs](https://github.com/rcore-os/trapframe-rs),
|
||||||
|
* which is released under the following license:
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 - 2024 Runji Wang
|
||||||
|
*
|
||||||
|
* We make the following new changes:
|
||||||
|
* * Skip saving/restoring the fsgsbase registers.
|
||||||
|
*
|
||||||
|
* These changes are released under the following license:
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
.text
|
||||||
|
# extern "sysv64" fn syscall_return(&mut GeneralRegs)
|
||||||
|
.global syscall_return
|
||||||
|
syscall_return:
|
||||||
|
# disable interrupt
|
||||||
|
cli
|
||||||
|
|
||||||
|
# save callee-saved registers
|
||||||
|
push r15
|
||||||
|
push r14
|
||||||
|
push r13
|
||||||
|
push r12
|
||||||
|
push rbp
|
||||||
|
push rbx
|
||||||
|
|
||||||
|
push rdi # keep rsp 16 bytes align
|
||||||
|
mov gs:4, rsp # store kernel rsp -> TSS.sp0
|
||||||
|
mov rsp, rdi # set rsp -> GeneralRegs
|
||||||
|
|
||||||
|
# restore user gsbase
|
||||||
|
swapgs
|
||||||
|
|
||||||
|
pop rax
|
||||||
|
pop rbx
|
||||||
|
pop rcx
|
||||||
|
pop rdx
|
||||||
|
pop rsi
|
||||||
|
pop rdi
|
||||||
|
pop rbp
|
||||||
|
pop r8 # skip rsp
|
||||||
|
pop r8
|
||||||
|
pop r9
|
||||||
|
pop r10
|
||||||
|
pop r11
|
||||||
|
pop r12
|
||||||
|
pop r13
|
||||||
|
pop r14
|
||||||
|
pop r15
|
||||||
|
# rip
|
||||||
|
# rflags
|
||||||
|
# fsbase
|
||||||
|
# gsbase
|
||||||
|
# trap_num
|
||||||
|
# error_code
|
||||||
|
|
||||||
|
# determain sysret or iret
|
||||||
|
cmp dword ptr [rsp + 4*8], 0x100 # syscall?
|
||||||
|
je sysret
|
||||||
|
iret:
|
||||||
|
# construct trap frame
|
||||||
|
push [USER_SS] # push ss
|
||||||
|
push [rsp - 8*8] # push rsp
|
||||||
|
push [rsp + 3*8] # push rflags
|
||||||
|
push [USER_CS] # push cs
|
||||||
|
push [rsp + 4*8] # push rip
|
||||||
|
|
||||||
|
iretq
|
||||||
|
|
||||||
|
sysret:
|
||||||
|
pop rcx # rcx = rip
|
||||||
|
pop r11 # r11 = rflags
|
||||||
|
mov rsp, [rsp - 11*8] # load rsp
|
||||||
|
|
||||||
|
sysretq
|
||||||
|
|
||||||
|
# sysretq instruction do:
|
||||||
|
# - load cs, ss
|
||||||
|
# - load rflags <- r11
|
||||||
|
# - load rip <- rcx
|
||||||
|
|
||||||
|
.global syscall_entry
|
||||||
|
syscall_entry:
|
||||||
|
# syscall instruction do:
|
||||||
|
# - load cs
|
||||||
|
# - store rflags -> r11
|
||||||
|
# - mask rflags
|
||||||
|
# - store rip -> rcx
|
||||||
|
# - load rip
|
||||||
|
|
||||||
|
swapgs # swap in kernel gs
|
||||||
|
mov gs:12, rsp # store user rsp -> scratch at TSS.sp1
|
||||||
|
mov rsp, gs:4 # load kernel rsp <- TSS.sp0
|
||||||
|
pop rsp # load rsp -> GeneralRegs
|
||||||
|
add rsp, 21*8 # rsp -> error code of GeneralRegs
|
||||||
|
|
||||||
|
push 0x100 # push trap_num
|
||||||
|
sub rsp, 16 # skip fsbase, gsbase
|
||||||
|
# push general registers
|
||||||
|
push r11 # push rflags
|
||||||
|
push rcx # push rip
|
||||||
|
|
||||||
|
.global trap_syscall_entry
|
||||||
|
trap_syscall_entry:
|
||||||
|
push r15
|
||||||
|
push r14
|
||||||
|
push r13
|
||||||
|
push r12
|
||||||
|
push r11
|
||||||
|
push r10
|
||||||
|
push r9
|
||||||
|
push r8
|
||||||
|
push gs:12 # push rsp
|
||||||
|
push rbp
|
||||||
|
push rdi
|
||||||
|
push rsi
|
||||||
|
push rdx
|
||||||
|
push rcx
|
||||||
|
push rbx
|
||||||
|
push rax
|
||||||
|
|
||||||
|
# restore callee-saved registers
|
||||||
|
mov rsp, gs:4 # load kernel rsp <- TSS.sp0
|
||||||
|
pop rbx
|
||||||
|
|
||||||
|
pop rbx
|
||||||
|
pop rbp
|
||||||
|
pop r12
|
||||||
|
pop r13
|
||||||
|
pop r14
|
||||||
|
pop r15
|
||||||
|
|
||||||
|
# go back to Rust
|
||||||
|
ret
|
101
ostd/src/arch/x86/trap/syscall.rs
Normal file
101
ostd/src/arch/x86/trap/syscall.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0 OR MIT
|
||||||
|
//
|
||||||
|
// The original source code is from [trapframe-rs](https://github.com/rcore-os/trapframe-rs),
|
||||||
|
// which is released under the following license:
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 - 2024 Runji Wang
|
||||||
|
//
|
||||||
|
// We make the following new changes:
|
||||||
|
// * Revise some comments.
|
||||||
|
//
|
||||||
|
// These changes are released under the following license:
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Configure fast syscall.
|
||||||
|
|
||||||
|
use core::arch::global_asm;
|
||||||
|
|
||||||
|
use x86::cpuid::CpuId;
|
||||||
|
use x86_64::{
|
||||||
|
registers::{
|
||||||
|
control::{Cr4, Cr4Flags},
|
||||||
|
model_specific::{Efer, EferFlags, LStar, SFMask},
|
||||||
|
rflags::RFlags,
|
||||||
|
},
|
||||||
|
VirtAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::UserContext;
|
||||||
|
|
||||||
|
global_asm!(include_str!("syscall.S"));
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
let cpuid = CpuId::new();
|
||||||
|
unsafe {
|
||||||
|
// Enable `syscall` instruction.
|
||||||
|
assert!(cpuid
|
||||||
|
.get_extended_processor_and_feature_identifiers()
|
||||||
|
.unwrap()
|
||||||
|
.has_syscall_sysret());
|
||||||
|
Efer::update(|efer| {
|
||||||
|
efer.insert(EferFlags::SYSTEM_CALL_EXTENSIONS);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enable `FSGSBASE` instructions.
|
||||||
|
assert!(cpuid.get_extended_feature_info().unwrap().has_fsgsbase());
|
||||||
|
Cr4::update(|cr4| {
|
||||||
|
cr4.insert(Cr4Flags::FSGSBASE);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Flags to clear on syscall.
|
||||||
|
// Copy from Linux 5.0, TF|DF|IF|IOPL|AC|NT
|
||||||
|
const RFLAGS_MASK: u64 = 0x47700;
|
||||||
|
|
||||||
|
LStar::write(VirtAddr::new(syscall_entry as usize as u64));
|
||||||
|
SFMask::write(RFlags::from_bits(RFLAGS_MASK).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "sysv64" {
|
||||||
|
fn syscall_entry();
|
||||||
|
fn syscall_return(regs: &mut UserContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserContext {
|
||||||
|
/// Go to user space with the context, and come back when a trap occurs.
|
||||||
|
///
|
||||||
|
/// On return, the context will be reset to the status before the trap.
|
||||||
|
/// Trap reason and error code will be placed at `trap_num` and `error_code`.
|
||||||
|
///
|
||||||
|
/// If the trap was triggered by `syscall` instruction, the `trap_num` will be set to `0x100`.
|
||||||
|
///
|
||||||
|
/// If `trap_num` is `0x100`, it will go user by `sysret` (`rcx` and `r11` are dropped),
|
||||||
|
/// otherwise it will use `iret`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```no_run
|
||||||
|
/// use trapframe::{UserContext, GeneralRegs};
|
||||||
|
///
|
||||||
|
/// // init user space context
|
||||||
|
/// let mut context = UserContext {
|
||||||
|
/// general: GeneralRegs {
|
||||||
|
/// rip: 0x1000,
|
||||||
|
/// rsp: 0x10000,
|
||||||
|
/// ..Default::default()
|
||||||
|
/// },
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
/// // go to user
|
||||||
|
/// context.run();
|
||||||
|
/// // back from user
|
||||||
|
/// println!("back from user: {:#x?}", context);
|
||||||
|
/// ```
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
syscall_return(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
149
ostd/src/arch/x86/trap/trap.S
Normal file
149
ostd/src/arch/x86/trap/trap.S
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/* SPDX-License-Identifier: MPL-2.0 OR MIT
|
||||||
|
*
|
||||||
|
* The original source code is from [trapframe-rs](https://github.com/rcore-os/trapframe-rs),
|
||||||
|
* which is released under the following license:
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 - 2024 Runji Wang
|
||||||
|
*
|
||||||
|
* We make the following new changes:
|
||||||
|
* * Add the `trap_handler_table`.
|
||||||
|
*
|
||||||
|
* These changes are released under the following license:
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
.equ NUM_INT, 256
|
||||||
|
|
||||||
|
.altmacro
|
||||||
|
.macro DEF_HANDLER, i
|
||||||
|
.Ltrap_handler_\i:
|
||||||
|
.if \i == 8 || (\i >= 10 && \i <= 14) || \i == 17
|
||||||
|
# error code pushed by CPU
|
||||||
|
push \i # interrupt vector
|
||||||
|
jmp trap_common
|
||||||
|
.else
|
||||||
|
push 0 # fill in error code in TrapFrame
|
||||||
|
push \i # interrupt vector
|
||||||
|
jmp trap_common
|
||||||
|
.endif
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
_trap_handlers:
|
||||||
|
.set i, 0
|
||||||
|
.rept NUM_INT
|
||||||
|
DEF_HANDLER %i
|
||||||
|
.set i, i + 1
|
||||||
|
.endr
|
||||||
|
|
||||||
|
.macro DEF_TABLE_ENTRY, i
|
||||||
|
.quad .Ltrap_handler_\i
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
.global trap_handler_table
|
||||||
|
trap_handler_table:
|
||||||
|
.set i, 0
|
||||||
|
.rept NUM_INT
|
||||||
|
DEF_TABLE_ENTRY %i
|
||||||
|
.set i, i + 1
|
||||||
|
.endr
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.global trap_common
|
||||||
|
trap_common:
|
||||||
|
push rax
|
||||||
|
mov ax, [rsp + 4*8] # load cs
|
||||||
|
and ax, 0x3 # test
|
||||||
|
jz __from_kernel # continue trap
|
||||||
|
|
||||||
|
__from_user:
|
||||||
|
/*
|
||||||
|
kernel stack:
|
||||||
|
- ptr to GeneralRegs
|
||||||
|
- ss
|
||||||
|
- rsp
|
||||||
|
- rflags
|
||||||
|
- cs
|
||||||
|
- rip
|
||||||
|
- error code
|
||||||
|
- trap num
|
||||||
|
- rax
|
||||||
|
*/
|
||||||
|
swapgs # swap in kernel gs
|
||||||
|
mov rax, [rsp + 6*8] # rax = user rsp
|
||||||
|
mov gs:12, rax # store user rsp -> scratch at TSS.sp1
|
||||||
|
|
||||||
|
mov rsp, [rsp + 8*8] # load rsp -> GeneralRegs
|
||||||
|
add rsp, 22*8 # rsp -> top of GeneralRegs
|
||||||
|
mov rax, gs:4 # rax = kernel stack
|
||||||
|
|
||||||
|
# push trap_num, error_code
|
||||||
|
push [rax - 6*8] # push error_code
|
||||||
|
push [rax - 7*8] # push trap_num
|
||||||
|
sub rsp, 16 # skip fsbase, gsbase
|
||||||
|
# push general registers
|
||||||
|
push [rax - 3*8] # push rflags
|
||||||
|
push [rax - 5*8] # push rip
|
||||||
|
mov rax, [rax - 8*8] # pop rax
|
||||||
|
jmp trap_syscall_entry
|
||||||
|
|
||||||
|
__from_kernel:
|
||||||
|
/*
|
||||||
|
kernel stack:
|
||||||
|
- rflags
|
||||||
|
- cs
|
||||||
|
- rip
|
||||||
|
- error code
|
||||||
|
- trap num
|
||||||
|
- rax
|
||||||
|
*/
|
||||||
|
pop rax
|
||||||
|
push 0
|
||||||
|
push r15
|
||||||
|
push r14
|
||||||
|
push r13
|
||||||
|
push r12
|
||||||
|
push r11
|
||||||
|
push r10
|
||||||
|
push r9
|
||||||
|
push r8
|
||||||
|
lea r8, [rsp + 13*8]
|
||||||
|
push r8 # push rsp
|
||||||
|
push rbp
|
||||||
|
push rdi
|
||||||
|
push rsi
|
||||||
|
push rdx
|
||||||
|
push rcx
|
||||||
|
push rbx
|
||||||
|
push rax
|
||||||
|
|
||||||
|
mov rdi, rsp
|
||||||
|
call trap_handler
|
||||||
|
|
||||||
|
.global trap_return
|
||||||
|
trap_return:
|
||||||
|
pop rax
|
||||||
|
pop rbx
|
||||||
|
pop rcx
|
||||||
|
pop rdx
|
||||||
|
pop rsi
|
||||||
|
pop rdi
|
||||||
|
pop rbp
|
||||||
|
pop r8 # skip rsp
|
||||||
|
pop r8
|
||||||
|
pop r9
|
||||||
|
pop r10
|
||||||
|
pop r11
|
||||||
|
pop r12
|
||||||
|
pop r13
|
||||||
|
pop r14
|
||||||
|
pop r15
|
||||||
|
|
||||||
|
# skip padding, trap_num, error_code
|
||||||
|
add rsp, 24
|
||||||
|
|
||||||
|
iretq
|
@ -121,7 +121,7 @@ fn ap_early_entry(local_apic_id: u32) -> ! {
|
|||||||
|
|
||||||
// SAFETY: this function is only called once on this AP.
|
// SAFETY: this function is only called once on this AP.
|
||||||
unsafe {
|
unsafe {
|
||||||
trapframe::init();
|
crate::arch::trap::init(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: this function is only called once on this AP, after the BSP has
|
// SAFETY: this function is only called once on this AP, after the BSP has
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(ptr_sub_ptr)]
|
#![feature(ptr_sub_ptr)]
|
||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
|
#![feature(sync_unsafe_cell)]
|
||||||
// The `generic_const_exprs` feature is incomplete however required for the page table
|
// The `generic_const_exprs` feature is incomplete however required for the page table
|
||||||
// const generic implementation. We are using this feature in a conservative manner.
|
// const generic implementation. We are using this feature in a conservative manner.
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
@ -87,7 +88,6 @@ pub unsafe fn init() {
|
|||||||
mm::kspace::init_kernel_page_table(mm::init_page_meta());
|
mm::kspace::init_kernel_page_table(mm::init_page_meta());
|
||||||
mm::misc_init();
|
mm::misc_init();
|
||||||
|
|
||||||
trapframe::init();
|
|
||||||
// SAFETY: This function is called only once in the entire system.
|
// SAFETY: This function is called only once in the entire system.
|
||||||
unsafe { trap::softirq::init() };
|
unsafe { trap::softirq::init() };
|
||||||
arch::init_on_bsp();
|
arch::init_on_bsp();
|
||||||
|
@ -32,6 +32,7 @@ pub struct Task {
|
|||||||
user_space: Option<Arc<UserSpace>>,
|
user_space: Option<Arc<UserSpace>>,
|
||||||
ctx: UnsafeCell<TaskContext>,
|
ctx: UnsafeCell<TaskContext>,
|
||||||
/// kernel stack, note that the top is SyscallFrame/TrapFrame
|
/// kernel stack, note that the top is SyscallFrame/TrapFrame
|
||||||
|
#[allow(dead_code)]
|
||||||
kstack: KernelStack,
|
kstack: KernelStack,
|
||||||
|
|
||||||
schedule_info: TaskScheduleInfo,
|
schedule_info: TaskScheduleInfo,
|
||||||
@ -53,6 +54,22 @@ impl Task {
|
|||||||
&self.ctx
|
&self.ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets thread-local storage pointer.
|
||||||
|
pub fn set_tls_pointer(&self, tls: usize) {
|
||||||
|
let ctx_ptr = self.ctx.get();
|
||||||
|
|
||||||
|
// SAFETY: it's safe to set user tls pointer in kernel context.
|
||||||
|
unsafe { (*ctx_ptr).set_tls_pointer(tls) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets thread-local storage pointer.
|
||||||
|
pub fn tls_pointer(&self) -> usize {
|
||||||
|
let ctx_ptr = self.ctx.get();
|
||||||
|
|
||||||
|
// SAFETY: it's safe to get user tls pointer in kernel context.
|
||||||
|
unsafe { (*ctx_ptr).tls_pointer() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Yields execution so that another task may be scheduled.
|
/// Yields execution so that another task may be scheduled.
|
||||||
///
|
///
|
||||||
/// Note that this method cannot be simply named "yield" as the name is
|
/// Note that this method cannot be simply named "yield" as the name is
|
||||||
@ -176,21 +193,14 @@ impl TaskOptions {
|
|||||||
current_task.exit();
|
current_task.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_task = Task {
|
let kstack = KernelStack::new_with_guard_page()?;
|
||||||
func: self.func.unwrap(),
|
|
||||||
data: self.data.unwrap(),
|
|
||||||
user_space: self.user_space,
|
|
||||||
ctx: UnsafeCell::new(TaskContext::default()),
|
|
||||||
kstack: KernelStack::new_with_guard_page()?,
|
|
||||||
schedule_info: TaskScheduleInfo {
|
|
||||||
cpu: AtomicCpuId::default(),
|
|
||||||
priority: self.priority,
|
|
||||||
cpu_affinity: self.cpu_affinity,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let ctx = new_task.ctx.get_mut();
|
let mut ctx = UnsafeCell::new(TaskContext::default());
|
||||||
ctx.set_instruction_pointer(kernel_task_entry as usize);
|
if let Some(user_space) = self.user_space.as_ref() {
|
||||||
|
ctx.get_mut().set_tls_pointer(user_space.tls_pointer());
|
||||||
|
};
|
||||||
|
ctx.get_mut()
|
||||||
|
.set_instruction_pointer(kernel_task_entry as usize);
|
||||||
// We should reserve space for the return address in the stack, otherwise
|
// We should reserve space for the return address in the stack, otherwise
|
||||||
// we will write across the page boundary due to the implementation of
|
// we will write across the page boundary due to the implementation of
|
||||||
// the context switch.
|
// the context switch.
|
||||||
@ -199,7 +209,21 @@ impl TaskOptions {
|
|||||||
// to at least 16 bytes. And a larger alignment is needed if larger arguments
|
// to at least 16 bytes. And a larger alignment is needed if larger arguments
|
||||||
// are passed to the function. The `kernel_task_entry` function does not
|
// are passed to the function. The `kernel_task_entry` function does not
|
||||||
// have any arguments, so we only need to align the stack pointer to 16 bytes.
|
// have any arguments, so we only need to align the stack pointer to 16 bytes.
|
||||||
ctx.set_stack_pointer(crate::mm::paddr_to_vaddr(new_task.kstack.end_paddr() - 16));
|
ctx.get_mut()
|
||||||
|
.set_stack_pointer(crate::mm::paddr_to_vaddr(kstack.end_paddr() - 16));
|
||||||
|
|
||||||
|
let new_task = Task {
|
||||||
|
func: self.func.unwrap(),
|
||||||
|
data: self.data.unwrap(),
|
||||||
|
user_space: self.user_space,
|
||||||
|
ctx,
|
||||||
|
kstack,
|
||||||
|
schedule_info: TaskScheduleInfo {
|
||||||
|
cpu: AtomicCpuId::default(),
|
||||||
|
priority: self.priority,
|
||||||
|
cpu_affinity: self.cpu_affinity,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
Ok(new_task)
|
Ok(new_task)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use trapframe::TrapFrame;
|
use crate::{arch::irq::IRQ_LIST, cpu_local_cell, trap::TrapFrame};
|
||||||
|
|
||||||
use crate::{arch::irq::IRQ_LIST, cpu_local_cell};
|
|
||||||
|
|
||||||
pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame, irq_number: usize) {
|
pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame, irq_number: usize) {
|
||||||
// For x86 CPUs, interrupts are not re-entrant. Local interrupts will be disabled when
|
// For x86 CPUs, interrupts are not re-entrant. Local interrupts will be disabled when
|
||||||
|
@ -4,11 +4,10 @@
|
|||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
use trapframe::TrapFrame;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::irq::{self, IrqCallbackHandle, IRQ_ALLOCATOR},
|
arch::irq::{self, IrqCallbackHandle, IRQ_ALLOCATOR},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
trap::TrapFrame,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ pub mod softirq;
|
|||||||
|
|
||||||
pub use handler::in_interrupt_context;
|
pub use handler::in_interrupt_context;
|
||||||
pub use softirq::SoftIrqLine;
|
pub use softirq::SoftIrqLine;
|
||||||
pub use trapframe::TrapFrame;
|
|
||||||
|
|
||||||
pub(crate) use self::handler::call_irq_callback_functions;
|
pub(crate) use self::handler::call_irq_callback_functions;
|
||||||
pub use self::irq::{disable_local, DisabledLocalIrqGuard, IrqCallbackFunction, IrqLine};
|
pub use self::irq::{disable_local, DisabledLocalIrqGuard, IrqCallbackFunction, IrqLine};
|
||||||
|
pub use crate::arch::trap::TrapFrame;
|
||||||
|
@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
//! User space.
|
//! User space.
|
||||||
|
|
||||||
use trapframe::TrapFrame;
|
use crate::{cpu::UserContext, mm::VmSpace, prelude::*, task::Task, trap::TrapFrame};
|
||||||
|
|
||||||
use crate::{cpu::UserContext, mm::VmSpace, prelude::*, task::Task};
|
|
||||||
|
|
||||||
/// A user space.
|
/// A user space.
|
||||||
///
|
///
|
||||||
@ -47,6 +45,16 @@ impl UserSpace {
|
|||||||
pub fn user_mode(&self) -> UserMode<'_> {
|
pub fn user_mode(&self) -> UserMode<'_> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets thread-local storage pointer.
|
||||||
|
pub fn set_tls_pointer(&mut self, tls: usize) {
|
||||||
|
self.init_ctx.set_tls_pointer(tls)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets thread-local storage pointer.
|
||||||
|
pub fn tls_pointer(&self) -> usize {
|
||||||
|
self.init_ctx.tls_pointer()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specific architectures need to implement this trait. This should only used in [`UserMode`]
|
/// Specific architectures need to implement this trait. This should only used in [`UserMode`]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user