diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 33 | ||||
-rw-r--r-- | boot.asm | 41 | ||||
-rw-r--r-- | constants.asm | 25 | ||||
-rw-r--r-- | io.asm | 25 | ||||
-rw-r--r-- | irq.asm | 248 | ||||
-rw-r--r-- | kernel.asm | 305 | ||||
-rw-r--r-- | link.ld | 9 |
8 files changed, 688 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c4ced56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +kernel diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8bb5127 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +nasm=nasm -f elf -g +TARGET=kernel + +all: $(TARGET) + +boot.o: boot.asm + $(nasm) -o boot.o boot.asm + +io.o: io.asm + $(nasm) -o io.o io.asm + +irq.o: irq.asm + $(nasm) -o irq.o irq.asm + +kernel.o: kernel.asm + $(nasm) -o kernel.o kernel.asm + +$(TARGET): irq.o io.o kernel.o boot.o + ld -g -m elf_i386 -T link.ld -o $(TARGET) boot.o io.o irq.o kernel.o + +run: $(TARGET) + qemu-system-i386 -m 2M -kernel $(TARGET) + +debug: $(TARGET) + qemu-system-i386 -d int,guest_errors -no-reboot -s -S -m 8M -kernel $(TARGET) & + gdb -ex 'kdev' \ + -ex 'continue' \ + $(TARGET) + +clean: + rm -f kernel + rm *.o + diff --git a/boot.asm b/boot.asm new file mode 100644 index 0000000..66009e8 --- /dev/null +++ b/boot.asm @@ -0,0 +1,41 @@ +bits 32 + +section .text + align 4 + dd 0x1BADB002 + dd 0x00 + dd - (0x1BADB002 + 0x00) + +global start +extern kmain + +start: + cli + mov esp, stack_top + call marker_begin + call kmain + call marker_done +.hltloop: + hlt +jmp .hltloop + +marker_begin: + mov word [VIDEO_RAM + CONSOLE_SIZE - 2], \ + 0x4F << 8 | 'B' ; END OF MAIN MARKER + ret + +marker_done: + mov word [VIDEO_RAM + CONSOLE_SIZE - 2], \ + 0x4F << 8 | 'H' ; END OF MAIN MARKER + ret + +section .data + +%include 'constants.asm' + +section .bss +align 4 +stack_bottom: + resb 8192 +stack_top: +EOK: diff --git a/constants.asm b/constants.asm new file mode 100644 index 0000000..d509f7d --- /dev/null +++ b/constants.asm @@ -0,0 +1,25 @@ +; Interrupt Controller +PIC1 equ 0x20 ; IO base address for master PIC +PIC2 equ 0xA0 ; IO base address for slave PIC +PIC1_COMMAND equ PIC1 +PIC1_DATA equ (PIC1+1) +PIC2_COMMAND equ PIC2 +PIC2_DATA equ (PIC2+1) + +ICW1_ICW4 equ 0x01 ; ICW4 (not) needed +ICW1_SINGLE equ 0x02 ; Single (cascade) mode +ICW1_INTERVAL4 equ 0x04 ; Call address interval 4 (8) +ICW1_LEVEL equ 0x08 ; Level triggered (edge) mode +ICW1_INIT equ 0x10 ; Initialization - required! + +ICW4_8086 equ 0x01 ; 8086/88 (MCS-80/85) mode +ICW4_AUTO equ 0x02 ; Auto (normal) EOI +ICW4_BUF_SLAVE equ 0x08 ; Buffered mode/slave +ICW4_BUF_MASTER equ 0x0C ; Buffered mode/master +ICW4_SFNM equ 0x10 ; Special fully nested (not) + +; Video +CONSOLE_W equ 80 +CONSOLE_H equ 25 +CONSOLE_SIZE equ CONSOLE_W * CONSOLE_H * 2 +VIDEO_RAM equ 0xb8000 @@ -0,0 +1,25 @@ +section .text + +global pio_read +global pio_write + +pio_read: + push ebp + mov ebp, esp + + mov edx, [esp + 8] + in al, dx + + leave + ret + +pio_write: + push ebp + mov ebp, esp + + mov edx, [esp + 8] + mov al, [esp + 12] + out dx, al + + leave + ret @@ -0,0 +1,248 @@ +section .text +global idt_entry +global PIC_sendEOI +global idt_init +extern interrupt_handler + +extern pio_read +extern pio_write + +struc idt_entry + .base_low: resw 1 + .selector: resw 1 + .zero: resb 1 + .flags: resb 1 + .base_high: resw 1 +endstruc + +%macro no_error_code_interrupt_handler 1 +global interrupt_handler_%1: +interrupt_handler_%1: + push dword 0 + push dword %1 + jmp common_interrupt_handler +%endmacro + +%macro error_code_interrupt_handler 1 +global interrupt_handler_%1 +interrupt_handler_%1: + push dword %1 + jmp common_interrupt_handler +%endmacro + +%macro idt_set_gate 2 + ; Assign values to IDT entry at interrupt (ecx) + ; with the offset of the interrupt handler (edx) + mov edx, %2 + mov [idt + %1 * 8 + idt_entry.base_low], dx + mov word [idt + %1 * 8 + idt_entry.selector], 0x8 + mov byte [idt + %1 * 8 + idt_entry.zero], 0x0 + mov byte [idt + %1 * 8 + idt_entry.flags], 0x8e + shr edx, 16 + mov word [idt + %1 * 8 + idt_entry.base_high], dx +%endmacro + +common_interrupt_handler: + pushad + call interrupt_handler + popad + add esp, 8 + iret + +no_error_code_interrupt_handler 0 +no_error_code_interrupt_handler 1 +no_error_code_interrupt_handler 2 +no_error_code_interrupt_handler 3 +no_error_code_interrupt_handler 4 +no_error_code_interrupt_handler 5 +no_error_code_interrupt_handler 6 +no_error_code_interrupt_handler 7 +error_code_interrupt_handler 8 +no_error_code_interrupt_handler 9 +error_code_interrupt_handler 10 +error_code_interrupt_handler 11 +error_code_interrupt_handler 12 +error_code_interrupt_handler 13 +error_code_interrupt_handler 14 +no_error_code_interrupt_handler 15 +no_error_code_interrupt_handler 16 +no_error_code_interrupt_handler 17 +no_error_code_interrupt_handler 18 +no_error_code_interrupt_handler 19 +no_error_code_interrupt_handler 20 +no_error_code_interrupt_handler 21 +no_error_code_interrupt_handler 22 +no_error_code_interrupt_handler 23 +no_error_code_interrupt_handler 24 +no_error_code_interrupt_handler 25 +no_error_code_interrupt_handler 26 +no_error_code_interrupt_handler 27 +no_error_code_interrupt_handler 28 +no_error_code_interrupt_handler 29 +no_error_code_interrupt_handler 30 +no_error_code_interrupt_handler 31 +; 32 unused +no_error_code_interrupt_handler 33 + + +;interrupt_handler: +; cmp byte [esp + 4], 0x21 +; je .int21 +; +; jmp .end +; +;.int21: +; mov dword [0xB8000], ': ) ' +; push m +; call kprint +; +;.end: +; ret + +PIC_sendEOI: + ret + +PIC_remap: + ;arguments: + ;offset1 - vector offset for master PIC + ; vectors on the master become offset1..offset1+7 + ;offset2 - same for slave PIC: offset2..offset2+7 + + push ebp + mov ebp, esp + + sub ebp, 8 + + push PIC1_DATA + call pio_read + mov [ebp - 4], al ; save PIC1 mask + + push PIC2_DATA + call pio_read + mov [ebp - 8], al ; save PIC2 mask + + push PIC1_COMMAND + push ICW1_INIT+ICW1_ICW4 ; initialization sequence (cascade) + call pio_write + + push PIC2_COMMAND + push ICW1_INIT+ICW1_ICW4 ; initialization sequence (cascade) + call pio_write + + push PIC1_DATA + push word [ebp + 8] ; ICW2: Master PIC vector offset + call pio_write + + push PIC2_DATA + push word [ebp + 12] ; ICW2: Save PIC vector offset + call pio_write + + push PIC1_DATA + push 0x4 ; ICW3: tell Master PIC there is a slave PIC at IRQ2 (0000 0100) + call pio_write + + push PIC2_DATA + push 2 ; ICW3: tell Slave PIC its cacade identity (0000 0010) + call pio_write + + push PIC1_DATA + push ICW4_8086 + call pio_write + + push PIC2_DATA + push ICW4_8086 + call pio_write + + + ;; ICW3 + ;push PIC1_DATA + ;push 0x20 + ;call pio_write + + ;push PIC2_DATA + ;push 0x28 + ;call pio_write + + ;; ICW4 + ;push PIC1_DATA + ;push 0x00 + ;call pio_write + + ;push PIC2_DATA + ;push 0x01 + ;call pio_write + + ;; mask interrupts + ;push PIC1_DATA + ;push 0xff + ;call pio_write + + ;push PIC2_DATA + ;push 0xff + ;call pio_write + + push PIC1_DATA + push word [ebp - 4] + call pio_write + + push PIC2_DATA + push word [ebp - 8] + call pio_write + + add ebp, 8 + leave + ret + + +idt_init: + push ebp + mov ebp, esp + + mov al, 0x0 ; idt's initial value + mov ecx, idt_entry_size * 256 - 1 ; Size of: idt + mov edi, idt ; pointer to: idt + cld ; clear direction flag + rep stosb ; fill array with zeros + + + idt_set_gate 33, interrupt_handler_33 ; implement INT 21 + + mov ebx, idt_entry_size * 256 - 1 ; size of: idt - 1 + mov eax, idt ; pointer to: idt + + mov [idt_ptr], ebx ; describe ITDR limit + mov [idt_ptr + 2], eax ; describe ITDR offset + + push idt_ptr + call idt_load ; load IDTR register + + leave + ret + + + +idt_load: + push ebp + mov ebp, esp + + mov edx, [esp + 8] + lidt [edx] + + leave + ret + + +section .data +%include 'constants.asm' + +section .bss +align 4 + +idt_ptr: + resw 1 + resd 1 + +idt: + resb idt_entry_size * 256 + + diff --git a/kernel.asm b/kernel.asm new file mode 100644 index 0000000..490273c --- /dev/null +++ b/kernel.asm @@ -0,0 +1,305 @@ +section .text +align 4 +global kmain +global interrupt_handler +extern idt_init +extern pio_read +extern pio_write + +interrupt_handler: + mov ebx, [esp + 34] + shr ebx, 16 + cmp ebx, 0x21 + je .int21 + + jmp .end + +.int21: + + cmp ah, 0x1 + je .int21.kprint + jmp .end + +.int21.kprint: + ;sub esp, 4 + ;mov [esp - 4], bx + + ;shr bx, 8 + ;push word bx + + ;mov bx, [esp - 4] + ;and bx, 0xff + ;push bx + + ;call screen_gotoxy + ;add esp, 8 + + push edx + call kprint + add esp, 4 + +.end: + ret + +cursor_move: + push ebp + mov ebp, esp + + sub ebp, 4 + call screen_getxy + mov [ebp - 4], eax + + push 0x3D4 + push 14 + call pio_write + + mov ebx, [ebp + 4] + shr ebx, 8 + push 0x3D5 + push word [ebx] + call pio_write + + push 0x3D4 + push 15 + call pio_write + + mov ebx, [ebp + 4] + push 0x3D5 + push word [ebx] + call pio_write + + add ebp, 4 + leave + ret + +screen_fill: + ; = purpose + ; Fills the screen with a character and color + ; + ; = stack arguments (order of use) + ; push ' ' ; character + ; push 0x07 ; color attribute + + push ebp + mov ebp, esp + + xor eax, eax ; clear eax + mov eax, [ebp + 8] ; get character + shl eax, 8 ; shift character into MSB + or eax, [ebp + 12] ; set color attribute + + mov ecx, CONSOLE_SIZE ; use entire screen + mov edi, screen_buffer ; destination = screen_buffer + cld ; will increment esi and edi + rep stosw ; char+color -> screen_buffer + + mov esp, ebp + pop ebp + + ret + +screen_refresh: + push ebp + mov ebp, esp + pusha + + mov ecx, CONSOLE_SIZE ; use entire screen + mov esi, screen_buffer ; source = screen_buffer + mov edi, VIDEO_RAM ; destination = video RAM + cld ; will increment esi and edi + rep movsw ; char+color -> screen_buffer + + popa + mov esp, ebp + pop ebp + ret + +screen_gotoxy: + push ebp + mov ebp, esp + pusha + + ; y * width + x + mov ebx, CONSOLE_W * 2 + mov eax, [ebp + 12] + mul ebx + add eax, [ebp + 8] + mov [screen_pos], eax + + popa + leave + ret + +screen_getxy: + push ebp + mov ebp, esp + + mov eax, [screen_pos] + + leave + ret + +screen_updatexy: + push ebp + mov ebp, esp + + add word [screen_pos], 2 + + cmp word [screen_pos], CONSOLE_SIZE + call screen_scroll_up + + leave + ret + +screen_scroll_up: + push ebp + mov ebp, esp + + nop + + leave + ret + +screen_scroll_down: + push ebp + mov ebp, esp + + nop + + leave + ret + + +kprint: + ; = purpose + ; Writes a buffer to the screen + ; + ; = globals + ; kprint_delay: if != 0; echo slowly + ; + ; = stack arguments (order of use) + ; push buffer + + push ebp + mov ebp, esp + + xor ebx, ebx + xor esi, esi + xor edi, edi + + mov esi, [ebp + 8] ; source buffer + mov edi, screen_buffer ; output to screen buffer + mov ebx, [screen_pos] ; get current screen position + add edi, ebx ; move to current screen position + mov ecx, 0xff ; delay counter + +.write: + + cmp byte [kprint_delay], 0 ; determine if we want a delay + je .nodelay ; if kprint_nodelay == 0: + ; nodelay() + ; else: + ; delay() + +.delay: + dec ecx ; while ecx != 0: ecx-- + call screen_refresh + jne .delay + +.nodelay: + mov ebx, [esi] ; get value from source buffer + mov [edi], bl ; write value to screen buffer + inc esi ; next char in source buffer + add edi, 2 ; skip over screen attribute byte + call screen_updatexy ; update screen_pos + + cmp bl, 0 ; if ch != 0: write + jne .write + + call screen_refresh ; dump screen buffer to video ram + + leave + ret + +kputc: + push ebp + mov ebp, esp + + mov esi, [screen_pos] + mov edi, screen_buffer + add edi, esi + + mov [edi], dl + call screen_updatexy + call screen_refresh + + leave + ret + +kprintnl: + push ebp + mov ebp, esp + + nop + + leave + ret + +kmain: + push ebp + mov ebp, esp + + mov byte [screen_pos], 2 ; Initialize screen position + ;call cursor_move + + call idt_init + + ; Fill screen with + push ' ' ; spaces && + push 0x07 ; white forground on blue background + call screen_fill ; fill the screen buffer + call screen_refresh ; dump screen buffer to video ram + + ;push 12 + ;push 30 + ;call screen_gotoxy + + ;mov byte [kprint_delay], 1 ; tell kprint to delay writes + push message ; push message address as argument + call kprint ; print message + + call kprintnl + + mov dl, 'A' + call kputc + + mov word [VIDEO_RAM + CONSOLE_SIZE - 6], \ + 0x4F << 8 | 'I' ; END OF MAIN MARKER + ;mov ah, 1 + ;mov bh, 2 + ;mov bl, 2 + ;mov edx, message2 + ;int 21h ; here goes nothing + + mov word [VIDEO_RAM + CONSOLE_SIZE - 6], \ + 0x2F << 8 | 'I' ; END OF MAIN MARKER + + mov word [VIDEO_RAM + CONSOLE_SIZE - 4], \ + 0x2F << 8 | 'K' ; END OF MAIN MARKER + + mov esp, ebp + pop ebp + ret + +section .data +%include 'constants.asm' + +message: db 'Kernel programming is fun!', 0 +message2: db 'This is a test.', 0 + +section .bss +kprint_delay: resb 1 +screen_pos: resd 1 +screen_buffer: resb CONSOLE_SIZE +screen_buffer_end: + @@ -0,0 +1,9 @@ +OUTPUT_FORMAT(elf32-i386) +ENTRY(start) +SECTIONS + { + . = 0x100000; + .text : { *(.text) } + .data : { *(.data) } + .bss : { *(.bss) } + } |