├── .cargo └── config.toml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── binary ├── Cargo.toml └── src │ ├── ascii │ ├── ascii.rs │ ├── main │ └── main.rs ├── bors.toml ├── rust-toolchain ├── src ├── interrupts.rs ├── lib.rs ├── main.rs ├── serial.rs └── vga_buffer.rs ├── tests ├── basic_boot.rs └── should_panic.rs └── x86_64-rust_os.json /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [unstable] 2 | build-std = ["core", "compiler_builtins"] 3 | build-std-features = ["compiler-builtins-mem"] 4 | 5 | [build] 6 | target = "x86_64-rust_os.json" 7 | 8 | [target.'cfg(target_os = "none")'] 9 | runner = "bootimage runner" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "bit_field" 7 | version = "0.10.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" 10 | 11 | [[package]] 12 | name = "bitflags" 13 | version = "1.3.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 16 | 17 | [[package]] 18 | name = "bootloader" 19 | version = "0.9.23" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "b6e02311b16c9819e7c72866d379cdd3026c3b7b25c1edf161f548f8e887e7ff" 22 | 23 | [[package]] 24 | name = "lazy_static" 25 | version = "1.4.0" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 28 | dependencies = [ 29 | "spin", 30 | ] 31 | 32 | [[package]] 33 | name = "rust_os" 34 | version = "0.1.0" 35 | dependencies = [ 36 | "bootloader", 37 | "lazy_static", 38 | "spin", 39 | "uart_16550", 40 | "volatile 0.2.7", 41 | "x86_64", 42 | ] 43 | 44 | [[package]] 45 | name = "rustversion" 46 | version = "1.0.9" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" 49 | 50 | [[package]] 51 | name = "spin" 52 | version = "0.5.2" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 55 | 56 | [[package]] 57 | name = "uart_16550" 58 | version = "0.2.18" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "b074eb9300ad949edd74c529c0e8d451625af71bb948e6b65fe69f72dc1363d9" 61 | dependencies = [ 62 | "bitflags", 63 | "rustversion", 64 | "x86_64", 65 | ] 66 | 67 | [[package]] 68 | name = "volatile" 69 | version = "0.2.7" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "f6b06ad3ed06fef1713569d547cdbdb439eafed76341820fb0e0344f29a41945" 72 | 73 | [[package]] 74 | name = "volatile" 75 | version = "0.4.5" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "e3ca98349dda8a60ae74e04fd90c7fb4d6a4fbe01e6d3be095478aa0b76f6c0c" 78 | 79 | [[package]] 80 | name = "x86_64" 81 | version = "0.14.10" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69" 84 | dependencies = [ 85 | "bit_field", 86 | "bitflags", 87 | "rustversion", 88 | "volatile 0.4.5", 89 | ] 90 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust_os" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [[test]] 9 | name = "should_panic" 10 | harness = false 11 | 12 | [dependencies] 13 | bootloader = "0.9.8" 14 | volatile = "0.2.6" 15 | spin = "0.5.2" 16 | x86_64 = "0.14.2" 17 | uart_16550 = "0.2.0" 18 | 19 | [dependencies.lazy_static] 20 | version = "1.0" 21 | features = ["spin_no_std"] 22 | 23 | 24 | [package.metadata.bootimage] 25 | test-args = [ 26 | "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio", 27 | "-display", "none" 28 | ] 29 | test-success-exit-code = 33 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust Kernel 2 | Rustda Yozilgan Kernel 3 | Rust dasturlash tilida yozilgan Operatsion Tizim 4 | -------------------------------------------------------------------------------- /binary/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "binary" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /binary/src/ascii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ismoilovdevml/rust-os/4bd625fb0b2120974c6948e4e4c3714c0544bb12/binary/src/ascii -------------------------------------------------------------------------------- /binary/src/ascii.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Write}; 2 | 3 | fn main() { 4 | println!("Matn kiriting:"); 5 | let mut input = String::new(); 6 | io::stdin().read_line(&mut input).unwrap(); 7 | let input = input.trim(); 8 | 9 | let mut total_ascii = 0; 10 | let mut total_size = 0; 11 | 12 | for c in input.chars() { 13 | let ascii_val = c as u32; 14 | let bin_val = format!("{:b}", ascii_val); 15 | let size = bin_val.len(); 16 | total_ascii += ascii_val; 17 | total_size += size; 18 | 19 | println!("Belgi: '{}', ASCII: {}, ikkilik: {}, o'lchami: {}", 20 | c, ascii_val, bin_val, size); 21 | } 22 | 23 | let total_bin_val = format!("{:b}", total_ascii); 24 | println!("umumiy ASCII: {}, umumiy ikkilikda: {}, umumiy o'lchami: {}", 25 | total_ascii, total_bin_val, total_size); 26 | } 27 | -------------------------------------------------------------------------------- /binary/src/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ismoilovdevml/rust-os/4bd625fb0b2120974c6948e4e4c3714c0544bb12/binary/src/main -------------------------------------------------------------------------------- /binary/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | fn main() { 4 | println!("O'nlik sanoq tizimida son yozing"); 5 | 6 | let mut input = String::new(); 7 | io::stdin().read_line(&mut input) 8 | .expect("O'qib bo'lmadi"); 9 | 10 | let input = input.trim().parse::() 11 | .expect("Iltimos faqat raqamlar yozing"); 12 | 13 | let binary = format!("{:b}", input); 14 | 15 | println!("Ikkilikdagi ko'rinishi: {}", binary); 16 | } 17 | -------------------------------------------------------------------------------- /bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "Test", 3 | ] 4 | delete_merged_branches = true -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly -------------------------------------------------------------------------------- /src/interrupts.rs: -------------------------------------------------------------------------------- 1 | use crate::println; 2 | use lazy_static::lazy_static; 3 | use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; 4 | 5 | lazy_static! { 6 | static ref IDT: InterruptDescriptorTable = { 7 | let mut idt = InterruptDescriptorTable::new(); 8 | idt.breakpoint.set_handler_fn(breakpoint_handler); 9 | idt 10 | }; 11 | } 12 | 13 | pub fn init_idt() { 14 | IDT.load(); 15 | } 16 | 17 | extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { 18 | println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); 19 | } 20 | 21 | #[test_case] 22 | fn test_breakpoint_exception() { 23 | x86_64::instructions::interrupts::int3(); 24 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![cfg_attr(test, no_main)] 3 | #![feature(custom_test_frameworks)] 4 | #![feature(abi_x86_interrupt)] 5 | #![test_runner(crate::test_runner)] 6 | #![reexport_test_harness_main = "test_main"] 7 | 8 | use core::panic::PanicInfo; 9 | 10 | pub mod interrupts; 11 | pub mod serial; 12 | pub mod vga_buffer; 13 | 14 | pub fn init() { 15 | interrupts::init_idt(); 16 | } 17 | pub trait Testable { 18 | fn run(&self) -> (); 19 | } 20 | 21 | impl Testable for T 22 | where 23 | T: Fn(), 24 | { 25 | fn run(&self) { 26 | serial_print!("{}...\t", core::any::type_name::()); 27 | self(); 28 | serial_println!("[ok]"); 29 | } 30 | } 31 | 32 | pub fn test_runner(tests: &[&dyn Testable]) { 33 | serial_println!("Running {} tests", tests.len()); 34 | for test in tests { 35 | test.run(); 36 | } 37 | exit_qemu(QemuExitCode::Success); 38 | } 39 | 40 | pub fn test_panic_handler(info: &PanicInfo) -> ! { 41 | serial_println!("[failed]\n"); 42 | serial_println!("Error: {}\n", info); 43 | exit_qemu(QemuExitCode::Failed); 44 | loop {} 45 | } 46 | 47 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 48 | #[repr(u32)] 49 | pub enum QemuExitCode { 50 | Success = 0x10, 51 | Failed = 0x11, 52 | } 53 | 54 | pub fn exit_qemu(exit_code: QemuExitCode) { 55 | use x86_64::instructions::port::Port; 56 | 57 | unsafe { 58 | let mut port = Port::new(0xf4); 59 | port.write(exit_code as u32); 60 | } 61 | } 62 | 63 | /// Entry point for `cargo xtest` 64 | #[cfg(test)] 65 | #[no_mangle] 66 | pub extern "C" fn _start() -> ! { 67 | init(); 68 | test_main(); 69 | loop {} 70 | } 71 | 72 | #[cfg(test)] 73 | #[panic_handler] 74 | fn panic(info: &PanicInfo) -> ! { 75 | test_panic_handler(info) 76 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use core::panic::PanicInfo; 5 | 6 | mod vga_buffer; 7 | 8 | #[no_mangle] 9 | pub extern "C" fn _start() -> ! { 10 | println!("Birinchi Kernel{}", "!"); 11 | 12 | loop {} 13 | } 14 | 15 | #[panic_handler] 16 | fn panic(info: &PanicInfo) -> ! { 17 | println!("{}", info); 18 | loop {} 19 | } -------------------------------------------------------------------------------- /src/serial.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use spin::Mutex; 3 | use uart_16550::SerialPort; 4 | 5 | lazy_static! { 6 | pub static ref SERIAL1: Mutex = { 7 | let mut serial_port = unsafe { SerialPort::new(0x3F8) }; 8 | serial_port.init(); 9 | Mutex::new(serial_port) 10 | }; 11 | } 12 | 13 | #[doc(hidden)] 14 | pub fn _print(args: ::core::fmt::Arguments) { 15 | use core::fmt::Write; 16 | SERIAL1 17 | .lock() 18 | .write_fmt(args) 19 | .expect("Printing to serial failed"); 20 | } 21 | 22 | #[macro_export] 23 | macro_rules! serial_print { 24 | ($($arg:tt)*) => { 25 | $crate::serial::_print(format_args!($($arg)*)); 26 | }; 27 | } 28 | 29 | #[macro_export] 30 | macro_rules! serial_println { 31 | () => ($crate::serial_print!("\n")); 32 | ($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n"))); 33 | ($fmt:expr, $($arg:tt)*) => ($crate::serial_print!( 34 | concat!($fmt, "\n"), $($arg)*)); 35 | } -------------------------------------------------------------------------------- /src/vga_buffer.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | use lazy_static::lazy_static; 3 | use spin::Mutex; 4 | use volatile::Volatile; 5 | 6 | lazy_static! { 7 | pub static ref WRITER: Mutex = Mutex::new(Writer { 8 | column_position: 0, 9 | color_code: ColorCode::new(Color::Yellow, Color::Black), 10 | buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, 11 | }); 12 | } 13 | 14 | #[allow(dead_code)] 15 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 16 | #[repr(u8)] 17 | pub enum Color { 18 | Black = 0, 19 | Blue = 1, 20 | Green = 2, 21 | Cyan = 3, 22 | Red = 4, 23 | Magenta = 5, 24 | Brown = 6, 25 | LightGray = 7, 26 | DarkGray = 8, 27 | LightBlue = 9, 28 | LightGreen = 10, 29 | LightCyan = 11, 30 | LightRed = 12, 31 | Pink = 13, 32 | Yellow = 14, 33 | White = 15, 34 | } 35 | 36 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 37 | #[repr(transparent)] 38 | struct ColorCode(u8); 39 | 40 | impl ColorCode { 41 | fn new(foreground: Color, background: Color) -> ColorCode { 42 | ColorCode((background as u8) << 4 | (foreground as u8)) 43 | } 44 | } 45 | 46 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 47 | #[repr(C)] 48 | struct ScreenChar { 49 | ascii_character: u8, 50 | color_code: ColorCode, 51 | } 52 | 53 | const BUFFER_HEIGHT: usize = 25; 54 | const BUFFER_WIDTH: usize = 80; 55 | 56 | #[repr(transparent)] 57 | struct Buffer { 58 | chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], 59 | } 60 | 61 | pub struct Writer { 62 | column_position: usize, 63 | color_code: ColorCode, 64 | buffer: &'static mut Buffer, 65 | } 66 | 67 | impl Writer { 68 | pub fn write_byte(&mut self, byte: u8) { 69 | match byte { 70 | b'\n' => self.new_line(), 71 | byte => { 72 | if self.column_position >= BUFFER_WIDTH { 73 | self.new_line(); 74 | } 75 | 76 | let row = BUFFER_HEIGHT - 1; 77 | let col = self.column_position; 78 | 79 | let color_code = self.color_code; 80 | self.buffer.chars[row][col].write(ScreenChar { 81 | ascii_character: byte, 82 | color_code, 83 | }); 84 | self.column_position += 1; 85 | } 86 | } 87 | } 88 | 89 | fn write_string(&mut self, s: &str) { 90 | for byte in s.bytes() { 91 | match byte { 92 | 0x20..=0x7e | b'\n' => self.write_byte(byte), 93 | _ => self.write_byte(0xfe), 94 | } 95 | } 96 | } 97 | 98 | fn new_line(&mut self) { 99 | for row in 1..BUFFER_HEIGHT { 100 | for col in 0..BUFFER_WIDTH { 101 | let character = self.buffer.chars[row][col].read(); 102 | self.buffer.chars[row - 1][col].write(character); 103 | } 104 | } 105 | self.clear_row(BUFFER_HEIGHT - 1); 106 | self.column_position = 0; 107 | } 108 | 109 | fn clear_row(&mut self, row: usize) { 110 | let blank = ScreenChar { 111 | ascii_character: b' ', 112 | color_code: self.color_code, 113 | }; 114 | for col in 0..BUFFER_WIDTH { 115 | self.buffer.chars[row][col].write(blank); 116 | } 117 | } 118 | } 119 | 120 | impl fmt::Write for Writer { 121 | fn write_str(&mut self, s: &str) -> fmt::Result { 122 | self.write_string(s); 123 | Ok(()) 124 | } 125 | } 126 | 127 | #[macro_export] 128 | macro_rules! print { 129 | ($($arg:tt)*) => ($crate::vga_buffer::_print(format_args!($($arg)*))); 130 | } 131 | 132 | #[macro_export] 133 | macro_rules! println { 134 | () => ($crate::print!("\n")); 135 | ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); 136 | } 137 | 138 | #[doc(hidden)] 139 | pub fn _print(args: fmt::Arguments) { 140 | use core::fmt::Write; 141 | WRITER.lock().write_fmt(args).unwrap(); 142 | } -------------------------------------------------------------------------------- /tests/basic_boot.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(custom_test_frameworks)] 4 | #![test_runner(rust_os::test_runner)] 5 | #![reexport_test_harness_main = "test_main"] 6 | 7 | use rust_os::println; 8 | use core::panic::PanicInfo; 9 | 10 | #[no_mangle] 11 | pub extern "C" fn _start() -> ! { 12 | test_main(); 13 | 14 | loop {} 15 | } 16 | 17 | #[panic_handler] 18 | fn panic(info: &PanicInfo) -> ! { 19 | rust_os::test_panic_handler(info) 20 | } 21 | 22 | #[test_case] 23 | fn test_println() { 24 | println!("test_println output"); 25 | } -------------------------------------------------------------------------------- /tests/should_panic.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use blog_os::{exit_qemu, serial_print, serial_println, QemuExitCode}; 5 | use core::panic::PanicInfo; 6 | 7 | #[no_mangle] 8 | pub extern "C" fn _start() -> ! { 9 | should_fail(); 10 | serial_println!("[test did not panic]"); 11 | exit_qemu(QemuExitCode::Failed); 12 | loop {} 13 | } 14 | 15 | fn should_fail() { 16 | serial_print!("should_panic::should_fail...\t"); 17 | assert_eq!(0, 1); 18 | } 19 | 20 | #[panic_handler] 21 | fn panic(_info: &PanicInfo) -> ! { 22 | serial_println!("[ok]"); 23 | exit_qemu(QemuExitCode::Success); 24 | loop {} 25 | } -------------------------------------------------------------------------------- /x86_64-rust_os.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "x86_64-unknown-none", 3 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", 4 | "arch": "x86_64", 5 | "target-endian": "little", 6 | "target-pointer-width": "64", 7 | "target-c-int-width": "32", 8 | "os": "none", 9 | "executables": true, 10 | "linker-flavor": "ld.lld", 11 | "linker": "rust-lld", 12 | "panic-strategy": "abort", 13 | "disable-redzone": true, 14 | "features": "-mmx,-sse,+soft-float" 15 | } --------------------------------------------------------------------------------