* Remove legacy boot, MP, ACPI. * Disable SMP. * Modify startup: boot -> arch::init -> kmain. * Fix FrameAllocator on x86_64. * Remove kernel remap. * Alloc kernel heap at bss.master
parent
0437e5cb17
commit
0a9c294814
@ -1,173 +0,0 @@
|
||||
global start
|
||||
global stack_bottom
|
||||
global stack_top
|
||||
extern long_mode_start
|
||||
|
||||
section .text
|
||||
bits 32
|
||||
start:
|
||||
mov esp, stack_top
|
||||
push ebx ; push Multiboot info pointer to stack_top
|
||||
|
||||
call check_multiboot
|
||||
call check_cpuid
|
||||
call check_long_mode
|
||||
|
||||
call set_up_page_tables
|
||||
call enable_paging
|
||||
|
||||
; load the 64-bit GDT
|
||||
lgdt [gdt64.pointer]
|
||||
|
||||
jmp gdt64.code:long_mode_start
|
||||
|
||||
; print `OK` to screen
|
||||
mov dword [0xb8000], 0x2f4b2f4f
|
||||
hlt
|
||||
|
||||
check_multiboot:
|
||||
cmp eax, 0x36d76289
|
||||
jne .no_multiboot
|
||||
ret
|
||||
.no_multiboot:
|
||||
mov al, "0"
|
||||
jmp error
|
||||
|
||||
check_cpuid:
|
||||
; Check if CPUID is supported by attempting to flip the ID bit (bit 21)
|
||||
; in the FLAGS register. If we can flip it, CPUID is available.
|
||||
|
||||
; Copy FLAGS in to EAX via stack
|
||||
pushfd
|
||||
pop eax
|
||||
|
||||
; Copy to ECX as well for comparing later on
|
||||
mov ecx, eax
|
||||
|
||||
; Flip the ID bit
|
||||
xor eax, 1 << 21
|
||||
|
||||
; Copy EAX to FLAGS via the stack
|
||||
push eax
|
||||
popfd
|
||||
|
||||
; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported)
|
||||
pushfd
|
||||
pop eax
|
||||
|
||||
; Restore FLAGS from the old version stored in ECX (i.e. flipping the
|
||||
; ID bit back if it was ever flipped).
|
||||
push ecx
|
||||
popfd
|
||||
|
||||
; Compare EAX and ECX. If they are equal then that means the bit
|
||||
; wasn't flipped, and CPUID isn't supported.
|
||||
cmp eax, ecx
|
||||
je .no_cpuid
|
||||
ret
|
||||
.no_cpuid:
|
||||
mov al, "1"
|
||||
jmp error
|
||||
|
||||
check_long_mode:
|
||||
; test if extended processor info in available
|
||||
mov eax, 0x80000000 ; implicit argument for cpuid
|
||||
cpuid ; get highest supported argument
|
||||
cmp eax, 0x80000001 ; it needs to be at least 0x80000001
|
||||
jb .no_long_mode ; if it's less, the CPU is too old for long mode
|
||||
|
||||
; use extended info to test if long mode is available
|
||||
mov eax, 0x80000001 ; argument for extended processor info
|
||||
cpuid ; returns various feature bits in ecx and edx
|
||||
test edx, 1 << 29 ; test if the LM-bit is set in the D-register
|
||||
jz .no_long_mode ; If it's not set, there is no long mode
|
||||
ret
|
||||
.no_long_mode:
|
||||
mov al, "2"
|
||||
jmp error
|
||||
|
||||
set_up_page_tables:
|
||||
; map P4 table recursively
|
||||
mov eax, p4_table
|
||||
or eax, 0b11 ; present + writable
|
||||
mov [p4_table + 511 * 8], eax
|
||||
|
||||
; map first & 510th P4 entry to P3 table
|
||||
mov eax, p3_table
|
||||
or eax, 0b11 ; present + writable
|
||||
mov [p4_table], eax
|
||||
mov [p4_table + 510 * 8], eax
|
||||
|
||||
; map first P3 entry to P2 table
|
||||
mov eax, p2_table
|
||||
or eax, 0b11 ; present + writable
|
||||
mov [p3_table], eax
|
||||
|
||||
; map each P2 entry to a huge 2MiB page
|
||||
mov ecx, 0 ; counter variable
|
||||
|
||||
.map_p2_table:
|
||||
; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx
|
||||
mov eax, 0x200000 ; 2MiB
|
||||
mul ecx ; start address of ecx-th page
|
||||
or eax, 0b10000011 ; present + writable + huge
|
||||
mov [p2_table + ecx * 8], eax ; map ecx-th entry
|
||||
|
||||
inc ecx ; increase counter
|
||||
cmp ecx, 512 ; if counter == 512, the whole P2 table is mapped
|
||||
jne .map_p2_table ; else map the next entry
|
||||
|
||||
ret
|
||||
|
||||
enable_paging:
|
||||
; load P4 to cr3 register (cpu uses this to access the P4 table)
|
||||
mov eax, p4_table
|
||||
mov cr3, eax
|
||||
|
||||
; enable PAE-flag in cr4 (Physical Address Extension)
|
||||
mov eax, cr4
|
||||
or eax, 1 << 5
|
||||
mov cr4, eax
|
||||
|
||||
; set the long mode bit & no execute bit in the EFER MSR (model specific register)
|
||||
mov ecx, 0xC0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8 | 1 << 11
|
||||
wrmsr
|
||||
|
||||
; enable paging & write protect in the cr0 register
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31 | 1 << 16
|
||||
mov cr0, eax
|
||||
|
||||
ret
|
||||
|
||||
; Prints `ERR: ` and the given error code to screen and hangs.
|
||||
; parameter: error code (in ascii) in al
|
||||
error:
|
||||
mov dword [0xb8000], 0x4f524f45
|
||||
mov dword [0xb8004], 0x4f3a4f52
|
||||
mov dword [0xb8008], 0x4f204f20
|
||||
mov byte [0xb800a], al
|
||||
hlt
|
||||
|
||||
section .bss
|
||||
align 4096
|
||||
p4_table:
|
||||
resb 4096
|
||||
p3_table:
|
||||
resb 4096
|
||||
p2_table:
|
||||
resb 4096
|
||||
stack_bottom:
|
||||
resb 4096 * 8
|
||||
stack_top:
|
||||
|
||||
section .rodata
|
||||
gdt64:
|
||||
dq 0 ; zero entry
|
||||
.code: equ $ - gdt64 ; new
|
||||
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
|
||||
.pointer:
|
||||
dw $ - gdt64 - 1
|
||||
dq gdt64
|
@ -1,141 +0,0 @@
|
||||
; xv6 x86_64 entryother.S
|
||||
|
||||
; Each non-boot CPU ("AP") is started up in response to a STARTUP
|
||||
; IPI from the boot CPU. Section B.4.2 of the Multi-Processor
|
||||
; Specification says that the AP will start in real mode with CS:IP
|
||||
; set to XY00:0000, where XY is an 8-bit value sent with the
|
||||
; STARTUP. Thus this code must start at a 4096-byte boundary.
|
||||
;
|
||||
; Because this code sets DS to zero, it must sit
|
||||
; at an address in the low 2^16 bytes.
|
||||
;
|
||||
; Startothers (in main.c) sends the STARTUPs one at a time.
|
||||
; It copies this code (start) at 0x7000. It puts the address of
|
||||
; a newly allocated per-core stack in start-4,the address of the
|
||||
; place to jump to (mpenter) in start-8, and the physical address
|
||||
; of entrypgdir in start-12.
|
||||
;
|
||||
; This code is identical to bootasm.S except:
|
||||
; - it does not need to enable A20
|
||||
; - it uses the address at start-4, start-8, and start-12
|
||||
|
||||
%define CR0_PE 1
|
||||
%define STA_X 0x8 ; Executable segment
|
||||
%define STA_E 0x4 ; Expand down (non-executable segments)
|
||||
%define STA_C 0x4 ; Conforming code segment (executable only)
|
||||
%define STA_W 0x2 ; Writeable (non-executable segments)
|
||||
%define STA_R 0x2 ; Readable (executable segments)
|
||||
%define STA_A 0x1 ; Accessed
|
||||
|
||||
extern other_main
|
||||
|
||||
section .text
|
||||
bits 16
|
||||
start:
|
||||
cli
|
||||
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
|
||||
lgdt [gdt.desc]
|
||||
mov eax, cr0
|
||||
or eax, CR0_PE
|
||||
mov cr0, eax
|
||||
|
||||
jmp gdt.code: start32
|
||||
|
||||
bits 32
|
||||
start32:
|
||||
mov ax, gdt.data
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
mov ax, 0
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; Switch to the stack allocated by startothers()
|
||||
mov esp, [top - 4]
|
||||
|
||||
call enable_paging
|
||||
|
||||
; load the 64-bit GDT
|
||||
lgdt [gdt64.pointer]
|
||||
|
||||
jmp gdt64.code: start64
|
||||
|
||||
error:
|
||||
mov ax, 0x8a00
|
||||
mov dx, ax
|
||||
out dx, ax
|
||||
mov ax, 0x8ae0
|
||||
out dx, ax
|
||||
spin:
|
||||
jmp spin
|
||||
|
||||
enable_paging:
|
||||
; load P4 to cr3 register (cpu uses this to access the P4 table)
|
||||
mov eax, [top - 8]
|
||||
mov cr3, eax
|
||||
|
||||
; enable PAE-flag in cr4 (Physical Address Extension)
|
||||
mov eax, cr4
|
||||
or eax, 1 << 5
|
||||
mov cr4, eax
|
||||
|
||||
; set the long mode bit & no execute bit in the EFER MSR (model specific register)
|
||||
mov ecx, 0xC0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8 | 1 << 11
|
||||
wrmsr
|
||||
|
||||
; enable paging & write protect in the cr0 register
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31 | 1 << 16
|
||||
mov cr0, eax
|
||||
|
||||
ret
|
||||
|
||||
bits 64
|
||||
start64:
|
||||
; load 0 into all data segment registers
|
||||
mov ax, 0
|
||||
mov ss, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; obtain kstack from data block before entryother
|
||||
mov rsp, [top - 16]
|
||||
|
||||
mov rax, other_main
|
||||
call rax
|
||||
|
||||
; section .rodata
|
||||
align 4
|
||||
gdt:
|
||||
; NULL
|
||||
dw 0, 0
|
||||
db 0, 0, 0, 0
|
||||
.code: equ $ - gdt
|
||||
dw 0xffff, 0
|
||||
db 0, (0x90 | STA_X | STA_R), 0xcf, 0
|
||||
.data: equ $ - gdt
|
||||
dw 0xffff, 0
|
||||
db 0, (0x90 | STA_W), 0xcf, 0
|
||||
.desc:
|
||||
dw $ - gdt - 1
|
||||
dq gdt
|
||||
|
||||
gdt64:
|
||||
dq 0 ; zero entry
|
||||
.code: equ $ - gdt64 ; new
|
||||
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
|
||||
.pointer:
|
||||
dw $ - gdt64 - 1
|
||||
dq gdt64
|
||||
|
||||
top: equ start + 0x1000
|
@ -1,7 +0,0 @@
|
||||
set timeout=0
|
||||
set default=0
|
||||
|
||||
menuentry "my os" {
|
||||
multiboot2 /boot/kernel.bin
|
||||
boot
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
ENTRY(start)
|
||||
|
||||
OTHER_OFFSET = 0x7000;
|
||||
BOOT_OFFSET = 0x100000;
|
||||
KERNEL_OFFSET = 0xffffff0000000000;
|
||||
|
||||
SECTIONS {
|
||||
|
||||
/* ensure that the multiboot header is at the beginning */
|
||||
|
||||
.multiboot_header :
|
||||
{
|
||||
KEEP(*(.multiboot_header))
|
||||
}
|
||||
|
||||
/* bootloader for other processors */
|
||||
|
||||
. = OTHER_OFFSET;
|
||||
|
||||
.text.other : AT(OTHER_OFFSET)
|
||||
{
|
||||
KEEP(*/entryother.o (.text))
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
/* bootloader for first processor */
|
||||
|
||||
. = BOOT_OFFSET;
|
||||
|
||||
.rodata.32 :
|
||||
{
|
||||
*/boot.o (.rodata)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
.text.32 :
|
||||
{
|
||||
*/boot.o (.text)
|
||||
*/long_mode_init.o (.text)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
.bss.32 :
|
||||
{
|
||||
*/boot.o (.bss)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
/* kernel */
|
||||
|
||||
. += KERNEL_OFFSET;
|
||||
|
||||
.user ALIGN(4K): AT(ADDR(.user) - KERNEL_OFFSET)
|
||||
{
|
||||
KEEP(user/*.o (.data))
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.rodata : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.text : AT(ADDR(.text) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.text .text.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.data : AT(ADDR(.data) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.data .data.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.bss ALIGN(4K): AT(ADDR(.bss) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.bss .bss.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.got ALIGN(4K): AT(ADDR(.got) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.got)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.got.plt : AT(ADDR(.got.plt) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.got.plt)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.data.rel.ro : AT(ADDR(.data.rel.ro) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.gcc_except_table)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
global long_mode_start
|
||||
extern rust_main
|
||||
|
||||
KERNEL_OFFSET equ 0xffff_ff00_0000_0000
|
||||
|
||||
section .text
|
||||
bits 64
|
||||
long_mode_start:
|
||||
; load 0 into all data segment registers
|
||||
mov ax, 0
|
||||
mov ss, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; translate rsp to virtual address
|
||||
mov rax, KERNEL_OFFSET
|
||||
add rsp, rax
|
||||
|
||||
; call the rust main
|
||||
extern rust_main
|
||||
mov rax, rust_main
|
||||
call rax
|
||||
|
||||
; print `OKAY` to screen
|
||||
mov rax, 0x2f592f412f4b2f4f
|
||||
mov qword [0xb8000], rax
|
||||
hlt
|
@ -1,15 +0,0 @@
|
||||
section .multiboot_header
|
||||
header_start:
|
||||
dd 0xe85250d6 ; magic number (multiboot 2)
|
||||
dd 0 ; architecture 0 (protected mode i386)
|
||||
dd header_end - header_start ; header length
|
||||
; checksum
|
||||
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))
|
||||
|
||||
; insert optional multiboot tags here
|
||||
|
||||
; required end tag
|
||||
dw 0 ; type
|
||||
dw 0 ; flags
|
||||
dd 8 ; size
|
||||
header_end:
|
@ -1,61 +0,0 @@
|
||||
// Migrate from xv6-x86_64 acpi.c
|
||||
|
||||
mod structs;
|
||||
use self::structs::*;
|
||||
use consts::*;
|
||||
|
||||
pub fn init(rsdt_addr: usize) -> Result<AcpiResult, AcpiError> {
|
||||
let rsdt = unsafe { &*(rsdt_addr as *const Rsdt) };
|
||||
let mut madt: Option<&'static Madt> = None;
|
||||
for i in 0 .. rsdt.entry_count() {
|
||||
let entry = rsdt.entry_at(i);
|
||||
let header = unsafe{ &*(entry as *const Header) };
|
||||
trace!("{:?}", header);
|
||||
if &header.signature == b"APIC" {
|
||||
madt = Some(unsafe{ &*(entry as *const Madt) });
|
||||
}
|
||||
}
|
||||
trace!("{:?}", madt);
|
||||
config_smp(madt.expect("acpi: madt not found."))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AcpiResult {
|
||||
pub cpu_num: u8,
|
||||
pub cpu_acpi_ids: [u8; MAX_CPU_NUM],
|
||||
pub ioapic_id: u8,
|
||||
pub lapic_addr: *const (),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AcpiError {
|
||||
NotMapped,
|
||||
IoacpiNotFound,
|
||||
}
|
||||
|
||||
fn config_smp(madt: &'static Madt) -> Result<AcpiResult, AcpiError> {
|
||||
let lapic_addr = madt.lapic_address as *const ();
|
||||
|
||||
let mut cpu_num = 0u8;
|
||||
let mut cpu_acpi_ids: [u8; MAX_CPU_NUM] = [0; MAX_CPU_NUM];
|
||||
let mut ioapic_id: Option<u8> = None;
|
||||
for entry in madt.entry_iter() {
|
||||
trace!("{:?}", entry);
|
||||
match &entry {
|
||||
&MadtEntry::LocalApic(ref lapic) => {
|
||||
cpu_acpi_ids[cpu_num as usize] = lapic.id;
|
||||
cpu_num += 1;
|
||||
},
|
||||
&MadtEntry::IoApic(ref ioapic) => {
|
||||
ioapic_id = Some(ioapic.id);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
if ioapic_id.is_none() {
|
||||
return Err(AcpiError::IoacpiNotFound);
|
||||
}
|
||||
let ioapic_id = ioapic_id.unwrap();
|
||||
Ok(AcpiResult { cpu_num, cpu_acpi_ids, ioapic_id, lapic_addr })
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
// Reference: xv6-x86_64 acpi.h
|
||||
// Copy from crate 'acpica-sys'
|
||||
|
||||
use util::{Checkable, bytes_sum};
|
||||
use core::mem::size_of;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Rsdp {
|
||||
pub signature: [u8; 8],
|
||||
pub checksum: u8,
|
||||
pub oem_id: [i8; 6],
|
||||
pub revision: u8,
|
||||
pub rsdt_physical_address: u32,
|
||||
pub length: u32,
|
||||
pub xsdt_physical_address: u64,
|
||||
pub extended_checksum: u8,
|
||||
pub reserved: [u8; 3],
|
||||
}
|
||||
|
||||
impl Checkable for Rsdp {
|
||||
fn check(&self) -> bool {
|
||||
&self.signature == b"RSD PTR " && bytes_sum(self) == 0
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Header {
|
||||
pub signature: [u8; 4],
|
||||
pub length: u32,
|
||||
pub revision: u8,
|
||||
pub checksum: u8,
|
||||
pub oem_id: [i8; 6],
|
||||
pub oem_table_id: [i8; 8],
|
||||
pub oem_revision: u32,
|
||||
pub asl_compiler_id: [i8; 4],
|
||||
pub asl_compiler_revision: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Rsdt {
|
||||
pub header: Header,
|
||||
table_offset_entry: [u32; 0],
|
||||
}
|
||||
|
||||
impl Rsdt {
|
||||
pub fn entry_count(&self) -> usize {
|
||||
(self.header.length as usize - size_of::<Self>()) / 4
|
||||
}
|
||||
pub fn entry_at(&self, id: usize) -> u32 {
|
||||
assert!(id < self.entry_count());
|
||||
unsafe {
|
||||
let p = (self as *const Self).offset(1) as *const u32;
|
||||
*(p.offset(id as isize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Madt {
|
||||
pub header: Header,
|
||||
pub lapic_address: u32,
|
||||
pub flags: u32,
|
||||
table: [u32; 0],
|
||||
}
|
||||
|
||||
impl Checkable for Madt {
|
||||
fn check(&self) -> bool {
|
||||
&self.header.signature == b"APIC" && self.header.length >= size_of::<Self>() as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MadtEntry {
|
||||
Unknown(MadtEntryUnknown),
|
||||
LocalApic(MadtEntryLocalApic),
|
||||
IoApic(MadtEntryIoApic),
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MadtEntryUnknown {
|
||||
pub type_: u8,
|
||||
pub length: u8,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MadtEntryLocalApic {
|
||||
pub type_: u8, // 0
|
||||
pub length: u8,
|
||||
pub processor_id: u8,
|
||||
pub id: u8,
|
||||
pub lapic_flags: u32,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MadtEntryIoApic {
|
||||
pub type_: u8, // 1
|
||||
pub length: u8,
|
||||
pub id: u8,
|
||||
pub reserved: u8,
|
||||
pub address: u32,
|
||||
pub global_irq_base: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MadtEntryIter<'a> {
|
||||
madt: &'a Madt,
|
||||
ptr: *const u8,
|
||||
end_ptr: *const u8,
|
||||
}
|
||||
|
||||
impl Madt {
|
||||
pub fn entry_iter(&self) -> MadtEntryIter {
|
||||
let ptr = unsafe{ (self as *const Self).offset(1) } as *const u8;
|
||||
let end_ptr = unsafe{ ptr.offset(self.header.length as isize) };
|
||||
MadtEntryIter { madt: self, ptr, end_ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for MadtEntryIter<'a> {
|
||||
type Item = MadtEntry;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.ptr >= self.end_ptr {
|
||||
return None;
|
||||
}
|
||||
unsafe {
|
||||
let type_id = *self.ptr.offset(0);
|
||||
let len = *self.ptr.offset(1);
|
||||
let ret = Some(match type_id {
|
||||
0 => MadtEntry::LocalApic( (&*(self.ptr as *const MadtEntryLocalApic)).clone() ),
|
||||
1 => MadtEntry::IoApic( (&*(self.ptr as *const MadtEntryIoApic)).clone() ),
|
||||
_ => MadtEntry::Unknown( (&*(self.ptr as *const MadtEntryUnknown)).clone() ),
|
||||
});
|
||||
self.ptr = self.ptr.offset(len as isize);
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +1,23 @@
|
||||
extern crate syscall as redox_syscall;
|
||||
|
||||
pub mod vga;
|
||||
pub mod acpi;
|
||||
pub mod apic;
|
||||
pub mod mp;
|
||||
pub mod serial;
|
||||
pub mod pic;
|
||||
pub mod keyboard;
|
||||
pub mod pit;
|
||||
pub mod ide;
|
||||
|
||||
pub fn init(rsdt_addr: usize) -> acpi::AcpiResult {
|
||||
pub fn init() {
|
||||
assert_has_not_been_called!();
|
||||
|
||||
let acpi = acpi::init(rsdt_addr).expect("Failed to init ACPI");
|
||||
assert_eq!(acpi.lapic_addr as usize, 0xfee00000);
|
||||
trace!("acpi = {:?}", acpi);
|
||||
|
||||
if cfg!(feature = "use_apic") {
|
||||
pic::disable();
|
||||
use consts::KERNEL_OFFSET;
|
||||
apic::init((KERNEL_OFFSET + 0xfee00000) as *const (), acpi.ioapic_id);
|
||||
apic::init();
|
||||
} else {
|
||||
pic::init();
|
||||
}
|
||||
pit::init();
|
||||
serial::init();
|
||||
keyboard::init();
|
||||
acpi
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
// Migrate from xv6 mp.c
|
||||
|
||||
// Multiprocessor support
|
||||
// Search memory for MP description structures.
|
||||
// http://developer.intel.com/design/pentium/datashts/24201606.pdf
|
||||
|
||||
mod structs;
|
||||
use self::structs::*;
|
||||
|
||||
/// Search for the MP Floating Pointer Structure, which according to the
|
||||
/// spec is in one of the following three locations:
|
||||
/// 1) in the first KB of the EBDA;
|
||||
/// 2) in the last KB of system base memory;
|
||||
/// 3) in the BIOS ROM address space between 0F0000h and 0FFFFFh.
|
||||
pub fn find_mp() -> Option<*const MP>
|
||||
{
|
||||
use core::mem::size_of;
|
||||
use util::find_in_memory;
|
||||
let ebda = unsafe { *(0x40E as *const u16) as usize } << 4;
|
||||
if ebda != 0 {
|
||||
let res = unsafe{ find_in_memory::<MP>(ebda, 1024, size_of::<MP>()) };
|
||||
if let Some(addr) = res {
|
||||
return Some(addr as *const MP);
|
||||
}
|
||||
}
|
||||
let p = unsafe { *(0x413 as *const u16) as usize } << 10;
|
||||
let res = unsafe{ find_in_memory::<MP>(p-1024, 1024, size_of::<MP>()) };
|
||||
if let Some(addr) = res {
|
||||
return Some(addr as *const MP);
|
||||
}
|
||||
let res = unsafe{ find_in_memory::<MP>(0xF0000, 0x10000, size_of::<MP>()) };
|
||||
res.map(|addr| addr as *const MP)
|
||||
}
|
||||
|
||||
/*
|
||||
struct cpu cpus[NCPU];
|
||||
int ncpu;
|
||||
uchar ioapicid;
|
||||
|
||||
// Search for an MP configuration table. For now,
|
||||
// don't accept the default configurations (physaddr == 0).
|
||||
// Check for correct signature, calculate the checksum and,
|
||||
// if correct, check the version.
|
||||
// To do: check extended table checksum.
|
||||
static struct mpconf*
|
||||
mpconfig(struct mp **pmp)
|
||||
{
|
||||
struct mpconf *conf;
|
||||
struct mp *mp;
|
||||
|
||||
if((mp = mpsearch()) == 0 || mp->physaddr == 0)
|
||||
return 0;
|
||||
conf = (struct mpconf*) P2V((uint) mp->physaddr);
|
||||
if(memcmp(conf, "PCMP", 4) != 0)
|
||||
return 0;
|
||||
if(conf->version != 1 && conf->version != 4)
|
||||
return 0;
|
||||
if(sum((uchar*)conf, conf->length) != 0)
|
||||
return 0;
|
||||
*pmp = mp;
|
||||
return conf;
|
||||
}
|
||||
|
||||
void
|
||||
mpinit(void)
|
||||
{
|
||||
uchar *p, *e;
|
||||
int ismp;
|
||||
struct mp *mp;
|
||||
struct mpconf *conf;
|
||||
struct mpproc *proc;
|
||||
struct mpioapic *ioapic;
|
||||
|
||||
if((conf = mpconfig(&mp)) == 0)
|
||||
panic("Expect to run on an SMP");
|
||||
ismp = 1;
|
||||
lapic = (uint*)conf->lapicaddr;
|
||||
for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
|
||||
switch(*p){
|
||||
case MPPROC:
|
||||
proc = (struct mpproc*)p;
|
||||
if(ncpu < NCPU) {
|
||||
cpus[ncpu].apicid = proc->apicid; // apicid may differ from ncpu
|
||||
ncpu++;
|
||||
}
|
||||
p += sizeof(struct mpproc);
|
||||
continue;
|
||||
case MPIOAPIC:
|
||||
ioapic = (struct mpioapic*)p;
|
||||
ioapicid = ioapic->apicno;
|
||||
p += sizeof(struct mpioapic);
|
||||
continue;
|
||||
case MPBUS:
|
||||
case MPIOINTR:
|
||||
case MPLINTR:
|
||||
p += 8;
|
||||
continue;
|
||||
default:
|
||||
ismp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ismp)
|
||||
panic("Didn't find a suitable machine");
|
||||
|
||||
if(mp->imcrp){
|
||||
// Bochs doesn't support IMCR, so this doesn't run on Bochs.
|
||||
// But it would on real hardware.
|
||||
outb(0x22, 0x70); // Select IMCR
|
||||
outb(0x23, inb(0x23) | 1); // Mask external interrupts.
|
||||
}
|
||||
}
|
||||
*/
|
@ -1,74 +0,0 @@
|
||||
// Migrate from xv6 mp.h
|
||||
|
||||
// See MultiProcessor Specification Version 1.[14]
|
||||
|
||||
use util::{Checkable, bytes_sum};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct MP { // floating pointer
|
||||
signature: [u8; 4], // "_MP_"
|
||||
physaddr: u32, // phys addr of MP config table
|
||||
length: u8, // 1
|
||||
specrev: u8, // [14]
|
||||
checksum: u8, // all bytes must add up to 0
|
||||
type_: u8, // MP system config type
|
||||
imcrp: u8,
|
||||
reserved: [u8; 3],
|
||||
}
|
||||
|
||||
impl Checkable for MP {
|
||||
fn check(&self) -> bool {
|
||||
&self.signature == b"_MP_" && bytes_sum(self) == 0
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
#[repr(C)]
|
||||
struct mpconf { // configuration table header
|
||||
signature: [byte; 4]; // "PCMP"
|
||||
length: u16, // total table length
|
||||
version: u8, // [14]
|
||||
checksum: u8, // all bytes must add up to 0
|
||||
product: [u8; 20], // product id
|
||||
uint *oemtable, // OEM table pointer
|
||||
ushort oemlength, // OEM table length
|
||||
ushort entry, // entry count
|
||||
uint *lapicaddr, // address of local APIC
|
||||
ushort xlength, // extended table length
|
||||
u8 xchecksum, // extended table checksum
|
||||
u8 reserved,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct mpproc { // processor table entry
|
||||
u8 type; // entry type (0)
|
||||
u8 apicid; // local APIC id
|
||||
u8 version; // local APIC verison
|
||||
u8 flags; // CPU flags
|
||||
#define MPBOOT 0x02 // This proc is the bootstrap processor.
|
||||
u8 signature[4]; // CPU signature
|
||||
uint feature; // feature flags from CPUID instruction
|
||||
u8 reserved[8];
|
||||
}
|
||||
|
||||
struct mpioapic { // I/O APIC table entry
|
||||
u8 type; // entry type (2)
|
||||
u8 apicno; // I/O APIC id
|
||||
u8 version; // I/O APIC version
|
||||
u8 flags; // I/O APIC flags
|
||||
uint *addr; // I/O APIC address
|
||||
}
|
||||
|
||||
// Table entry types
|
||||
const MPPROC : u8 = 0x00; // One per processor
|
||||
const MPBUS : u8 = 0x01; // One per bus
|
||||
const MPIOAPIC : u8 = 0x02; // One per I/O APIC
|
||||
const MPIOINTR : u8 = 0x03; // One per bus interrupt source
|
||||
const MPLINTR : u8 = 0x04; // One per system interrupt source
|
||||
|
||||
//PAGEBREAK!
|
||||
// Blank page.
|
||||
|
||||
*/
|
@ -1,112 +1,24 @@
|
||||
use bit_allocator::{BitAlloc, BitAlloc64K};
|
||||
use bit_allocator::BitAlloc;
|
||||
use consts::KERNEL_OFFSET;
|
||||
// Depends on kernel
|
||||
use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, Stack};
|
||||
use super::multiboot2::{ElfSection, ElfSectionFlags, ElfSectionsTag};
|
||||
use super::multiboot2::BootInformation;
|
||||
use memory::{FRAME_ALLOCATOR, init_heap};
|
||||
use super::{BootInfo, MemoryRegionType};
|
||||
use ucore_memory::PAGE_SIZE;
|
||||
use ucore_memory::paging::PageTable;
|
||||
|
||||
// BootInformation may trigger page fault after kernel remap
|
||||
// So just take its ownership
|
||||
pub fn init(boot_info: BootInformation) {
|
||||
pub fn init(boot_info: &BootInfo) {
|
||||
assert_has_not_been_called!("memory::init must be called only once");
|
||||
info!("{:?}", boot_info);
|
||||
init_frame_allocator(&boot_info);
|
||||
// remap_the_kernel(&boot_info);
|
||||
init_frame_allocator(boot_info);
|
||||
init_heap();
|
||||
info!("memory: init end");
|
||||
}
|
||||
|
||||
fn init_frame_allocator(boot_info: &BootInformation) {
|
||||
let memory_areas = boot_info.memory_map_tag().expect("Memory map tag required")
|
||||
.memory_areas();
|
||||
let elf_sections = boot_info.elf_sections_tag().expect("Elf sections tag required")
|
||||
.sections().filter(|s| s.is_allocated());
|
||||
|
||||
/// Init FrameAllocator and insert all 'Usable' regions from BootInfo.
|
||||
fn init_frame_allocator(boot_info: &BootInfo) {
|
||||
let mut ba = FRAME_ALLOCATOR.lock();
|
||||
for area in memory_areas {
|
||||
ba.insert(to_range(area.start_address() as usize, area.end_address() as usize));
|
||||
}
|
||||
for section in elf_sections {
|
||||
ba.remove(to_range(section.start_address() as usize, section.end_address() as usize));
|
||||
}
|
||||
ba.remove(to_range(boot_info.start_address(), boot_info.end_address()));
|
||||
|
||||
use core::ops::Range;
|
||||
fn to_range(mut start_addr: usize, mut end_addr: usize) -> Range<usize> {
|
||||
use consts::KERNEL_OFFSET;
|
||||
if start_addr >= KERNEL_OFFSET {
|
||||
start_addr -= KERNEL_OFFSET;
|
||||
}
|
||||
if end_addr >= KERNEL_OFFSET {
|
||||
end_addr -= KERNEL_OFFSET;
|
||||
for region in boot_info.memory_map.iter() {
|
||||
if region.region_type == MemoryRegionType::Usable {
|
||||
ba.insert(region.range.start_frame_number as usize..region.range.end_frame_number as usize);
|
||||
}
|
||||
let page_start = start_addr / PAGE_SIZE;
|
||||
let mut page_end = (end_addr - 1) / PAGE_SIZE + 1;
|
||||
if page_end >= BitAlloc64K::CAP {
|
||||
warn!("page num {:#x} out of range {:#x}", page_end, BitAlloc64K::CAP);
|
||||
page_end = BitAlloc64K::CAP;
|
||||
}
|
||||
page_start..page_end
|
||||
}
|
||||
}
|
||||
|
||||
fn remap_the_kernel(boot_info: &BootInformation) {
|
||||
extern { fn stack_bottom(); }
|
||||
extern { fn stack_top(); }
|
||||
let kstack = Stack {
|
||||
top: stack_top as usize + KERNEL_OFFSET,
|
||||
bottom: stack_bottom as usize + PAGE_SIZE + KERNEL_OFFSET,
|
||||
};
|
||||
|
||||
let mut memory_set = memory_set_from(boot_info.elf_sections_tag().unwrap(), kstack);
|
||||
|
||||
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
|
||||
use super::smp::ENTRYOTHER_ADDR;
|
||||
memory_set.push(MemoryArea::new_physical(0xb8000, 0xb9000, KERNEL_OFFSET, MemoryAttr::default(), "VGA"));
|
||||
memory_set.push(MemoryArea::new_physical(0xfee00000, 0xfee01000, KERNEL_OFFSET, MemoryAttr::default(), "LAPIC"));
|
||||
memory_set.push(MemoryArea::new_identity(0x07fe1000, 0x07fe1000 + PAGE_SIZE, MemoryAttr::default(), "RSDT"));
|
||||
memory_set.push(MemoryArea::new_identity(0xfec00000, 0xfec00000 + PAGE_SIZE, MemoryAttr::default(), "IOAPIC"));
|
||||
memory_set.push(MemoryArea::new(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MemoryAttr::default(), "kernel_heap"));
|
||||
memory_set.push(MemoryArea::new_identity(ENTRYOTHER_ADDR, ENTRYOTHER_ADDR + PAGE_SIZE, MemoryAttr::default().execute(), "entry_other.text"));
|
||||
memory_set.push(MemoryArea::new_physical(0, 4096, KERNEL_OFFSET, MemoryAttr::default(), "entry_other.ctrl"));
|
||||
debug!("{:#x?}", memory_set);
|
||||
|
||||
unsafe { memory_set.activate(); }
|
||||
info!("NEW TABLE!!!");
|
||||
|
||||
use core::mem::forget;
|
||||
forget(memory_set);
|
||||
}
|
||||
|
||||
fn memory_set_from(sections: ElfSectionsTag, kstack: Stack) -> MemorySet {
|
||||
assert_has_not_been_called!();
|
||||
// WARNING: must ensure it's large enough
|
||||
static mut SPACE: [u8; 0x1000] = [0; 0x1000];
|
||||
let mut set = unsafe { MemorySet::new_from_raw_space(&mut SPACE, kstack) };
|
||||
for section in sections.sections().filter(|s| s.is_allocated()) {
|
||||
set.push(memory_area_from(section));
|
||||
}
|
||||
set
|
||||
}
|
||||
|
||||
fn memory_area_from(section: ElfSection) -> MemoryArea {
|
||||
let mut start_addr = section.start_address() as usize;
|
||||
let mut end_addr = section.end_address() as usize;
|
||||
assert_eq!(start_addr % PAGE_SIZE, 0, "sections need to be page aligned");
|
||||
let name = unsafe { &*(section.name() as *const str) };
|
||||
if start_addr >= KERNEL_OFFSET {
|
||||
start_addr -= KERNEL_OFFSET;
|
||||
end_addr -= KERNEL_OFFSET;
|
||||
}
|
||||
MemoryArea::new_physical(start_addr, end_addr, KERNEL_OFFSET, memory_attr_from(section.flags()), name)
|
||||
}
|
||||
|
||||
fn memory_attr_from(elf_flags: ElfSectionFlags) -> MemoryAttr {
|
||||
let mut flags = MemoryAttr::default();
|
||||
|
||||
if !elf_flags.contains(ElfSectionFlags::ALLOCATED) { flags = flags.hide(); }
|
||||
if !elf_flags.contains(ElfSectionFlags::WRITABLE) { flags = flags.readonly(); }
|
||||
if elf_flags.contains(ElfSectionFlags::EXECUTABLE) { flags = flags.execute(); }
|
||||
flags
|
||||
}
|
Loading…
Reference in new issue