Browse Source

lesson 14

Carlos Fenollosa 10 years ago
parent
commit
d5d1a88cae

+ 43 - 0
14-checkpoint/Makefile

@@ -0,0 +1,43 @@
+C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
+HEADERS = $(wildcard kernel/*.h drivers/*.h)
+OBJ = ${C_SOURCES:.c=.o}
+
+# Change this if your cross-compiler is somewhere else
+CC = /usr/local/i386elfgcc/bin/i386-elf-gcc
+GDB = /usr/local/i386elfgcc/bin/i386-elf-gdb
+# -g: Use debugging symbols
+CFLAGS = -g
+
+# First rule is run by default
+os-image.bin: boot/bootsect.bin kernel.bin
+	cat $^ > os-image.bin
+
+kernel.bin: kernel.elf
+	i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
+
+run: os-image.bin
+	qemu-system-i386 -fda os-image.bin
+
+debug: os-image.bin kernel.elf
+	qemu-system-i386 -s -fda os-image.bin &
+	${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"
+
+# To build the kernel: make all objects first
+kernel.elf: boot/kernel_entry.o ${OBJ}
+	i386-elf-ld -o $@ -Ttext 0x1000 $^ 
+
+# To make an object, always compile from its .c
+%.o: %.c ${HEADERS}
+	${CC} ${CFLAGS} -ffreestanding -c $< -o $@
+
+# Object files from asm files
+%.o: %.asm
+	nasm $< -f elf -o $@
+
+%.bin: %.asm
+	nasm $< -f bin -o $@
+
+
+clean:
+	rm -rf *.bin *.dis *.o os-image.bin *.elf
+	rm -rf kernel/*.o boot/*.bin drivers/*.o

+ 34 - 1
14-checkpoint/README.md

@@ -1,4 +1,4 @@
-*Concepts you may want to Google beforehand: monolithic kernel, microkernel*
+*Concepts you may want to Google beforehand: monolithic kernel, microkernel, debugger, gdb*
 
 
 **Goal: Pause and organize our code a little bit**
 **Goal: Pause and organize our code a little bit**
 
 
@@ -13,6 +13,39 @@ Take a look at the new folder structure. Most of the files have been symlinked
 from previous lessons, so if we have to change them at some point, it will be
 from previous lessons, so if we have to change them at some point, it will be
 a better idea to remove the symlink and create a new file.
 a better idea to remove the symlink and create a new file.
 
 
+Furthermore, since from now on we will use mostly C to code, we'll take advantage of qemu's
+ability to open a connection to gdb. First, let's install a cross-compiled `gdb` since
+OSX uses `lldb` which is not compatible with the ELF file format (neither is the `gdb` available
+on Homebrew's repos)
+
+```sh
+cd /tmp/src
+curl -O http://ftp.rediris.es/mirror/GNU/gnu/gdb/gdb-7.8.tar.gz
+tar xf gdb-7.8.tar.gz
+mkdir gdb-build
+cd gdb-build
+export PREFIX="/usr/local/i386elfgcc"
+export TARGET=i386-elf
+../gdb-7.8/configure --target="$TARGET" --prefix="$PREFIX" --program-prefix=i386-elf-
+make
+make install
+```
+
+Check out the Makefile target `make debug`. We can take
+advantage of this cool qemu feature. Type `make debug` and, on the gdb shell:
+
+- Set up a breakpoint in `kernel.c:main()`: `b main`
+- Run the OS: `continue`
+- Run two steps into the code: `next` then `next`. You will see that we are just about to set
+  the 'X' on the screen, but it isn't there yet (chech out the qemu screen)
+- Let's see what's in the video memory: `print *video_memory`. There is the 'L' from "Landed in
+  32-bit Protected Mode"
+- Hmmm, let's make sure that `video_memory` points to the correct address: `print video_memory`
+- `next` to put there our 'X'
+- Let's make sure: `print *video_memory` and look at the qemu screen. It's definitely there.
+
+Now is a good time to read some tutorial on `gdb`!
+
 
 
 Strategy
 Strategy
 --------
 --------

+ 1 - 0
14-checkpoint/boot/32bit_print.asm

@@ -0,0 +1 @@
+../../08-32bit-print/32bit-print.asm

+ 51 - 0
14-checkpoint/boot/bootsect.asm

@@ -0,0 +1,51 @@
+; Identical to lesson 13's boot sector, but the %included files have new paths
+[org 0x7c00]
+KERNEL_OFFSET equ 0x1000 ; The same one we used when linking the kernel
+
+    mov [BOOT_DRIVE], dl ; Remember that the BIOS sets us the boot drive in 'dl' on boot
+    mov bp, 0x9000
+    mov sp, bp
+
+    mov bx, MSG_REAL_MODE 
+    call print
+    call print_nl
+
+    call load_kernel ; read the kernel from disk
+    call switch_to_pm ; disable interrupts, load GDT,  etc. Finally jumps to 'BEGIN_PM'
+    jmp $ ; Never executed
+
+%include "boot/print.asm"
+%include "boot/print_hex.asm"
+%include "boot/disk.asm"
+%include "boot/gdt.asm"
+%include "boot/32bit_print.asm"
+%include "boot/switch_pm.asm"
+
+[bits 16]
+load_kernel:
+    mov bx, MSG_LOAD_KERNEL
+    call print
+    call print_nl
+
+    mov bx, KERNEL_OFFSET ; Read from disk and store in 0x1000
+    mov dh, 2
+    mov dl, [BOOT_DRIVE]
+    call disk_load
+    ret
+
+[bits 32]
+BEGIN_PM:
+    mov ebx, MSG_PROT_MODE
+    call print_string_pm
+    call KERNEL_OFFSET ; Give control to the kernel
+    jmp $ ; Stay here when the kernel returns control to us (if ever)
+
+
+BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
+MSG_REAL_MODE db "Started in 16-bit Real Mode", 0
+MSG_PROT_MODE db "Landed in 32-bit Protected Mode", 0
+MSG_LOAD_KERNEL db "Loading kernel into memory", 0
+
+; padding
+times 510 - ($-$$) db 0
+dw 0xaa55

BIN
14-checkpoint/boot/bootsect.bin


+ 1 - 0
14-checkpoint/boot/disk.asm

@@ -0,0 +1 @@
+../../07-bootsector-disk/boot_sect_disk.asm

+ 1 - 0
14-checkpoint/boot/gdt.asm

@@ -0,0 +1 @@
+../../09-32bit-gdt/32bit-gdt.asm

+ 1 - 0
14-checkpoint/boot/kernel_entry.asm

@@ -0,0 +1 @@
+../../13-kernel-barebones/kernel_entry.asm

BIN
14-checkpoint/boot/kernel_entry.o


+ 1 - 0
14-checkpoint/boot/switch_pm.asm

@@ -0,0 +1 @@
+../../10-32bit-enter/32bit-switch.asm

BIN
14-checkpoint/kernel.elf


BIN
14-checkpoint/kernel.sym


+ 8 - 0
14-checkpoint/kernel/kernel.c

@@ -0,0 +1,8 @@
+/* This will force us to create a kernel entry function instead of jumping to kernel.c:0x00 */
+void dummy_test_entrypoint() {
+}
+
+void main() {
+    char* video_memory = (char*) 0xb8000;
+    *video_memory = 'X';
+}

BIN
14-checkpoint/kernel/kernel.o