Merge branch 'dev' into move-kernel-va

# Conflicts:
#	src/arch/x86_64/boot/linker.ld
#	src/consts.rs
#	src/interrupts/mod.rs
toolchain_update
WangRunji 7 years ago
commit d330bd8224

@ -7,6 +7,7 @@ authors = ["Philipp Oppermann <dev@phil-opp.com>"]
crate-type = ["staticlib"]
[features]
use_apic = []
test = []
qemu_auto_exit = []
@ -20,6 +21,7 @@ bitflags = "0.7.0"
x86_64 = "0.1.2"
once = "0.3.3"
linked_list_allocator = "0.5.0"
redox_syscall = "0.1.37"
[build-dependencies]
cc = "1.0"

@ -10,7 +10,8 @@ grub_cfg := $(boot_src)/grub.cfg
assembly_source_files := $(wildcard $(boot_src)/*.asm)
assembly_object_files := $(patsubst $(boot_src)/%.asm, \
build/arch/$(arch)/boot/%.o, $(assembly_source_files))
qemu_opts := -cdrom $(iso) -smp 2 -serial stdio
qemu_opts := -cdrom $(iso) -smp 2 -serial mon:stdio
features := use_apic
ifdef travis
test := 1

@ -45,13 +45,13 @@ SECTIONS {
. = ALIGN(4K);
}
.bss : AT(ADDR(.bss) - KERNEL_OFFSET)
.bss ALIGN(4K): AT(ADDR(.bss) - KERNEL_OFFSET)
{
*(.bss .bss.*)
. = ALIGN(4K);
}
.got : AT(ADDR(.got) - KERNEL_OFFSET)
.got ALIGN(4K): AT(ADDR(.got) - KERNEL_OFFSET)
{
*(.got)
. = ALIGN(4K);

@ -5,12 +5,11 @@ use self::structs::*;
use consts::*;
pub fn init() -> Result<ACPI_Result, ACPI_Error> {
use core::mem::size_of;
use util::Checkable;
let rsdp = find_rsdp().expect("acpi: rsdp not found.");
if rsdp.RsdtPhysicalAddress > PHYSICAL_MEMORY_LIMIT {
return Err(ACPI_Error::NotMapped);
}
debug!("RSDT at {:#x}", rsdp.RsdtPhysicalAddress);
let rsdt = unsafe{ &*(rsdp.RsdtPhysicalAddress as *const rsdt) };
let mut madt: Option<&'static madt> = None;
for i in 0 .. rsdt.entry_count() {

@ -4,73 +4,96 @@
/// http://www.intel.com/design/chipsets/datashts/29056601.pdf
/// See also picirq.c.
use core::ptr::{read_volatile, write_volatile};
use syscall::io::{Io, Mmio};
use bit_field::BitField;
use consts::irq::T_IRQ0;
use spin::Mutex;
pub fn init() {
pub fn init(ioapic_id: u8)
{
let mut ioapic = IOAPIC.lock();
assert!(ioapic.id() == ioapic_id, "ioapic.init: id isn't equal to ioapicid; not a MP");
// Mark all interrupts edge-triggered, active high, disabled,
// and not routed to any CPUs.
for i in 0.. ioapic.maxintr() + 1 {
ioapic.write_irq(i, DISABLED, 0);
}
debug!("ioapic: init end");
}
const IOAPIC_ADDRESS : u32 = 0xFEC00000; // Default physical address of IO APIC
const REG_ID : u32 = 0x00; // Register index: ID
const REG_VER : u32 = 0x01; // Register index: version
const REG_TABLE : u32 = 0x10; // Redirection table base
const REG_ID : u8 = 0x00; // Register index: ID
const REG_VER : u8 = 0x01; // Register index: version
const REG_TABLE : u8 = 0x10; // Redirection table base
// The redirection table starts at REG_TABLE and uses
// two registers to configure each interrupt.
// The first (low) register in a pair contains configuration bits.
// The second (high) register contains a bitmask telling which
// CPUs can serve that interrupt.
const INT_DISABLED : u32 = 0x00010000; // Interrupt disabled
const INT_LEVEL : u32 = 0x00008000; // Level-triggered (vs edge-)
const INT_ACTIVELOW : u32 = 0x00002000; // Active low (vs high)
const INT_LOGICAL : u32 = 0x00000800; // Destination is CPU id (vs APIC ID)
// static IOAPIC: *mut IoApic = IOAPIC_ADDRESS as *mut _;
bitflags! {
flags RedirectionEntry: u32 {
const DISABLED = 0x00010000, // Interrupt disabled
const LEVEL = 0x00008000, // Level-triggered (vs edge-)
const ACTIVELOW = 0x00002000, // Active low (vs high)
const LOGICAL = 0x00000800, // Destination is CPU id (vs APIC ID)
const NONE = 0x00000000,
}
}
const ioapicid: u32 = 0; // TODO fix
const T_IRQ0: u32 = 32;
lazy_static! {
pub static ref IOAPIC: Mutex<IoApic> = Mutex::new(unsafe{IoApic::new()});
}
// IO APIC MMIO structure: write reg, then read or write data.
#[repr(C)]
struct IoApic {
reg: u32,
pad: [u32; 3],
data: u32,
struct IoApicMmio {
reg: Mmio<u32>,
pad: [Mmio<u32>; 3],
data: Mmio<u32>,
}
pub struct IoApic {
mmio: &'static mut IoApicMmio
}
impl IoApic {
unsafe fn read(&mut self, reg: u32) -> u32
{
write_volatile(&mut self.reg as *mut _, reg);
read_volatile(&self.data as *const _)
unsafe fn new() -> Self {
IoApic { mmio: &mut *(IOAPIC_ADDRESS as *mut IoApicMmio) }
}
unsafe fn write(&mut self, reg: u32, data: u32)
fn read(&mut self, reg: u8) -> u32
{
write_volatile(&mut self.reg as *mut _, reg);
write_volatile(&mut self.data as *mut _, data);
self.mmio.reg.write(reg as u32);
self.mmio.data.read()
}
unsafe fn init(&mut self)
fn write(&mut self, reg: u8, data: u32)
{
let maxintr = (self.read(REG_VER) >> 16) & 0xFF;
let id = self.read(REG_ID) >> 24;
if id != ioapicid {
println!("ioapicinit: id isn't equal to ioapicid; not a MP");
}
// Mark all interrupts edge-triggered, active high, disabled,
// and not routed to any CPUs.
for i in 0 .. maxintr+1 {
self.write(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i));
self.write(REG_TABLE+2*i+1, 0);
self.mmio.reg.write(reg as u32);
self.mmio.data.write(data);
}
fn write_irq(&mut self, irq: u8, flags: RedirectionEntry, dest: u8)
{
self.write(REG_TABLE+2*irq, (T_IRQ0 + irq) as u32 | flags.bits());
self.write(REG_TABLE+2*irq+1, (dest as u32) << 24);
}
unsafe fn enable(&mut self, irq: u32, cpunum: u32)
pub fn enable(&mut self, irq: u8, cpunum: u8)
{
debug!("ioapic: enable irq {} @ cpu{}", irq, cpunum);
// Mark interrupt edge-triggered, active high,
// enabled, and routed to the given cpunum,
// which happens to be that cpu's APIC ID.
self.write(REG_TABLE+2*irq, T_IRQ0 + irq);
self.write(REG_TABLE+2*irq+1, cpunum << 24);
self.write_irq(irq, NONE, cpunum);
}
fn id(&mut self) -> u8 {
self.read(REG_ID).get_bits(24..28) as u8
}
fn version(&mut self) -> u8 {
self.read(REG_VER).get_bits(0..8) as u8
}
fn maxintr(&mut self) -> u8 {
self.read(REG_VER).get_bits(16..24) as u8
}
}

@ -98,3 +98,11 @@ lapicinit(void)
// Enable interrupts on the APIC (but not on the processor).
lapicw(TPR, 0);
}
// Acknowledge interrupt.
void
lapiceoi(void)
{
if(lapic)
lapicw(EOI, 0);
}

@ -1,14 +1,20 @@
extern {
static mut lapic: *const ();
fn lapicinit(); // must set `lapic` first
fn lapiceoi(); // ack
}
pub fn init(lapic_addr: *const ()) {
debug!("WARNING: lapic::init use C lib");
unsafe {
lapic = lapic_addr;
debug!("lapic = {:?}", lapic);
unimplemented!();
lapicinit();
}
debug!("lapic: init end");
}
pub fn ack(_irq: u8) {
unsafe {
lapiceoi();
}
}

@ -1,7 +1,11 @@
pub use self::ioapic::IOAPIC;
pub use self::lapic::ack;
mod lapic;
mod ioapic;
pub fn init(lapic_addr: *const ()) {
pub fn init(lapic_addr: *const (), ioapic_id: u8) {
assert_has_not_been_called!("apic::init must be called only once");
self::lapic::init(lapic_addr);
// self::ioapic::init();
self::ioapic::init(ioapic_id);
}

@ -0,0 +1,8 @@
pub fn init() {
use consts::irq::{IRQ_KBD, IRQ_COM1};
// TODO set irq handler
// super::pic::enable_irq(IRQ_KBD);
let mut ioapic = super::apic::IOAPIC.lock();
ioapic.enable(IRQ_KBD, 0);
ioapic.enable(IRQ_COM1, 0);
}

@ -0,0 +1,9 @@
use x86_64;
pub fn enable() {
unsafe{ x86_64::instructions::interrupts::enable(); }
}
pub fn disable() {
unsafe{ x86_64::instructions::interrupts::disable(); }
}

@ -3,3 +3,6 @@ pub mod acpi;
pub mod apic;
pub mod mp;
pub mod serial;
pub mod pic;
pub mod console;
pub mod interrupt;

@ -0,0 +1,98 @@
// Copy from Redox
use syscall::io::*;
use spin::Mutex;
static MASTER: Mutex<Pic> = Mutex::new(Pic::new(0x20));
static SLAVE: Mutex<Pic> = Mutex::new(Pic::new(0xA0));
pub fn disable() {
// Mask all interrupts (Copy from xv6 x86_64)
MASTER.lock().cmd.write(0xFF);
SLAVE.lock().cmd.write(0xFF);
debug!("pic: disabled");
}
pub fn init() {
assert_has_not_been_called!("pic::init must be called only once");
let mut master = MASTER.lock();
let mut slave = SLAVE.lock();
// Start initialization
master.cmd.write(0x11);
slave.cmd.write(0x11);
// Set offsets
master.data.write(0x20);
slave.data.write(0x28);
// Set up cascade
master.data.write(4);
slave.data.write(2);
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
master.data.write(1);
slave.data.write(1);
// Unmask interrupts
master.data.write(0);
slave.data.write(0);
// Ack remaining interrupts
master.ack();
slave.ack();
debug!("pic: init end");
}
pub fn enable_irq(irq: u8)
{
match irq {
_ if irq < 8 => MASTER.lock().mask_set(irq),
_ if irq < 16 => SLAVE.lock().mask_set(irq-8),
_ => panic!("irq not in 0..16"),
}
}
pub fn ack(irq: u8) {
assert!(irq < 16);
MASTER.lock().ack();
if irq >= 8 {
SLAVE.lock().ack();
}
}
struct Pic {
cmd: Pio<u8>,
data: Pio<u8>,
}
impl Pic {
const fn new(port: u16) -> Pic {
Pic {
cmd: Pio::new(port),
data: Pio::new(port + 1),
}
}
fn ack(&mut self) {
self.cmd.write(0x20);
}
fn mask_set(&mut self, irq: u8) {
assert!(irq < 8);
let mut mask = self.data.read();
mask |= 1 << irq;
self.data.write(mask);
}
fn mask_clear(&mut self, irq: u8) {
assert!(irq < 8);
let mut mask = self.data.read();
mask &= !(1 << irq);
self.data.write(mask);
}
}

@ -94,3 +94,13 @@ pub const MAX_CPU_NUM: usize = 8;
/// Offset for usage in other temporary pages
pub const USER_TMP_MISC_OFFSET: usize = USER_TMP_TLS_OFFSET + PML4_SIZE;
pub const USER_TMP_MISC_PML4: usize = (USER_TMP_MISC_OFFSET & PML4_MASK)/PML4_SIZE;
pub mod irq {
pub const T_IRQ0 : u8 = 32; // IRQ 0 corresponds to int T_IRQ
pub const IRQ_TIMER : u8 = 0;
pub const IRQ_KBD : u8 = 1;
pub const IRQ_COM1 : u8 = 4;
pub const IRQ_IDE : u8 = 14;
pub const IRQ_ERROR : u8 = 19;
pub const IRQ_SPURIOUS : u8 = 31;
}

@ -1,3 +1,5 @@
use core::fmt;
use core::fmt::Debug;
use x86_64::structures::tss::TaskStateSegment;
use x86_64::structures::gdt::SegmentSelector;
use x86_64::PrivilegeLevel;
@ -85,11 +87,27 @@ impl Descriptor {
}
bitflags! {
/// Reference: https://wiki.osdev.org/GDT
flags DescriptorFlags: u64 {
const ACCESSED = 1 << 40,
const DATA_WRITABLE = 1 << 41,
const CODE_READABLE = 1 << 41,
const CONFORMING = 1 << 42,
const EXECUTABLE = 1 << 43,
const USER_SEGMENT = 1 << 44,
const USER_MODE = 1 << 45 | 1 << 46,
const PRESENT = 1 << 47,
const LONG_MODE = 1 << 53,
}
}
impl Debug for Descriptor {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
Descriptor::UserSegment(flags) =>
write!(f, "UserSegment( {:?} )", DescriptorFlags{bits: *flags}),
Descriptor::SystemSegment(low, high) =>
write!(f, "SystemSegment{:?}", (low, high)),
}
}
}

@ -0,0 +1,49 @@
use x86_64::structures::idt::*;
pub extern "x86-interrupt" fn breakpoint_handler(
stack_frame: &mut ExceptionStackFrame)
{
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
}
pub extern "x86-interrupt" fn double_fault_handler(
stack_frame: &mut ExceptionStackFrame, _error_code: u64)
{
println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}\nErrorCode: {:#x}", stack_frame, _error_code);
loop {}
}
pub extern "x86-interrupt" fn page_fault_handler(
stack_frame: &mut ExceptionStackFrame, error_code: PageFaultErrorCode)
{
println!("\nEXCEPTION: PAGE FAULT\n{:#?}\n{:#?}", stack_frame, error_code);
loop {}
}
#[cfg(feature = "use_apic")]
use arch::driver::apic::ack;
#[cfg(not(feature = "use_apic"))]
use arch::driver::pic::ack;
use consts::irq::*;
pub extern "x86-interrupt" fn keyboard_handler(
stack_frame: &mut ExceptionStackFrame)
{
println!("\nInterupt: Keyboard \n{:#?}", stack_frame);
ack(IRQ_KBD);
}
pub extern "x86-interrupt" fn serial_handler(
stack_frame: &mut ExceptionStackFrame)
{
println!("\nInterupt: Serial \n{:#?}", stack_frame);
ack(IRQ_COM1);
}
pub extern "x86-interrupt" fn timer_handler(
stack_frame: &mut ExceptionStackFrame)
{
println!("\nInterupt: Timer \n{:#?}", stack_frame);
ack(IRQ_TIMER);
}

@ -1,10 +1,18 @@
use x86_64::VirtualAddress;
use x86_64::structures::idt::{Idt, ExceptionStackFrame, PageFaultErrorCode};
use x86_64::structures::idt::Idt;
use x86_64::structures::tss::TaskStateSegment;
use memory::MemoryController;
use spin::Once;
mod gdt;
mod irq;
// Copied from xv6 x86_64
const GNULL: gdt::Descriptor = gdt::Descriptor::UserSegment(0);
const KCODE: gdt::Descriptor = gdt::Descriptor::UserSegment(0x0020980000000000); // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE
const UCODE: gdt::Descriptor = gdt::Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE
const KDATA: gdt::Descriptor = gdt::Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT
const UDATA: gdt::Descriptor = gdt::Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT
static TSS: Once<TaskStateSegment> = Once::new();
static GDT: Once<gdt::Gdt> = Once::new();
@ -13,6 +21,9 @@ static IDT: Once<Idt> = Once::new();
const DOUBLE_FAULT_IST_INDEX: usize = 0;
pub fn init(memory_controller: &mut MemoryController) {
test::print_flags();
use x86_64::structures::gdt::SegmentSelector;
use x86_64::instructions::segmentation::set_cs;
use x86_64::instructions::tables::load_tss;
@ -31,7 +42,12 @@ pub fn init(memory_controller: &mut MemoryController) {
let mut tss_selector = SegmentSelector(0);
let gdt = GDT.call_once(|| {
let mut gdt = gdt::Gdt::new();
code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment());
gdt.add_entry(GNULL);
code_selector =
gdt.add_entry(KCODE);
gdt.add_entry(UCODE);
gdt.add_entry(KDATA);
gdt.add_entry(UDATA);
tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss));
gdt
});
@ -45,9 +61,15 @@ pub fn init(memory_controller: &mut MemoryController) {
}
let idt = IDT.call_once(|| {
use self::irq::*;
use consts::irq::*;
let mut idt = Idt::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt.double_fault.set_handler_fn(double_fault_handler);
idt[(T_IRQ0 + IRQ_COM1) as usize].set_handler_fn(serial_handler);
idt[(T_IRQ0 + IRQ_KBD) as usize].set_handler_fn(keyboard_handler);
idt[(T_IRQ0 + IRQ_TIMER) as usize].set_handler_fn(timer_handler);
unsafe {
idt.page_fault.set_handler_fn(page_fault_handler)
.set_stack_index(DOUBLE_FAULT_IST_INDEX as u16);
@ -58,24 +80,21 @@ pub fn init(memory_controller: &mut MemoryController) {
idt.load();
}
extern "x86-interrupt" fn breakpoint_handler(
stack_frame: &mut ExceptionStackFrame)
{
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
}
extern "x86-interrupt" fn double_fault_handler(
stack_frame: &mut ExceptionStackFrame, _error_code: u64)
{
println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
loop {}
}
extern "x86-interrupt" fn page_fault_handler(
stack_frame: &mut ExceptionStackFrame, _error_code: PageFaultErrorCode)
pub mod test
{
use x86_64::registers::control_regs::cr2;
let addr = cr2();
println!("\nEXCEPTION: PAGE FAULT\n{:#?}\nAddress: {:#x}", stack_frame, addr);
loop {}
pub fn print_flags() {
use super::gdt::*;
// The following 4 GDT entries were copied from xv6 x86_64
let list: [(&str, Descriptor); 4] = [
("KCODE", super::KCODE), // Code, DPL=0, R/X
("UCODE", super::UCODE), // Code, DPL=3, R/X
("KDATA", super::KDATA), // Data, DPL=0, W
("UDATA", super::UDATA), // Data, DPL=3, W
];
// Let's see what that means
println!("GDT Segments from xv6 x86_64:");
for (name, desc) in list.iter() {
println!(" {}: {:?}", name, desc);
}
}
}

@ -27,6 +27,7 @@ extern crate linked_list_allocator;
#[macro_use]
extern crate lazy_static;
extern crate bit_field;
extern crate syscall;
#[macro_use] // print!
mod io;
@ -66,14 +67,27 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) {
test!(guard_page);
test!(find_mp);
// TODO Build temp page map. Now page fault.
// TODO Handle this temp page map.
memory_controller.map_page_identity(0); // EBDA
for addr in (0xE0000 .. 0x100000).step_by(0x1000) {
memory_controller.map_page_identity(addr);
}
memory_controller.map_page_identity(0x7fe1000); // RSDT
memory_controller.print_page_table();
let acpi = arch::driver::acpi::init().expect("Failed to init ACPI");
debug!("{:?}", acpi);
unimplemented!();
arch::driver::apic::init(acpi.lapic_addr);
io::init();
if cfg!(feature = "use_apic") {
arch::driver::pic::disable();
memory_controller.map_page_identity(acpi.lapic_addr as usize); // LAPIC
memory_controller.map_page_identity(0xFEC00000); // IOAPIC
arch::driver::apic::init(acpi.lapic_addr, acpi.ioapic_id);
} else {
arch::driver::pic::init();
}
arch::driver::interrupt::enable();
loop{}
test_end!();
}

@ -48,8 +48,6 @@ pub fn init(boot_info: &BootInformation) -> MemoryController {
let mut active_table = remap_the_kernel(&mut frame_allocator, boot_info);
println!("{:?}", active_table);
use self::paging::Page;
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
@ -208,4 +206,13 @@ impl MemoryController {
stack_allocator.alloc_stack(active_table, frame_allocator,
size_in_pages)
}
pub fn map_page_identity(&mut self, addr: usize) {
use self::paging::{WRITABLE};
let frame = Frame::containing_address(addr);
let flags = WRITABLE;
self.active_table.identity_map(frame, flags, &mut self.frame_allocator);
}
pub fn print_page_table(&self) {
debug!("{:?}", self.active_table);
}
}

Loading…
Cancel
Save