Hooks to get the other CPUs into long mode

This commit is contained in:
Jeremy Soller 2016-08-16 20:37:38 -06:00
parent 08900d56c8
commit a8948fb246
2 changed files with 182 additions and 108 deletions

View file

@ -1,6 +1,8 @@
//! # ACPI //! # ACPI
//! Code to parse the ACPI tables //! Code to parse the ACPI tables
use core::intrinsics::{atomic_load, atomic_store};
use memory::{Frame, FrameAllocator}; use memory::{Frame, FrameAllocator};
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
@ -16,6 +18,9 @@ pub mod rsdt;
pub mod sdt; pub mod sdt;
pub mod xsdt; pub mod xsdt;
const TRAMPOLINE: usize = 0x7E00;
const AP_STARTUP: usize = 0x8000;
pub fn init_sdt(sdt: &'static Sdt) { pub fn init_sdt(sdt: &'static Sdt) {
print!(" "); print!(" ");
for &c in sdt.signature.iter() { for &c in sdt.signature.iter() {
@ -37,16 +42,33 @@ pub fn init_sdt(sdt: &'static Sdt) {
println!(" This is my local APIC"); println!(" This is my local APIC");
} else { } else {
if asp_local_apic.flags & 1 == 1 { if asp_local_apic.flags & 1 == 1 {
let ap_ready = TRAMPOLINE as *mut u64;
let ap_stack = unsafe { ap_ready.offset(1) };
// Set the ap_ready to 0, volatile
unsafe { atomic_store(ap_ready, 0) };
// Send INIT IPI
{ {
let icr = 0x00004500 | (asp_local_apic.id as u64) << 32; let icr = 0x00004500 | (asp_local_apic.id as u64) << 32;
println!(" Sending IPI to {}: {:>016X} {:?}", asp_local_apic.id, icr, LocalApicIcr::from_bits(icr)); println!(" Sending IPI to {}: {:>016X} {:?}", asp_local_apic.id, icr, LocalApicIcr::from_bits(icr));
local_apic.set_icr(icr); local_apic.set_icr(icr);
} }
// Send START IPI
{ {
let icr = 0x00004600 | (asp_local_apic.id as u64) << 32; let ap_segment = (AP_STARTUP >> 12) & 0xFF;
let icr = 0x00004600 | ((asp_local_apic.id as u64) << 32) | ap_segment as u64; //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
println!(" Sending SIPI to {}: {:>016X} {:?}", asp_local_apic.id, icr, LocalApicIcr::from_bits(icr)); println!(" Sending SIPI to {}: {:>016X} {:?}", asp_local_apic.id, icr, LocalApicIcr::from_bits(icr));
local_apic.set_icr(icr); local_apic.set_icr(icr);
} }
// Wait for trampoline ready
println!(" Waiting for AP {}", asp_local_apic.id);
while unsafe { atomic_load(ap_ready) } == 0 {
unsafe { asm!("pause" : : : : "intel", "volatile") };
}
println!(" AP {} is ready!", asp_local_apic.id);
} else { } else {
println!(" CPU Disabled"); println!(" CPU Disabled");
} }
@ -63,15 +85,6 @@ pub fn init_sdt(sdt: &'static Sdt) {
pub unsafe fn init<A>(allocator: &mut A, active_table: &mut ActivePageTable) -> Option<Acpi> pub unsafe fn init<A>(allocator: &mut A, active_table: &mut ActivePageTable) -> Option<Acpi>
where A: FrameAllocator where A: FrameAllocator
{ {
// Stupidity of enormous proportion. Write the halt opcode to the 0'th physical address
// so that START IPI's can halt the processor
{
if active_table.translate_page(Page::containing_address(VirtualAddress::new(0))).is_none() {
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0)), entry::PRESENT | entry::WRITABLE, allocator);
}
unsafe { *(0 as *mut u8) = 0xF4 };
}
let start_addr = 0xE0000; let start_addr = 0xE0000;
let end_addr = 0xFFFFF; let end_addr = 0xFFFFF;
@ -86,6 +99,13 @@ pub unsafe fn init<A>(allocator: &mut A, active_table: &mut ActivePageTable) ->
} }
} }
// Map trampoline
{
if active_table.translate_page(Page::containing_address(VirtualAddress::new(TRAMPOLINE))).is_none() {
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(TRAMPOLINE)), entry::PRESENT | entry::WRITABLE, allocator);
}
}
// Search for RSDP // Search for RSDP
if let Some(rsdp) = RSDP::search(start_addr, end_addr) { if let Some(rsdp) = RSDP::search(start_addr, end_addr) {
println!("{:?}", rsdp); println!("{:?}", rsdp);

View file

@ -1,3 +1,45 @@
trampoline:
.ready: dq 0
.stack: dq 0
times 512 - ($ - trampoline) db 0
startup_ap:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
; initialize stack
mov sp, 0x7C00
;cr3 holds pointer to PML4
mov edi, 0x70000
mov cr3, edi
;enable Page Address Extension and Page Size Extension
mov eax, cr4
or eax, 1 << 5 | 1 << 4
mov cr4, eax
; load protected mode GDT
lgdt [gdtr]
mov ecx, 0xC0000080 ; Read from the EFER MSR.
rdmsr
or eax, 1 << 11 | 1 << 8 ; Set the Long-Mode-Enable and NXE bit.
wrmsr
;enabling paging and protection simultaneously
mov ebx, cr0
or ebx, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
mov cr0, ebx
; far jump to enable Long Mode and load CS with 64 bit segment
jmp gdt.kernel_code:long_mode_ap
%include "startup-common.asm" %include "startup-common.asm"
startup_arch: startup_arch:
@ -74,9 +116,21 @@ long_mode:
;rust init ;rust init
xor rax, rax xor rax, rax
mov eax, [kernel_base + 0x18] mov eax, [kernel_base + 0x18]
mov rbx, gdtr
jmp rax jmp rax
long_mode_ap:
mov rax, gdt.kernel_data
mov ds, rax
mov es, rax
mov fs, rax
mov gs, rax
mov ss, rax
mov qword [trampoline.ready], 1
.lp:
hlt
jmp .lp
gdtr: gdtr:
dw gdt.end + 1 ; size dw gdt.end + 1 ; size
dq gdt ; offset dq gdt ; offset