commit 3e19945c405dbfe1e4b54f73d5d81469029b04d3 Author: juls0730 Date: Sun Jun 25 17:09:32 2023 -0500 initial commit diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..54102b0 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,5 @@ +[build] +target = "x86_64-unknown-none" + +[unstable] +build-std = ["core", "compiler_builtins"] \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..657ab43 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "operating-system" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c1cfc6c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "operating-system" +version = "0.1.0" +edition = "2021" + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dc7df4b --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +.PHONY: all clean + +all: cargo-build compile-bootloader copy-bootloader objcopy-elf-file build-os-image + +build-os-image: + dd if=target/x86_64-unknown-none/release/bootloader.bin conv=notrunc of=os-image bs=512 + dd if=target/x86_64-unknown-none/release/operating-system.bin conv=notrunc of=os-image bs=512 seek=1 + +compile-bootloader: + nasm -f bin bootloader/bootloader.asm -o bootloader/bootloader.bin + +objcopy-elf-file: + objcopy -O binary target/x86_64-unknown-none/release/operating-system.elf target/x86_64-unknown-none/release/operating-system.bin + +copy-bootloader: + cp bootloader/bootloader.bin target/x86_64-unknown-none/release/bootloader.bin + +cargo-build: + cargo rustc --release --target x86_64-unknown-none.json + +run: all + qemu-system-x86_64 -drive format=raw,file=os-image -serial mon:stdio -s + +clean: + cargo clean + rm -f os-image bootloader/bootloader.bin \ No newline at end of file diff --git a/bootloader/bootloader.asm b/bootloader/bootloader.asm new file mode 100644 index 0000000..9c61505 --- /dev/null +++ b/bootloader/bootloader.asm @@ -0,0 +1,89 @@ +[BITS 16] +[org 0x7c00] + +mov [BOOT_DEVICE], dl + +; setup stack +mov bp, 0x9000 +mov sp, bp + +; Set video mode (640 x 480 @ 16 colors) +mov ah, 0x00 +mov al, 0x12 +int 0x10 + +call load_kernel +call switch_to_32bit + +load_kernel: + mov bx, 0x1000 ; Destination address + mov dh, 2 ; Sector number + mov dl, [BOOT_DEVICE] ; Drive Number + + mov al, dh + mov ch, 0x00 ; Cylinder number + mov cl, 0x02 ; Start from sector 2, sector 1 is our bootloader + mov ah, 0x02 ; Set read mode + mov dh, 0x00 + + int 0x13 + ret + +gdtp: + dw gdt_end - gdt_start - 1 + dw gdt_start + +gdt_start: + dq 0x0 +gdt_code_segment: + dw 0xFFFF ; Limit (16-bit) (set to 0xFFFF for maximum) + dw 0x0 ; Base (16-bit) + db 0x0 ; Base (8-bit) + db 10011010b ; Access flags + db 11001111b ; Granularity flags (set to 0xCF for 4 KB granularity) + db 0x0 ; Segment bits +gdt_data_segment: + dw 0xFFFF ; Limit (16-bit) (set to 0xFFFF for maximum) + dw 0x0 ; Base (16-bit) + db 0x0 ; Base (8-bit) + db 10010010b ; Access flags + db 11001111b ; Granularity flags (set to 0xCF for 4 KB granularity) + db 0x0 ; Segment bits +gdt_end: + +GDT_CODE_SEG_ADDR equ gdt_code_segment - gdt_start +GDT_DATA_SEG_ADDR equ gdt_data_segment - gdt_start + +switch_to_32bit: + ; Disable interrupts and setup gdt + cli + lgdt [gdtp] + + ; Set PE (Protection Enable) bit in CR0 + mov eax, cr0 + or eax, 0x01 + mov cr0, eax + jmp GDT_CODE_SEG_ADDR:init_32bit + +[BITS 32] +init_32bit: + mov ax, GDT_DATA_SEG_ADDR + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + mov ebp, 0x90000 + mov esp, ebp + + call init_kernel + +init_kernel: + call 0x1000 + jmp $ + +BOOT_DEVICE db 0x00 + +times 510 - ($ - $$) db 0 ; make sure file is 510 bytes in size +dw 0xAA55 ; write boot signature \ No newline at end of file diff --git a/bootloader/bootloader.bin b/bootloader/bootloader.bin new file mode 100644 index 0000000..dd03c24 Binary files /dev/null and b/bootloader/bootloader.bin differ diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..a7ee78d --- /dev/null +++ b/linker.ld @@ -0,0 +1,28 @@ +/* We want the symbol _start to be our entry point */ +ENTRY(_start) + +SECTIONS +{ + . = 0xFFFFF; + + .text : { + *(.text) + } + + /* Read-only data. */ + .rodata : { + *(.rodata) + } + + /* Read-write data (initialized) */ + .data : { + *(.data) + } + + /* Read-write data (uninitialized) and stack */ + .bss : { + *(COMMON) + *(.bss) + } + +} \ No newline at end of file diff --git a/src/drivers/mod.rs b/src/drivers/mod.rs new file mode 100644 index 0000000..fffbe08 --- /dev/null +++ b/src/drivers/mod.rs @@ -0,0 +1,2 @@ +pub mod serial; +pub mod vga; diff --git a/src/drivers/serial.rs b/src/drivers/serial.rs new file mode 100644 index 0000000..e5f3c35 --- /dev/null +++ b/src/drivers/serial.rs @@ -0,0 +1,33 @@ +use crate::libs::io::{inb, outb}; + +pub static PORT: u16 = 0x3f8; + +pub fn init_serial() -> u8 { + outb(PORT + 1, 0x00); + outb(PORT + 3, 0x80); + outb(PORT + 0, 0x03); + outb(PORT + 1, 0x00); + outb(PORT + 3, 0x03); + outb(PORT + 2, 0xC7); + outb(PORT + 4, 0x0B); + outb(PORT + 4, 0x1E); + outb(PORT + 0, 0xAE); + + // Check if serial is faulty + if inb(PORT + 0) != 0xAE { + return 1; + } + + // Set serial in normal operation mode + outb(PORT + 4, 0x0F); + return 0; +} + +fn is_transmit_empty() -> bool { + return (inb(PORT + 5) & 0x20) != 0x20; +} + +pub fn write_serial(a: u8) { + while is_transmit_empty() {} + outb(PORT, a); +} \ No newline at end of file diff --git a/src/drivers/vga.rs b/src/drivers/vga.rs new file mode 100644 index 0000000..f05d783 --- /dev/null +++ b/src/drivers/vga.rs @@ -0,0 +1,137 @@ +use crate::libs::io::{inb, outb}; + +static VGA_AC_INDEX: u16 = 0x3C0; +static VGA_AC_WRITE: u16 = 0x3C0; +static VGA_AC_READ: u16 = 0x3C1; +static VGA_MISC_WRITE: u16 = 0x3C2; +static VGA_SEQ_INDEX: u16 = 0x3C4; +static VGA_SEQ_DATA: u16 = 0x3C5; +static VGA_DAC_READ_INDEX: u16 = 0x3C7; +static VGA_DAC_WRITE_INDEX: u16 = 0x3C8; +static VGA_DAC_DATA: u16 = 0x3C9; +static VGA_MISC_READ: u16 = 0x3CC; +static VGA_GC_INDEX: u16 = 0x3CE; +static VGA_GC_DATA: u16 = 0x3CF; +/* COLOR emulation MONO emulation */ +static VGA_CRTC_INDEX: u16 = 0x3D4; /* 0x3B4 */ +static VGA_CRTC_DATA: u16 = 0x3D5; /* 0x3B5 */ +static VGA_INSTAT_READ: u16 = 0x3DA; + +static VGA_NUM_SEQ_REGS: u16 = 5; +static VGA_NUM_CRTC_REGS: u16 = 25; +static VGA_NUM_GC_REGS: u16 = 9; +static VGA_NUM_AC_REGS: u16 = 21; +static VGA_NUM_REGS: u16 = 1 + VGA_NUM_SEQ_REGS + VGA_NUM_CRTC_REGS + VGA_NUM_GC_REGS + VGA_NUM_AC_REGS; + +const VGA_BUFFER: *mut u8 = 0xA0000 as *mut u8; + +pub fn init_vga() { + // Set the registers for mode 12h + let mut registers_720x480x16 = [ + /* MISC */ + 0xE7, + /* SEQ */ + 0x03, 0x01, 0x08, 0x00, 0x06, + /* CRTC */ + 0x6B, 0x59, 0x5A, 0x82, 0x60, 0x8D, 0x0B, 0x3E, + 0x00, 0x40, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x2D, 0x08, 0xE8, 0x05, 0xE3, + 0xFF, + /* GC */ + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x0F, + 0xFF, + /* AC */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x01, 0x00, 0x0F, 0x00, 0x00, + ]; + + write_regs(&mut registers_720x480x16); + + for x in 0..2 { + put_pixel(x, 0, 9); + } +} + +fn put_pixel(mut pos_x: usize, pos_y: usize, vga_color: u8) { + unsafe { + let width_in_bytes = 720 / 8; + + let offset = width_in_bytes * pos_y + pos_x / 8; + pos_x = (pos_x & 7) * 1; + let mask: u8 = 0x80 >> pos_x; + let mut pmask: u8 = 1; + + for plane in 0..4 { + set_plane(plane); + if pmask & vga_color != 0 { + *VGA_BUFFER.offset(offset as isize) = *VGA_BUFFER.offset(offset as isize) | mask; + } else { + *VGA_BUFFER.offset(offset as isize) = *VGA_BUFFER.offset(offset as isize) & !mask; + } + pmask <<= 1; + } + } +} + +fn set_plane(plane: u8) { + let plane = plane & 3; + let pmask = 1 << plane; + + /* set read plane */ + outb(VGA_GC_INDEX, 4); + outb(VGA_GC_DATA, plane); + + /* set write plane */ + outb(VGA_SEQ_INDEX, 2); + outb(VGA_SEQ_DATA, pmask); +} + +fn write_regs(mut regs: &mut [u8]) { + /* write MISCELLANEOUS reg */ + outb(VGA_MISC_WRITE, regs[0]); + regs = &mut regs[1..]; + + /* write SEQUENCER regs */ + for i in 0..VGA_NUM_SEQ_REGS { + outb(VGA_SEQ_INDEX, i as u8); + outb(VGA_SEQ_DATA, regs[0]); + regs = &mut regs[1..]; + } + + /* unlock CRTC registers */ + outb(VGA_CRTC_INDEX, 0x03); + outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) | 0x80); + outb(VGA_CRTC_INDEX, 0x11); + outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) & !0x80); + + /* make sure they remain unlocked */ + regs[0x03] |= 0x80; + regs[0x11] &= !0x80; + + /* write CRTC regs */ + for i in 0..VGA_NUM_CRTC_REGS { + outb(VGA_CRTC_INDEX, i as u8); + outb(VGA_CRTC_DATA, regs[0]); + regs = &mut regs[1..]; + } + + /* write GRAPHICS CONTROLLER regs */ + for i in 0..VGA_NUM_GC_REGS { + outb(VGA_GC_INDEX, i as u8); + outb(VGA_GC_DATA, regs[0]); + regs = &mut regs[1..]; + } + + /* write ATTRIBUTE CONTROLLER regs */ + for i in 0..VGA_NUM_AC_REGS { + // inb(VGA_INSTAT_READ); + outb(VGA_AC_INDEX, i as u8); + outb(VGA_AC_WRITE, regs[0]); + regs = &mut regs[1..]; + } + + /* lock 16-color palette and unblank display */ + inb(VGA_INSTAT_READ); + outb(VGA_AC_INDEX, 0x20); +} diff --git a/src/libs/io.rs b/src/libs/io.rs new file mode 100644 index 0000000..c8bf84f --- /dev/null +++ b/src/libs/io.rs @@ -0,0 +1,28 @@ +use core::arch::asm; + +#[inline] +pub fn outb(port: u16, value: u8) { + unsafe { + asm!( + "out dx, al", + in("dx") port, + in("al") value, + options(preserves_flags, nomem, nostack) + ); + } + return; +} + +#[inline] +pub fn inb(port: u16) -> u8 { + let mut value: u8; + unsafe { + asm!( + "in al, dx", + out("al") value, + in("dx") port, + options(preserves_flags, nomem, nostack) + ); + } + return value; +} \ No newline at end of file diff --git a/src/libs/mod.rs b/src/libs/mod.rs new file mode 100644 index 0000000..678b90e --- /dev/null +++ b/src/libs/mod.rs @@ -0,0 +1 @@ +pub mod io; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..0974c48 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] + +mod drivers; +mod libs; + +use drivers::{serial, vga}; +use libs::io; + +#[no_mangle] +pub extern "C" fn _start() -> ! { + serial::init_serial(); + + // let crash_message = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + // let garbage_message = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + let message = b"A"; + + for (_i, &byte) in message.iter().enumerate() { + serial::write_serial(byte); + } + + vga::init_vga(); + + loop {} +} + + +#[panic_handler] +fn panic (_info: &core::panic::PanicInfo) -> ! { + loop {} +} \ No newline at end of file diff --git a/x86_64-unknown-none.json b/x86_64-unknown-none.json new file mode 100644 index 0000000..6ce7e9d --- /dev/null +++ b/x86_64-unknown-none.json @@ -0,0 +1,25 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float", + "dynamic-linking": false, + "relocation-model": "pic", + "code-model": "kernel", + "exe-suffix": ".elf", + "has-rpath": false, + "no-default-libraries": true, + "position-independent-executables": false, + "pre-link-args": { + "ld.lld": ["--script=linker.ld"] + } +} \ No newline at end of file