commit 4700f983f83818d35203201ff4433e06c0ada272 Author: Nicolás Ortega Froysa Date: Fri Feb 23 17:20:31 2018 +0100 Adding code so far. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8092403 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bin/* +*.bin +*.o diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..71806a0 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +ASM=nasm +AFLAGS=-f bin +BIN=bin +CFLAGS=-ffreestanding -fno-pie -m32 +CC=gcc +LD=ld +LDFLAGS=-melf_i386 -Ttext 0x1000 --oformat binary + +basicos: + mkdir -p $(BIN) + $(ASM) boot_sect.asm $(AFLAGS) -o boot_sect.bin + $(CC) $(CFLAGS) -c kernel.c -o kernel.o + $(LD) $(LDFLAGS) -o kernel.bin kernel.o + cat boot_sect.bin kernel.bin > $(BIN)/os-image + + +.PHONY: clean + +clean: + rm *.bin *.o diff --git a/boot_sect.asm b/boot_sect.asm new file mode 100644 index 0000000..3ec1862 --- /dev/null +++ b/boot_sect.asm @@ -0,0 +1,55 @@ +[org 0x7c00] +KERNEL_OFFSET: equ 0x1000 ; kernel memory offset + mov [BOOT_DRIVE], dl ; store boot drive for later. + mov bp, 0x9000 ; setup the stack + mov sp, bp + + mov bx, MSG_REAL_MODE + call print_string + + call load_kernel ; load our kernel from memory + call switch_to_pm ; switch to 32-bit protected mode + + jmp $ + +%include "print.asm" +%include "print32.asm" +%include "disk.asm" +%include "gdt.asm" +%include "switch_prot.asm" + +[bits 16] + +load_kernel: + mov bx, MSG_LOAD_KERNEL + call print_string + + mov bx, KERNEL_OFFSET ; address to load the kernel to + mov dh, 15 ; number of sectors to load + mov dl, [BOOT_DRIVE] ; drive to load from + call disk_load + + mov bx, MSG_KERNEL_LOADED + call print_string + + ret + +[bits 32] +BEGIN_PM: + mov ebx, MSG_PROT_MODE + call print_string_pm + + call KERNEL_OFFSET + + jmp $ + +;;; +; Data +BOOT_DRIVE: db 0 +MSG_REAL_MODE: db "Started in 16-bit Real Mode",0 +MSG_PROT_MODE: db "Successfully landed in 32-bit Protected Mode",0 +MSG_LOAD_KERNEL: db "Loading kernel into memory...",0 +MSG_KERNEL_LOADED: db "Successfully loaded kernel into memory",0 + +times 510-($-$$) db 0 +dw 0xaa55 diff --git a/disk.asm b/disk.asm new file mode 100644 index 0000000..698646c --- /dev/null +++ b/disk.asm @@ -0,0 +1,43 @@ +;;; +; disk_load +; --------- +; Load disk sectors into memory. +; +; Parameters: +; - dh: number of sectors to read +disk_load: + pusha + push dx ; store `dx' to check if the appropriate number of + ; sectors were read later on. + mov ah, 0x02 ; BIOS read routine + mov al, dh ; read `dh' sectors + mov ch, 0x00 ; select cylinder 0 + mov dh, 0x00 ; select head 0 + mov cl, 0x02 ; start reading from second sector (after the boot + ; sector) + + int 0x13 ; BIOS interrupt + + jc disk_load_error ; if `cf' flag has gone off then a read error has + ; occurred + + pop dx ; restore `dx' + cmp dh, al ; were the appropriate amount of sectors read? + jne disk_load_unexp ; if not then there was an error + popa + ret + +disk_load_error: + mov bx, DISK_READ_ERROR ; print the error + jmp disk_load_print_exit +disk_load_unexp: + mov bx, DISK_READ_UNEXP +disk_load_print_exit: + call print_string + jmp $ ; lock due to failure + +DISK_READ_UNEXP: + db "Unexpected amount of sectors read!",0 + +DISK_READ_ERROR: + db "Disk read error!",0 diff --git a/gdt.asm b/gdt.asm new file mode 100644 index 0000000..32193e0 --- /dev/null +++ b/gdt.asm @@ -0,0 +1,37 @@ +; GDT +gdt_start: + +gdt_null: + dd 0x0 ; the mandatory null-descriptor + dd 0x0 + +gdt_code: ; code segment of descriptor + dw 0xFFFF ; Limit (bits 0-15) + dw 0x0 ; Base (bits 0-15) + db 0x0 ; Base (bits 16-23 + ; 1st flags: (present)1, (privilege)00, (descriptor type)1 -> 1001b + ; type flags: (code)1, (conforming)0, (readable)1, (accessed)0 -> 1010b + ; 2nd flags: (granularity)1, (32-bit default)1, (64-bit seg)0, (AVL)0 -> 1100b + db 10011010b ; 1st flags and type flags + db 11001111b ; 2nd flags and Limit (bits 16-19) + db 0x0 ; Base (bits 24-31) + +gdt_data: + ; type flags: (code)0, (expand down)0, (writable)1, (accessed)0 -> 0010b + dw 0xFFFF ; Limit (bits 0-15) + dw 0x0 ; Base (bits 0-15) + db 0x0 ; Base (bits 16-23) + db 10010010b ; 1st flags and type flags + db 11001111b ; 2nd flags and Limit (bits 16-19) + db 0x0 ; Base (bits 24-31) + +gdt_end: ; for calculating size of the gdt + +gdt_descriptor: + dw gdt_end - gdt_start - 1 ; size of our GDT, always decrement true size by one + dd gdt_start ; start address of our GDT + +;;; +; Constants used for GDT segment offsets +GDT_CODE_SEG: equ gdt_code - gdt_start +GDT_DATA_SEG: equ gdt_data - gdt_start diff --git a/kernel.c b/kernel.c new file mode 100644 index 0000000..0592e41 --- /dev/null +++ b/kernel.c @@ -0,0 +1,10 @@ +void main() { + /* + * point to first text cell of the video memory + */ + char *video_memory = (char*) 0xb8000; + /* + * store the character 'X' there + */ + *video_memory = 'X'; +} diff --git a/print.asm b/print.asm new file mode 100644 index 0000000..60cf444 --- /dev/null +++ b/print.asm @@ -0,0 +1,27 @@ +;;; +; print_string +; ------------ +; Print a string from memory. +; +; Parameters: +; - bx: pointer to string +; +; Internal Variables: +; - ah: scrolling teletype BIOS routine code +; - al: Byte containing character to print +; - bx: shifting pointer to string +print_string: + pusha ; save the state of all registers to the stack + + mov ah, 0x0e ; scrolling teletype BIOS routine code +print_string_start: + mov al, [bx] ; load first letter into `al' + cmp al, 0 + je print_string_end ; if null-termination then return + int 0x10 ; print the letter + add bx, 0x1 ; offset to next character + jmp print_string_start ; go back to beginning + +print_string_end: + popa ; return the state of all the registers + ret diff --git a/print32.asm b/print32.asm new file mode 100644 index 0000000..e1c38bf --- /dev/null +++ b/print32.asm @@ -0,0 +1,30 @@ +[bits 32] +VIDEO_MEMORY: equ 0xB8000 +WHITE_ON_BLACK: equ 0x0F + +;;; +; print_string_pm +; ------------ +; Print a string stored in memory. +; +; Parameters: +; - ebx: pointer to string in memory +print_string_pm: + pusha + mov edx, VIDEO_MEMORY ; set `edx' to the start of the video memory + +print_string_pm_loop: + mov al, [ebx] ; store the char at `ebx' in `al' + mov ah, WHITE_ON_BLACK ; store the attributes in `ah' + cmp al, 0 ; if null-termination then done + je print_string_pm_done + + mov [edx], ax ; store char and attributes + add ebx, 1 ; increment ebx to next char + add edx, 2 ; increment to next char cell in vidmem + + jmp print_string_pm_loop + +print_string_pm_done: + popa + ret diff --git a/switch_prot.asm b/switch_prot.asm new file mode 100644 index 0000000..48e099e --- /dev/null +++ b/switch_prot.asm @@ -0,0 +1,29 @@ +[bits 16] +switch_to_pm: + cli ; turn off all interrupts until we have properly + ; properly set them up + + lgdt [gdt_descriptor] ; load the global descriptor table defining + ; protected mode segments + + mov eax, cr0 ; set flag in register to switch to protected mode + or eax, 0x1 + mov cr0, eax + + jmp GDT_CODE_SEG:init_pm ; make a far jump to the 32-bit code forcing a flush + ; of the pipelining + +[bits 32] +; initialize registers and the stack once in protected mode +init_pm: + mov ax, GDT_DATA_SEG ; point our new segment registers to the data + mov ds, ax ; selector defined in the GDT, since we cannot + mov ss, ax ; use the old 16-bit code + mov es, ax + mov fs, ax + mov gs, ax + + mov ebp, 0x90000 ; Update the stack position so it's at the top + mov esp, ebp ; of the free space + + call BEGIN_PM