Skip to content

Commit 0134c56

Browse files
committed
lesson 23, initial commit
1 parent d271f5b commit 0134c56

31 files changed

+1554
-0
lines changed

23-fixes/Makefile

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
C_SOURCES = $(wildcard kernel/*.c drivers/*.c cpu/*.c libc/*.c)
2+
HEADERS = $(wildcard kernel/*.h drivers/*.h cpu/*.h libc/*.h)
3+
# Nice syntax for file extension replacement
4+
OBJ = ${C_SOURCES:.c=.o cpu/interrupt.o}
5+
6+
# Change this if your cross-compiler is somewhere else
7+
CC = /usr/local/i386elfgcc/bin/i386-elf-gcc
8+
GDB = /usr/local/i386elfgcc/bin/i386-elf-gdb
9+
# -g: Use debugging symbols in gcc
10+
CFLAGS = -g -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs \
11+
-Wall -Wextra -Werror
12+
13+
# First rule is run by default
14+
os-image.bin: boot/bootsect.bin kernel.bin
15+
cat $^ > os-image.bin
16+
17+
# '--oformat binary' deletes all symbols as a collateral, so we don't need
18+
# to 'strip' them manually on this case
19+
kernel.bin: boot/kernel_entry.o ${OBJ}
20+
i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
21+
22+
# Used for debugging purposes
23+
kernel.elf: boot/kernel_entry.o ${OBJ}
24+
i386-elf-ld -o $@ -Ttext 0x1000 $^
25+
26+
run: os-image.bin
27+
qemu-system-i386 -fda os-image.bin
28+
29+
# Open the connection to qemu and load our kernel-object file with symbols
30+
debug: os-image.bin kernel.elf
31+
qemu-system-i386 -s -fda os-image.bin -d guest_errors,int &
32+
${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"
33+
34+
# Generic rules for wildcards
35+
# To make an object, always compile from its .c
36+
%.o: %.c ${HEADERS}
37+
${CC} ${CFLAGS} -ffreestanding -c $< -o $@
38+
39+
%.o: %.asm
40+
nasm $< -f elf -o $@
41+
42+
%.bin: %.asm
43+
nasm $< -f bin -o $@
44+
45+
clean:
46+
rm -rf *.bin *.dis *.o os-image.bin *.elf
47+
rm -rf kernel/*.o boot/*.bin drivers/*.o boot/*.o cpu/*.o libc/*.o

23-fixes/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
*Concepts you may want to Google beforehand: XX*
2+
3+
**Goal: Fix miscellaneous issues with our code**
4+
5+
The OSDev wiki has a section [which describes some issues with
6+
JamesM's tutorial](http://wiki.osdev.org/James_Molloy%27s_Tutorial_Known_Bugs).
7+
Since we followed his tutorial for lessons 18-22 (interrupts through malloc), we'll
8+
need to make sure we fix any of the issues before moving on.
9+
10+

23-fixes/boot/32bit_print.asm

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[bits 32] ; using 32-bit protected mode
2+
3+
; this is how constants are defined
4+
VIDEO_MEMORY equ 0xb8000
5+
WHITE_OB_BLACK equ 0x0f ; the color byte for each character
6+
7+
print_string_pm:
8+
pusha
9+
mov edx, VIDEO_MEMORY
10+
11+
print_string_pm_loop:
12+
mov al, [ebx] ; [ebx] is the address of our character
13+
mov ah, WHITE_OB_BLACK
14+
15+
cmp al, 0 ; check if end of string
16+
je print_string_pm_done
17+
18+
mov [edx], ax ; store character + attribute in video memory
19+
add ebx, 1 ; next char
20+
add edx, 2 ; next video memory position
21+
22+
jmp print_string_pm_loop
23+
24+
print_string_pm_done:
25+
popa
26+
ret

23-fixes/boot/bootsect.asm

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
; Identical to lesson 13's boot sector, but the %included files have new paths
2+
[org 0x7c00]
3+
KERNEL_OFFSET equ 0x1000 ; The same one we used when linking the kernel
4+
5+
mov [BOOT_DRIVE], dl ; Remember that the BIOS sets us the boot drive in 'dl' on boot
6+
mov bp, 0x9000
7+
mov sp, bp
8+
9+
mov bx, MSG_REAL_MODE
10+
call print
11+
call print_nl
12+
13+
call load_kernel ; read the kernel from disk
14+
call switch_to_pm ; disable interrupts, load GDT, etc. Finally jumps to 'BEGIN_PM'
15+
jmp $ ; Never executed
16+
17+
%include "boot/print.asm"
18+
%include "boot/print_hex.asm"
19+
%include "boot/disk.asm"
20+
%include "boot/gdt.asm"
21+
%include "boot/32bit_print.asm"
22+
%include "boot/switch_pm.asm"
23+
24+
[bits 16]
25+
load_kernel:
26+
mov bx, MSG_LOAD_KERNEL
27+
call print
28+
call print_nl
29+
30+
mov bx, KERNEL_OFFSET ; Read from disk and store in 0x1000
31+
mov dh, 31 ; Our future kernel will be larger, make this big
32+
mov dl, [BOOT_DRIVE]
33+
call disk_load
34+
ret
35+
36+
[bits 32]
37+
BEGIN_PM:
38+
mov ebx, MSG_PROT_MODE
39+
call print_string_pm
40+
call KERNEL_OFFSET ; Give control to the kernel
41+
jmp $ ; Stay here when the kernel returns control to us (if ever)
42+
43+
44+
BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
45+
MSG_REAL_MODE db "Started in 16-bit Real Mode", 0
46+
MSG_PROT_MODE db "Landed in 32-bit Protected Mode", 0
47+
MSG_LOAD_KERNEL db "Loading kernel into memory", 0
48+
MSG_RETURNED_KERNEL db "Returned from kernel. Error?", 0
49+
50+
; padding
51+
times 510 - ($-$$) db 0
52+
dw 0xaa55

23-fixes/boot/disk.asm

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; load 'dh' sectors from drive 'dl' into ES:BX
2+
disk_load:
3+
pusha
4+
; reading from disk requires setting specific values in all registers
5+
; so we will overwrite our input parameters from 'dx'. Let's save it
6+
; to the stack for later use.
7+
push dx
8+
9+
mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
10+
mov al, dh ; al <- number of sectors to read (0x01 .. 0x80)
11+
mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
12+
; 0x01 is our boot sector, 0x02 is the first 'available' sector
13+
mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
14+
; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
15+
; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
16+
mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)
17+
18+
; [es:bx] <- pointer to buffer where the data will be stored
19+
; caller sets it up for us, and it is actually the standard location for int 13h
20+
int 0x13 ; BIOS interrupt
21+
jc disk_error ; if error (stored in the carry bit)
22+
23+
pop dx
24+
cmp al, dh ; BIOS also sets 'al' to the # of sectors read. Compare it.
25+
jne sectors_error
26+
popa
27+
ret
28+
29+
30+
disk_error:
31+
mov bx, DISK_ERROR
32+
call print
33+
call print_nl
34+
mov dh, ah ; ah = error code, dl = disk drive that dropped the error
35+
call print_hex ; check out the code at http://stanislavs.org/helppc/int_13-1.html
36+
jmp disk_loop
37+
38+
sectors_error:
39+
mov bx, SECTORS_ERROR
40+
call print
41+
42+
disk_loop:
43+
jmp $
44+
45+
DISK_ERROR: db "Disk read error", 0
46+
SECTORS_ERROR: db "Incorrect number of sectors read", 0

23-fixes/boot/gdt.asm

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps
2+
; the GDT starts with a null 8-byte
3+
dd 0x0 ; 4 byte
4+
dd 0x0 ; 4 byte
5+
6+
; GDT for code segment. base = 0x00000000, length = 0xfffff
7+
; for flags, refer to os-dev.pdf document, page 36
8+
gdt_code:
9+
dw 0xffff ; segment length, bits 0-15
10+
dw 0x0 ; segment base, bits 0-15
11+
db 0x0 ; segment base, bits 16-23
12+
db 10011010b ; flags (8 bits)
13+
db 11001111b ; flags (4 bits) + segment length, bits 16-19
14+
db 0x0 ; segment base, bits 24-31
15+
16+
; GDT for data segment. base and length identical to code segment
17+
; some flags changed, again, refer to os-dev.pdf
18+
gdt_data:
19+
dw 0xffff
20+
dw 0x0
21+
db 0x0
22+
db 10010010b
23+
db 11001111b
24+
db 0x0
25+
26+
gdt_end:
27+
28+
; GDT descriptor
29+
gdt_descriptor:
30+
dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size
31+
dd gdt_start ; address (32 bit)
32+
33+
; define some constants for later use
34+
CODE_SEG equ gdt_code - gdt_start
35+
DATA_SEG equ gdt_data - gdt_start

23-fixes/boot/kernel_entry.asm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[bits 32]
2+
[extern main] ; Define calling point. Must have same name as kernel.c 'main' function
3+
call main ; Calls the C function. The linker will know where it is placed in memory
4+
jmp $

23-fixes/boot/print.asm

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
print:
2+
pusha
3+
4+
; keep this in mind:
5+
; while (string[i] != 0) { print string[i]; i++ }
6+
7+
; the comparison for string end (null byte)
8+
start:
9+
mov al, [bx] ; 'bx' is the base address for the string
10+
cmp al, 0
11+
je done
12+
13+
; the part where we print with the BIOS help
14+
mov ah, 0x0e
15+
int 0x10 ; 'al' already contains the char
16+
17+
; increment pointer and do next loop
18+
add bx, 1
19+
jmp start
20+
21+
done:
22+
popa
23+
ret
24+
25+
26+
27+
print_nl:
28+
pusha
29+
30+
mov ah, 0x0e
31+
mov al, 0x0a ; newline char
32+
int 0x10
33+
mov al, 0x0d ; carriage return
34+
int 0x10
35+
36+
popa
37+
ret

23-fixes/boot/print_hex.asm

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; receiving the data in 'dx'
2+
; For the examples we'll assume that we're called with dx=0x1234
3+
print_hex:
4+
pusha
5+
6+
mov cx, 0 ; our index variable
7+
8+
; Strategy: get the last char of 'dx', then convert to ASCII
9+
; Numeric ASCII values: '0' (ASCII 0x30) to '9' (0x39), so just add 0x30 to byte N.
10+
; For alphabetic characters A-F: 'A' (ASCII 0x41) to 'F' (0x46) we'll add 0x40
11+
; Then, move the ASCII byte to the correct position on the resulting string
12+
hex_loop:
13+
cmp cx, 4 ; loop 4 times
14+
je end
15+
16+
; 1. convert last char of 'dx' to ascii
17+
mov ax, dx ; we will use 'ax' as our working register
18+
and ax, 0x000f ; 0x1234 -> 0x0004 by masking first three to zeros
19+
add al, 0x30 ; add 0x30 to N to convert it to ASCII "N"
20+
cmp al, 0x39 ; if > 9, add extra 8 to represent 'A' to 'F'
21+
jle step2
22+
add al, 7 ; 'A' is ASCII 65 instead of 58, so 65-58=7
23+
24+
step2:
25+
; 2. get the correct position of the string to place our ASCII char
26+
; bx <- base address + string length - index of char
27+
mov bx, HEX_OUT + 5 ; base + length
28+
sub bx, cx ; our index variable
29+
mov [bx], al ; copy the ASCII char on 'al' to the position pointed by 'bx'
30+
ror dx, 4 ; 0x1234 -> 0x4123 -> 0x3412 -> 0x2341 -> 0x1234
31+
32+
; increment index and loop
33+
add cx, 1
34+
jmp hex_loop
35+
36+
end:
37+
; prepare the parameter and call the function
38+
; remember that print receives parameters in 'bx'
39+
mov bx, HEX_OUT
40+
call print
41+
42+
popa
43+
ret
44+
45+
HEX_OUT:
46+
db '0x0000',0 ; reserve memory for our new string

23-fixes/boot/switch_pm.asm

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[bits 16]
2+
switch_to_pm:
3+
cli ; 1. disable interrupts
4+
lgdt [gdt_descriptor] ; 2. load the GDT descriptor
5+
mov eax, cr0
6+
or eax, 0x1 ; 3. set 32-bit mode bit in cr0
7+
mov cr0, eax
8+
jmp CODE_SEG:init_pm ; 4. far jump by using a different segment
9+
10+
[bits 32]
11+
init_pm: ; we are now using 32-bit instructions
12+
mov ax, DATA_SEG ; 5. update the segment registers
13+
mov ds, ax
14+
mov ss, ax
15+
mov es, ax
16+
mov fs, ax
17+
mov gs, ax
18+
19+
mov ebp, 0x90000 ; 6. update the stack right at the top of the free space
20+
mov esp, ebp
21+
22+
call BEGIN_PM ; 7. Call a well-known label with useful code

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy