summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/src/lib.rs10
-rw-r--r--kernel/src/vga_text.rs139
2 files changed, 149 insertions, 0 deletions
diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs
index 05b90ef..a27f0a7 100644
--- a/kernel/src/lib.rs
+++ b/kernel/src/lib.rs
@@ -4,8 +4,18 @@
extern crate compiler_builtins;
+mod vga_text;
+
+use core::fmt::Write;
+
+
#[no_mangle]
pub extern "C" fn _start() -> ! {
+
+ let mut stdout = vga_text::OStream::new();
+ stdout.clear();
+ write!(&mut stdout, "hello world!");
+
loop {}
}
diff --git a/kernel/src/vga_text.rs b/kernel/src/vga_text.rs
new file mode 100644
index 0000000..ef488e9
--- /dev/null
+++ b/kernel/src/vga_text.rs
@@ -0,0 +1,139 @@
+#[repr(u8)]
+pub enum Color {
+ Black = 0,
+ Blue = 1,
+ Green = 2,
+ Cyan = 3,
+ Red = 4,
+ Magenta = 5,
+ Brown = 6,
+ LightGray = 7,
+ DarkGray = 8,
+ LightBlue = 9,
+ LightGreen = 10,
+ LightCyan = 11,
+ LightRed = 12,
+ Pink = 13,
+ Yellow = 14,
+ White = 15,
+}
+
+#[derive(Clone, Copy)]
+pub struct CharState(pub u8);
+
+impl CharState {
+ pub fn from_colors(fg: Color, bg: Color) -> Self {
+ Self((fg as u8) | ((bg as u8) << 4))
+ }
+
+ pub fn set_fg(&mut self, fg: Color) {
+ self.0 = (self.0 & 240) | (fg as u8)
+ }
+
+ pub fn set_bg(&mut self, bg: Color) {
+ self.0 = (self.0 & 15) | ((bg as u8) << 4)
+ }
+}
+
+#[derive(Clone, Copy)]
+pub struct VgaChar {
+ pub state: CharState,
+ pub byte: u8
+}
+
+impl VgaChar {
+ pub fn from_state_and_byte(state: CharState, byte: u8) -> Self {
+ Self{ state, byte }
+ }
+}
+
+pub struct OStream {
+ pos: (u8, u8),
+ cursor: *mut VgaChar,
+ state: CharState,
+}
+
+impl OStream {
+ pub fn new() -> Self {
+ Self {
+ pos: (0, 0),
+ cursor: 0xb8000 as *mut VgaChar,
+ state: CharState::from_colors(Color::White, Color::Black)
+ }
+ }
+
+ fn at(n: usize) -> *mut VgaChar {
+ (0xb8000 + (n << 1)) as *mut VgaChar
+ }
+
+ fn compute_cursor(&mut self) {
+ self.cursor = Self::at(self.pos.0 as usize + self.pos.1 as usize * 80)
+ }
+
+ pub fn set_col(&mut self, col: u8) {
+ self.pos.0 = core::cmp::min(col, 79);
+ self.compute_cursor()
+ }
+
+ pub fn set_row(&mut self, row: u8) {
+ self.pos.1 = core::cmp::min(row, 24);
+ self.compute_cursor()
+ }
+
+ pub fn set_cursor(&mut self, col: u8, row: u8) {
+ self.pos = (core::cmp::min(col, 79), core::cmp::min(row, 24));
+ self.compute_cursor()
+ }
+
+ fn set_char(&mut self, c: VgaChar) {
+ unsafe {self.cursor.write_volatile(c)}
+ }
+
+ pub fn put_char(&mut self, c: VgaChar) {
+ if c.byte == b'\n' {
+ self.new_line();
+ } else if self.pos.0 >= 79 {
+ self.new_line();
+ self.put_char(c);
+ } else {
+ self.set_char(c);
+ self.cursor = self.cursor.wrapping_offset(1);
+ self.pos.0 += 1;
+ }
+ }
+
+ pub fn put_byte(&mut self, b: u8) {
+ self.put_char(VgaChar::from_state_and_byte(self.state, b))
+ }
+
+ pub fn clear(&self) {
+ let c = VgaChar::from_state_and_byte(self.state, b' ');
+ for i in 0..2000 {
+ unsafe {Self::at(i).write_volatile(c)}
+ }
+ }
+
+ pub fn new_line(&mut self) {
+ if self.pos.1 >= 24 {
+ self.set_col(0);
+ for i in 0..1920 {
+ unsafe {Self::at(i).write_volatile(*Self::at(i + 80))}
+ }
+ } else {
+ self.set_cursor(0, self.pos.1 + 1);
+ }
+ }
+
+ pub fn set_state(&mut self, state: CharState) {
+ self.state = state
+ }
+}
+
+impl core::fmt::Write for OStream {
+ fn write_str(&mut self, s: &str) -> core::fmt::Result {
+ for &b in s.as_bytes() {
+ self.put_byte(b)
+ }
+ Ok(())
+ }
+}