Commit 962004fc authored by Jeremy Soller's avatar Jeremy Soller

Support booting kernel

parent 61985132
......@@ -8,14 +8,14 @@ name = "bootloader-coreboot"
version = "0.1.0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"coreboot-table 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"coreboot-table 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "coreboot-table"
version = "0.1.2"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -25,11 +25,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "spin"
version = "0.4.10"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum coreboot-table 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ac6a4e3520869dfcad4ad323dd091683fb3680759fdc2bac7861e98c2b05f76"
"checksum coreboot-table 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "721884a67ad340571ea4362e7e4894dc78e68370b9265a07241a5ca232e70702"
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
......@@ -9,7 +9,7 @@ path = "src/lib.rs"
crate-type = ["staticlib"]
[dependencies]
bitflags = "1.0.3"
coreboot-table = "0.1.2"
bitflags = "1.0.4"
coreboot-table = "0.1.4"
redox_syscall = "0.1.51"
spin = "0.4.8"
spin = "0.5.0"
......@@ -8,11 +8,14 @@ export XARGO_HOME=$(CURDIR)/build/xargo
all: build/bootloader
build/libstartup.o: src/nasm/startup.asm src/nasm/* build/kernel
nasm -f elf32 $< -I src/nasm/ -o $@
build/libbootloader.a: Cargo.lock Cargo.toml src/* src/*/* src/*/*/* src/*/*/*/*
mkdir -p build
xargo rustc --lib --target $(TARGET) --release -- -C soft-float -C debuginfo=2 --emit link=$@
build/bootloader: linkers/$(ARCH).ld build/libbootloader.a
$(LD) -m elf_i386 --gc-sections -z max-page-size=0x1000 -T $< -o $@ build/libbootloader.a && \
build/bootloader: linkers/$(ARCH).ld build/libstartup.o build/libbootloader.a
$(LD) -m elf_i386 --gc-sections -z max-page-size=0x1000 -T $< -o $@ build/libstartup.o build/libbootloader.a && \
$(OBJCOPY) --only-keep-debug $@ $@.sym && \
$(OBJCOPY) --strip-debug $@
......@@ -2,7 +2,7 @@ ENTRY(kstart)
OUTPUT_FORMAT(elf32-i386)
SECTIONS {
. = 0x100000;
. = 0x8000;
. += SIZEOF_HEADERS;
. = ALIGN(4096);
......@@ -46,6 +46,12 @@ SECTIONS {
__end = .;
. = 0x100000;
.kernel : {
*(.kernel*)
}
/DISCARD/ : {
*(.comment*)
*(.eh_frame*)
......
......@@ -10,33 +10,14 @@ extern crate coreboot_table;
extern crate spin;
extern crate syscall;
use core::slice;
use coreboot_table::{Mapper, PhysicalAddress, VirtualAddress, Table};
#[macro_use]
pub mod arch;
pub mod devices;
pub mod externs;
pub mod loader;
pub mod panic;
struct IdentityMapper;
impl Mapper for IdentityMapper {
unsafe fn map_aligned(&mut self, address: PhysicalAddress, _size: usize) -> Result<VirtualAddress, &'static str> {
Ok(VirtualAddress(address.0))
}
unsafe fn unmap_aligned(&mut self, _address: VirtualAddress) -> Result<(), &'static str> {
Ok(())
}
fn page_size(&self) -> usize {
4096
}
}
#[naked]
#[no_mangle]
pub unsafe fn kstart() -> ! {
......@@ -48,54 +29,10 @@ pub unsafe fn kstart() -> ! {
kmain()
}
pub fn kmain() -> ! {
println!("Test");
let mut framebuffer_opt = None;
let mut mapper = IdentityMapper;
coreboot_table::tables(|table| {
match table {
Table::Framebuffer(framebuffer) => {
println!("{:?}", framebuffer);
framebuffer_opt = Some(framebuffer.clone());
},
Table::Memory(memory) => println!("{:?}", memory.ranges()),
Table::Other(other) => println!("{:?}", other),
}
Ok(())
}, &mut mapper).unwrap();
if let Some(framebuffer) = framebuffer_opt {
if framebuffer.bits_per_pixel == 32 {
let x = framebuffer.x_resolution;
let y = framebuffer.y_resolution;
println!("Framebuffer of resolution {}x{}", x, y);
let size = framebuffer.bytes_per_line as usize * y as usize;
let address = unsafe {
mapper.map(
PhysicalAddress(framebuffer.physical_address as usize),
size
).unwrap()
};
let buf = unsafe {
slice::from_raw_parts_mut(
address.0 as *mut u8,
size
)
};
pub unsafe fn kmain() -> ! {
println!("Loader");
for i in 0..buf.len() {
buf[i] = (i % 256) as u8;
}
} else {
println!("Unsupported framebuffer bits per pixel {}", framebuffer.bits_per_pixel);
}
}
loader::main();
println!("Halt");
......
use core::ptr;
use coreboot_table::{Memory, MemoryRangeKind};
static MM_BASE: u64 = 0x500;
static MM_SIZE: u64 = 0x4B00;
/// Memory does not exist
pub const MEMORY_AREA_NULL: u32 = 0;
/// Memory is free to use
pub const MEMORY_AREA_FREE: u32 = 1;
/// Memory is reserved
pub const MEMORY_AREA_RESERVED: u32 = 2;
/// Memory is used by ACPI, and can be reclaimed
pub const MEMORY_AREA_ACPI: u32 = 3;
/// A memory map area
#[derive(Copy, Clone, Debug, Default)]
#[repr(packed)]
pub struct MemoryArea {
pub base_addr: u64,
pub length: u64,
pub _type: u32,
pub acpi: u32
}
pub unsafe fn memory_map(memory: &Memory) {
ptr::write_bytes(MM_BASE as *mut u8, 0, MM_SIZE as usize);
for (i, range) in memory.ranges().iter().enumerate() {
let bios_type = match range.kind {
MemoryRangeKind::Ram => {
MEMORY_AREA_FREE
},
_ => {
MEMORY_AREA_RESERVED
}
};
let bios_area = MemoryArea {
base_addr: range.start.unpack(),
length: range.size.unpack(),
_type: bios_type,
acpi: 0,
};
ptr::write((MM_BASE as *mut MemoryArea).offset(i as isize), bios_area);
}
}
use coreboot_table::{Mapper, PhysicalAddress, VirtualAddress, Table};
use self::memory_map::memory_map;
use self::paging::paging;
use self::vesa::vesa;
mod memory_map;
mod paging;
mod vesa;
struct IdentityMapper;
impl Mapper for IdentityMapper {
unsafe fn map_aligned(&mut self, address: PhysicalAddress, _size: usize) -> Result<VirtualAddress, &'static str> {
Ok(VirtualAddress(address.0))
}
unsafe fn unmap_aligned(&mut self, _address: VirtualAddress) -> Result<(), &'static str> {
Ok(())
}
fn page_size(&self) -> usize {
4096
}
}
pub unsafe fn main() {
extern "C" {
fn startup() -> !;
}
let mut framebuffer_opt = None;
coreboot_table::tables(|table| {
match table {
Table::Framebuffer(framebuffer) => {
println!("{:?}", framebuffer);
framebuffer_opt = Some(framebuffer.clone());
},
Table::Memory(memory) => {
println!("{:?}", memory.ranges());
memory_map(memory);
},
Table::Other(other) => println!("{:?}", other),
}
Ok(())
}, &mut IdentityMapper).unwrap();
if let Some(framebuffer) = framebuffer_opt {
if framebuffer.bits_per_pixel == 32 {
println!("Framebuffer of resolution {}x{}", framebuffer.x_resolution, framebuffer.y_resolution);
vesa(Some(&framebuffer));
} else {
println!("Unsupported framebuffer bits per pixel {}", framebuffer.bits_per_pixel);
vesa(None);
}
} else {
println!("No framebuffer found");
vesa(None);
}
println!("Paging");
paging();
println!("Startup");
startup();
}
use core::ptr;
static PT_BASE: u64 = 0x70000;
pub unsafe fn paging() {
// Zero PML4, PDP, and 4 PD
ptr::write_bytes(PT_BASE as *mut u8, 0, 6 * 4096);
let mut base = PT_BASE;
// Link first PML4 and second to last PML4 to PDP
ptr::write(base as *mut u64, (PT_BASE + 0x1000) | 1 << 1 | 1);
ptr::write((base + 510*8) as *mut u64, (PT_BASE + 0x1000) | 1 << 1 | 1);
// Link last PML4 to PML4
ptr::write((base + 511*8) as *mut u64, PT_BASE | 1 << 1 | 1);
// Move to PDP
base += 4096;
// Link first four PDP to PD
ptr::write(base as *mut u64, (PT_BASE + 0x2000) | 1 << 1 | 1);
ptr::write((base + 8) as *mut u64, (PT_BASE + 0x3000) | 1 << 1 | 1);
ptr::write((base + 16) as *mut u64, (PT_BASE + 0x4000) | 1 << 1 | 1);
ptr::write((base + 24) as *mut u64, (PT_BASE + 0x5000) | 1 << 1 | 1);
// Move to PD
base += 4096;
// Link all PD's (512 per PDP, 2MB each)
let mut entry = 1 << 7 | 1 << 1 | 1;
for i in 0..4*512 {
ptr::write((base + i*8) as *mut u64, entry);
entry += 0x200000;
}
}
use core::ptr;
use coreboot_table::Framebuffer;
static VBE_BASE: u64 = 0x5200;
/// The info of the VBE mode
#[derive(Copy, Clone, Default, Debug)]
#[repr(packed)]
pub struct VBEModeInfo {
attributes: u16,
win_a: u8,
win_b: u8,
granularity: u16,
winsize: u16,
segment_a: u16,
segment_b: u16,
winfuncptr: u32,
bytesperscanline: u16,
pub xresolution: u16,
pub yresolution: u16,
xcharsize: u8,
ycharsize: u8,
numberofplanes: u8,
bitsperpixel: u8,
numberofbanks: u8,
memorymodel: u8,
banksize: u8,
numberofimagepages: u8,
unused: u8,
redmasksize: u8,
redfieldposition: u8,
greenmasksize: u8,
greenfieldposition: u8,
bluemasksize: u8,
bluefieldposition: u8,
rsvdmasksize: u8,
rsvdfieldposition: u8,
directcolormodeinfo: u8,
pub physbaseptr: u32,
offscreenmemoryoffset: u32,
offscreenmemsize: u16,
}
pub unsafe fn vesa(framebuffer_opt: Option<&Framebuffer>) {
let mut mode_info = VBEModeInfo::default();
if let Some(framebuffer) = framebuffer_opt {
mode_info.xresolution = framebuffer.x_resolution as u16;
mode_info.yresolution = framebuffer.y_resolution as u16;
mode_info.physbaseptr = framebuffer.physical_address as u32;
}
ptr::write(VBE_BASE as *mut VBEModeInfo, mode_info);
}
attrib:
.present equ 1 << 7
.ring1 equ 1 << 5
.ring2 equ 1 << 6
.ring3 equ 1 << 5 | 1 << 6
.user equ 1 << 4
;user
.code equ 1 << 3
; code
.conforming equ 1 << 2
.readable equ 1 << 1
; data
.expand_down equ 1 << 2
.writable equ 1 << 1
.accessed equ 1 << 0
;system
; legacy
.tssAvailabe16 equ 0x1
.ldt equ 0x2
.tssBusy16 equ 0x3
.call16 equ 0x4
.task equ 0x5
.interrupt16 equ 0x6
.trap16 equ 0x7
.tssAvailabe32 equ 0x9
.tssBusy32 equ 0xB
.call32 equ 0xC
.interrupt32 equ 0xE
.trap32 equ 0xF
; long mode
.ldt32 equ 0x2
.tssAvailabe64 equ 0x9
.tssBusy64 equ 0xB
.call64 equ 0xC
.interrupt64 equ 0xE
.trap64 equ 0xF
flags:
.granularity equ 1 << 7
.available equ 1 << 4
;user
.default_operand_size equ 1 << 6
; code
.long_mode equ 1 << 5
; data
.reserved equ 1 << 5
struc GDTEntry
.limitl resw 1
.basel resw 1
.basem resb 1
.attribute resb 1
.flags__limith resb 1
.baseh resb 1
endstruc
SECTION .text
USE32
GLOBAL startup
startup:
;disable paging
mov eax, cr0
and eax, 0x7FFFFFFF
mov cr0, eax
;cr3 holds pointer to PML4
mov eax, 0x70000
mov cr3, eax
;enable OSXSAVE, FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension
mov eax, cr4
or eax, 1 << 18 | 1 << 9 | 1 << 7 | 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 eax, cr0
or eax, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
mov cr0, eax
; far jump to enable Long Mode and load CS with 64 bit segment
jmp gdt.kernel_code:long_mode
USE64
long_mode:
; load all the other segments with 64 bit data segments
mov rax, gdt.kernel_data
mov ds, rax
mov es, rax
mov fs, rax
mov gs, rax
mov ss, rax
; set kernel size
mov rax, __kernel_end
sub rax, __kernel
mov [args.kernel_size], rax
; set stack pointer
mov rsp, [args.stack_base]
add rsp, [args.stack_size]
; align stack
and rsp, 0xFFFFFFFFFFFFFFF0
; set args
mov rdi, args
; entry point
mov rax, [args.kernel_base]
call [rax + 0x18]
.halt:
cli
hlt
jmp .halt
SECTION .data
args:
.kernel_base dq 0x100000
.kernel_size dq 0
.stack_base dq 0xFFFFFF0000080000
.stack_size dq 0x1F000
.env_base dq 0
.env_size dq 0
%include "descriptor_flags.inc"
%include "gdt_entry.inc"
gdtr:
dw gdt.end + 1 ; size
dq gdt ; offset
gdt:
.null equ $ - gdt
dq 0
.kernel_code equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code
at GDTEntry.flags__limith, db flags.long_mode
at GDTEntry.baseh, db 0
iend
.kernel_data equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
; AMD System Programming Manual states that the writeable bit is ignored in long mode, but ss can not be set to this descriptor without it
at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable
at GDTEntry.flags__limith, db 0
at GDTEntry.baseh, db 0
iend
.end equ $ - gdt
SECTION .kernel
__kernel:
INCBIN "build/kernel"
__kernel_end:
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment