1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-23 08:26:17 +04:00

Fix set TSS in SMP

This commit is contained in:
WangRunji 2018-05-20 22:12:18 +08:00
parent 2f71eab39b
commit ffb7e194f9
4 changed files with 37 additions and 19 deletions

View File

@ -35,6 +35,9 @@ pub fn start_ap(apicid: u8, addr: u32) {
pub fn lapic_id() -> u8 {
unsafe{
if lapic.is_null() {
return 0;
}
(*(lapic as *const u32).offset(0x0020/4) >> 24) as u8
}
}

View File

@ -3,9 +3,10 @@ use core::fmt::Debug;
use x86_64::structures::tss::TaskStateSegment;
use x86_64::structures::gdt::SegmentSelector;
use x86_64::{PrivilegeLevel, VirtualAddress};
use spin::Once;
use spin::{Once, Mutex, MutexGuard};
use alloc::boxed::Box;
use core::ptr::Unique;
use arch::driver::apic::lapic_id;
use consts::MAX_CPU_NUM;
/// Alloc TSS & GDT at kernel heap, then init and load it.
/// The double fault stack will be allocated at kernel heap too.
@ -26,8 +27,7 @@ pub fn init() {
tss
});
unsafe{ TSS_PTR = Unique::new_unchecked(Box::into_raw(tss)); }
let tss = unsafe{ TSS_PTR.as_ref() };
let tss = Box::into_raw(tss);
let gdt = Box::new({
let mut gdt = Gdt::new();
@ -37,7 +37,7 @@ pub fn init() {
gdt.add_entry(UDATA);
gdt.add_entry(UCODE32);
gdt.add_entry(UDATA32);
gdt.add_entry(Descriptor::tss_segment(&tss));
gdt.add_entry(Descriptor::tss_segment(unsafe { &*tss }));
gdt
});
let gdt = unsafe{ &*Box::into_raw(gdt) };
@ -49,19 +49,35 @@ pub fn init() {
// load TSS
load_tss(TSS_SELECTOR);
}
CPUS[lapic_id() as usize].call_once(||
Mutex::new(Cpu { gdt, tss: unsafe { &mut *tss } }));
}
// TODO: more elegant?
static mut TSS_PTR: Unique<TaskStateSegment> = unsafe{ Unique::new_unchecked(0 as *mut _) };
static CPUS: [Once<Mutex<Cpu>>; MAX_CPU_NUM] = [
// TODO: More elegant ?
Once::new(), Once::new(), Once::new(), Once::new(),
Once::new(), Once::new(), Once::new(), Once::new(),
];
pub struct Cpu {
gdt: &'static Gdt,
tss: &'static mut TaskStateSegment,
}
impl Cpu {
pub fn current() -> MutexGuard<'static, Cpu> {
CPUS[lapic_id() as usize].try().unwrap().lock()
}
/// 设置从Ring3跳到Ring0时自动切换栈的地址
///
/// 每次进入用户态前,都要调用此函数,才能保证正确返回内核态
pub fn set_ring0_rsp(rsp: usize) {
pub fn set_ring0_rsp(&mut self, rsp: usize) {
trace!("gdt.set_ring0_rsp: {:#x}", rsp);
unsafe {
TSS_PTR.as_mut().privilege_stack_table[0] = VirtualAddress(rsp);
trace!("TSS:\n{:?}", TSS_PTR.as_ref());
self.tss.privilege_stack_table[0] = VirtualAddress(rsp);
}
}
}

View File

@ -126,10 +126,10 @@ pub extern fn rust_trap(tf: &mut TrapFrame) -> usize {
}
fn set_return_rsp(tf: &TrapFrame) {
use arch::gdt;
use arch::gdt::Cpu;
use core::mem::size_of;
if tf.cs & 0x3 == 3 {
gdt::set_ring0_rsp(tf as *const _ as usize + size_of::<TrapFrame>());
Cpu::current().set_ring0_rsp(tf as *const _ as usize + size_of::<TrapFrame>());
}
}

View File

@ -81,8 +81,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
|addr: usize| memory_controller.map_page_identity(addr));
// memory_controller.print_page_table();
// FIXME: 开启SMP后导致switch_to_user中设置rsp无效
// arch::smp::start_other_cores(&acpi, &mut memory_controller);
arch::smp::start_other_cores(&acpi, &mut memory_controller);
process::init(memory_controller);
fs::load_sfs();