Massive reorganization. Most files moved, lots of stuff renamed.
parent
ae7e7d3a80
commit
bc850fecd6
7
run.sh
7
run.sh
|
@ -2,4 +2,9 @@
|
||||||
profile=${1:-"debug"}
|
profile=${1:-"debug"}
|
||||||
mkdir -p drive/EFI/Boot
|
mkdir -p drive/EFI/Boot
|
||||||
cp "target/x86_64-unknown-uefi/$profile/bootproof.efi" drive/EFI/Boot/BootX64.efi
|
cp "target/x86_64-unknown-uefi/$profile/bootproof.efi" drive/EFI/Boot/BootX64.efi
|
||||||
qemu-system-x86_64 -nodefaults -cpu host -smp 8 -m 1G -machine "q35,accel=kvm:tcg" -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on" -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_VARS.fd,readonly=on" -drive "format=raw,file=fat:rw:drive" -display gtk,gl=on -vga virtio -serial stdio
|
qemu-system-x86_64 \
|
||||||
|
-drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on" \
|
||||||
|
-drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_VARS.fd,readonly=on" \
|
||||||
|
-drive "format=raw,file=fat:rw:drive" \
|
||||||
|
-nodefaults -cpu host -smp 8 -m 128M -machine "q35,accel=kvm:tcg" \
|
||||||
|
-display gtk,gl=on -vga virtio -serial stdio
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
use crate::graphics::color::RGB;
|
use crate::graphics::color::RGB;
|
||||||
use crate::graphics::font::Glyph;
|
use crate::graphics::font::Glyph;
|
||||||
|
|
||||||
pub trait Display {
|
pub trait GraphicDisplay {
|
||||||
fn resolution(&self) -> (usize, usize);
|
fn resolution(&self) -> (usize, usize);
|
||||||
fn width(&self) -> usize { self.resolution().0 }
|
fn width(&self) -> usize { self.resolution().0 }
|
||||||
fn height(&self) -> usize { self.resolution().1 }
|
fn height(&self) -> usize { self.resolution().1 }
|
||||||
|
|
||||||
// HACK: This interface sucks.
|
// HACK: This interface sucks.
|
||||||
|
// These interfaces don't support any color (e.g. `impl Color`)
|
||||||
|
// because then I can't use this as a `dyn` trait because of the generic.
|
||||||
|
// I *could* use `dyn Color`, but... why would you do that??
|
||||||
|
/// Unsafe: it is the responsibility of the caller to ensure
|
||||||
|
/// that the pixel is within the boundaries of the screen.
|
||||||
unsafe fn set_pixel(&mut self, color: RGB, x: usize, y: usize);
|
unsafe fn set_pixel(&mut self, color: RGB, x: usize, y: usize);
|
||||||
fn set_pixel_ignore_oob(&mut self, color: RGB, x: usize, y: usize) {
|
fn set_pixel_ignore_oob(&mut self, color: RGB, x: usize, y: usize) {
|
||||||
if x > self.width() || y > self.height() {
|
if x > self.width() || y > self.height() {
|
||||||
|
@ -18,8 +23,14 @@ pub trait Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the entire display to the same color, clearing everything previously drawn.
|
||||||
fn clear(&mut self, color: RGB);
|
fn clear(&mut self, color: RGB);
|
||||||
|
|
||||||
|
/// Display everything that was drawn to the screen.
|
||||||
|
fn refresh(&mut self);
|
||||||
|
|
||||||
|
/// Unsafe: it is the responsibility of the caller to ensure
|
||||||
|
/// that the entire glyph fits within the boundaries of the screen.
|
||||||
unsafe fn draw_glyph(&mut self, bounding_box: (usize, usize), x: usize, y: usize, color: RGB, glyph: &dyn Glyph) {
|
unsafe fn draw_glyph(&mut self, bounding_box: (usize, usize), x: usize, y: usize, color: RGB, glyph: &dyn Glyph) {
|
||||||
// We only assume that space was left for pixels within the bounding box,
|
// We only assume that space was left for pixels within the bounding box,
|
||||||
// and that pixels outside the bounding box may be out-of-bounds.
|
// and that pixels outside the bounding box may be out-of-bounds.
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod graphic_display;
|
||||||
|
pub mod text_display;
|
||||||
|
pub mod tty;
|
|
@ -0,0 +1,66 @@
|
||||||
|
pub mod graphic;
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
|
/// A text-mode display. Basically, an array of characters that you can set in any order.
|
||||||
|
pub trait TextDisplay {
|
||||||
|
fn borrow_frame<'a>(&'a self) -> &'a TextDisplayFrame;
|
||||||
|
fn borrow_mut_frame<'a>(&'a mut self) -> &'a mut TextDisplayFrame;
|
||||||
|
/// Display all changes made to the frame.
|
||||||
|
fn refresh(&mut self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A frame of a text display; basically a 2d array of characters which you can set how you please.
|
||||||
|
/// However, this frame doesn't know anything about how to display itself;
|
||||||
|
/// that's what the TextDisplay trait is for.
|
||||||
|
pub struct TextDisplayFrame {
|
||||||
|
resolution: (usize, usize),
|
||||||
|
buf: Box<[char]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextDisplayFrame {
|
||||||
|
pub fn new(resolution: (usize, usize)) -> TextDisplayFrame {
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
let (width, height) = resolution;
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
buf.resize(width * height, '\u{0}');
|
||||||
|
|
||||||
|
TextDisplayFrame {
|
||||||
|
resolution: resolution,
|
||||||
|
buf: buf.into_boxed_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolution(&self) -> (usize, usize) {
|
||||||
|
self.resolution
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(&self) -> usize {
|
||||||
|
self.resolution.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(&self) -> usize {
|
||||||
|
self.resolution.1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set all characters in this frame to null.
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
for i in 0..self.buf.len() {
|
||||||
|
self.buf[i] = '\u{0}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(&self, x: usize, y: usize) -> usize {
|
||||||
|
self.width() * y + x
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, x: usize, y: usize) -> char {
|
||||||
|
self.buf[self.index(x, y)]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, x: usize, y: usize, c: char) {
|
||||||
|
let i = self.index(x, y);
|
||||||
|
self.buf[i] = c;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,43 +1,43 @@
|
||||||
|
use crate::driver::graphic_display::GraphicDisplay;
|
||||||
|
use crate::driver::text_display::{TextDisplayFrame, TextDisplay};
|
||||||
use crate::graphics::color::{Color, RGB};
|
use crate::graphics::color::{Color, RGB};
|
||||||
use crate::graphics::display::Display;
|
|
||||||
use crate::graphics::font::{Font, Glyph};
|
use crate::graphics::font::{Font, Glyph};
|
||||||
use crate::graphics::terminal::Terminal;
|
|
||||||
use crate::graphics::terminal::frame::TerminalFrame;
|
|
||||||
|
|
||||||
pub struct DisplayTerminal<'d, 'f, G: Glyph> {
|
/// A virtual text display that renders itself onto a graphic display.
|
||||||
display: &'d mut (dyn Display + 'd),
|
pub struct GraphicTextDisplay<'d, 'f, G: Glyph> {
|
||||||
|
display: &'d mut (dyn GraphicDisplay + 'd),
|
||||||
font: &'f (dyn Font<Glyph = G> + 'f),
|
font: &'f (dyn Font<Glyph = G> + 'f),
|
||||||
frame: TerminalFrame,
|
frame: TextDisplayFrame,
|
||||||
bg: RGB,
|
bg: RGB,
|
||||||
fg: RGB,
|
fg: RGB,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Glyph> DisplayTerminal<'_, '_, G> {
|
impl<G: Glyph> GraphicTextDisplay<'_, '_, G> {
|
||||||
pub fn new<'d, 'f>
|
pub fn new<'d, 'f>
|
||||||
(display: &'d mut (dyn Display + 'd), font: &'f (dyn Font<Glyph = G> + 'f),
|
(display: &'d mut (dyn GraphicDisplay + 'd), font: &'f (dyn Font<Glyph = G> + 'f),
|
||||||
bg: impl Color, fg: impl Color)
|
bg: impl Color, fg: impl Color)
|
||||||
-> DisplayTerminal<'d, 'f, G> {
|
-> GraphicTextDisplay<'d, 'f, G> {
|
||||||
let (dp_width, dp_height) = display.resolution();
|
let (dp_width, dp_height) = display.resolution();
|
||||||
let (ft_width, ft_height) = font.bounding_box();
|
let (ft_width, ft_height) = font.bounding_box();
|
||||||
let ch_width = dp_width / ft_width as usize;
|
let ch_width = dp_width / ft_width as usize;
|
||||||
let ch_height = dp_height / ft_height as usize;
|
let ch_height = dp_height / ft_height as usize;
|
||||||
|
|
||||||
DisplayTerminal {
|
GraphicTextDisplay {
|
||||||
display: display,
|
display: display,
|
||||||
font: font,
|
font: font,
|
||||||
frame: TerminalFrame::new((ch_width, ch_height)),
|
frame: TextDisplayFrame::new((ch_width, ch_height)),
|
||||||
bg: bg.into_rgb(),
|
bg: bg.into_rgb(),
|
||||||
fg: fg.into_rgb(),
|
fg: fg.into_rgb(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Glyph> Terminal for DisplayTerminal<'_, '_, G> {
|
impl<G: Glyph> TextDisplay for GraphicTextDisplay<'_, '_, G> {
|
||||||
fn get_frame<'a>(&'a self) -> &'a TerminalFrame {
|
fn borrow_frame<'a>(&'a self) -> &'a TextDisplayFrame {
|
||||||
&self.frame
|
&self.frame
|
||||||
}
|
}
|
||||||
|
|
||||||
fn borrow_frame<'a>(&'a mut self) -> &'a mut TerminalFrame {
|
fn borrow_mut_frame<'a>(&'a mut self) -> &'a mut TextDisplayFrame {
|
||||||
&mut self.frame
|
&mut self.frame
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
pub mod serial;
|
||||||
|
pub mod text_display;
|
||||||
|
|
||||||
|
/// A teletypewriter, or really, because those don't exist anymore,
|
||||||
|
/// a device that behaves like or emulates a teletypewriter.
|
||||||
|
/// Basically, this is a device that lets you output text and not much else.
|
||||||
|
/// Its output may be buffered, so make sure you `flush` the output.
|
||||||
|
pub trait Tty {
|
||||||
|
/// Print a single character to the TTY.
|
||||||
|
fn putc(&mut self, c: char);
|
||||||
|
/// Print an entire string to the TTY.
|
||||||
|
fn puts(&mut self, s: &str);
|
||||||
|
/// Clear all TTY output.
|
||||||
|
fn clear(&mut self);
|
||||||
|
/// Synchronously flush any buffered output.
|
||||||
|
fn flush(&mut self);
|
||||||
|
}
|
|
@ -1,17 +1,30 @@
|
||||||
use crate::graphics::tty::Tty;
|
use crate::driver::tty::Tty;
|
||||||
|
|
||||||
#[derive(Clone)]
|
/// A TTY attached via a serial port.
|
||||||
|
///
|
||||||
|
/// Serial ports don't commonly exist on physical devices anymore,
|
||||||
|
/// but many emulators support them and can map them to the host's TTY/terminal emulator,
|
||||||
|
/// which makes them useful for debugging in a VM.
|
||||||
pub struct SerialTty {
|
pub struct SerialTty {
|
||||||
port: u16,
|
port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The port used by COM1 on x86 devices.
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub const COM1_PORT: u16 = 0x3F8;
|
||||||
|
|
||||||
impl SerialTty {
|
impl SerialTty {
|
||||||
|
/// Creates a new serial TTY which will use the provided port for output.
|
||||||
|
///
|
||||||
|
/// Unsafe because it is up to the caller to make sure
|
||||||
|
/// that the port is actually the port for a TTY device.
|
||||||
pub unsafe fn new(port: u16) -> SerialTty {
|
pub unsafe fn new(port: u16) -> SerialTty {
|
||||||
SerialTty {
|
SerialTty {
|
||||||
port: port,
|
port: port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn outb(&self, cmd: u8) {
|
fn outb(&self, cmd: u8) {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("out dx, al", in("dx") self.port, in("al") cmd);
|
asm!("out dx, al", in("dx") self.port, in("al") cmd);
|
||||||
|
@ -44,6 +57,6 @@ impl Tty for SerialTty {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&mut self) {
|
fn flush(&mut self) {
|
||||||
// This TTY doesn't support buffering.
|
// This TTY doesn't use buffering.
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
use alloc::string::{String, ToString};
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use crate::driver::text_display::TextDisplay;
|
||||||
|
use crate::driver::tty::Tty;
|
||||||
|
|
||||||
|
/// A buffered virtual TTY implemented over a textual display.
|
||||||
|
pub struct TextDisplayTty<'display> {
|
||||||
|
term: &'display mut (dyn TextDisplay + 'display),
|
||||||
|
history: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextDisplayTty<'_> {
|
||||||
|
pub fn new<'a>(term: &'a mut dyn TextDisplay) -> TextDisplayTty<'a> {
|
||||||
|
TextDisplayTty {
|
||||||
|
term: term,
|
||||||
|
history: {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
vec.push("".to_string());
|
||||||
|
vec
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tty for TextDisplayTty<'_> {
|
||||||
|
fn putc(&mut self, c: char) {
|
||||||
|
if c == '\n' {
|
||||||
|
self.history.push("".to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let i = self.history.len() - 1;
|
||||||
|
self.history[i].push(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn puts(&mut self, s: &str) {
|
||||||
|
for c in s.chars() {
|
||||||
|
self.putc(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.history.clear();
|
||||||
|
self.history.push("".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) {
|
||||||
|
// Each line of the history represents a virtual line of output.
|
||||||
|
// However, a line of output may be longer than the physical width of the display,
|
||||||
|
// in which case we may need to wrap the line so that it takes up two physical lines.
|
||||||
|
let mut physical_lines = Vec::new();
|
||||||
|
for line in &self.history {
|
||||||
|
let mut chars = line.chars().collect::<Vec<_>>().into_iter();
|
||||||
|
// We iterate over all of the characters in a virtual line
|
||||||
|
// until every character has been added to a physical line.
|
||||||
|
while chars.len() > 0 {
|
||||||
|
let mut physical_line = String::new();
|
||||||
|
// The width of a physical line may be no more than the width of the frame.
|
||||||
|
let width = chars.len().min(self.term.borrow_frame().width());
|
||||||
|
for _ in 0..width {
|
||||||
|
physical_line.push(chars.next().unwrap());
|
||||||
|
}
|
||||||
|
physical_lines.push(physical_line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is how many lines on the display we'll need for all of our physical lines.
|
||||||
|
// We cannot have more lines than allowed by the display.
|
||||||
|
let mut y = physical_lines.len().min(self.term.borrow_frame().height() - 1);
|
||||||
|
let frame = self.term.borrow_mut_frame();
|
||||||
|
// We start from the lowest line and display each line until we reach the top of the screen.
|
||||||
|
// We cannot run out of physical lines because the lowest line
|
||||||
|
// is at lowest the number of physical lines necessary to display all lines.
|
||||||
|
for line in physical_lines.into_iter().rev() {
|
||||||
|
let mut x = 0;
|
||||||
|
for c in line.chars() {
|
||||||
|
frame.set(x, y, c);
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if y == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
y -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.term.refresh();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
pub mod color;
|
|
||||||
pub mod display;
|
|
||||||
pub mod font;
|
|
||||||
pub mod terminal;
|
|
||||||
pub mod tty;
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod color;
|
||||||
|
pub mod font;
|
|
@ -1,10 +0,0 @@
|
||||||
pub mod display;
|
|
||||||
pub mod frame;
|
|
||||||
|
|
||||||
use crate::graphics::terminal::frame::TerminalFrame;
|
|
||||||
|
|
||||||
pub trait Terminal {
|
|
||||||
fn get_frame<'a>(&'a self) -> &'a TerminalFrame;
|
|
||||||
fn borrow_frame<'a>(&'a mut self) -> &'a mut TerminalFrame;
|
|
||||||
fn refresh(&mut self);
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
pub struct TerminalFrame {
|
|
||||||
resolution: (usize, usize),
|
|
||||||
buf: Vec<char>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TerminalFrame {
|
|
||||||
pub fn new(resolution: (usize, usize)) -> TerminalFrame {
|
|
||||||
let (width, height) = resolution;
|
|
||||||
let buf_length = width * height;
|
|
||||||
let mut buf = Vec::with_capacity(buf_length);
|
|
||||||
for _ in 0..buf_length {
|
|
||||||
buf.push('\u{0}');
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminalFrame {
|
|
||||||
resolution: resolution,
|
|
||||||
buf: buf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolution(&self) -> (usize, usize) {
|
|
||||||
self.resolution
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn width(&self) -> usize {
|
|
||||||
self.resolution.0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn height(&self) -> usize {
|
|
||||||
self.resolution.1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
for i in 0..self.buf.len() {
|
|
||||||
self.buf[i] = '\u{0}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn index(&self, x: usize, y: usize) -> usize {
|
|
||||||
self.width() * y + x
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, x: usize, y: usize) -> char {
|
|
||||||
self.buf[self.index(x, y)]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&mut self, x: usize, y: usize, c: char) {
|
|
||||||
let i = self.index(x, y);
|
|
||||||
self.buf[i] = c;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
pub mod serial;
|
|
||||||
pub mod terminal;
|
|
||||||
|
|
||||||
pub trait Tty {
|
|
||||||
fn putc(&mut self, c: char);
|
|
||||||
fn puts(&mut self, s: &str);
|
|
||||||
fn clear(&mut self);
|
|
||||||
fn flush(&mut self);
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
use alloc::string::{String, ToString};
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use crate::graphics::terminal::Terminal;
|
|
||||||
use crate::graphics::tty::Tty;
|
|
||||||
|
|
||||||
pub struct TerminalTty<'terminal> {
|
|
||||||
term: &'terminal mut dyn Terminal,
|
|
||||||
history: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TerminalTty<'_> {
|
|
||||||
pub fn new<'a>(term: &'a mut dyn Terminal) -> TerminalTty<'a> {
|
|
||||||
TerminalTty {
|
|
||||||
term: term,
|
|
||||||
history: {
|
|
||||||
let mut vec = Vec::new();
|
|
||||||
vec.push("".to_string());
|
|
||||||
vec
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tty for TerminalTty<'_> {
|
|
||||||
fn putc(&mut self, c: char) {
|
|
||||||
if c == '\n' {
|
|
||||||
self.history.push("".to_string());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let i = self.history.len() - 1;
|
|
||||||
self.history[i].push(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn puts(&mut self, s: &str) {
|
|
||||||
for c in s.chars() {
|
|
||||||
self.putc(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(&mut self) {
|
|
||||||
self.history.clear();
|
|
||||||
self.history.push("".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) {
|
|
||||||
let mut physical_lines = Vec::new();
|
|
||||||
for line in &self.history {
|
|
||||||
let mut chars = line.chars().collect::<Vec<_>>().into_iter();
|
|
||||||
while chars.len() > 0 {
|
|
||||||
let mut physical_line = String::new();
|
|
||||||
let width = chars.len().min(self.term.get_frame().width());
|
|
||||||
for _ in 0..width {
|
|
||||||
physical_line.push(chars.next().unwrap());
|
|
||||||
}
|
|
||||||
physical_lines.push(physical_line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut y = physical_lines.len().min(self.term.get_frame().height() - 1);
|
|
||||||
let frame = self.term.borrow_frame();
|
|
||||||
for line in physical_lines.into_iter().rev() {
|
|
||||||
let mut x = 0;
|
|
||||||
for c in line.chars() {
|
|
||||||
frame.set(x, y, c);
|
|
||||||
x += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if y == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
y -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.term.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use crate::graphics::tty::Tty;
|
use crate::driver::tty::Tty;
|
||||||
use crate::graphics::tty::serial::SerialTty;
|
use crate::driver::tty::serial::SerialTty;
|
||||||
use log::{Record, LevelFilter, Metadata, SetLoggerError};
|
use log::{Record, LevelFilter, Metadata, SetLoggerError};
|
||||||
|
|
||||||
enum GlobalLogger {
|
enum GlobalLogger {
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -7,19 +7,18 @@
|
||||||
#![feature(generic_associated_types)]
|
#![feature(generic_associated_types)]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod allocator;
|
|
||||||
mod arch;
|
mod arch;
|
||||||
|
mod driver;
|
||||||
mod graphics;
|
mod graphics;
|
||||||
|
mod memory;
|
||||||
mod logger;
|
mod logger;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use crate::graphics::tty::serial::SerialTty;
|
|
||||||
use uefi::prelude::*;
|
use uefi::prelude::*;
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn efi_main(handle: Handle, st_boot: SystemTable<Boot>) -> Status {
|
fn efi_main(handle: Handle, st_boot: SystemTable<Boot>) -> Status {
|
||||||
use crate::allocator::{ALLOCATOR, GlobalAllocator};
|
use crate::memory::allocator::{ALLOCATOR, GlobalAllocator};
|
||||||
unsafe {
|
unsafe {
|
||||||
// Generally speaking, we want to depend on UEFI as little as possible,
|
// Generally speaking, we want to depend on UEFI as little as possible,
|
||||||
// so the need for a UEFI allocator may seem a bit strange.
|
// so the need for a UEFI allocator may seem a bit strange.
|
||||||
|
@ -29,14 +28,15 @@ fn efi_main(handle: Handle, st_boot: SystemTable<Boot>) -> Status {
|
||||||
// In theory there are probably ways to get around it, but why bother?
|
// In theory there are probably ways to get around it, but why bother?
|
||||||
// Just taking advantage of the UEFI allocator briefly is a lot easier.
|
// Just taking advantage of the UEFI allocator briefly is a lot easier.
|
||||||
// (This also lets us use `println!` prior to our main allocator being set up.)
|
// (This also lets us use `println!` prior to our main allocator being set up.)
|
||||||
use crate::allocator::uefi::UefiAllocator;
|
use crate::memory::allocator::uefi::UefiAllocator;
|
||||||
// ABSOLUTELY DO NOT FORGET TO DISABLE THIS AFTER LEAVING UEFI BOOT SERVICES.
|
// ABSOLUTELY DO NOT FORGET TO DISABLE THIS AFTER LEAVING UEFI BOOT SERVICES.
|
||||||
// ALL ALLOCATIONS MUST BE STATIC OR BE FREED BEFORE BOOT SERVICES EXITS.
|
// ALL ALLOCATIONS MUST BE STATIC OR BE FREED BEFORE BOOT SERVICES EXITS.
|
||||||
// If the're not, Rust still try to free UEFI-allocated data using the new allocator,
|
// If the're not, Rust still try to free UEFI-allocated data using the new allocator,
|
||||||
// which is undefined behavior.
|
// which is undefined behavior.
|
||||||
ALLOCATOR = GlobalAllocator::Uefi(UefiAllocator::new(st_boot.unsafe_clone()));
|
ALLOCATOR = GlobalAllocator::Uefi(UefiAllocator::new(st_boot.unsafe_clone()));
|
||||||
|
|
||||||
logger::set_tty(SerialTty::new(0x3F8));
|
use crate::driver::tty::serial::{COM1_PORT, SerialTty};
|
||||||
|
logger::set_tty(SerialTty::new(COM1_PORT));
|
||||||
logger::init().unwrap();
|
logger::init().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ fn efi_main(handle: Handle, st_boot: SystemTable<Boot>) -> Status {
|
||||||
|
|
||||||
// HACK: I hate having to use the UEFI allocator just to set up another allocator!
|
// HACK: I hate having to use the UEFI allocator just to set up another allocator!
|
||||||
// There's got to be a better way.
|
// There's got to be a better way.
|
||||||
use crate::allocator::standard::StandardAllocator;
|
use crate::memory::allocator::standard::StandardAllocator;
|
||||||
let mut allocator;
|
let mut allocator;
|
||||||
{
|
{
|
||||||
let mut mmap = bs.memory_map(mmap_buf.as_mut_slice())
|
let mut mmap = bs.memory_map(mmap_buf.as_mut_slice())
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod allocator;
|
Loading…
Reference in New Issue