├── .gitignore ├── Makefile ├── Readme.md ├── boot ├── boot_sect.asm ├── disk_load.asm ├── gdt.asm ├── print_hex.asm ├── print_string.asm ├── print_string_pm.asm └── switch_to_pm.asm ├── docs ├── basickernel.pdf ├── links.MD └── os-dev.pdf └── kernel ├── .exrc ├── drivers └── screen.c ├── idt.c ├── include ├── drivers │ └── screen.h ├── low_level.h └── system.h ├── irq.c ├── isrs.c ├── kdb.c ├── kernel.c ├── kernel_entry.asm ├── low_level.c └── timer.c /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.o 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD=build/ 2 | 3 | KERNEL_SOURCES=$(wildcard kernel/*.c kernel/drivers/*.c) 4 | OBJ=${KERNEL_SOURCES:.c=.o} 5 | 6 | C_FLAGS=-m32 -ffreestanding -g 7 | LD_FLAGS=-melf_i386 8 | NASMFLAGS=-felf32 9 | 10 | #C_FLAGS=-ffreestanding -g 11 | #LD_FLAGS=-melf 12 | #NASMFLAGS=-felf 13 | 14 | QEMU=qemu-system-i386 15 | 16 | all: dir kernel.bin boot.bin os-image os 17 | 18 | run: 19 | $(QEMU) -hda ${BUILD}os.img 20 | 21 | debug: 22 | $(QEMU) -fda ${BUILD}os.img -gdb tcp::9999 -S 23 | 24 | os-image: 25 | cat ${BUILD}boot.bin ${BUILD}kernel.bin > ${BUILD}os-image 26 | 27 | os: $(BUILD)os-image 28 | dd if=/dev/zero bs=1024 count=1440 > ${BUILD}$@.img 29 | dd if=$< of=${BUILD}$@.img conv=notrunc 30 | 31 | boot.bin: boot/boot_sect.asm 32 | nasm $(NASM_FLAGS) $< -f bin -I 'boot/' -o ${BUILD}$@ 33 | 34 | %kernel_entry.o: kernel/kernel_entry.asm 35 | nasm $< $(NASMFLAGS) -o kernel/kernel_entry.o 36 | 37 | kernel.bin: kernel/kernel_entry.o $(OBJ) 38 | ld $(LD_FLAGS) -o ${BUILD}$@ -Ttext 0x1000 $^ --oformat binary 39 | 40 | %.o: %.c 41 | gcc $(C_FLAGS) -c $< -o $@ 42 | 43 | dir: 44 | mkdir -p $(BUILD) 45 | 46 | clean: 47 | @rm -f kernel/*.o kernel/drivers/*.o 48 | @rm -r $(BUILD) 49 | 50 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # MiniOS 2 | 3 | OS from scratch using Nick Blundell, Bran's Kernel and OSDev.org. 4 | 5 | ### Needs 6 | 7 | - [Qemu](http://wiki.qemu-project.org/Main_Page) 8 | 9 | ### Build 10 | 11 | ```sh 12 | make 13 | ``` 14 | 15 | ### Use 16 | 17 | ```sh 18 | make run 19 | ``` 20 | 21 | ### References 22 | 23 | see docs 24 | -------------------------------------------------------------------------------- /boot/boot_sect.asm: -------------------------------------------------------------------------------- 1 | ; A boot sector that enters 32- bit protected mode. 2 | [org 0x7c00] 3 | KERNEL_OFFSET equ 0x1000 4 | 5 | mov [BOOT_DRIVE], dl 6 | 7 | mov bp, 0x9000 ; Set the stack. 8 | mov sp, bp 9 | 10 | call print_new_line 11 | mov bx, MSG_REAL_MODE 12 | call print_string 13 | 14 | ;call print_new_line 15 | ;mov bx, KERNEL_VERSION 16 | ;call print_string 17 | 18 | call load_kernel 19 | 20 | call switch_to_pm ; Note that we never return from here. 21 | 22 | jmp $ 23 | 24 | ;KERNEL_VERSION : 25 | ; db 'kernel v0.0.1', 0x0d, 0x0a, 0 26 | 27 | %include "print_string.asm" 28 | %include "gdt.asm" 29 | %include "print_string_pm.asm" 30 | %include "switch_to_pm.asm" 31 | %include "disk_load.asm" 32 | 33 | [bits 16] 34 | 35 | load_kernel: 36 | mov bx, MSG_LOAD_KERNEL 37 | call print_string 38 | 39 | mov bx, KERNEL_OFFSET 40 | mov dh, 15 41 | mov dl, [BOOT_DRIVE] 42 | call disk_load 43 | 44 | ret 45 | 46 | [bits 32] 47 | 48 | ; This is where we arrive after switching to and initialising protected mode. 49 | BEGIN_PM: 50 | mov ebx , MSG_PROT_MODE 51 | call print_string_pm ; Use our 32- bit print routine. 52 | 53 | call KERNEL_OFFSET 54 | 55 | jmp $ ; Hang. 56 | 57 | ; Global variables 58 | MSG_REAL_MODE db "Started in 16-bit Real Mode", 0 59 | MSG_PROT_MODE db "Successfully landed in 32-bit Protected Mode", 0 60 | BOOT_DRIVE db 0 61 | MSG_LOAD_KERNEL db "Loading kernel into memory", 0 62 | 63 | 64 | ; Bootsector padding 65 | times 510 -($-$$) db 0 66 | dw 0xaa55 67 | -------------------------------------------------------------------------------- /boot/disk_load.asm: -------------------------------------------------------------------------------- 1 | ; load DH sectors to ES:BX from drive DL 2 | disk_load: 3 | push dx ; Store DX on stack so later we can recall 4 | ; how many sectors were request to be read , 5 | ; even if it is altered in the meantime 6 | mov ah , 0x02 ; BIOS read sector function 7 | mov al , dh ; Read DH sectors 8 | mov ch , 0x00 ; Select cylinder 0 9 | mov dh , 0x00 ; Select head 0 10 | mov cl , 0x02 ; Start reading from second sector ( i.e. 11 | ; after the boot sector ) 12 | int 0x13 ; BIOS interrupt 13 | jc disk_error ; Jump if error ( i.e. carry flag set ) 14 | pop dx ; Restore DX from the stack 15 | cmp dh , al ; if AL ( sectors read ) != DH ( sectors expected ) 16 | jne disk_error ; display error message 17 | ret 18 | 19 | disk_error : 20 | mov bx , DISK_ERROR_MSG 21 | call print_string 22 | jmp $ 23 | 24 | ; Variables 25 | DISK_ERROR_MSG db " Disk read error !", 0 -------------------------------------------------------------------------------- /boot/gdt.asm: -------------------------------------------------------------------------------- 1 | ; GDT 2 | gdt_start: 3 | 4 | gdt_null: ; the mandatory null descriptor 5 | dd 0x0 ; ’dd ’ means define double word ( i.e. 4 bytes ) 6 | dd 0x0 7 | 8 | gdt_code: ; the code segment descriptor 9 | ; base =0x0 , limit =0 xfffff , 10 | ; 1st flags : ( present )1 ( privilege )00 ( descriptor type )1 -> 1001 b 11 | ; type flags : ( code )1 ( conforming )0 ( readable )1 ( accessed )0 -> 1010 b 12 | ; 2nd flags : ( granularity )1 (32 - bit default )1 (64 - bit seg )0 ( AVL )0 -> 1100 b 13 | 14 | dw 0xffff ; Limit ( bits 0 -15) 15 | dw 0x0 ; Base ( bits 0 -15) 16 | db 0x0 ; Base ( bits 16 -23) 17 | db 10011010b ; 1st flags , type flags 18 | db 11001111b ; 2nd flags , Limit ( bits 16 -19) 19 | db 0x0 ; Base ( bits 24 -31) 20 | 21 | gdt_data: ; the data segment descriptor 22 | ; Same as code segment except for the type flags : 23 | ; type flags : ( code )0 ( expand down )0 ( writable )1 ( accessed )0 -> 0010 b 24 | 25 | dw 0xffff ; Limit ( bits 0 -15) 26 | dw 0x0 ; Base ( bits 0 -15) 27 | db 0x0 ; Base ( bits 16 -23) 28 | db 10010010b ; 1st flags , type flags 29 | db 11001111b ; 2nd flags , Limit ( bits 16 -19) 30 | db 0x0 ; Base ( bits 24 -31) 31 | 32 | gdt_end: ; The reason for putting a label at the end of the 33 | ; GDT is so we can have the assembler calculate 34 | ; the size of the GDT for the GDT decriptor ( below ) 35 | ; GDT descriptior 36 | gdt_descriptor: 37 | dw gdt_end - gdt_start - 1 ; Size of our GDT , always less one 38 | ; of the true size 39 | dd gdt_start ; Start address of our GDT 40 | 41 | ; Define some handy constants for the GDT segment descriptor offsets , which 42 | ; are what segment registers must contain when in protected mode. For example , 43 | ; when we set DS = 0 x10 in PM , the CPU knows that we mean it to use the 44 | ; segment described at offset 0 x10 ( i.e. 16 bytes ) in our GDT , which in our 45 | ; case is the DATA segment (0 x0 -> NULL ; 0 x08 -> CODE ; 0 x10 -> DATA ) 46 | CODE_SEG equ gdt_code - gdt_start 47 | DATA_SEG equ gdt_data - gdt_start 48 | -------------------------------------------------------------------------------- /boot/print_hex.asm: -------------------------------------------------------------------------------- 1 | ; https://github.com/sukwon0709/osdev/blob/master/print_hex.asm 2 | 3 | print_hex: 4 | ; manipulate chars at HEX_OUT to reflect DX 5 | mov cx, dx 6 | and cx, 0xf000 7 | shr cx, 12 8 | call to_char 9 | mov [HEX_OUT + 2], cx 10 | 11 | mov cx, dx 12 | and cx, 0x0f00 13 | shr cx, 8 14 | call to_char 15 | mov [HEX_OUT + 3], cx 16 | 17 | mov cx, dx 18 | and cx, 0x00f0 19 | shr cx, 4 20 | call to_char 21 | mov [HEX_OUT + 4], cx 22 | 23 | mov cx, dx 24 | and cx, 0x000f 25 | call to_char 26 | mov [HEX_OUT + 5], cx 27 | 28 | mov bx, HEX_OUT 29 | call print_string 30 | mov byte [HEX_OUT + 2], '0' 31 | mov byte [HEX_OUT + 3], '0' 32 | mov byte [HEX_OUT + 4], '0' 33 | mov byte [HEX_OUT + 5], '0' 34 | ret 35 | 36 | to_char: 37 | cmp cx, 0xa 38 | jl digits 39 | sub cx, 0xa 40 | add cx, 'a' 41 | ret 42 | 43 | digits: 44 | add cx, '0' 45 | ret 46 | 47 | HEX_OUT: db '0x0000', 0 -------------------------------------------------------------------------------- /boot/print_string.asm: -------------------------------------------------------------------------------- 1 | print_string: 2 | pusha 3 | mov ah, 0x0e 4 | loops: 5 | mov al, [bx] 6 | int 0x10 7 | add bx, 1 8 | cmp al, 0 9 | jne loops 10 | popa 11 | ret 12 | 13 | print_new_line: 14 | mov ah , 0x0e 15 | mov al, 0x0d 16 | int 0x10 17 | mov al, 0x0a 18 | int 0x10 19 | ret 20 | -------------------------------------------------------------------------------- /boot/print_string_pm.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; Define some constants 4 | VIDEO_MEMORY equ 0xb8000 5 | WHITE_ON_BLACK equ 0x0f 6 | 7 | ; prints a null - terminated string pointed to by EDX 8 | print_string_pm: 9 | pusha 10 | mov edx , VIDEO_MEMORY ; Set edx to the start of vid mem. 11 | 12 | 13 | print_string_pm_loop: 14 | mov al, [ ebx ] ; Store the char at EBX in AL 15 | mov ah, WHITE_ON_BLACK ; Store the attributes in AH 16 | cmp al, 0 ; if (al == 0), at end of string , so 17 | je print_string_pm_done ; jump to done 18 | mov [edx], ax ; Store char and attributes at current 19 | ; character cell. 20 | add ebx, 1 ; Increment EBX to the next char in string. 21 | add edx, 2 ; Move to next character cell in vid mem. 22 | jmp print_string_pm_loop ; loop around to print the next char. 23 | 24 | print_string_pm_done: 25 | popa 26 | ret ; Return from the function 27 | 28 | -------------------------------------------------------------------------------- /boot/switch_to_pm.asm: -------------------------------------------------------------------------------- 1 | [bits 16] 2 | 3 | ; Switch to protected mode 4 | switch_to_pm: 5 | cli ; We must switch of interrupts until we have 6 | ; set -up the protected mode interrupt vector 7 | ; otherwise interrupts will run riot. 8 | 9 | lgdt [ gdt_descriptor ] ; Load our global descriptor table , which defines 10 | ; the protected mode segments ( e.g. for code and data ) 11 | 12 | mov eax , cr0 ; To make the switch to protected mode , we set 13 | or eax , 0x1 ; the first bit of CR0 , a control register 14 | mov cr0 , eax 15 | 16 | jmp CODE_SEG:init_pm ; Make a far jump ( i.e. to a new segment ) to our 32- bit 17 | ; code. This also forces the CPU to flush its cache of 18 | ; pre - fetched and real - mode decoded instructions , which can 19 | ; cause problems. 20 | 21 | [bits 32] 22 | 23 | ; Initialise registers and the stack once in PM. 24 | init_pm: 25 | mov ax, DATA_SEG ; Now in PM , our old segments are meaningless , 26 | mov ds, ax ; so we point our segment registers to the 27 | mov ss, ax ; data selector we defined in our GDT 28 | mov es, ax 29 | mov fs, ax 30 | mov gs, ax 31 | mov ebp, 0x90000 ; Update our stack position so it is right 32 | mov esp, ebp ; at the top of the free space. 33 | 34 | call BEGIN_PM ; Finally , call some well - known label 35 | -------------------------------------------------------------------------------- /docs/basickernel.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisfmcalado/MiniOS/9a4ad9cbe3a962147217643a73638e63f217b882/docs/basickernel.pdf -------------------------------------------------------------------------------- /docs/links.MD: -------------------------------------------------------------------------------- 1 | #Links 2 | 3 | ##### Nick Blundell - Writing a Simple Operating System from Scratch 4 | https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf 5 | 6 | ##### Bran's Kernel Development - A tutorial on writing kernels 7 | http://www.osdever.net/bkerndev/Docs/title.htm 8 | 9 | ##### OSDev.org 10 | http://wiki.osdev.org/Main_Page 11 | 12 | -------------------------------------------------------------------------------- /docs/os-dev.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisfmcalado/MiniOS/9a4ad9cbe3a962147217643a73638e63f217b882/docs/os-dev.pdf -------------------------------------------------------------------------------- /kernel/.exrc: -------------------------------------------------------------------------------- 1 | if &cp | set nocp | endif 2 | let s:cpo_save=&cpo 3 | set cpo&vim 4 | inoremap  5 | imap 6 | inoremap pumvisible() ? "\" : "\" 7 | inoremap pumvisible() ? "\" : "\" 8 | inoremap pumvisible() ? "\" : "\" 9 | nnoremap  :nohlsearch=has('diff')?'|diffupdate':''   10 | map  :NERDTreeToggle 11 | nnoremap  :CtrlP 12 | vmap [% [%m'gv`` 13 | nmap [c GitGutterPrevHunk 14 | nmap \hp GitGutterPreviewHunk 15 | nmap \hr GitGutterRevertHunk 16 | nmap \hs GitGutterStageHunk 17 | nnoremap \d :YcmShowDetailedDiagnostic 18 | vmap ]% ]%m'gv`` 19 | nmap ]c GitGutterNextHunk 20 | vmap a% [%v]% 21 | vmap gx NetrwBrowseXVis 22 | nmap gx NetrwBrowseX 23 | vnoremap NetrwBrowseXVis :call netrw#BrowseXVis() 24 | nnoremap NetrwBrowseX :call netrw#BrowseX(expand((exists("g:netrw_gx")? g:netrw_gx : '')),netrw#CheckIfRemote()) 25 | nnoremap GitGutterPreviewHunk :GitGutterPreviewHunk 26 | nnoremap GitGutterRevertHunk :GitGutterRevertHunk 27 | nnoremap GitGutterStageHunk :GitGutterStageHunk 28 | nnoremap GitGutterPrevHunk &diff ? '[c' : ":\execute v:count1 . 'GitGutterPrevHunk'\ " 29 | nnoremap GitGutterNextHunk &diff ? ']c' : ":\execute v:count1 . 'GitGutterNextHunk'\ " 30 | nnoremap 57_: :=v:count ? v:count : '' 31 | inoremap  pumvisible() ? "\" : "\ " 32 | inoremap  u 33 | let &cpo=s:cpo_save 34 | unlet s:cpo_save 35 | set autoindent 36 | set autoread 37 | set backspace=indent,eol,start 38 | set complete=.,w,b,u,t 39 | set completefunc=youcompleteme#Complete 40 | set completeopt=preview,menuone 41 | set display=lastline 42 | set fileencodings=ucs-bom,utf-8,default,latin1 43 | set formatoptions=tcqj 44 | set helplang=pt 45 | set history=1000 46 | set incsearch 47 | set laststatus=2 48 | set listchars=tab:>\ ,trail:-,extends:>,precedes:<,nbsp:+ 49 | set nrformats=bin,hex 50 | set pyxversion=2 51 | set ruler 52 | set runtimepath=~/.vim,~/.vim/bundle/Vundle.vim,~/.vim/bundle/YouCompleteMe,~/.vim/bundle/ctrlp.vim,~/.vim/bundle/nerdtree,~/.vim/bundle/syntastic,~/.vim/bundle/vim-airline,~/.vim/bundle/vim-autoformat,~/.vim/bundle/vim-fugitive,~/.vim/bundle/vim-gitgutter,~/.vim/bundle/vim-markdown,~/.vim/bundle/vim-markdown-preview,~/.vim/bundle/vim-sensible,/usr/share/vim/vimfiles,/usr/share/vim/vim80,/usr/share/vim/vim80/pack/dist/opt/matchit,/usr/share/vim/vimfiles/after,~/.vim/bundle/vim-markdown/after,~/.vim/after,~/.vim/bundle/Vundle.vim/after,~/.vim/bundle/YouCompleteMe/after 53 | set scrolloff=1 54 | set sessionoptions=blank,buffers,curdir,folds,help,tabpages,winsize 55 | set shortmess=filnxtToOc 56 | set sidescrolloff=5 57 | set smarttab 58 | set suffixes=.bak,~,.swp,.o,.info,.aux,.log,.dvi,.bbl,.blg,.brf,.cb,.ind,.idx,.ilg,.inx,.out,.toc,.png,.jpg 59 | set tabpagemax=50 60 | set tags=./tags;,./TAGS,tags,TAGS 61 | set ttimeout 62 | set ttimeoutlen=100 63 | set updatetime=2000 64 | set viminfo=!,'100,<50,s10,h 65 | set wildmenu 66 | " vim: set ft=vim : 67 | -------------------------------------------------------------------------------- /kernel/drivers/screen.c: -------------------------------------------------------------------------------- 1 | #include "../include/drivers/screen.h" 2 | #include "../include/low_level.h" 3 | 4 | unsigned char* vidmem; 5 | 6 | int get_screen_offset(int row, int col){ 7 | return (row * MAX_COLS + col) * 2; 8 | } 9 | 10 | int get_cursor(){ 11 | port_byte_out(REG_SCREEN_CTRL, 14); 12 | int offset = port_byte_in(REG_SCREEN_DATA) << 8; 13 | port_byte_out(REG_SCREEN_CTRL, 15); 14 | offset += port_byte_in(REG_SCREEN_DATA); 15 | return offset * 2; 16 | } 17 | 18 | void set_cursor(int offset){ 19 | offset /= 2; 20 | port_byte_out(REG_SCREEN_CTRL, 14); 21 | port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8)); 22 | port_byte_out(REG_SCREEN_CTRL, 15); 23 | port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset)); 24 | } 25 | 26 | void clear_screen() 27 | { 28 | int i,j; 29 | for(i=0; i= 0 && col >= 0){ 40 | set_cursor(get_screen_offset(row, col)); 41 | } 42 | 43 | char c; 44 | int i = 0; 45 | while((c = message[i++]) != 0){ 46 | print_char(c, -1, -1, 0); 47 | } 48 | } 49 | 50 | int scroll(int offset){ 51 | 52 | if(offset < MAX_ROWS * MAX_COLS * 2){ 53 | return offset; 54 | } 55 | 56 | int i, j; 57 | char *c, *cc; 58 | for(i = 1; i < MAX_ROWS; i++){ 59 | for(j = 0; j < MAX_COLS * 2; j++){ 60 | vidmem[get_screen_offset(i-1,j)] = vidmem[get_screen_offset(i,j)]; 61 | } 62 | } 63 | 64 | for(j = 0; j < MAX_COLS * 2; j++){ 65 | vidmem[get_screen_offset(MAX_ROWS - 1, j)] = 0; 66 | } 67 | 68 | offset = get_screen_offset(MAX_ROWS - 1, 0); 69 | return offset; 70 | } 71 | 72 | void print_char(char c, int row, int col, char att){ 73 | 74 | if(!att){ 75 | att = WHITE_ON_BLACK; 76 | } 77 | 78 | int offset; 79 | if (row >= 0 && col >= 0){ 80 | offset = get_screen_offset(row, col); 81 | } else { 82 | offset = get_cursor(); 83 | } 84 | 85 | int rows; 86 | switch (c){ 87 | case '\n': 88 | rows = offset / (2*MAX_COLS); 89 | offset = get_screen_offset(rows, 79); 90 | break; 91 | default: 92 | vidmem[offset] = c; 93 | vidmem[offset + 1] = att; 94 | } 95 | 96 | offset = scroll(offset+2); 97 | set_cursor(offset); 98 | } 99 | 100 | void print(char *str) 101 | { 102 | int i; 103 | for(i=0; str[i]!='\0'; i++) 104 | print_char(str[i], -1, -1, 0); 105 | } 106 | 107 | void screen_init(){ 108 | vidmem = (unsigned char*)VIDEO_ADDRESS; 109 | } 110 | 111 | -------------------------------------------------------------------------------- /kernel/idt.c: -------------------------------------------------------------------------------- 1 | #include "include/system.h" 2 | #include "include/low_level.h" 3 | 4 | /* Defines an IDT entry */ 5 | struct idt_entry 6 | { 7 | unsigned short base_lo; 8 | unsigned short sel; /* Our kernel segment goes here! */ 9 | unsigned char always0; /* This will ALWAYS be set to 0! */ 10 | unsigned char flags; /* Set using the above table! */ 11 | unsigned short base_hi; 12 | } __attribute__((packed)); 13 | 14 | struct idt_ptr 15 | { 16 | unsigned short limit; 17 | unsigned int base; 18 | } __attribute__((packed)); 19 | 20 | /* Declare an IDT of 256 entries. Although we will only use the 21 | * first 32 entries in this tutorial, the rest exists as a bit 22 | * of a trap. If any undefined IDT entry is hit, it normally 23 | * will cause an "Unhandled Interrupt" exception. Any descriptor 24 | * for which the 'presence' bit is cleared (0) will generate an 25 | * "Unhandled Interrupt" exception */ 26 | struct idt_entry idt[256]; 27 | struct idt_ptr idtp; 28 | 29 | /* This exists in 'start.asm', and is used to load our IDT */ 30 | extern void idt_load(); 31 | 32 | /* Use this function to set an entry in the IDT. Alot simpler 33 | * than twiddling with the GDT ;) */ 34 | void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags) 35 | { 36 | /* The interrupt routine's base address */ 37 | idt[num].base_lo = (base & 0xFFFF); 38 | idt[num].base_hi = (base >> 16) & 0xFFFF; 39 | 40 | /* The segment or 'selector' that this IDT entry will use 41 | * is set here, along with any access flags */ 42 | idt[num].sel = sel; 43 | idt[num].always0 = 0; 44 | idt[num].flags = flags; 45 | } 46 | 47 | /* Installs the IDT */ 48 | void idt_install() 49 | { 50 | /* Sets the special IDT pointer up, just like in 'gdt.c' */ 51 | idtp.limit = (sizeof (struct idt_entry) * 256) - 1; 52 | idtp.base = &idt; 53 | 54 | /* Clear out the entire IDT, initializing it to zeros */ 55 | memset(&idt, 0, sizeof(struct idt_entry) * 256); 56 | 57 | /* Add any new ISRs to the IDT here using idt_set_gate */ 58 | 59 | /* Points the processor's internal register to the new IDT */ 60 | idt_load(); 61 | } 62 | -------------------------------------------------------------------------------- /kernel/include/drivers/screen.h: -------------------------------------------------------------------------------- 1 | #ifndef SCREEN_H 2 | #define SCREEN_H 3 | 4 | #define VIDEO_ADDRESS 0xb8000 5 | #define MAX_ROWS 25 6 | #define MAX_COLS 80 7 | 8 | #define BLACK_ON_WHITE 0xf0 9 | #define WHITE_ON_BLACK 0x0f 10 | 11 | #define REG_SCREEN_CTRL 0x3D4 12 | #define REG_SCREEN_DATA 0x3D5 13 | 14 | void screen_init(); 15 | void clear_screen(); 16 | int get_cursor(); 17 | void set_cursor(int offset); 18 | void print_at(char* message, int row, int col); 19 | void print_char(char c, int row, int col, char att); 20 | void print(char *str); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /kernel/include/low_level.h: -------------------------------------------------------------------------------- 1 | #ifndef LOW_LEVEL_H 2 | #define LOW_LEVEL_H 3 | 4 | unsigned char port_byte_in( unsigned short port ); 5 | void port_byte_out( unsigned short port , unsigned char data ); 6 | unsigned short port_word_in ( unsigned short port ); 7 | void port_word_out ( unsigned short port , unsigned short data ); 8 | 9 | unsigned char *memset(unsigned char *dest, unsigned char val, int count); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /kernel/include/system.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSTEM_H 2 | #define SYSTEM_H 3 | 4 | struct regs 5 | { 6 | unsigned int gs, fs, es, ds; /* pushed the segs last */ 7 | unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by 'pusha' */ 8 | unsigned int int_no, err_code; /* our 'push byte #' and ecodes do this */ 9 | unsigned int eip, cs, eflags, useresp, ss; /* pushed by the processor automatically */ 10 | }; 11 | 12 | 13 | void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags); 14 | void idt_install(); 15 | 16 | void isrs_install(); 17 | 18 | void irq_install(); 19 | void irq_uninstall_handler(int irq); 20 | void irq_install_handler(int irq, void (*handler)(struct regs *r)); 21 | 22 | void timer_install(); 23 | void timer_wait(int ticks); 24 | 25 | void keyboard_install(); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /kernel/irq.c: -------------------------------------------------------------------------------- 1 | #include "include/system.h" 2 | #include "include/low_level.h" 3 | 4 | extern void irq0(); 5 | extern void irq1(); 6 | extern void irq2(); 7 | extern void irq3(); 8 | extern void irq4(); 9 | extern void irq5(); 10 | extern void irq6(); 11 | extern void irq7(); 12 | extern void irq8(); 13 | extern void irq9(); 14 | extern void irq10(); 15 | extern void irq11(); 16 | extern void irq12(); 17 | extern void irq13(); 18 | extern void irq14(); 19 | extern void irq15(); 20 | 21 | void *irq_routines[16] = 22 | { 23 | 0, 0, 0, 0, 0, 0, 0, 0, 24 | 0, 0, 0, 0, 0, 0, 0, 0 25 | }; 26 | 27 | void irq_install_handler(int irq, void (*handler)(struct regs *r)) 28 | { 29 | irq_routines[irq] = handler; 30 | } 31 | 32 | void irq_uninstall_handler(int irq) 33 | { 34 | irq_routines[irq] = 0; 35 | } 36 | 37 | void irq_remap(void) 38 | { 39 | port_byte_out(0x20, 0x11); 40 | port_byte_out(0xA0, 0x11); 41 | port_byte_out(0x21, 0x20); 42 | port_byte_out(0xA1, 0x28); 43 | port_byte_out(0x21, 0x04); 44 | port_byte_out(0xA1, 0x02); 45 | port_byte_out(0x21, 0x01); 46 | port_byte_out(0xA1, 0x01); 47 | port_byte_out(0x21, 0x0); 48 | port_byte_out(0xA1, 0x0); 49 | } 50 | 51 | void irq_install() 52 | { 53 | irq_remap(); 54 | 55 | idt_set_gate(32, (unsigned)irq0, 0x08, 0x8E); 56 | idt_set_gate(33, (unsigned)irq1, 0x08, 0x8E); 57 | idt_set_gate(34, (unsigned)irq2, 0x08, 0x8E); 58 | idt_set_gate(35, (unsigned)irq3, 0x08, 0x8E); 59 | idt_set_gate(36, (unsigned)irq4, 0x08, 0x8E); 60 | idt_set_gate(37, (unsigned)irq5, 0x08, 0x8E); 61 | idt_set_gate(38, (unsigned)irq6, 0x08, 0x8E); 62 | idt_set_gate(39, (unsigned)irq7, 0x08, 0x8E); 63 | idt_set_gate(40, (unsigned)irq8, 0x08, 0x8E); 64 | idt_set_gate(41, (unsigned)irq9, 0x08, 0x8E); 65 | idt_set_gate(42, (unsigned)irq10, 0x08, 0x8E); 66 | idt_set_gate(43, (unsigned)irq11, 0x08, 0x8E); 67 | idt_set_gate(44, (unsigned)irq12, 0x08, 0x8E); 68 | idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E); 69 | idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E); 70 | idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E); 71 | } 72 | 73 | void irq_handler(struct regs *r) 74 | { 75 | /* This is a blank function pointer */ 76 | void (*handler)(struct regs *r); 77 | 78 | /* Find out if we have a custom handler to run for this 79 | * IRQ, and then finally, run it */ 80 | handler = irq_routines[r->int_no - 32]; 81 | if (handler) 82 | { 83 | handler(r); 84 | } 85 | 86 | /* If the IDT entry that was invoked was greater than 40 87 | * (meaning IRQ8 - 15), then we need to send an EOI to 88 | * the slave controller */ 89 | if (r->int_no >= 40) 90 | { 91 | port_byte_out(0xA0, 0x20); 92 | } 93 | 94 | /* In either case, we need to send an EOI to the master 95 | * interrupt controller too */ 96 | port_byte_out(0x20, 0x20); 97 | } 98 | -------------------------------------------------------------------------------- /kernel/isrs.c: -------------------------------------------------------------------------------- 1 | #include "include/drivers/screen.h" 2 | #include "include/system.h" 3 | 4 | extern void isr0(); 5 | extern void isr1(); 6 | extern void isr2(); 7 | extern void isr3(); 8 | extern void isr4(); 9 | extern void isr5(); 10 | extern void isr6(); 11 | extern void isr7(); 12 | extern void isr8(); 13 | extern void isr9(); 14 | extern void isr10(); 15 | extern void isr11(); 16 | extern void isr12(); 17 | extern void isr13(); 18 | extern void isr14(); 19 | extern void isr15(); 20 | extern void isr16(); 21 | extern void isr17(); 22 | extern void isr18(); 23 | extern void isr19(); 24 | extern void isr20(); 25 | extern void isr21(); 26 | extern void isr22(); 27 | extern void isr23(); 28 | extern void isr24(); 29 | extern void isr25(); 30 | extern void isr26(); 31 | extern void isr27(); 32 | extern void isr28(); 33 | extern void isr29(); 34 | extern void isr30(); 35 | extern void isr31(); 36 | 37 | char *exception_messages[32]; 38 | 39 | void isrs_install() { 40 | idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E); 41 | idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E); 42 | idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E); 43 | idt_set_gate(3, (unsigned)isr3, 0x08, 0x8E); 44 | idt_set_gate(4, (unsigned)isr4, 0x08, 0x8E); 45 | idt_set_gate(5, (unsigned)isr5, 0x08, 0x8E); 46 | idt_set_gate(6, (unsigned)isr6, 0x08, 0x8E); 47 | idt_set_gate(7, (unsigned)isr7, 0x08, 0x8E); 48 | idt_set_gate(8, (unsigned)isr8, 0x08, 0x8E); 49 | idt_set_gate(9, (unsigned)isr9, 0x08, 0x8E); 50 | idt_set_gate(10, (unsigned)isr10, 0x08, 0x8E); 51 | idt_set_gate(11, (unsigned)isr11, 0x08, 0x8E); 52 | idt_set_gate(12, (unsigned)isr12, 0x08, 0x8E); 53 | idt_set_gate(13, (unsigned)isr13, 0x08, 0x8E); 54 | idt_set_gate(14, (unsigned)isr14, 0x08, 0x8E); 55 | idt_set_gate(15, (unsigned)isr15, 0x08, 0x8E); 56 | idt_set_gate(16, (unsigned)isr16, 0x08, 0x8E); 57 | idt_set_gate(17, (unsigned)isr17, 0x08, 0x8E); 58 | idt_set_gate(18, (unsigned)isr18, 0x08, 0x8E); 59 | idt_set_gate(19, (unsigned)isr19, 0x08, 0x8E); 60 | idt_set_gate(20, (unsigned)isr20, 0x08, 0x8E); 61 | idt_set_gate(21, (unsigned)isr21, 0x08, 0x8E); 62 | idt_set_gate(22, (unsigned)isr22, 0x08, 0x8E); 63 | idt_set_gate(23, (unsigned)isr23, 0x08, 0x8E); 64 | idt_set_gate(24, (unsigned)isr24, 0x08, 0x8E); 65 | idt_set_gate(25, (unsigned)isr25, 0x08, 0x8E); 66 | idt_set_gate(26, (unsigned)isr26, 0x08, 0x8E); 67 | idt_set_gate(27, (unsigned)isr27, 0x08, 0x8E); 68 | idt_set_gate(28, (unsigned)isr28, 0x08, 0x8E); 69 | idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E); 70 | idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E); 71 | idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E); 72 | 73 | exception_messages[0] = "Division By Zero"; 74 | exception_messages[1] = "Debug"; 75 | exception_messages[2] = "Non Maskable Interrupt"; 76 | exception_messages[3] = "Breakpoint Exception"; 77 | exception_messages[4] = "Into Detected Overflow Exception"; 78 | exception_messages[5] = "Out of Bounds Exception"; 79 | exception_messages[6] = "Invalid Opcode Exception"; 80 | exception_messages[7] = "No Coprocessor Exception"; 81 | exception_messages[8] = "Double Fault Exception"; 82 | exception_messages[9] = "Coprocessor Segment Overrun Exception"; 83 | exception_messages[10] = "Bad TSS Exception"; 84 | exception_messages[11] = "Xegment Not Present Exception"; 85 | exception_messages[12] = "Ytack Fault Exception"; 86 | exception_messages[13] = "General Protection Fault Exception"; 87 | exception_messages[14] = "Page Fault Exception"; 88 | exception_messages[15] = "Unknown Interrupt Exception"; 89 | exception_messages[16] = "Coprocessor Fault Exception"; 90 | exception_messages[17] = "Alignment Check Exception (486+)"; 91 | exception_messages[18] = "Machine Check Exception (Pentium/586+)"; 92 | exception_messages[19] = "Reserved"; 93 | exception_messages[20] = "Reserved"; 94 | exception_messages[21] = "Reserved"; 95 | exception_messages[22] = "Reserved"; 96 | exception_messages[23] = "Reserved"; 97 | exception_messages[24] = "Reserved"; 98 | exception_messages[25] = "Reserved"; 99 | exception_messages[26] = "Reserved"; 100 | exception_messages[27] = "Reserved"; 101 | exception_messages[28] = "Reserved"; 102 | exception_messages[29] = "Reserved"; 103 | exception_messages[30] = "Reserved"; 104 | exception_messages[31] = "Reserved"; 105 | } 106 | 107 | void fault_handler(struct regs *r) { 108 | if (r->int_no < 32) { 109 | print(exception_messages[r->int_no]); 110 | print(" - Exception. System Halted!\n"); 111 | for (;;) 112 | ; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /kernel/kdb.c: -------------------------------------------------------------------------------- 1 | #include "include/drivers/screen.h" 2 | #include "include/low_level.h" 3 | #include "include/system.h" 4 | 5 | unsigned char kbdus[128]; 6 | 7 | /* Handles the keyboard interrupt */ 8 | void keyboard_handler(struct regs *r) { 9 | unsigned char scancode; 10 | 11 | /* Read from the keyboard's data buffer */ 12 | scancode = port_byte_in(0x60); 13 | 14 | if (scancode & 0x80) { 15 | /* You can use this one to see if the user released the 16 | * shift, alt, or control keys... */ 17 | } else { 18 | print_char(kbdus[scancode], -1, -1, 0); 19 | } 20 | } 21 | 22 | void keyboard_install() { 23 | kbdus[0] = 0; 24 | kbdus[1] = 27; 25 | kbdus[2] = '1'; 26 | kbdus[3] = '2'; 27 | kbdus[4] = '3'; 28 | kbdus[5] = '4'; 29 | kbdus[6] = '5'; 30 | kbdus[7] = '6'; 31 | kbdus[8] = '7'; 32 | kbdus[9] = '8'; /* 9 */ 33 | kbdus[10] = '9'; 34 | kbdus[11] = '0'; 35 | kbdus[12] = '-'; 36 | kbdus[13] = '='; 37 | kbdus[14] = '\b'; /* Backspace */ 38 | kbdus[15] = '\t'; /* Tab */ 39 | kbdus[16] = 'q'; 40 | kbdus[17] = 'w'; 41 | kbdus[18] = 'e'; 42 | kbdus[19] = 'r'; /* 19 */ 43 | kbdus[20] = 't'; 44 | kbdus[21] = 'y'; 45 | kbdus[22] = 'u'; 46 | kbdus[23] = 'i'; 47 | kbdus[24] = 'o'; 48 | kbdus[25] = 'p'; 49 | kbdus[26] = '['; 50 | kbdus[27] = ']'; 51 | kbdus[28] = '\n'; /* Enter key */ 52 | kbdus[29] = 0; /* 29 - Control */ 53 | kbdus[30] = 'a'; 54 | kbdus[31] = 's'; 55 | kbdus[32] = 'd'; 56 | kbdus[33] = 'f'; 57 | kbdus[34] = 'g'; 58 | kbdus[35] = 'h'; 59 | kbdus[36] = 'j'; 60 | kbdus[37] = 'k'; 61 | kbdus[38] = 'l'; 62 | kbdus[39] = ';'; /* 39 */ 63 | kbdus[40] = '\''; 64 | kbdus[41] = '`'; 65 | kbdus[42] = 0; /* Left shift */ 66 | kbdus[43] = '\\'; 67 | kbdus[44] = 'z'; 68 | kbdus[45] = 'x'; 69 | kbdus[46] = 'c'; 70 | kbdus[47] = 'v'; 71 | kbdus[48] = 'b'; 72 | kbdus[49] = 'n'; /* 49 */ 73 | kbdus[50] = 'm'; 74 | kbdus[51] = ','; 75 | kbdus[52] = '.'; 76 | kbdus[53] = '/'; 77 | kbdus[54] = 0; /* Right shift */ 78 | kbdus[55] = '*'; 79 | kbdus[56] = 0; /* Alt */ 80 | kbdus[57] = ' '; /* Space bar */ 81 | kbdus[58] = 0; /* Caps lock */ 82 | kbdus[59] = 0; /* 59 - F1 key ... > */ 83 | kbdus[60] = 0; 84 | kbdus[61] = 0; 85 | kbdus[62] = 0; 86 | kbdus[63] = 0; 87 | kbdus[64] = 0; 88 | kbdus[65] = 0; 89 | kbdus[66] = 0; 90 | kbdus[67] = 0; 91 | kbdus[68] = 0; /* < ... F10 */ 92 | kbdus[69] = 0; /* 69 - Num lock*/ 93 | kbdus[70] = 0; /* Scroll Lock */ 94 | kbdus[71] = 0; /* Home key */ 95 | kbdus[72] = 0; /* Up Arrow */ 96 | kbdus[73] = 0; /* Page Up */ 97 | kbdus[74] = '-'; 98 | kbdus[75] = 0; /* Left Arrow */ 99 | kbdus[76] = 0; 100 | kbdus[77] = 0; /* Right Arrow */ 101 | kbdus[78] = '+'; 102 | kbdus[79] = 0; /* 79 - End key*/ 103 | kbdus[80] = 0; /* Down Arrow */ 104 | kbdus[81] = 0; /* Page Down */ 105 | kbdus[82] = 0; /* Insert Key */ 106 | kbdus[83] = 0; /* Delete Key */ 107 | kbdus[84] = 0; 108 | kbdus[85] = 0; 109 | kbdus[86] = 0; 110 | kbdus[87] = 0; /* F11 Key */ 111 | kbdus[88] = 0; /* F12 Key */ 112 | kbdus[89] = 0; /* All other keys are undefined */ 113 | 114 | irq_install_handler(1, keyboard_handler); 115 | } 116 | -------------------------------------------------------------------------------- /kernel/kernel.c: -------------------------------------------------------------------------------- 1 | #include "include/system.h" 2 | #include "include/drivers/screen.h" 3 | #include "include/system.h" 4 | 5 | void printi(){ 6 | print("OSxxxx\n"); 7 | print("kernel 0.1v\n"); 8 | } 9 | 10 | void main(){ 11 | screen_init(); // init vga driver 12 | clear_screen(); // clear the entire screen 13 | 14 | printi(); //print OS and kernel information 15 | 16 | //init IDT 17 | idt_install(); 18 | 19 | //init ISRs 20 | isrs_install(); 21 | 22 | //init IRQ 23 | irq_install(); 24 | __asm__ __volatile__ ("sti"); 25 | 26 | timer_install(); 27 | keyboard_install(); 28 | 29 | print("wait started.\n"); 30 | timer_wait(18*2); // 2 seconds wait 31 | print("wait ended.\n"); 32 | 33 | while(1); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /kernel/kernel_entry.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | [extern main] 4 | call main 5 | jmp $ 6 | 7 | ; Loads the IDT defined in '_idtp' into the processor. 8 | ; This is declared in C as 'extern void idt_load();' 9 | global idt_load 10 | extern idtp 11 | idt_load: 12 | lidt [idtp] 13 | ret 14 | 15 | ; Service Routines (ISRs) 16 | global isr0 17 | global isr1 18 | global isr2 19 | global isr3 20 | global isr4 21 | global isr5 22 | global isr6 23 | global isr7 24 | global isr8 25 | global isr9 26 | global isr10 27 | global isr11 28 | global isr12 29 | global isr13 30 | global isr14 31 | global isr15 32 | global isr16 33 | global isr17 34 | global isr18 35 | global isr19 36 | global isr20 37 | global isr21 38 | global isr22 39 | global isr23 40 | global isr24 41 | global isr25 42 | global isr26 43 | global isr27 44 | global isr28 45 | global isr29 46 | global isr30 47 | global isr31 48 | 49 | ; 0: Divide By Zero Exception 50 | isr0: 51 | cli 52 | push byte 0 ; A normal ISR stub that pops a dummy error code to keep a 53 | ; uniform stack frame 54 | push byte 0 55 | jmp isr_common_stub 56 | 57 | ; 1: Debug Exception 58 | isr1: 59 | cli 60 | push byte 0 61 | push byte 1 62 | jmp isr_common_stub 63 | 64 | isr2: 65 | cli 66 | push byte 0 67 | push byte 2 68 | jmp isr_common_stub 69 | 70 | isr3: 71 | cli 72 | push byte 0 73 | push byte 3 74 | jmp isr_common_stub 75 | 76 | isr4: 77 | cli 78 | push byte 0 79 | push byte 4 80 | jmp isr_common_stub 81 | 82 | isr5: 83 | cli 84 | push byte 0 85 | push byte 5 86 | jmp isr_common_stub 87 | 88 | isr6: 89 | cli 90 | push byte 0 91 | push byte 6 92 | jmp isr_common_stub 93 | 94 | isr7: 95 | cli 96 | push byte 0 97 | push byte 7 98 | jmp isr_common_stub 99 | 100 | ; 8: Double Fault Exception (With Error Code!) 101 | isr8: 102 | cli 103 | push byte 8 ; Note that we DON'T push a value on the stack in this one! 104 | ; It pushes one already! Use this type of stub for exceptions 105 | ; that pop error codes! 106 | jmp isr_common_stub 107 | 108 | isr9: 109 | cli 110 | push byte 0 111 | push byte 9 112 | jmp isr_common_stub 113 | 114 | isr10: 115 | cli 116 | push byte 10 117 | jmp isr_common_stub 118 | 119 | isr11: 120 | cli 121 | push byte 11 122 | jmp isr_common_stub 123 | 124 | isr12: 125 | cli 126 | push byte 12 127 | jmp isr_common_stub 128 | 129 | isr13: 130 | cli 131 | push byte 13 132 | jmp isr_common_stub 133 | 134 | isr14: 135 | cli 136 | push byte 14 137 | jmp isr_common_stub 138 | 139 | isr15: 140 | cli 141 | push byte 0 142 | push byte 15 143 | jmp isr_common_stub 144 | 145 | isr16: 146 | cli 147 | push byte 0 148 | push byte 16 149 | jmp isr_common_stub 150 | 151 | isr17: 152 | cli 153 | push byte 0 154 | push byte 17 155 | jmp isr_common_stub 156 | 157 | isr18: 158 | cli 159 | push byte 0 160 | push byte 18 161 | jmp isr_common_stub 162 | 163 | isr19: 164 | cli 165 | push byte 0 166 | push byte 19 167 | jmp isr_common_stub 168 | 169 | isr20: 170 | cli 171 | push byte 0 172 | push byte 20 173 | jmp isr_common_stub 174 | 175 | isr21: 176 | cli 177 | push byte 0 178 | push byte 21 179 | jmp isr_common_stub 180 | 181 | isr22: 182 | cli 183 | push byte 0 184 | push byte 22 185 | jmp isr_common_stub 186 | 187 | isr23: 188 | cli 189 | push byte 0 190 | push byte 23 191 | jmp isr_common_stub 192 | 193 | isr24: 194 | cli 195 | push byte 0 196 | push byte 24 197 | jmp isr_common_stub 198 | 199 | isr25: 200 | cli 201 | push byte 0 202 | push byte 25 203 | jmp isr_common_stub 204 | 205 | isr26: 206 | cli 207 | push byte 0 208 | push byte 26 209 | jmp isr_common_stub 210 | 211 | isr27: 212 | cli 213 | push byte 0 214 | push byte 27 215 | jmp isr_common_stub 216 | 217 | isr28: 218 | cli 219 | push byte 0 220 | push byte 28 221 | jmp isr_common_stub 222 | 223 | isr29: 224 | cli 225 | push byte 0 226 | push byte 29 227 | jmp isr_common_stub 228 | 229 | isr30: 230 | cli 231 | push byte 0 232 | push byte 30 233 | jmp isr_common_stub 234 | 235 | isr31: 236 | cli 237 | push byte 0 238 | push byte 31 239 | jmp isr_common_stub 240 | 241 | ; We call a C function in here. We need to let the assembler know 242 | ; that '_fault_handler' exists in another file 243 | extern fault_handler 244 | 245 | ; This is our common ISR stub. It saves the processor state, sets 246 | ; up for kernel mode segments, calls the C-level fault handler, 247 | ; and finally restores the stack frame. 248 | isr_common_stub: 249 | pusha 250 | push ds 251 | push es 252 | push fs 253 | push gs 254 | mov ax, 0x10 ; Load the Kernel Data Segment descriptor! 255 | mov ds, ax 256 | mov es, ax 257 | mov fs, ax 258 | mov gs, ax 259 | mov eax, esp ; Push us the stack 260 | push eax 261 | mov eax, fault_handler 262 | call eax ; A special call, preserves the 'eip' register 263 | pop eax 264 | pop gs 265 | pop fs 266 | pop es 267 | pop ds 268 | popa 269 | add esp, 8 ; Cleans up the pushed error code and pushed ISR number 270 | iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP! 271 | 272 | 273 | ; Interrupt Requests (IRQs) 274 | global irq0 275 | global irq1 276 | global irq2 277 | global irq3 278 | global irq4 279 | global irq5 280 | global irq6 281 | global irq7 282 | global irq8 283 | global irq9 284 | global irq10 285 | global irq11 286 | global irq12 287 | global irq13 288 | global irq14 289 | global irq15 290 | 291 | ; 32: IRQ0 292 | irq0: 293 | cli 294 | push byte 0 ; Note that these don't push an error code on the stack: 295 | ; We need to push a dummy error code 296 | push byte 32 297 | jmp irq_common_stub 298 | 299 | ; 33: IRQ1 300 | irq1: 301 | cli 302 | push byte 0 ; Note that these don't push an error code on the stack: 303 | ; We need to push a dummy error code 304 | push byte 33 305 | jmp irq_common_stub 306 | 307 | ; 34: IRQ2 308 | irq2: 309 | cli 310 | push byte 0 ; Note that these don't push an error code on the stack: 311 | ; We need to push a dummy error code 312 | push byte 34 313 | jmp irq_common_stub 314 | 315 | ; 35: IRQ3 316 | irq3: 317 | cli 318 | push byte 0 ; Note that these don't push an error code on the stack: 319 | ; We need to push a dummy error code 320 | push byte 35 321 | jmp irq_common_stub 322 | 323 | ; 36: IRQ4 324 | irq4: 325 | cli 326 | push byte 0 ; Note that these don't push an error code on the stack: 327 | ; We need to push a dummy error code 328 | push byte 36 329 | jmp irq_common_stub 330 | 331 | ; 37: IRQ5 332 | irq5: 333 | cli 334 | push byte 0 ; Note that these don't push an error code on the stack: 335 | ; We need to push a dummy error code 336 | push byte 37 337 | jmp irq_common_stub 338 | 339 | ; 38: IRQ6 340 | irq6: 341 | cli 342 | push byte 0 ; Note that these don't push an error code on the stack: 343 | ; We need to push a dummy error code 344 | push byte 38 345 | jmp irq_common_stub 346 | 347 | ; 39: IRQ7 348 | irq7: 349 | cli 350 | push byte 0 ; Note that these don't push an error code on the stack: 351 | ; We need to push a dummy error code 352 | push byte 39 353 | jmp irq_common_stub 354 | 355 | ; 40: IRQ8 356 | irq8: 357 | cli 358 | push byte 0 ; Note that these don't push an error code on the stack: 359 | ; We need to push a dummy error code 360 | push byte 40 361 | jmp irq_common_stub 362 | 363 | ; 41: IRQ9 364 | irq9: 365 | cli 366 | push byte 0 ; Note that these don't push an error code on the stack: 367 | ; We need to push a dummy error code 368 | push byte 41 369 | jmp irq_common_stub 370 | 371 | ; 42: IRQ10 372 | irq10: 373 | cli 374 | push byte 0 ; Note that these don't push an error code on the stack: 375 | ; We need to push a dummy error code 376 | push byte 42 377 | jmp irq_common_stub 378 | 379 | ; 43: IRQ11 380 | irq11: 381 | cli 382 | push byte 0 ; Note that these don't push an error code on the stack: 383 | ; We need to push a dummy error code 384 | push byte 43 385 | jmp irq_common_stub 386 | 387 | ; 44: IRQ12 388 | irq12: 389 | cli 390 | push byte 0 ; Note that these don't push an error code on the stack: 391 | ; We need to push a dummy error code 392 | push byte 44 393 | jmp irq_common_stub 394 | 395 | ; 45: IRQ13 396 | irq13: 397 | cli 398 | push byte 0 ; Note that these don't push an error code on the stack: 399 | ; We need to push a dummy error code 400 | push byte 45 401 | jmp irq_common_stub 402 | 403 | ; 46: IRQ14 404 | irq14: 405 | cli 406 | push byte 0 ; Note that these don't push an error code on the stack: 407 | ; We need to push a dummy error code 408 | push byte 46 409 | jmp irq_common_stub 410 | 411 | ; 47: IRQ15 412 | irq15: 413 | cli 414 | push byte 0 415 | push byte 47 416 | jmp irq_common_stub 417 | 418 | extern irq_handler 419 | 420 | irq_common_stub: 421 | pusha 422 | push ds 423 | push es 424 | push fs 425 | push gs 426 | mov ax, 0x10 427 | mov ds, ax 428 | mov es, ax 429 | mov fs, ax 430 | mov gs, ax 431 | mov eax, esp 432 | push eax 433 | mov eax, irq_handler 434 | call eax 435 | pop eax 436 | pop gs 437 | pop fs 438 | pop es 439 | pop ds 440 | popa 441 | add esp, 8 442 | iret 443 | -------------------------------------------------------------------------------- /kernel/low_level.c: -------------------------------------------------------------------------------- 1 | #include "include/low_level.h" 2 | 3 | unsigned char port_byte_in(unsigned short port) { 4 | unsigned char result; 5 | __asm__("in %%dx, %%al" : "=a" (result) : "d" (port)); 6 | return result; 7 | } 8 | 9 | void port_byte_out(unsigned short port , unsigned char data) { 10 | __asm__("out %%al, %%dx" : :"a" (data) , "d" (port)); 11 | } 12 | 13 | unsigned short port_word_in(unsigned short port) { 14 | unsigned short result ; 15 | __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port)); 16 | return result ; 17 | } 18 | 19 | void port_word_out(unsigned short port , unsigned short data) { 20 | __asm__("out %%ax, %%dx " : :"a" (data) , "d" (port)); 21 | } 22 | 23 | unsigned char *memset(unsigned char *dest, unsigned char val, int count){ 24 | int i; 25 | for(i = 0; i < count; i++){ 26 | *(dest + i) = val; 27 | } 28 | return dest; 29 | } 30 | -------------------------------------------------------------------------------- /kernel/timer.c: -------------------------------------------------------------------------------- 1 | #include "include/drivers/screen.h" 2 | #include "include/system.h" 3 | 4 | int timer_ticks = 0; 5 | 6 | void timer_handler(struct regs *r) { 7 | 8 | /* Increment our 'tick count' */ 9 | timer_ticks++; 10 | 11 | /* Every 18 clocks (approximately 1 second), we will 12 | * display a message on the screen */ 13 | if (timer_ticks % 18 == 0) { 14 | print("One second has passed\n"); 15 | } 16 | } 17 | 18 | void timer_wait(int ticks) { 19 | unsigned long eticks; 20 | 21 | eticks = timer_ticks + ticks; 22 | while (timer_ticks < eticks) 23 | ; 24 | } 25 | 26 | void timer_install() { 27 | timer_ticks = 0; 28 | irq_install_handler(0, timer_handler); 29 | } 30 | --------------------------------------------------------------------------------