initial commit
This commit is contained in:
Generated
+12
@@ -0,0 +1,12 @@
|
||||
[root]
|
||||
name = "mahdi_os"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rlibc 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rlibc"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "mahdi_os"
|
||||
version = "0.1.0"
|
||||
authors = ["Mahdi Dibaiee <mdibaiee@aol.com>"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rlibc = "0.1.4"
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
@@ -0,0 +1,39 @@
|
||||
arch ?= x86_64
|
||||
kernel := build/kernel-$(arch).bin
|
||||
iso := build/os-$(arch).iso
|
||||
target ?= $(arch)-unknown-linux-gnu
|
||||
rust_os := target/$(target)/debug/libmahdi_os.a
|
||||
|
||||
linker_script = src/arch/$(arch)/linker.ld
|
||||
grub_cfg = src/arch/$(arch)/grub.cfg
|
||||
assembly_source_files = $(wildcard src/arch/$(arch)/*.asm)
|
||||
assembly_object_files = $(patsubst src/arch/$(arch)/%.asm, build/arch/$(arch)/%.o, $(assembly_source_files))
|
||||
|
||||
.PHONY: all clean run iso
|
||||
|
||||
all: $(kernel)
|
||||
|
||||
clean:
|
||||
@rm -r build
|
||||
|
||||
run: $(iso)
|
||||
@qemu-system-x86_64 -curses -cdrom $(iso)
|
||||
|
||||
iso: $(iso)
|
||||
|
||||
$(iso): $(kernel) $(grub_cfg)
|
||||
@mkdir -p build/isofiles/boot/grub
|
||||
@cp $(kernel) build/isofiles/boot/kernel.bin
|
||||
@cp $(grub_cfg) build/isofiles/boot/grub
|
||||
@grub-mkrescue -o $(iso) build/isofiles -d /usr/lib/grub/i386-pc 2> /dev/null
|
||||
@rm -r build/isofiles
|
||||
|
||||
$(kernel): cargo $(rust_os) $(assembly_object_files) $(linker_script)
|
||||
@ld -n --gc-sections -T $(linker_script) -o $(kernel) $(assembly_object_files) $(rust_os)
|
||||
|
||||
cargo:
|
||||
@cargo build --target $(target)
|
||||
|
||||
build/arch/$(arch)/%.o: src/arch/$(arch)/%.asm
|
||||
@mkdir -p $(shell dirname $@)
|
||||
@nasm -felf64 $< -o $@
|
||||
@@ -0,0 +1,128 @@
|
||||
; Copyright 2015 Philipp Oppermann
|
||||
;
|
||||
; Licensed under the Apache License, Version 2.0 (the "License");
|
||||
; you may not use this file except in compliance with the License.
|
||||
; You may obtain a copy of the License at
|
||||
;
|
||||
; http://www.apache.org/licenses/LICENSE-2.0
|
||||
;
|
||||
; Unless required by applicable law or agreed to in writing, software
|
||||
; distributed under the License is distributed on an "AS IS" BASIS,
|
||||
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; See the License for the specific language governing permissions and
|
||||
; limitations under the License.
|
||||
|
||||
global start
|
||||
|
||||
section .text
|
||||
bits 32
|
||||
start:
|
||||
mov esp, stack_top
|
||||
|
||||
call check_multiboot
|
||||
call check_cpuid
|
||||
call check_long_mode
|
||||
|
||||
call setup_page_tables
|
||||
call enable_paging
|
||||
|
||||
; print `OK` to screen
|
||||
mov dword [0xb8000], 0x2f4b2f4f
|
||||
hlt
|
||||
|
||||
setup_page_tables:
|
||||
; map first P4 entry to P3 table
|
||||
mov eax, p3_table
|
||||
or eax, 0b11 ; present + writable
|
||||
mov [p4_table], eax
|
||||
|
||||
; map first P3 entry to a huge page that starts at address 0
|
||||
mov dword [p3_table], 0b10000011 ; present + writable + huge
|
||||
|
||||
ret
|
||||
|
||||
enable_paging:
|
||||
; load P4 to cr3 register (cpu uses this to access the P4 table)
|
||||
mov eax, p4_table
|
||||
mov cr3, eax
|
||||
|
||||
; enable PAE-flag in cr4 (Physical Address Extension)
|
||||
mov eax, cr4
|
||||
or eax, 1 << 5
|
||||
mov cr4, eax
|
||||
|
||||
; set the long mode bit in the EFER MSR (model specific register)
|
||||
mov ecx, 0xC0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8
|
||||
wrmsr
|
||||
|
||||
; enable paging in the cr0 register
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31
|
||||
or eax, 1 << 16
|
||||
mov cr0, eax
|
||||
|
||||
ret
|
||||
|
||||
; Prints `ERR: ` and the given error code to screen and hangs.
|
||||
; parameter: error code (in ascii) in al
|
||||
error:
|
||||
mov dword [0xb8000], 0x4f524f45
|
||||
mov dword [0xb8004], 0x4f3a4f52
|
||||
mov dword [0xb8008], 0x4f204f20
|
||||
mov byte [0xb800a], al
|
||||
hlt
|
||||
|
||||
; Throw error 0 if eax doesn't contain the Multiboot 2 magic value (0x36d76289).
|
||||
check_multiboot:
|
||||
cmp eax, 0x36d76289
|
||||
jne .no_multiboot
|
||||
ret
|
||||
.no_multiboot:
|
||||
mov al, "0"
|
||||
jmp error
|
||||
|
||||
; Throw error 1 if the CPU doesn't support the CPUID command.
|
||||
check_cpuid:
|
||||
pushfd ; Store the FLAGS-register.
|
||||
pop eax ; Restore the A-register.
|
||||
mov ecx, eax ; Set the C-register to the A-register.
|
||||
xor eax, 1 << 21 ; Flip the ID-bit, which is bit 21.
|
||||
push eax ; Store the A-register.
|
||||
popfd ; Restore the FLAGS-register.
|
||||
pushfd ; Store the FLAGS-register.
|
||||
pop eax ; Restore the A-register.
|
||||
push ecx ; Store the C-register.
|
||||
popfd ; Restore the FLAGS-register.
|
||||
xor eax, ecx ; Do a XOR-operation on the A-register and the C-register.
|
||||
jz .no_cpuid ; The zero flag is set, no CPUID.
|
||||
ret ; CPUID is available for use.
|
||||
.no_cpuid:
|
||||
mov al, "1"
|
||||
jmp error
|
||||
|
||||
; Throw error 2 if the CPU doesn't support Long Mode.
|
||||
check_long_mode:
|
||||
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
|
||||
cpuid ; CPU identification.
|
||||
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
|
||||
jb .no_long_mode ; It is less, there is no long mode.
|
||||
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
|
||||
cpuid ; CPU identification.
|
||||
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
|
||||
jb .no_long_mode ; It is less, there is no long mode.
|
||||
ret
|
||||
.no_long_mode:
|
||||
mov al, "2"
|
||||
jmp error
|
||||
|
||||
section .bss
|
||||
align 4096
|
||||
p4_table:
|
||||
resb 4096
|
||||
p3_table:
|
||||
resb 4096
|
||||
stack_bottom:
|
||||
resb 64
|
||||
stack_top:
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,189 @@
|
||||
global start
|
||||
extern long_mode_start
|
||||
|
||||
section .text
|
||||
bits 32
|
||||
start:
|
||||
; move stack pointer register
|
||||
mov esp, stack_top
|
||||
|
||||
call check_multiboot
|
||||
call check_cpuid
|
||||
call check_long_mode
|
||||
|
||||
call set_up_page_tables
|
||||
call enable_paging
|
||||
call set_up_SSE
|
||||
|
||||
lgdt [gdt64.pointer]
|
||||
|
||||
; update selectors
|
||||
; data
|
||||
mov ax, gdt64.data
|
||||
mov ss, ax ; stack selector
|
||||
mov ds, ax ; data selector
|
||||
mov es, ax ; extra selector
|
||||
|
||||
; code
|
||||
jmp gdt64.code:long_mode_start
|
||||
|
||||
|
||||
; print "ERR: " and the given error code to screen and hang
|
||||
error:
|
||||
mov dword [0xb8000], 0x4f524f45
|
||||
mov dword [0xb8004], 0x4f3a4f52
|
||||
mov dword [0xb8008], 0x4f204f20
|
||||
mov byte [0xb800a], al
|
||||
hlt
|
||||
|
||||
check_multiboot:
|
||||
cmp eax, 0x36d76289
|
||||
jne .no_multiboot
|
||||
ret
|
||||
.no_multiboot:
|
||||
mov al, "0"
|
||||
jmp error
|
||||
|
||||
check_cpuid:
|
||||
; Check if CPUID is supported by attempting to flip the ID bit (bit 21)
|
||||
; in the FLAGS register. If we can flip it, CPUID is available.
|
||||
|
||||
; Copy FLAGS in to EAX via stack
|
||||
pushfd
|
||||
pop eax
|
||||
|
||||
; Copy to ECX as well for comparing later on
|
||||
mov ecx, eax
|
||||
|
||||
; Flip the ID bit
|
||||
xor eax, 1 << 21
|
||||
|
||||
; Copy EAX to FLAGS via the stack
|
||||
push eax
|
||||
popfd
|
||||
|
||||
; Restore FLAGS from the old version stored in ECX
|
||||
; (i.e. flipping the ID bit back if it was ever flipped).
|
||||
push ecx
|
||||
popfd
|
||||
|
||||
; Compare EAX and ECX, If they are equal then that means the bit wasn't flipped,
|
||||
; and CPUID is not supported.
|
||||
cmp eax, ecx
|
||||
je .no_cpuid
|
||||
ret
|
||||
.no_cpuid:
|
||||
mov al, "1"
|
||||
jmp error
|
||||
|
||||
check_long_mode:
|
||||
; test if extended processor info is available
|
||||
mov eax, 0x80000000 ; implicit argument for cpuid
|
||||
cpuid ; get highest supported argument
|
||||
cmp eax, 0x80000001 ; it needs to be at least this value
|
||||
jb .no_long_mode ; if it's less, the CPU is too old for long mode
|
||||
|
||||
; use extended info to test if long mode is available
|
||||
mov eax, 0x80000001 ; argument for extended processor info
|
||||
cpuid ; returns various feature bits in ecx and edx
|
||||
test edx, 1 << 29 ; test if the LM-bit is set in the D-register
|
||||
jz .no_long_mode ; If it's not set, there is no long mode
|
||||
ret
|
||||
.no_long_mode:
|
||||
mov al, "2"
|
||||
jmp error
|
||||
|
||||
set_up_page_tables:
|
||||
; map first P4 entry to P3 table
|
||||
mov eax, p3_table
|
||||
or eax, 0b11 ; present + writable
|
||||
mov [p4_table], eax
|
||||
|
||||
; map first P3 entry to P2 table
|
||||
mov eax, p2_table
|
||||
or eax, 0b11 ; present + writable
|
||||
mov [p3_table], eax
|
||||
|
||||
; map each P2 entry to a huge 2MiB page
|
||||
mov ecx, 0
|
||||
|
||||
.map_p2_table:
|
||||
; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx
|
||||
mov eax, 0x200000 ; 2MiB
|
||||
mul ecx ; start address of ecx-th page
|
||||
or eax, 0b10000011 ; present + writable + huge
|
||||
mov [p2_table + ecx * 8], eax ; map ecx-th entry
|
||||
|
||||
inc ecx ; increase
|
||||
cmp ecx, 512 ; if counter == 512, the whole P2 table is mapped
|
||||
jne .map_p2_table
|
||||
|
||||
ret
|
||||
|
||||
enable_paging:
|
||||
; load P4 to cr3 register (cpu uses this to access the P4 table)
|
||||
mov eax, p4_table
|
||||
mov cr3, eax
|
||||
|
||||
; enable PAE-flag in cr4 (physical address extension)
|
||||
mov eax, cr4
|
||||
or eax, 1 << 5
|
||||
mov cr4, eax
|
||||
|
||||
; set the long mode bit in the EFER MSR (model specific register)
|
||||
mov ecx, 0xC0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8
|
||||
wrmsr
|
||||
|
||||
; enable paging in the cr0 register
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31
|
||||
mov cr0, eax
|
||||
|
||||
ret
|
||||
|
||||
; Check for SSE and enable it, if it's not supported throw error "a"
|
||||
set_up_SSE:
|
||||
; check for SSE
|
||||
mov eax, 0x1
|
||||
cpuid
|
||||
test edx, 1<<25
|
||||
jz .no_SSE
|
||||
|
||||
; enable SSE
|
||||
mov eax, cr0
|
||||
and ax, 0xFFFB ; clear coprocessor emulation CR0.EM
|
||||
or ax, 0x2 ; set coprocessor monitoring CR0.MP
|
||||
mov cr0, eax
|
||||
mov eax, cr4
|
||||
or ax, 3 << 9 ; set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
|
||||
mov cr4, eax
|
||||
|
||||
ret
|
||||
.no_SSE:
|
||||
mov al, "a"
|
||||
jmp error
|
||||
|
||||
section .rodata
|
||||
gdt64:
|
||||
dq 0 ; zero entry
|
||||
.code: equ $ - gdt64
|
||||
dq (1 << 44) | (1 << 47) | (1 << 41) | (1 << 43) | (1 << 54) ; code segment
|
||||
.data equ $ - gdt64
|
||||
dq (1 << 44) | (1 << 47) | (1 << 41) ; data segment
|
||||
.pointer:
|
||||
dw $ - gdt64 - 1
|
||||
dq gdt64
|
||||
|
||||
section .bss
|
||||
align 4096
|
||||
p4_table:
|
||||
resb 4096
|
||||
p3_table:
|
||||
resb 4096
|
||||
p2_table:
|
||||
resb 4096
|
||||
stack_bottom:
|
||||
resb 64
|
||||
stack_top:
|
||||
@@ -0,0 +1,7 @@
|
||||
set timeout=0
|
||||
set default=0
|
||||
|
||||
menuentry "Mahdi OS :|" {
|
||||
multiboot2 /boot/kernel.bin
|
||||
boot
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
ENTRY(start)
|
||||
|
||||
SECTIONS {
|
||||
. = 1M;
|
||||
|
||||
.boot :
|
||||
{
|
||||
/* ensure that the multiboot header is tat the beginning */
|
||||
KEEP(*(.multiboot_header))
|
||||
}
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
global long_mode_start
|
||||
|
||||
section .text
|
||||
bits 64
|
||||
long_mode_start:
|
||||
extern rust_main
|
||||
call rust_main
|
||||
|
||||
; rust main returned, print `OS returned!`
|
||||
mov rax, 0x4f724f204f534f4f
|
||||
mov [0xb8000], rax
|
||||
mov rax, 0x4f724f754f744f65
|
||||
mov [0xb8008], rax
|
||||
mov rax, 0x4f214f644f654f6e
|
||||
mov [0xb8010], rax
|
||||
hlt
|
||||
@@ -0,0 +1,14 @@
|
||||
section .multiboot_header
|
||||
header_start:
|
||||
dd 0xe85250d6 ; magic number (multiboot 2)
|
||||
dd 0 ; architecture 0 (protected mode i386)
|
||||
dd header_end - header_start ; header length
|
||||
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)) ; checksum
|
||||
|
||||
; optional tags
|
||||
|
||||
; end tags
|
||||
dw 0 ; type
|
||||
dw 0 ; flags
|
||||
dd 8 ; size
|
||||
header_end:
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#![feature(lang_items)]
|
||||
#![no_std]
|
||||
|
||||
extern crate rlibc;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn rust_main() {
|
||||
// ATTENTION: we have a very small stack and no guard page
|
||||
let hello = b"Hello World!";
|
||||
let color_byte = 0x1f; // white foreground, blue background
|
||||
|
||||
let mut hello_colored = [color_byte; 24];
|
||||
for (i, char_byte) in hello.into_iter().enumerate() {
|
||||
hello_colored[i*2] = *char_byte;
|
||||
}
|
||||
|
||||
let buffer_ptr = (0xb8000 + 1988) as *mut _;
|
||||
unsafe { *buffer_ptr = hello_colored };
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _Unwind_Resume() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "panic_fmt"] extern fn panic_fmt() -> ! { loop {} }
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
20518e01a07acda9
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"rustc":6621389328642914105,"target":6192930460042594332,"profile":10749699831569892475,"local":{"variant":"MtimeBased","fields":[[1466853811,226666665],[47,114,111,111,116,47,107,101,114,110,101,108,47,116,97,114,103,101,116,47,120,56,54,95,54,52,45,117,110,107,110,111,119,110,45,108,105,110,117,120,45,103,110,117,47,100,101,98,117,103,47,46,102,105,110,103,101,114,112,114,105,110,116,47,109,97,104,100,105,95,111,115,45,56,52,101,51,51,55,102,51,99,54,57,102,100,55,97,98,47,100,101,112,45,108,105,98,45,109,97,104,100,105,95,111,115]]},"features":"None","deps":[["rlibc v0.1.5",9884570034738440005]],"rustflags":[]}
|
||||
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
||||
45270e6e130c2d89
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"rustc":6621389328642914105,"target":9571294117447932849,"profile":10749699831569892475,"local":{"variant":"Precalculated","fields":["0.1.5"]},"features":"None","deps":[],"rustflags":[]}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"llvm-target": "x86_64-unknown-none-gnu",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"os": "none",
|
||||
"arch": "x86_64",
|
||||
"data-layout": "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128",
|
||||
"pre-link-args": ["-m64"],
|
||||
"cpu": "x86-64",
|
||||
"features": "-mmx,-sse,-sse2,-sse3,-ssse3",
|
||||
"disable-redzone": true,
|
||||
"eliminate-frame-pointer": false,
|
||||
"linker-is-gnu": true,
|
||||
"no-compiler-rt": true,
|
||||
"archive-format": "gnu"
|
||||
}
|
||||
Reference in New Issue
Block a user