Fix x86_64 startup. TODO: higher half.

* 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
WangRunji 6 years ago
parent 0437e5cb17
commit 0a9c294814

10
kernel/Cargo.lock generated

@ -110,14 +110,6 @@ dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "multiboot2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "once" name = "once"
version = "0.3.3" version = "0.3.3"
@ -227,7 +219,6 @@ dependencies = [
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"multiboot2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"riscv 0.3.0", "riscv 0.3.0",
@ -337,7 +328,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
"checksum linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "655d57c71827fe0891ce72231b6aa5e14033dae3f604609e6a6f807267c1678d" "checksum linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "655d57c71827fe0891ce72231b6aa5e14033dae3f604609e6a6f807267c1678d"
"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" "checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
"checksum multiboot2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebbe89ab663a65cab341428d5fc7013b0eab5543ace92a401a86581e50fdd81"
"checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73" "checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73"
"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" "checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a"
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"

@ -33,7 +33,6 @@ simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-R
[target.'cfg(target_arch = "x86_64")'.dependencies] [target.'cfg(target_arch = "x86_64")'.dependencies]
bootloader = "0.3" bootloader = "0.3"
multiboot2 = "0.7"
x86_64 = "0.2.11" x86_64 = "0.2.11"
redox_syscall = "0.1" redox_syscall = "0.1"
uart_16550 = "0.1" uart_16550 = "0.1"

@ -46,7 +46,6 @@ fn remap_the_kernel() {
ms.push(MemoryArea::new_identity(sdata as usize, edata as usize, MemoryAttr::default(), "data")); ms.push(MemoryArea::new_identity(sdata as usize, edata as usize, MemoryAttr::default(), "data"));
ms.push(MemoryArea::new_identity(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), "rodata")); ms.push(MemoryArea::new_identity(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), "rodata"));
ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss")); ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss"));
ms.push(MemoryArea::new_identity(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MemoryAttr::default(), "kernel_heap"));
unsafe { ms.activate(); } unsafe { ms.activate(); }
use core::mem::forget; use core::mem::forget;
forget(ms); forget(ms);

@ -8,11 +8,14 @@ pub mod paging;
pub mod memory; pub mod memory;
pub mod compiler_rt; pub mod compiler_rt;
pub fn init() { #[no_mangle]
pub extern fn rust_main() -> ! {
println!("Hello RISCV! {}", 123); println!("Hello RISCV! {}", 123);
::logging::init();
interrupt::init(); interrupt::init();
memory::init(); memory::init();
timer::init(); timer::init();
::kmain();
} }
#[cfg(feature = "no_bbl")] #[cfg(feature = "no_bbl")]

@ -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
}
}
}

@ -9,10 +9,9 @@ use bit_field::BitField;
use arch::interrupt::consts::T_IRQ0; use arch::interrupt::consts::T_IRQ0;
use spin::Mutex; use spin::Mutex;
pub fn init(ioapic_id: u8) pub fn init()
{ {
let mut ioapic = IOAPIC.lock(); let mut ioapic = IOAPIC.lock();
assert_eq!(ioapic.id(), ioapic_id, "ioapic.init: id isn't equal to ioapicid; not a MP");
// Mark all interrupts edge-triggered, active high, disabled, // Mark all interrupts edge-triggered, active high, disabled,
// and not routed to any CPUs. // and not routed to any CPUs.

@ -6,7 +6,7 @@ extern {
fn lapicstartap(apicid: u8, addr: u32); fn lapicstartap(apicid: u8, addr: u32);
} }
pub fn set_addr(lapic_addr: *const ()) { pub fn set_addr(lapic_addr: usize) {
unsafe { unsafe {
// lapic = lapic_addr; // lapic = lapic_addr;
} }

@ -4,11 +4,12 @@ pub use self::lapic::{ack, start_ap, lapic_id};
mod lapic; mod lapic;
mod ioapic; mod ioapic;
pub fn init(lapic_addr: *const (), ioapic_id: u8) { pub fn init() {
assert_has_not_been_called!("apic::init must be called only once"); assert_has_not_been_called!("apic::init must be called only once");
self::lapic::set_addr(lapic_addr); use consts::KERNEL_OFFSET;
self::lapic::set_addr(KERNEL_OFFSET + 0xfee00000);
self::lapic::init(); self::lapic::init();
self::ioapic::init(ioapic_id); self::ioapic::init();
} }
pub fn other_init() { pub fn other_init() {

@ -1,31 +1,23 @@
extern crate syscall as redox_syscall; extern crate syscall as redox_syscall;
pub mod vga; pub mod vga;
pub mod acpi;
pub mod apic; pub mod apic;
pub mod mp;
pub mod serial; pub mod serial;
pub mod pic; pub mod pic;
pub mod keyboard; pub mod keyboard;
pub mod pit; pub mod pit;
pub mod ide; pub mod ide;
pub fn init(rsdt_addr: usize) -> acpi::AcpiResult { pub fn init() {
assert_has_not_been_called!(); 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") { if cfg!(feature = "use_apic") {
pic::disable(); pic::disable();
use consts::KERNEL_OFFSET; apic::init();
apic::init((KERNEL_OFFSET + 0xfee00000) as *const (), acpi.ioapic_id);
} else { } else {
pic::init(); pic::init();
} }
pit::init(); pit::init();
serial::init(); serial::init();
keyboard::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; use consts::KERNEL_OFFSET;
// Depends on kernel // Depends on kernel
use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, Stack}; use memory::{FRAME_ALLOCATOR, init_heap};
use super::multiboot2::{ElfSection, ElfSectionFlags, ElfSectionsTag}; use super::{BootInfo, MemoryRegionType};
use super::multiboot2::BootInformation;
use ucore_memory::PAGE_SIZE; use ucore_memory::PAGE_SIZE;
use ucore_memory::paging::PageTable; use ucore_memory::paging::PageTable;
// BootInformation may trigger page fault after kernel remap pub fn init(boot_info: &BootInfo) {
// So just take its ownership
pub fn init(boot_info: BootInformation) {
assert_has_not_been_called!("memory::init must be called only once"); assert_has_not_been_called!("memory::init must be called only once");
info!("{:?}", boot_info); init_frame_allocator(boot_info);
init_frame_allocator(&boot_info);
// remap_the_kernel(&boot_info);
init_heap(); init_heap();
info!("memory: init end");
} }
fn init_frame_allocator(boot_info: &BootInformation) { /// Init FrameAllocator and insert all 'Usable' regions from BootInfo.
let memory_areas = boot_info.memory_map_tag().expect("Memory map tag required") fn init_frame_allocator(boot_info: &BootInfo) {
.memory_areas();
let elf_sections = boot_info.elf_sections_tag().expect("Elf sections tag required")
.sections().filter(|s| s.is_allocated());
let mut ba = FRAME_ALLOCATOR.lock(); let mut ba = FRAME_ALLOCATOR.lock();
for area in memory_areas { for region in boot_info.memory_map.iter() {
ba.insert(to_range(area.start_address() as usize, area.end_address() as usize)); if region.region_type == MemoryRegionType::Usable {
} ba.insert(region.range.start_frame_number as usize..region.range.end_frame_number 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;
} }
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
}

@ -1,6 +1,6 @@
extern crate multiboot2; extern crate bootloader;
use memory::MemorySet; use self::bootloader::bootinfo::{BootInfo, MemoryRegionType};
pub mod driver; pub mod driver;
pub mod cpu; pub mod cpu;
@ -8,20 +8,31 @@ pub mod interrupt;
pub mod paging; pub mod paging;
pub mod gdt; pub mod gdt;
pub mod idt; pub mod idt;
pub mod smp; // TODO: Move multi-core init to bootloader
//pub mod smp;
pub mod memory; pub mod memory;
pub mod io; pub mod io;
pub fn init() { /// The entry point of kernel
#[no_mangle] // don't mangle the name of this function
pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! {
// First init log mod, so that we can print log info.
::logging::init();
info!("Hello world!");
info!("{:#?}", boot_info);
// Init trap handling.
idt::init(); idt::init();
let boot_info_addr = unsafe { *(0 as *const u32).offset(-1) } as usize;
let boot_info = unsafe { multiboot2::load(boot_info_addr) }; // Init physical memory management and heap.
let rsdt_addr = boot_info.rsdp_v1_tag().unwrap().rsdt_address();
memory::init(boot_info); memory::init(boot_info);
// Now heap is available // Now heap is available
gdt::init(); gdt::init();
let acpi = driver::init(rsdt_addr);
smp::start_other_cores(&acpi); driver::init();
::kmain();
} }
/// The entry point for another processors /// The entry point for another processors
@ -31,7 +42,7 @@ pub extern "C" fn other_main() -> ! {
gdt::init(); gdt::init();
driver::apic::other_init(); driver::apic::other_init();
let cpu_id = driver::apic::lapic_id(); let cpu_id = driver::apic::lapic_id();
let ms = unsafe { smp::notify_started(cpu_id) }; // let ms = unsafe { smp::notify_started(cpu_id) };
println!("Hello world! from CPU {}!", cpu_id); println!("Hello world! from CPU {}!", cpu_id);
// unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault // unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault
loop {} loop {}

@ -7,7 +7,7 @@ use core::alloc::Layout;
extern fn eh_personality() { extern fn eh_personality() {
} }
#[panic_implementation] #[panic_handler]
#[no_mangle] #[no_mangle]
pub fn panic(info: &PanicInfo) -> ! { pub fn panic(info: &PanicInfo) -> ! {
let location = info.location().unwrap(); let location = info.location().unwrap();

@ -2,14 +2,10 @@
#![feature(lang_items)] #![feature(lang_items)]
#![feature(const_fn)] #![feature(const_fn)]
#![feature(alloc)] #![feature(alloc)]
#![feature(allocator_api)]
#![feature(abi_x86_interrupt)]
#![feature(iterator_step_by)]
#![feature(unboxed_closures)]
#![feature(naked_functions)] #![feature(naked_functions)]
#![feature(asm)] #![feature(asm)]
#![feature(optin_builtin_traits)] #![feature(optin_builtin_traits)]
#![feature(panic_implementation)] #![feature(panic_handler)]
#![feature(panic_info_message)] #![feature(panic_info_message)]
#![feature(global_asm)] #![feature(global_asm)]
#![feature(compiler_builtins_lib)] #![feature(compiler_builtins_lib)]
@ -64,14 +60,7 @@ pub mod arch;
#[path = "arch/riscv32/mod.rs"] #[path = "arch/riscv32/mod.rs"]
pub mod arch; pub mod arch;
/// The entry point of Rust kernel pub fn kmain() -> ! {
#[no_mangle]
pub extern "C" fn rust_main() -> ! {
// ATTENTION: we have a very small stack and no guard page
println!("Hello World{}", "!");
logging::init();
arch::init();
process::init(); process::init();
unsafe { arch::interrupt::enable(); } unsafe { arch::interrupt::enable(); }

@ -4,10 +4,3 @@
#[macro_use] #[macro_use]
extern crate ucore; extern crate ucore;
#[cfg(not(test))]
#[cfg(target_arch = "x86_64")]
#[no_mangle] // don't mangle the name of this function
pub extern "C" fn _start() -> ! {
ucore::rust_main();
}

@ -1,5 +1,5 @@
pub use arch::paging::*; pub use arch::paging::*;
use bit_allocator::{BitAlloc, BitAlloc4K}; use bit_allocator::{BitAlloc, BitAlloc4K, BitAlloc64K};
use consts::MEMORY_OFFSET; use consts::MEMORY_OFFSET;
use spin::{Mutex, MutexGuard}; use spin::{Mutex, MutexGuard};
use super::HEAP_ALLOCATOR; use super::HEAP_ALLOCATOR;
@ -9,8 +9,16 @@ pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, MemorySet as MemorySe
pub type MemorySet = MemorySet_<InactivePageTable0>; pub type MemorySet = MemorySet_<InactivePageTable0>;
// x86_64 support up to 256M memory
#[cfg(target_arch = "x86_64")]
pub type FrameAlloc = BitAlloc64K;
// RISCV only have 8M memory
#[cfg(target_arch = "riscv32")]
pub type FrameAlloc = BitAlloc4K;
lazy_static! { lazy_static! {
pub static ref FRAME_ALLOCATOR: Mutex<BitAlloc4K> = Mutex::new(BitAlloc4K::default()); pub static ref FRAME_ALLOCATOR: Mutex<FrameAlloc> = Mutex::new(FrameAlloc::default());
} }
pub fn alloc_frame() -> Option<usize> { pub fn alloc_frame() -> Option<usize> {
@ -52,8 +60,9 @@ pub fn page_fault_handler(addr: usize) -> bool {
} }
pub fn init_heap() { pub fn init_heap() {
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; use consts::KERNEL_HEAP_SIZE;
unsafe { HEAP_ALLOCATOR.lock().init(KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE); } static mut HEAP: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE];
unsafe { HEAP_ALLOCATOR.lock().init(HEAP.as_ptr() as usize, KERNEL_HEAP_SIZE); }
info!("heap init end"); info!("heap init end");
} }

@ -1,26 +1,5 @@
use core::fmt::Debug; use core::fmt::Debug;
pub fn bytes_sum<T>(p: &T) -> u8 {
use core::mem::size_of_val;
let len = size_of_val(p);
let p = p as *const T as *const u8;
(0..len).map(|i| unsafe { &*p.offset(i as isize) })
.fold(0, |a, &b| a.overflowing_add(b).0)
}
///
pub trait Checkable {
fn check(&self) -> bool;
}
/// Scan memory to find the struct
pub unsafe fn find_in_memory<T: Checkable>
(begin: usize, len: usize, step: usize) -> Option<usize> {
(begin .. begin + len).step_by(step)
.find(|&addr| { (&*(addr as *const T)).check() })
}
/// Convert C string to Rust string /// Convert C string to Rust string
pub unsafe fn from_cstr(s: *const u8) -> &'static str { pub unsafe fn from_cstr(s: *const u8) -> &'static str {
use core::{str, slice}; use core::{str, slice};

Loading…
Cancel
Save