Commit 61985132 authored by Jeremy Soller's avatar Jeremy Soller

Implementation for grabbing framebuffer

parent c22c2d0f
/build
/target
**/*.rs.bk
Cargo.lock
[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
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)",
"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)",
]
[[package]]
name = "coreboot-table"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_syscall"
version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "spin"
version = "0.4.10"
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 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"
......@@ -2,6 +2,14 @@
name = "bootloader-coreboot"
version = "0.1.0"
authors = ["Jeremy Soller <jeremy@system76.com>"]
edition = "2018"
[lib]
name = "bootloader"
path = "src/lib.rs"
crate-type = ["staticlib"]
[dependencies]
bitflags = "1.0.3"
coreboot-table = "0.1.2"
redox_syscall = "0.1.51"
spin = "0.4.8"
ARCH=x86
TARGET=$(ARCH)-unknown-none
export LD=ld
export OBJCOPY=objcopy
export RUST_TARGET_PATH=$(CURDIR)/targets
export XARGO_HOME=$(CURDIR)/build/xargo
all: build/bootloader
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 && \
$(OBJCOPY) --only-keep-debug $@ $@.sym && \
$(OBJCOPY) --strip-debug $@
[dependencies.alloc]
ENTRY(kstart)
OUTPUT_FORMAT(elf32-i386)
SECTIONS {
. = 0x100000;
. += SIZEOF_HEADERS;
. = ALIGN(4096);
.text : {
__text_start = .;
*(.text*)
. = ALIGN(4096);
__text_end = .;
}
.rodata : {
__rodata_start = .;
*(.rodata*)
. = ALIGN(4096);
__rodata_end = .;
}
.data : {
__data_start = .;
*(.data*)
. = ALIGN(4096);
__data_end = .;
__bss_start = .;
*(.bss*)
. = ALIGN(4096);
__bss_end = .;
}
.tdata : {
__tdata_start = .;
*(.tdata*)
. = ALIGN(4096);
__tdata_end = .;
__tbss_start = .;
*(.tbss*)
. += 8;
. = ALIGN(4096);
__tbss_end = .;
}
__end = .;
/DISCARD/ : {
*(.comment*)
*(.eh_frame*)
*(.gcc_except_table*)
*(.note*)
*(.rel.eh_frame*)
}
}
nightly-2018-11-07
#[cfg(target_arch = "x86")]
#[macro_use]
pub mod x86;
#[cfg(target_arch = "x86")]
pub use self::x86::*;
use core::fmt;
use spin::MutexGuard;
use devices::uart_16550::SerialPort;
use syscall::io::Pio;
use super::device::serial::COM1;
pub struct Writer<'a> {
serial: MutexGuard<'a, SerialPort<Pio<u8>>>,
}
impl<'a> Writer<'a> {
pub fn new() -> Writer<'a> {
Writer {
serial: COM1.lock(),
}
}
}
impl<'a> fmt::Write for Writer<'a> {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
self.serial.write_str(s)
}
}
use devices::uart_16550::SerialPort;
use syscall::io::Pio;
use spin::Mutex;
pub static COM1: Mutex<SerialPort<Pio<u8>>> = Mutex::new(SerialPort::<Pio<u8>>::new(0x3F8));
pub static COM2: Mutex<SerialPort<Pio<u8>>> = Mutex::new(SerialPort::<Pio<u8>>::new(0x2F8));
pub unsafe fn init() {
COM1.lock().init();
COM2.lock().init();
}
/// Print to console
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ({
use core::fmt::Write;
let _ = write!($crate::arch::debug::Writer::new(), $($arg)*);
});
}
/// Print with new line to console
#[macro_export]
macro_rules! println {
() => (print!("\n"));
($fmt:expr) => (print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
#[macro_use]
pub mod macros;
pub mod debug;
pub mod device;
pub mod uart_16550;
use core::fmt::{self, Write};
use syscall::io::{Io, Pio, Mmio, ReadOnly};
bitflags! {
/// Interrupt enable flags
struct IntEnFlags: u8 {
const RECEIVED = 1;
const SENT = 1 << 1;
const ERRORED = 1 << 2;
const STATUS_CHANGE = 1 << 3;
// 4 to 7 are unused
}
}
bitflags! {
/// Line status flags
struct LineStsFlags: u8 {
const INPUT_FULL = 1;
// 1 to 4 unknown
const OUTPUT_EMPTY = 1 << 5;
// 6 and 7 unknown
}
}
#[allow(dead_code)]
pub struct SerialPort<T: Io<Value = u8>> {
/// Data register, read to receive, write to send
data: T,
/// Interrupt enable
int_en: T,
/// FIFO control
fifo_ctrl: T,
/// Line control
line_ctrl: T,
/// Modem control
modem_ctrl: T,
/// Line status
line_sts: ReadOnly<T>,
/// Modem status
modem_sts: ReadOnly<T>,
}
impl SerialPort<Pio<u8>> {
pub const fn new(base: u16) -> SerialPort<Pio<u8>> {
SerialPort {
data: Pio::new(base),
int_en: Pio::new(base + 1),
fifo_ctrl: Pio::new(base + 2),
line_ctrl: Pio::new(base + 3),
modem_ctrl: Pio::new(base + 4),
line_sts: ReadOnly::new(Pio::new(base + 5)),
modem_sts: ReadOnly::new(Pio::new(base + 6))
}
}
}
impl SerialPort<Mmio<u8>> {
pub fn new(_base: usize) -> SerialPort<Mmio<u8>> {
SerialPort {
data: Mmio::new(),
int_en: Mmio::new(),
fifo_ctrl: Mmio::new(),
line_ctrl: Mmio::new(),
modem_ctrl: Mmio::new(),
line_sts: ReadOnly::new(Mmio::new()),
modem_sts: ReadOnly::new(Mmio::new())
}
}
}
impl<T: Io<Value = u8>> SerialPort<T> {
pub fn init(&mut self) {
//TODO: Cleanup
self.int_en.write(0x00);
self.line_ctrl.write(0x80);
self.data.write(0x03);
self.int_en.write(0x00);
self.line_ctrl.write(0x03);
self.fifo_ctrl.write(0xC7);
self.modem_ctrl.write(0x0B);
self.int_en.write(0x01);
}
fn line_sts(&self) -> LineStsFlags {
LineStsFlags::from_bits_truncate(self.line_sts.read())
}
pub fn receive(&mut self) {
while self.line_sts().contains(LineStsFlags::INPUT_FULL) {
let _b = self.data.read();
}
}
pub fn send(&mut self, data: u8) {
match data {
8 | 0x7F => {
while ! self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
self.data.write(8);
while ! self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
self.data.write(b' ');
while ! self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
self.data.write(8);
},
_ => {
while ! self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
self.data.write(data);
}
}
}
}
impl<T: Io<Value = u8>> Write for SerialPort<T> {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
for byte in s.bytes() {
self.send(byte);
}
Ok(())
}
}
use core::mem;
const WORD_SIZE: usize = mem::size_of::<usize>();
/// Memcpy
///
/// Copy N bytes of memory from one location to another.
///
/// This faster implementation works by copying bytes not one-by-one, but in
/// groups of 8 bytes (or 4 bytes in the case of 32-bit architectures).
#[no_mangle]
pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
n: usize) -> *mut u8 {
let n_usize: usize = n/WORD_SIZE; // Number of word sized groups
let mut i: usize = 0;
// Copy `WORD_SIZE` bytes at a time
let n_fast = n_usize*WORD_SIZE;
while i < n_fast {
*((dest as usize + i) as *mut usize) =
*((src as usize + i) as *const usize);
i += WORD_SIZE;
}
// Copy 1 byte at a time
while i < n {
*((dest as usize + i) as *mut u8) = *((src as usize + i) as *const u8);
i += 1;
}
dest
}
/// Memmove
///
/// Copy N bytes of memory from src to dest. The memory areas may overlap.
///
/// This faster implementation works by copying bytes not one-by-one, but in
/// groups of 8 bytes (or 4 bytes in the case of 32-bit architectures).
#[no_mangle]
pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
n: usize) -> *mut u8 {
if src < dest as *const u8 {
let n_usize: usize = n/WORD_SIZE; // Number of word sized groups
let mut i: usize = n_usize*WORD_SIZE;
// Copy `WORD_SIZE` bytes at a time
while i != 0 {
i -= WORD_SIZE;
*((dest as usize + i) as *mut usize) =
*((src as usize + i) as *const usize);
}
let mut i: usize = n;
// Copy 1 byte at a time
while i != n_usize*WORD_SIZE {
i -= 1;
*((dest as usize + i) as *mut u8) =
*((src as usize + i) as *const u8);
}
} else {
let n_usize: usize = n/WORD_SIZE; // Number of word sized groups
let mut i: usize = 0;
// Copy `WORD_SIZE` bytes at a time
let n_fast = n_usize*WORD_SIZE;
while i < n_fast {
*((dest as usize + i) as *mut usize) =
*((src as usize + i) as *const usize);
i += WORD_SIZE;
}
// Copy 1 byte at a time
while i < n {
*((dest as usize + i) as *mut u8) =
*((src as usize + i) as *const u8);
i += 1;
}
}
dest
}
/// Memset
///
/// Fill a block of memory with a specified value.
///
/// This faster implementation works by setting bytes not one-by-one, but in
/// groups of 8 bytes (or 4 bytes in the case of 32-bit architectures).
#[no_mangle]
pub unsafe extern fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 {
let c: usize = mem::transmute([c as u8; WORD_SIZE]);
let n_usize: usize = n/WORD_SIZE;
let mut i: usize = 0;
// Set `WORD_SIZE` bytes at a time
let n_fast = n_usize*WORD_SIZE;
while i < n_fast {
*((dest as usize + i) as *mut usize) = c;
i += WORD_SIZE;
}
let c = c as u8;
// Set 1 byte at a time
while i < n {
*((dest as usize + i) as *mut u8) = c;
i += 1;
}
dest
}
/// Memcmp
///
/// Compare two blocks of memory.
///
/// This faster implementation works by comparing bytes not one-by-one, but in
/// groups of 8 bytes (or 4 bytes in the case of 32-bit architectures).
#[no_mangle]
pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
let n_usize: usize = n/WORD_SIZE;
let mut i: usize = 0;
let n_fast = n_usize*WORD_SIZE;
while i < n_fast {
let a = *((s1 as usize + i) as *const usize);
let b = *((s2 as usize + i) as *const usize);
if a != b {
let n: usize = i + WORD_SIZE;
// Find the one byte that is not equal
while i < n {
let a = *((s1 as usize + i) as *const u8);
let b = *((s2 as usize + i) as *const u8);
if a != b {
return a as i32 - b as i32;
}
i += 1;
}
}
i += WORD_SIZE;
}
while i < n {
let a = *((s1 as usize + i) as *const u8);
let b = *((s2 as usize + i) as *const u8);
if a != b {
return a as i32 - b as i32;
}
i += 1;
}
0
}
extern "C" {
/// Returns `n / d` and sets `*rem = n % d`
fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64;
}
/// Returns `n / d`
#[no_mangle]
pub unsafe extern "C" fn __udivdi3(n: u64, d: u64) -> u64 {
__udivmoddi4(n, d, None)
}
/// Returns `n % d`
#[no_mangle]
pub unsafe extern "C" fn __umoddi3(n: u64, d: u64) -> u64 {
let mut rem = 0;
__udivmoddi4(n, d, Some(&mut rem));
rem
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
#![no_std]
#![feature(asm)]
#![feature(core_intrinsics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#[macro_use]
extern crate bitflags;
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 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() -> ! {
asm!("
cli
cld
mov esp, 0x7000
" : : : : "intel", "volatile");
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
)
};
for i in 0..buf.len() {
buf[i] = (i % 256) as u8;
}
} else {
println!("Unsupported framebuffer bits per pixel {}", framebuffer.bits_per_pixel);
}
}
println!("Halt");
loop {}
}
//! Intrinsics for panic handling
use core::alloc::Layout;
use core::panic::PanicInfo;
#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}
/// Required to handle panics
#[panic_handler]
#[no_mangle]
pub extern "C" fn rust_begin_unwind(info: &PanicInfo) -> ! {
println!("BOOTLOADER PANIC: {}", info);
loop {
unsafe {
asm!("hlt" : : : : "intel", "volatile");
}
}
}
#[lang = "oom"]
#[no_mangle]
pub extern fn rust_oom(_layout: Layout) -> ! {
panic!("kernel memory allocation failed");
}
#[allow(non_snake_case)]
#[no_mangle]
/// Required to handle panics
pub extern "C" fn _Unwind_Resume() -> ! {
loop {
unsafe {
asm!("hlt" : : : : "intel", "volatile");
}
}
}
{
"llvm-target": "i686-unknown-none",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128",
"arch": "x86",
"os": "none",
"env": "",
"vendor": "unknown",
"linker-flavor": "gcc",
"target-family": "redox",
"pre-link-args": {
"gcc": ["-m32", "-nostdlib", "-static"]
},
"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float",
"dynamic-linking": false,
"executables": false,
"relocation-model": "pic",
"code-model": "kernel",
"disable-redzone": true,
"eliminate-frame-pointer": false,
"exe-suffix": "",
"has-rpath": false,
"no-compiler-rt": true,
"no-default-libraries": true,
"position-independent-executables": false,
"has-elf-tls": true
}
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