Copy start_ap to lapic.c . Simple startothers(). Try to boot AP but failed.

master
WangRunji 7 years ago
parent cc34857482
commit 8a8aff8917

@ -27,11 +27,14 @@
%define STA_R 0x2 ; Readable (executable segments) %define STA_R 0x2 ; Readable (executable segments)
%define STA_A 0x1 ; Accessed %define STA_A 0x1 ; Accessed
global otherstart global entryother_start
global entryother_end
entryother_start:
section .text section .text
bits 16 bits 16
otherstart: start:
cli cli
xor ax, ax xor ax, ax
@ -62,9 +65,9 @@ start32:
mov ebx, 1 mov ebx, 1
; Switch to the stack allocated by startothers() ; Switch to the stack allocated by startothers()
mov esp, [otherstart-4] mov esp, [start-4]
; Call mpenter() ; Call mpenter()
call [otherstart-8] call [start-8]
mov ax, 0x8a00 mov ax, 0x8a00
mov dx, ax mov dx, ax
@ -74,10 +77,7 @@ start32:
spin: spin:
jmp spin jmp spin
section .bss ; section .rodata
resb 4096
section .rodata
align 4 align 4
gdt: gdt:
; NULL ; NULL
@ -92,3 +92,5 @@ gdt:
.desc: .desc:
dw ($ - gdt - 1) dw ($ - gdt - 1)
dq gdt dq gdt
entryother_end:

@ -6,23 +6,6 @@ KERNEL_OFFSET = 0xffffff0000000000;
SECTIONS { SECTIONS {
. = OTHER_OFFSET - 0x1000;
.bss.other :
{
KEEP(*/entryother.o (.bss))
. = ALIGN(4K);
}
.text.other :
{
KEEP(*/entryother.o (.text))
. = ALIGN(4K);
}
.rodata.other :
{
KEEP(*/entryother.o (.rodata))
. = ALIGN(4K);
}
. = BOOT_OFFSET; . = BOOT_OFFSET;
.rodata.32 : .rodata.32 :
@ -44,6 +27,17 @@ SECTIONS {
. = ALIGN(4K); . = ALIGN(4K);
} }
/* bootloader for other processors */
real = .; /* backup va */
. = OTHER_OFFSET;
.text.other : AT(real)
{
KEEP(*/entryother.o (.text))
. = ALIGN(4K);
}
. = . - OTHER_OFFSET + real; /* recover va */
. += KERNEL_OFFSET; . += KERNEL_OFFSET;
.rodata : AT(ADDR(.rodata) - KERNEL_OFFSET) .rodata : AT(ADDR(.rodata) - KERNEL_OFFSET)

@ -2,6 +2,17 @@
// See Chapter 8 & Appendix C of Intel processor manual volume 3. // See Chapter 8 & Appendix C of Intel processor manual volume 3.
typedef unsigned int uint; typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;
static inline void
outb(ushort port, uchar data)
{
asm volatile("out %0,%1" : : "a" (data), "d" (port));
}
#define KERNBASE 0xFFFFFF0000000000 // First kernel virtual address
#define P2V(a) (((void *) (a)) + KERNBASE)
#define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ #define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ
@ -106,3 +117,49 @@ lapiceoi(void)
if(lapic) if(lapic)
lapicw(EOI, 0); lapicw(EOI, 0);
} }
// Spin for a given number of microseconds.
// On real hardware would want to tune this dynamically.
void
microdelay(int us)
{
}
#define CMOS_PORT 0x70
#define CMOS_RETURN 0x71
// Start additional processor running entry code at addr.
// See Appendix B of MultiProcessor Specification.
void
lapicstartap(uchar apicid, uint addr)
{
int i;
ushort *wrv;
// "The BSP must initialize CMOS shutdown code to 0AH
// and the warm reset vector (DWORD based at 40:67) to point at
// the AP startup code prior to the [universal startup algorithm]."
outb(CMOS_PORT, 0xF); // offset 0xF is shutdown code
outb(CMOS_PORT+1, 0x0A);
wrv = (ushort*)P2V((0x40<<4 | 0x67)); // Warm reset vector
wrv[0] = 0;
wrv[1] = addr >> 4;
// "Universal startup algorithm."
// Send INIT (level-triggered) interrupt to reset other CPU.
lapicw(ICRHI, apicid<<24);
lapicw(ICRLO, INIT | LEVEL | ASSERT);
microdelay(200);
lapicw(ICRLO, INIT | LEVEL);
microdelay(10000);
// Send startup IPI (twice!) to enter code.
// Regular hardware is supposed to only accept a STARTUP
// when it is in the halted state due to an INIT. So the second
// should be ignored, but it is part of the official Intel algorithm.
for(i = 0; i < 2; i++){
lapicw(ICRHI, apicid<<24);
lapicw(ICRLO, STARTUP | (addr>>12));
microdelay(200);
}
}

@ -2,6 +2,7 @@ extern {
static mut lapic: *const (); static mut lapic: *const ();
fn lapicinit(); // must set `lapic` first fn lapicinit(); // must set `lapic` first
fn lapiceoi(); // ack fn lapiceoi(); // ack
fn lapicstartap(apicid: u8, addr: u32);
} }
pub fn init(lapic_addr: *const ()) { pub fn init(lapic_addr: *const ()) {
@ -18,3 +19,10 @@ pub fn ack(_irq: u8) {
lapiceoi(); lapiceoi();
} }
} }
pub fn start_ap(apicid: u8, addr: u32) {
debug!("WARNING: lapic::start_ap use C lib");
unsafe {
lapicstartap(apicid, addr);
}
}

@ -1,5 +1,5 @@
pub use self::ioapic::IOAPIC; pub use self::ioapic::IOAPIC;
pub use self::lapic::ack; pub use self::lapic::{ack, start_ap};
mod lapic; mod lapic;
mod ioapic; mod ioapic;

@ -7,7 +7,7 @@ pub mod pic;
pub mod keyboard; pub mod keyboard;
pub mod pit; pub mod pit;
pub fn init<F>(mut page_map: F) pub fn init<F>(mut page_map: F) -> acpi::ACPI_Result
where F: FnMut(usize) { where F: FnMut(usize) {
assert_has_not_been_called!(); assert_has_not_been_called!();
@ -35,4 +35,5 @@ pub fn init<F>(mut page_map: F)
pit::init(); pit::init();
serial::init(); serial::init();
keyboard::init(); keyboard::init();
acpi
} }

@ -16,7 +16,9 @@ pub extern "x86-interrupt" fn double_fault_handler(
pub extern "x86-interrupt" fn page_fault_handler( pub extern "x86-interrupt" fn page_fault_handler(
stack_frame: &mut ExceptionStackFrame, error_code: PageFaultErrorCode) stack_frame: &mut ExceptionStackFrame, error_code: PageFaultErrorCode)
{ {
println!("\nEXCEPTION: PAGE FAULT\n{:#?}\n{:#?}", stack_frame, error_code); use x86_64::registers::control_regs::cr2;
println!("\nEXCEPTION: PAGE FAULT\n{:#?}\nErrorCode: {:#?}\nAddress: {:#x}",
stack_frame, error_code, cr2());
loop {} loop {}
} }

@ -4,6 +4,7 @@ pub mod interrupt;
pub mod paging; pub mod paging;
pub mod gdt; pub mod gdt;
pub mod idt; pub mod idt;
pub mod smp;
pub fn init() { pub fn init() {
cpu::enable_nxe_bit(); cpu::enable_nxe_bit();

@ -0,0 +1,47 @@
use arch::driver::{acpi::ACPI_Result, apic::start_ap};
use memory::{MemoryController, PhysicalAddress};
extern {
fn entryother_start();
fn entryother_end();
}
const ENTRYOTHER_ADDR: u32 = 0x7000;
pub fn start_other_cores(acpi: &ACPI_Result, mc: &mut MemoryController) {
mc.map_page_identity(ENTRYOTHER_ADDR as usize - 1);
mc.map_page_identity(ENTRYOTHER_ADDR as usize);
mc.map_page_p2v(PhysicalAddress(0));
copy_entryother();
let args = unsafe{ &mut *(ENTRYOTHER_ADDR as *mut EntryArgs).offset(-1) };
for i in 1 .. acpi.cpu_num {
let apic_id = acpi.cpu_acpi_ids[i as usize];
*args = EntryArgs {
kstack: mc.alloc_stack(1).unwrap().top() as u64,
next_code: 0,
stack: 0x8000, // just enough stack to get us to entry64mp
};
start_ap(apic_id, ENTRYOTHER_ADDR);
}
}
fn hello_world() {
println!("Hello world!");
}
fn copy_entryother() {
use rlibc::memmove;
let entryother_start = entryother_start as usize;
let entryother_end = entryother_end as usize;
let size = entryother_end - entryother_start;
unsafe{ memmove(ENTRYOTHER_ADDR as *mut u8, entryother_start as *mut u8, size); }
debug!("smp: copied entryother code to 0x7000");
}
#[repr(C)]
struct EntryArgs {
kstack: u64,
next_code: u32,
stack: u32,
}

@ -69,8 +69,10 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) {
test!(guard_page); test!(guard_page);
test!(find_mp); test!(find_mp);
arch::driver::init(|addr: usize| memory_controller.map_page_identity(addr)); let acpi = arch::driver::init(
|addr: usize| memory_controller.map_page_identity(addr));
// memory_controller.print_page_table(); // memory_controller.print_page_table();
arch::smp::start_other_cores(&acpi, &mut memory_controller);
unsafe{ arch::interrupt::enable(); } unsafe{ arch::interrupt::enable(); }
loop{} loop{}

@ -164,6 +164,12 @@ impl MemoryController {
let flags = EntryFlags::WRITABLE; let flags = EntryFlags::WRITABLE;
self.active_table.identity_map(frame, flags, &mut self.frame_allocator); self.active_table.identity_map(frame, flags, &mut self.frame_allocator);
} }
pub fn map_page_p2v(&mut self, addr: PhysicalAddress) {
let page = Page::containing_address(addr.to_kernel_virtual());
let frame = Frame::containing_address(addr.get());
let flags = EntryFlags::WRITABLE;
self.active_table.map_to(page, frame, flags, &mut self.frame_allocator);
}
pub fn print_page_table(&self) { pub fn print_page_table(&self) {
debug!("{:?}", self.active_table); debug!("{:?}", self.active_table);
} }

Loading…
Cancel
Save