initial commit
This commit is contained in:
5
.cargo/config
Normal file
5
.cargo/config
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[build]
|
||||||
|
target = "x86_64-unknown-none"
|
||||||
|
|
||||||
|
[unstable]
|
||||||
|
build-std = ["core", "compiler_builtins"]
|
||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@@ -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"
|
||||||
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "operating-system"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
26
Makefile
Normal file
26
Makefile
Normal file
@@ -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
|
||||||
89
bootloader/bootloader.asm
Normal file
89
bootloader/bootloader.asm
Normal file
@@ -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
|
||||||
BIN
bootloader/bootloader.bin
Normal file
BIN
bootloader/bootloader.bin
Normal file
Binary file not shown.
28
linker.ld
Normal file
28
linker.ld
Normal file
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
2
src/drivers/mod.rs
Normal file
2
src/drivers/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod serial;
|
||||||
|
pub mod vga;
|
||||||
33
src/drivers/serial.rs
Normal file
33
src/drivers/serial.rs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
137
src/drivers/vga.rs
Normal file
137
src/drivers/vga.rs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
28
src/libs/io.rs
Normal file
28
src/libs/io.rs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
1
src/libs/mod.rs
Normal file
1
src/libs/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod io;
|
||||||
31
src/main.rs
Normal file
31
src/main.rs
Normal file
@@ -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 {}
|
||||||
|
}
|
||||||
25
x86_64-unknown-none.json
Normal file
25
x86_64-unknown-none.json
Normal file
@@ -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"]
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user