Carlos Fenollosa před 10 roky
rodič
revize
418bb11305

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

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

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

@@ -0,0 +1,26 @@
+[bits 32] ; using 32-bit protected mode
+
+; this is how constants are defined
+VIDEO_MEMORY equ 0xb8000
+WHITE_OB_BLACK equ 0x0f ; the color byte for each character
+
+print_string_pm:
+    pusha
+    mov edx, VIDEO_MEMORY
+
+print_string_pm_loop:
+    mov al, [ebx] ; [ebx] is the address of our character
+    mov ah, WHITE_OB_BLACK
+
+    cmp al, 0 ; check if end of string
+    je print_string_pm_done
+
+    mov [edx], ax ; store character + attribute in video memory
+    add ebx, 1 ; next char
+    add edx, 2 ; next video memory position
+
+    jmp print_string_pm_loop
+
+print_string_pm_done:
+    popa
+    ret

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

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

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

@@ -0,0 +1,46 @@
+; load 'dh' sectors from drive 'dl' into ES:BX
+disk_load:
+    pusha
+    ; reading from disk requires setting specific values in all registers
+    ; so we will overwrite our input parameters from 'dx'. Let's save it
+    ; to the stack for later use.
+    push dx
+
+    mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
+    mov al, dh   ; al <- number of sectors to read (0x01 .. 0x80)
+    mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
+                 ; 0x01 is our boot sector, 0x02 is the first 'available' sector
+    mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
+    ; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
+    ; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
+    mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)
+
+    ; [es:bx] <- pointer to buffer where the data will be stored
+    ; caller sets it up for us, and it is actually the standard location for int 13h
+    int 0x13      ; BIOS interrupt
+    jc disk_error ; if error (stored in the carry bit)
+
+    pop dx
+    cmp al, dh    ; BIOS also sets 'al' to the # of sectors read. Compare it.
+    jne sectors_error
+    popa
+    ret
+
+
+disk_error:
+    mov bx, DISK_ERROR
+    call print
+    call print_nl
+    mov dh, ah ; ah = error code, dl = disk drive that dropped the error
+    call print_hex ; check out the code at http://stanislavs.org/helppc/int_13-1.html
+    jmp disk_loop
+
+sectors_error:
+    mov bx, SECTORS_ERROR
+    call print
+
+disk_loop:
+    jmp $
+
+DISK_ERROR: db "Disk read error", 0
+SECTORS_ERROR: db "Incorrect number of sectors read", 0

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

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

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

@@ -0,0 +1,35 @@
+gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps
+    ; the GDT starts with a null 8-byte
+    dd 0x0 ; 4 byte
+    dd 0x0 ; 4 byte
+
+; GDT for code segment. base = 0x00000000, length = 0xfffff
+; for flags, refer to os-dev.pdf document, page 36
+gdt_code: 
+    dw 0xffff    ; segment length, bits 0-15
+    dw 0x0       ; segment base, bits 0-15
+    db 0x0       ; segment base, bits 16-23
+    db 10011010b ; flags (8 bits)
+    db 11001111b ; flags (4 bits) + segment length, bits 16-19
+    db 0x0       ; segment base, bits 24-31
+
+; GDT for data segment. base and length identical to code segment
+; some flags changed, again, refer to os-dev.pdf
+gdt_data:
+    dw 0xffff
+    dw 0x0
+    db 0x0
+    db 10010010b
+    db 11001111b
+    db 0x0
+
+gdt_end:
+
+; GDT descriptor
+gdt_descriptor:
+    dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size
+    dd gdt_start ; address (32 bit)
+
+; define some constants for later use
+CODE_SEG equ gdt_code - gdt_start
+DATA_SEG equ gdt_data - gdt_start

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

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

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

@@ -0,0 +1,4 @@
+[bits 32]
+[extern main] ; Define calling point. Must have same name as kernel.c 'main' function
+call main ; Calls the C function. The linker will know where it is placed in memory
+jmp $

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

@@ -1 +0,0 @@
-../../05-bootsector-functions-strings/boot_sect_print.asm

+ 37 - 0
14-checkpoint/boot/print.asm

@@ -0,0 +1,37 @@
+print:
+    pusha
+
+; keep this in mind:
+; while (string[i] != 0) { print string[i]; i++ }
+
+; the comparison for string end (null byte)
+start:
+    mov al, [bx] ; 'bx' is the base address for the string
+    cmp al, 0 
+    je done
+
+    ; the part where we print with the BIOS help
+    mov ah, 0x0e
+    int 0x10 ; 'al' already contains the char
+
+    ; increment pointer and do next loop
+    add bx, 1
+    jmp start
+
+done:
+    popa
+    ret
+
+
+
+print_nl:
+    pusha
+    
+    mov ah, 0x0e
+    mov al, 0x0a ; newline char
+    int 0x10
+    mov al, 0x0d ; carriage return
+    int 0x10
+    
+    popa
+    ret

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

@@ -1 +0,0 @@
-../../05-bootsector-functions-strings/boot_sect_print_hex.asm

+ 46 - 0
14-checkpoint/boot/print_hex.asm

@@ -0,0 +1,46 @@
+; receiving the data in 'dx'
+; For the examples we'll assume that we're called with dx=0x1234
+print_hex:
+    pusha
+
+    mov cx, 0 ; our index variable
+
+; Strategy: get the last char of 'dx', then convert to ASCII
+; Numeric ASCII values: '0' (ASCII 0x30) to '9' (0x39), so just add 0x30 to byte N.
+; For alphabetic characters A-F: 'A' (ASCII 0x41) to 'F' (0x46) we'll add 0x40
+; Then, move the ASCII byte to the correct position on the resulting string
+hex_loop:
+    cmp cx, 4 ; loop 4 times
+    je end
+    
+    ; 1. convert last char of 'dx' to ascii
+    mov ax, dx ; we will use 'ax' as our working register
+    and ax, 0x000f ; 0x1234 -> 0x0004 by masking first three to zeros
+    add al, 0x30 ; add 0x30 to N to convert it to ASCII "N"
+    cmp al, 0x39 ; if > 9, add extra 8 to represent 'A' to 'F'
+    jle step2
+    add al, 7 ; 'A' is ASCII 65 instead of 58, so 65-58=7
+
+step2:
+    ; 2. get the correct position of the string to place our ASCII char
+    ; bx <- base address + string length - index of char
+    mov bx, HEX_OUT + 5 ; base + length
+    sub bx, cx  ; our index variable
+    mov [bx], al ; copy the ASCII char on 'al' to the position pointed by 'bx'
+    ror dx, 4 ; 0x1234 -> 0x4123 -> 0x3412 -> 0x2341 -> 0x1234
+
+    ; increment index and loop
+    add cx, 1
+    jmp hex_loop
+
+end:
+    ; prepare the parameter and call the function
+    ; remember that print receives parameters in 'bx'
+    mov bx, HEX_OUT
+    call print
+
+    popa
+    ret
+
+HEX_OUT:
+    db '0x0000',0 ; reserve memory for our new string

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

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

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

@@ -0,0 +1,22 @@
+[bits 16]
+switch_to_pm:
+    cli ; 1. disable interrupts
+    lgdt [gdt_descriptor] ; 2. load the GDT descriptor
+    mov eax, cr0
+    or eax, 0x1 ; 3. set 32-bit mode bit in cr0
+    mov cr0, eax
+    jmp CODE_SEG:init_pm ; 4. far jump by using a different segment
+
+[bits 32]
+init_pm: ; we are now using 32-bit instructions
+    mov ax, DATA_SEG ; 5. update the segment registers
+    mov ds, ax
+    mov ss, ax
+    mov es, ax
+    mov fs, ax
+    mov gs, ax
+
+    mov ebp, 0x90000 ; 6. update the stack right at the top of the free space
+    mov esp, ebp
+
+    call BEGIN_PM ; 7. Call a well-known label with useful code

+ 0 - 1
15-video-ports/Makefile

@@ -1 +0,0 @@
-../14-checkpoint/Makefile

+ 46 - 0
15-video-ports/Makefile

@@ -0,0 +1,46 @@
+C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
+HEADERS = $(wildcard kernel/*.h drivers/*.h)
+# Nice syntax for file extension replacement
+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 in gcc
+CFLAGS = -g
+
+# First rule is run by default
+os-image.bin: boot/bootsect.bin kernel.bin
+	cat $^ > os-image.bin
+
+# '--oformat binary' deletes all symbols as a collateral, so we don't need
+# to 'strip' them manually on this case
+kernel.bin: boot/kernel_entry.o ${OBJ}
+	i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
+
+# Used for debugging purposes
+kernel.elf: boot/kernel_entry.o ${OBJ}
+	i386-elf-ld -o $@ -Ttext 0x1000 $^ 
+
+run: os-image.bin
+	qemu-system-i386 -fda os-image.bin
+
+# Open the connection to qemu and load our kernel-object file with symbols
+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"
+
+# Generic rules for wildcards
+# To make an object, always compile from its .c
+%.o: %.c ${HEADERS}
+	${CC} ${CFLAGS} -ffreestanding -c $< -o $@
+
+%.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 boot/*.o

+ 0 - 1
15-video-ports/boot

@@ -1 +0,0 @@
-../14-checkpoint/boot

+ 0 - 1
16-video-driver/Makefile

@@ -1 +0,0 @@
-../14-checkpoint/Makefile

+ 46 - 0
16-video-driver/Makefile

@@ -0,0 +1,46 @@
+C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
+HEADERS = $(wildcard kernel/*.h drivers/*.h)
+# Nice syntax for file extension replacement
+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 in gcc
+CFLAGS = -g
+
+# First rule is run by default
+os-image.bin: boot/bootsect.bin kernel.bin
+	cat $^ > os-image.bin
+
+# '--oformat binary' deletes all symbols as a collateral, so we don't need
+# to 'strip' them manually on this case
+kernel.bin: boot/kernel_entry.o ${OBJ}
+	i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
+
+# Used for debugging purposes
+kernel.elf: boot/kernel_entry.o ${OBJ}
+	i386-elf-ld -o $@ -Ttext 0x1000 $^ 
+
+run: os-image.bin
+	qemu-system-i386 -fda os-image.bin
+
+# Open the connection to qemu and load our kernel-object file with symbols
+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"
+
+# Generic rules for wildcards
+# To make an object, always compile from its .c
+%.o: %.c ${HEADERS}
+	${CC} ${CFLAGS} -ffreestanding -c $< -o $@
+
+%.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 boot/*.o

+ 0 - 1
16-video-driver/boot

@@ -1 +0,0 @@
-../14-checkpoint/boot

+ 0 - 1
17-video-scroll/Makefile

@@ -1 +0,0 @@
-../14-checkpoint/Makefile

+ 46 - 0
17-video-scroll/Makefile

@@ -0,0 +1,46 @@
+C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
+HEADERS = $(wildcard kernel/*.h drivers/*.h)
+# Nice syntax for file extension replacement
+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 in gcc
+CFLAGS = -g
+
+# First rule is run by default
+os-image.bin: boot/bootsect.bin kernel.bin
+	cat $^ > os-image.bin
+
+# '--oformat binary' deletes all symbols as a collateral, so we don't need
+# to 'strip' them manually on this case
+kernel.bin: boot/kernel_entry.o ${OBJ}
+	i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
+
+# Used for debugging purposes
+kernel.elf: boot/kernel_entry.o ${OBJ}
+	i386-elf-ld -o $@ -Ttext 0x1000 $^ 
+
+run: os-image.bin
+	qemu-system-i386 -fda os-image.bin
+
+# Open the connection to qemu and load our kernel-object file with symbols
+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"
+
+# Generic rules for wildcards
+# To make an object, always compile from its .c
+%.o: %.c ${HEADERS}
+	${CC} ${CFLAGS} -ffreestanding -c $< -o $@
+
+%.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 boot/*.o

+ 0 - 1
17-video-scroll/boot

@@ -1 +0,0 @@
-../14-checkpoint/boot/

+ 0 - 1
17-video-scroll/drivers/ports.c

@@ -1 +0,0 @@
-../../16-video-driver/drivers/ports.c

+ 35 - 0
17-video-scroll/drivers/ports.c

@@ -0,0 +1,35 @@
+/**
+ * Read a byte from the specified port
+ */
+unsigned char port_byte_in (unsigned short port) {
+    unsigned char result;
+    /* Inline assembler syntax
+     * !! Notice how the source and destination registers are switched from NASM !!
+     *
+     * '"=a" (result)'; set '=' the C variable '(result)' to the value of register e'a'x
+     * '"d" (port)': map the C variable '(port)' into e'd'x register
+     *
+     * Inputs and outputs are separated by colons
+     */
+    __asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
+    return result;
+}
+
+void port_byte_out (unsigned short port, unsigned char data) {
+    /* Notice how here both registers are mapped to C variables and
+     * nothing is returned, thus, no equals '=' in the asm syntax 
+     * However we see a comma since there are two variables in the input area
+     * and none in the 'return' area
+     */
+    __asm__("out %%al, %%dx" : : "a" (data), "d" (port));
+}
+
+unsigned short port_word_in (unsigned short port) {
+    unsigned short result;
+    __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
+    return result;
+}
+
+void port_word_out (unsigned short port, unsigned short data) {
+    __asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
+}

+ 0 - 1
17-video-scroll/drivers/ports.h

@@ -1 +0,0 @@
-../../16-video-driver/drivers/ports.h

+ 4 - 0
17-video-scroll/drivers/ports.h

@@ -0,0 +1,4 @@
+unsigned char port_byte_in (unsigned short port);
+void port_byte_out (unsigned short port, unsigned char data);
+unsigned short port_word_in (unsigned short port);
+void port_word_out (unsigned short port, unsigned short data);

+ 0 - 1
17-video-scroll/drivers/screen.h

@@ -1 +0,0 @@
-../../16-video-driver/drivers/screen.h

+ 14 - 0
17-video-scroll/drivers/screen.h

@@ -0,0 +1,14 @@
+#define VIDEO_ADDRESS 0xb8000
+#define MAX_ROWS 25
+#define MAX_COLS 80
+#define WHITE_ON_BLACK 0x0f
+#define RED_ON_WHITE 0xf4
+
+/* Screen i/o ports */
+#define REG_SCREEN_CTRL 0x3d4
+#define REG_SCREEN_DATA 0x3d5
+
+/* Public kernel API */
+void clear_screen();
+void kprint_at(char *message, int col, int row);
+void kprint(char *message);

+ 5 - 0
18-interrupts/kernel/util.h

@@ -1,5 +1,10 @@
+#ifndef UTIL_H
+#define UTIL_H
+
 #include "../cpu/types.h"
 
 void memory_copy(char *source, char *dest, int nbytes);
 void memory_set(u8 *dest, u8 val, u32 len);
 void int_to_ascii(int n, char str[]);
+
+#endif