Stephen Downward 1 year ago
parent
commit
33a075a030
43 changed files with 1999 additions and 0 deletions
  1. 7 0
      .gitignore
  2. 48 0
      Makefile
  3. 26 0
      boot/32bit_print.asm
  4. 75 0
      boot/bootsect.asm
  5. 59 0
      boot/bootsect2.asm
  6. 45 0
      boot/disk.asm
  7. 35 0
      boot/gdt.asm
  8. 4 0
      boot/kernel_entry.asm
  9. 37 0
      boot/print.asm
  10. 46 0
      boot/print_hex.asm
  11. 22 0
      boot/switch_pm.asm
  12. 16 0
      cpu/idt.c
  13. 39 0
      cpu/idt.h
  14. 425 0
      cpu/interrupt.asm
  15. 153 0
      cpu/isr.c
  16. 89 0
      cpu/isr.h
  17. 37 0
      cpu/ports.c
  18. 11 0
      cpu/ports.h
  19. 26 0
      cpu/timer.c
  20. 8 0
      cpu/timer.h
  21. 16 0
      cpu/types.h
  22. 10 0
      drivers/floppy.c
  23. 17 0
      drivers/floppy.h
  24. 83 0
      drivers/keyboard.c
  25. 3 0
      drivers/keyboard.h
  26. 180 0
      drivers/screen.c
  27. 70 0
      drivers/screen.h
  28. 53 0
      kernel/kernel.c
  29. 6 0
      kernel/kernel.h
  30. 8 0
      libc/function.h
  31. 13 0
      libc/mem.c
  32. 9 0
      libc/mem.h
  33. 59 0
      libc/string.c
  34. 11 0
      libc/string.h
  35. 10 0
      makeiso.sh
  36. 31 0
      programs/texteditor.c
  37. 4 0
      programs/texteditor.h
  38. 14 0
      util/bitmap.c
  39. 0 0
      util/bitmap.h
  40. 109 0
      util/font.c
  41. 7 0
      util/font.h
  42. 63 0
      util/terminal.c
  43. 15 0
      util/terminal.h

+ 7 - 0
.gitignore

@ -32,3 +32,10 @@
32 32
# Debug files
33 33
*.dSYM/
34 34
35
#Customs
36
flp
37
Other
38
*~
39
*.bin
40
*.o
41
*.iso

+ 48 - 0
Makefile

@ -0,0 +1,48 @@
1
C_SOURCES = $(wildcard kernel/*.c drivers/*.c cpu/*.c libc/*.c programs/*.c util/*.c)
2
HEADERS = $(wildcard kernel/*.h drivers/*.h cpu/*.h libc/*.h programs/*.h util/*.c)
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 = /home/stephen/opt/cross/bin/i686-elf-gcc
8
GDB = /home/stephen/opt/cross/bin/i686-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 boot/bootsect2.bin kernel.bin
15
	cat $^ > os-image.bin
16
	#Pad os-image.bin
17
	dd if=/dev/null of=os-image.bin bs=1 count=0 seek=1474560
18
# '--oformat binary' deletes all symbols as a collateral, so we don't need
19
# to 'strip' them manually on this case
20
kernel.bin: boot/kernel_entry.o ${OBJ}
21
	i686-elf-ld -o $@ -Ttext 0x1800 $^ --oformat binary
22
23
# Used for debugging purposes
24
kernel.elf: boot/kernel_entry.o ${OBJ}
25
	i686-elf-ld -o $@ -Ttext 0x1800 $^ 
26
27
run: os-image.bin
28
	qemu-system-i386 -fda os-image.bin
29
30
# Open the connection to qemu and load our kernel-object file with symbols
31
debug: os-image.bin kernel.elf
32
	qemu-system-i386 -s -fda os-image.bin -d guest_errors,int &
33
	${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"
34
35
# Generic rules for wildcards
36
# To make an object, always compile from its .c
37
%.o: %.c ${HEADERS}
38
	${CC} ${CFLAGS} -ffreestanding -c $< -o $@
39
40
%.o: %.asm
41
	nasm $< -f elf -o $@
42
43
%.bin: %.asm
44
	nasm $< -f bin -o $@
45
46
clean:
47
	rm -rf *.bin *.dis *.o os-image.bin *.elf
48
	rm -rf kernel/*.o boot/*.bin drivers/*.o boot/*.o cpu/*.o libc/*.o

+ 26 - 0
boot/32bit_print.asm

@ -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

+ 75 - 0
boot/bootsect.asm

@ -0,0 +1,75 @@
1
[org 0x7c00]
2
[bits 16]
3
BOOTLOADER_OFFSET equ 0x1000 ; Second stage of bootloader
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 al, 0x0002
10
    call load_bootloader ; read the kernel (and the rest of the bootloader) from disk
11
    jmp BOOTLOADER_OFFSET
12
    jmp $ ; Should never be called
13
14
%include "boot/disk.asm"
15
%include "boot/print.asm"
16
%include "boot/print_hex.asm"
17
18
load_bootloader:
19
    pusha
20
    mov bx, [CURRENT_MEM_LOAD] ; Read from disk and store into ax
21
    mov dh, [HEAD_COUNT] ; dh <- head number (0x0 .. 0xF) //Redundant?
22
    mov cl, al
23
    mov al, 1 ;Num sectors
24
    mov ch, [CYL_COUNT] ;Cylinder number
25
    mov dl, [BOOT_DRIVE]
26
    call disk_load
27
    popa
28
29
    ;Increment CURRENT_MEM_LOAD
30
    mov cx, [CURRENT_MEM_LOAD]
31
    add cx, 0x200
32
    mov [CURRENT_MEM_LOAD], cx
33
34
35
    cmp al, 0x12 ; If al >= 0x11, increment cylinder 18 = 0x12
36
    jge inc_head
37
38
    mov ch, [CYL_COUNT]
39
    cmp ch, 1
40
    jge done_load
41
42
    ;Increment sector ID
43
    inc al
44
    jmp load_bootloader
45
46
inc_head:
47
    mov dh, [HEAD_COUNT]
48
    cmp dh, 1
49
    jge inc_cyl
50
    inc dh
51
    mov [HEAD_COUNT], dh
52
    mov al, 1
53
    jmp load_bootloader
54
55
inc_cyl:
56
    mov ch, [CYL_COUNT]
57
    inc ch
58
    mov [CYL_COUNT], ch
59
    ;Reset head count
60
    mov dh, 0
61
    mov [HEAD_COUNT], dh
62
    ;Reset sector count
63
    mov al, 1
64
    jmp load_bootloader
65
66
done_load:
67
    ret;jmp BOOTLOADER_OFFSET ;ret
68
69
CYL_COUNT db 0
70
HEAD_COUNT db 0
71
CURRENT_MEM_LOAD dw 0x1000
72
BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
73
; padding
74
times 510 - ($-$$) db 0
75
dw 0xaa55

+ 59 - 0
boot/bootsect2.asm

@ -0,0 +1,59 @@
1
[bits 16]
2
[org 0x1000]
3
KERNEL_OFFSET equ 0x1800
4
VBE_INFO equ 0x900
5
6
;TODO: What are these for?
7
;MOV AX, CS ; initialize
8
;MOV DS, AX ; segments
9
;MOV ES, AX ; correctly, ALWAYS gen
10
11
mov ax, 0x4F02 ;VBD mode
12
mov bx, 0x4118 ;1024x768x? TODO: Query BIOS to find out supported modes
13
int 0x10 ; switch to VGA 640x480
14
cmp ax, 0x004F   ; test for error
15
jne error
16
17
;Get VBE mode
18
mov esi, 0
19
mov di, VBE_INFO
20
mov ax, 0x4f01
21
mov cx, 0x4118 ;Redundant for now
22
int 0x10
23
cmp ax, 0x004F   ; test for error
24
jne error
25
26
27
mov bx, MSG_REAL_MODE
28
call print
29
call print_nl
30
31
call switch_to_pm ; disable interrupts, load GDT,  etc. Finally jumps to 'BEGIN_PM'
32
jmp $ ; Never executed
33
34
35
%include "boot/print.asm"
36
%include "boot/print_hex.asm"
37
%include "boot/gdt.asm"
38
%include "boot/32bit_print.asm"
39
%include "boot/switch_pm.asm"
40
41
MSG_REAL_MODE db "Started in 16-bit Real Mode", 0
42
MSG_PROT_MODE db "Landed in 32-bit Protected Mode", 0
43
MSG_LOAD_KERNEL db "Loading kernel into memory", 0
44
MSG_RETURNED_KERNEL db "Returned from kernel. Error?", 0
45
MSG_VIDEO_ERROR db "VESA_ERR", 0
46
47
[bits 32]
48
BEGIN_PM:
49
    mov ebx, MSG_PROT_MODE
50
    call print_string_pm
51
    call KERNEL_OFFSET; Give control to the kernel
52
    jmp $ ; Stay here when the kernel returns control to us (if ever)
53
54
error:
55
    mov ebx, MSG_VIDEO_ERROR
56
    call print_string_pm
57
    jmp $
58
59
times 2048 - ($-$$) db 0 ; This second stage can be up to 2KB, for now

+ 45 - 0
boot/disk.asm

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

+ 35 - 0
boot/gdt.asm

@ -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

+ 4 - 0
boot/kernel_entry.asm

@ -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 $

+ 37 - 0
boot/print.asm

@ -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

+ 46 - 0
boot/print_hex.asm

@ -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

+ 22 - 0
boot/switch_pm.asm

@ -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

+ 16 - 0
cpu/idt.c

@ -0,0 +1,16 @@
1
#include "idt.h"
2
3
void set_idt_gate(int n, u32 handler) {
4
    idt[n].low_offset = low_16(handler);
5
    idt[n].sel = KERNEL_CS;
6
    idt[n].always0 = 0;
7
    idt[n].flags = 0x8E; 
8
    idt[n].high_offset = high_16(handler);
9
}
10
11
void set_idt() {
12
    idt_reg.base = (u32) &idt;
13
    idt_reg.limit = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
14
    /* Don't make the mistake of loading &idt -- always load &idt_reg */
15
    __asm__ __volatile__("lidtl (%0)" : : "r" (&idt_reg));
16
}

+ 39 - 0
cpu/idt.h

@ -0,0 +1,39 @@
1
#ifndef IDT_H
2
#define IDT_H
3
4
#include "types.h"
5
6
/* Segment selectors */
7
#define KERNEL_CS 0x08
8
9
/* How every interrupt gate (handler) is defined */
10
typedef struct {
11
    u16 low_offset; /* Lower 16 bits of handler function address */
12
    u16 sel; /* Kernel segment selector */
13
    u8 always0;
14
    /* First byte
15
     * Bit 7: "Interrupt is present"
16
     * Bits 6-5: Privilege level of caller (0=kernel..3=user)
17
     * Bit 4: Set to 0 for interrupt gates
18
     * Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */
19
    u8 flags; 
20
    u16 high_offset; /* Higher 16 bits of handler function address */
21
} __attribute__((packed)) idt_gate_t ;
22
23
/* A pointer to the array of interrupt handlers.
24
 * Assembly instruction 'lidt' will read it */
25
typedef struct {
26
    u16 limit;
27
    u32 base;
28
} __attribute__((packed)) idt_register_t;
29
30
#define IDT_ENTRIES 256
31
idt_gate_t idt[IDT_ENTRIES];
32
idt_register_t idt_reg;
33
34
35
/* Functions implemented in idt.c */
36
void set_idt_gate(int n, u32 handler);
37
void set_idt();
38
39
#endif

+ 425 - 0
cpu/interrupt.asm

@ -0,0 +1,425 @@
1
; Defined in isr.c
2
[extern isr_handler]
3
[extern irq_handler]
4
5
; Common ISR code
6
isr_common_stub:
7
    ; 1. Save CPU state
8
	pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
9
	mov ax, ds ; Lower 16-bits of eax = ds.
10
	push eax ; save the data segment descriptor
11
	mov ax, 0x10  ; kernel data segment descriptor
12
	mov ds, ax
13
	mov es, ax
14
	mov fs, ax
15
	mov gs, ax
16
	
17
    ; 2. Call C handler
18
	call isr_handler
19
	
20
    ; 3. Restore state
21
	pop eax 
22
	mov ds, ax
23
	mov es, ax
24
	mov fs, ax
25
	mov gs, ax
26
	popa
27
	add esp, 8 ; Cleans up the pushed error code and pushed ISR number
28
	sti
29
	iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
30
31
; Common IRQ code. Identical to ISR code except for the 'call' 
32
; and the 'pop ebx'
33
irq_common_stub:
34
    pusha 
35
    mov ax, ds
36
    push eax
37
    mov ax, 0x10
38
    mov ds, ax
39
    mov es, ax
40
    mov fs, ax
41
    mov gs, ax
42
    call irq_handler ; Different than the ISR code
43
    pop ebx  ; Different than the ISR code
44
    mov ds, bx
45
    mov es, bx
46
    mov fs, bx
47
    mov gs, bx
48
    popa
49
    add esp, 8
50
    sti
51
    iret 
52
	
53
; We don't get information about which interrupt was caller
54
; when the handler is run, so we will need to have a different handler
55
; for every interrupt.
56
; Furthermore, some interrupts push an error code onto the stack but others
57
; don't, so we will push a dummy error code for those which don't, so that
58
; we have a consistent stack for all of them.
59
60
; First make the ISRs global
61
global isr0
62
global isr1
63
global isr2
64
global isr3
65
global isr4
66
global isr5
67
global isr6
68
global isr7
69
global isr8
70
global isr9
71
global isr10
72
global isr11
73
global isr12
74
global isr13
75
global isr14
76
global isr15
77
global isr16
78
global isr17
79
global isr18
80
global isr19
81
global isr20
82
global isr21
83
global isr22
84
global isr23
85
global isr24
86
global isr25
87
global isr26
88
global isr27
89
global isr28
90
global isr29
91
global isr30
92
global isr31
93
; IRQs
94
global irq0
95
global irq1
96
global irq2
97
global irq3
98
global irq4
99
global irq5
100
global irq6
101
global irq7
102
global irq8
103
global irq9
104
global irq10
105
global irq11
106
global irq12
107
global irq13
108
global irq14
109
global irq15
110
111
; 0: Divide By Zero Exception
112
isr0:
113
    cli
114
    push byte 0
115
    push byte 0
116
    jmp isr_common_stub
117
118
; 1: Debug Exception
119
isr1:
120
    cli
121
    push byte 0
122
    push byte 1
123
    jmp isr_common_stub
124
125
; 2: Non Maskable Interrupt Exception
126
isr2:
127
    cli
128
    push byte 0
129
    push byte 2
130
    jmp isr_common_stub
131
132
; 3: Int 3 Exception
133
isr3:
134
    cli
135
    push byte 0
136
    push byte 3
137
    jmp isr_common_stub
138
139
; 4: INTO Exception
140
isr4:
141
    cli
142
    push byte 0
143
    push byte 4
144
    jmp isr_common_stub
145
146
; 5: Out of Bounds Exception
147
isr5:
148
    cli
149
    push byte 0
150
    push byte 5
151
    jmp isr_common_stub
152
153
; 6: Invalid Opcode Exception
154
isr6:
155
    cli
156
    push byte 0
157
    push byte 6
158
    jmp isr_common_stub
159
160
; 7: Coprocessor Not Available Exception
161
isr7:
162
    cli
163
    push byte 0
164
    push byte 7
165
    jmp isr_common_stub
166
167
; 8: Double Fault Exception (With Error Code!)
168
isr8:
169
    cli
170
    push byte 8
171
    jmp isr_common_stub
172
173
; 9: Coprocessor Segment Overrun Exception
174
isr9:
175
    cli
176
    push byte 0
177
    push byte 9
178
    jmp isr_common_stub
179
180
; 10: Bad TSS Exception (With Error Code!)
181
isr10:
182
    cli
183
    push byte 10
184
    jmp isr_common_stub
185
186
; 11: Segment Not Present Exception (With Error Code!)
187
isr11:
188
    cli
189
    push byte 11
190
    jmp isr_common_stub
191
192
; 12: Stack Fault Exception (With Error Code!)
193
isr12:
194
    cli
195
    push byte 12
196
    jmp isr_common_stub
197
198
; 13: General Protection Fault Exception (With Error Code!)
199
isr13:
200
    cli
201
    push byte 13
202
    jmp isr_common_stub
203
204
; 14: Page Fault Exception (With Error Code!)
205
isr14:
206
    cli
207
    push byte 14
208
    jmp isr_common_stub
209
210
; 15: Reserved Exception
211
isr15:
212
    cli
213
    push byte 0
214
    push byte 15
215
    jmp isr_common_stub
216
217
; 16: Floating Point Exception
218
isr16:
219
    cli
220
    push byte 0
221
    push byte 16
222
    jmp isr_common_stub
223
224
; 17: Alignment Check Exception
225
isr17:
226
    cli
227
    push byte 0
228
    push byte 17
229
    jmp isr_common_stub
230
231
; 18: Machine Check Exception
232
isr18:
233
    cli
234
    push byte 0
235
    push byte 18
236
    jmp isr_common_stub
237
238
; 19: Reserved
239
isr19:
240
    cli
241
    push byte 0
242
    push byte 19
243
    jmp isr_common_stub
244
245
; 20: Reserved
246
isr20:
247
    cli
248
    push byte 0
249
    push byte 20
250
    jmp isr_common_stub
251
252
; 21: Reserved
253
isr21:
254
    cli
255
    push byte 0
256
    push byte 21
257
    jmp isr_common_stub
258
259
; 22: Reserved
260
isr22:
261
    cli
262
    push byte 0
263
    push byte 22
264
    jmp isr_common_stub
265
266
; 23: Reserved
267
isr23:
268
    cli
269
    push byte 0
270
    push byte 23
271
    jmp isr_common_stub
272
273
; 24: Reserved
274
isr24:
275
    cli
276
    push byte 0
277
    push byte 24
278
    jmp isr_common_stub
279
280
; 25: Reserved
281
isr25:
282
    cli
283
    push byte 0
284
    push byte 25
285
    jmp isr_common_stub
286
287
; 26: Reserved
288
isr26:
289
    cli
290
    push byte 0
291
    push byte 26
292
    jmp isr_common_stub
293
294
; 27: Reserved
295
isr27:
296
    cli
297
    push byte 0
298
    push byte 27
299
    jmp isr_common_stub
300
301
; 28: Reserved
302
isr28:
303
    cli
304
    push byte 0
305
    push byte 28
306
    jmp isr_common_stub
307
308
; 29: Reserved
309
isr29:
310
    cli
311
    push byte 0
312
    push byte 29
313
    jmp isr_common_stub
314
315
; 30: Reserved
316
isr30:
317
    cli
318
    push byte 0
319
    push byte 30
320
    jmp isr_common_stub
321
322
; 31: Reserved
323
isr31:
324
    cli
325
    push byte 0
326
    push byte 31
327
    jmp isr_common_stub
328
329
; IRQ handlers
330
irq0:
331
	cli
332
	push byte 0
333
	push byte 32
334
	jmp irq_common_stub
335
336
irq1:
337
	cli
338
	push byte 1
339
	push byte 33
340
	jmp irq_common_stub
341
342
irq2:
343
	cli
344
	push byte 2
345
	push byte 34
346
	jmp irq_common_stub
347
348
irq3:
349
	cli
350
	push byte 3
351
	push byte 35
352
	jmp irq_common_stub
353
354
irq4:
355
	cli
356
	push byte 4
357
	push byte 36
358
	jmp irq_common_stub
359
360
irq5:
361
	cli
362
	push byte 5
363
	push byte 37
364
	jmp irq_common_stub
365
366
irq6:
367
	cli
368
	push byte 6
369
	push byte 38
370
	jmp irq_common_stub
371
372
irq7:
373
	cli
374
	push byte 7
375
	push byte 39
376
	jmp irq_common_stub
377
378
irq8:
379
	cli
380
	push byte 8
381
	push byte 40
382
	jmp irq_common_stub
383
384
irq9:
385
	cli
386
	push byte 9
387
	push byte 41
388
	jmp irq_common_stub
389
390
irq10:
391
	cli
392
	push byte 10
393
	push byte 42
394
	jmp irq_common_stub
395
396
irq11:
397
	cli
398
	push byte 11
399
	push byte 43
400
	jmp irq_common_stub
401
402
irq12:
403
	cli
404
	push byte 12
405
	push byte 44
406
	jmp irq_common_stub
407
408
irq13:
409
	cli
410
	push byte 13
411
	push byte 45
412
	jmp irq_common_stub
413
414
irq14:
415
	cli
416
	push byte 14
417
	push byte 46
418
	jmp irq_common_stub
419
420
irq15:
421
	cli
422
	push byte 15
423
	push byte 47
424
	jmp irq_common_stub
425

+ 153 - 0
cpu/isr.c

@ -0,0 +1,153 @@
1
#include "isr.h"
2
#include "idt.h"
3
#include "../drivers/screen.h"
4
#include "../drivers/keyboard.h"
5
#include "../libc/string.h"
6
#include "timer.h"
7
#include "ports.h"
8
9
isr_t interrupt_handlers[256];
10
11
/* Can't do this with a loop because we need the address
12
 * of the function names */
13
void isr_install() {
14
    set_idt_gate(0, (u32)isr0);
15
    set_idt_gate(1, (u32)isr1);
16
    set_idt_gate(2, (u32)isr2);
17
    set_idt_gate(3, (u32)isr3);
18
    set_idt_gate(4, (u32)isr4);
19
    set_idt_gate(5, (u32)isr5);
20
    set_idt_gate(6, (u32)isr6);
21
    set_idt_gate(7, (u32)isr7);
22
    set_idt_gate(8, (u32)isr8);
23
    set_idt_gate(9, (u32)isr9);
24
    set_idt_gate(10, (u32)isr10);
25
    set_idt_gate(11, (u32)isr11);
26
    set_idt_gate(12, (u32)isr12);
27
    set_idt_gate(13, (u32)isr13);
28
    set_idt_gate(14, (u32)isr14);
29
    set_idt_gate(15, (u32)isr15);
30
    set_idt_gate(16, (u32)isr16);
31
    set_idt_gate(17, (u32)isr17);
32
    set_idt_gate(18, (u32)isr18);
33
    set_idt_gate(19, (u32)isr19);
34
    set_idt_gate(20, (u32)isr20);
35
    set_idt_gate(21, (u32)isr21);
36
    set_idt_gate(22, (u32)isr22);
37
    set_idt_gate(23, (u32)isr23);
38
    set_idt_gate(24, (u32)isr24);
39
    set_idt_gate(25, (u32)isr25);
40
    set_idt_gate(26, (u32)isr26);
41
    set_idt_gate(27, (u32)isr27);
42
    set_idt_gate(28, (u32)isr28);
43
    set_idt_gate(29, (u32)isr29);
44
    set_idt_gate(30, (u32)isr30);
45
    set_idt_gate(31, (u32)isr31);
46
47
    // Remap the PIC
48
    port_byte_out(0x20, 0x11);
49
    port_byte_out(0xA0, 0x11);
50
    port_byte_out(0x21, 0x20);
51
    port_byte_out(0xA1, 0x28);
52
    port_byte_out(0x21, 0x04);
53
    port_byte_out(0xA1, 0x02);
54
    port_byte_out(0x21, 0x01);
55
    port_byte_out(0xA1, 0x01);
56
    port_byte_out(0x21, 0x0);
57
    port_byte_out(0xA1, 0x0); 
58
59
    // Install the IRQs
60
    set_idt_gate(32, (u32)irq0);
61
    set_idt_gate(33, (u32)irq1);
62
    set_idt_gate(34, (u32)irq2);
63
    set_idt_gate(35, (u32)irq3);
64
    set_idt_gate(36, (u32)irq4);
65
    set_idt_gate(37, (u32)irq5);
66
    set_idt_gate(38, (u32)irq6);
67
    set_idt_gate(39, (u32)irq7);
68
    set_idt_gate(40, (u32)irq8);
69
    set_idt_gate(41, (u32)irq9);
70
    set_idt_gate(42, (u32)irq10);
71
    set_idt_gate(43, (u32)irq11);
72
    set_idt_gate(44, (u32)irq12);
73
    set_idt_gate(45, (u32)irq13);
74
    set_idt_gate(46, (u32)irq14);
75
    set_idt_gate(47, (u32)irq15);
76
77
    set_idt(); // Load with ASM
78
}
79
80
/* To print the message which defines every exception */
81
char *exception_messages[] = {
82
    "Division By Zero",
83
    "Debug",
84
    "Non Maskable Interrupt",
85
    "Breakpoint",
86
    "Into Detected Overflow",
87
    "Out of Bounds",
88
    "Invalid Opcode",
89
    "No Coprocessor",
90
91
    "Double Fault",
92
    "Coprocessor Segment Overrun",
93
    "Bad TSS",
94
    "Segment Not Present",
95
    "Stack Fault",
96
    "General Protection Fault",
97
    "Page Fault",
98
    "Unknown Interrupt",
99
100
    "Coprocessor Fault",
101
    "Alignment Check",
102
    "Machine Check",
103
    "Reserved",
104
    "Reserved",
105
    "Reserved",
106
    "Reserved",
107
    "Reserved",
108
109
    "Reserved",
110
    "Reserved",
111
    "Reserved",
112
    "Reserved",
113
    "Reserved",
114
    "Reserved",
115
    "Reserved",
116
    "Reserved"
117
};
118
119
void isr_handler(registers_t r) {
120
    kprint("received interrupt: ");
121
    char s[3];
122
    int_to_ascii(r.int_no, s);
123
    kprint(s);
124
    kprint("\n");
125
    kprint(exception_messages[r.int_no]);
126
    kprint("\n");
127
}
128
129
void register_interrupt_handler(u8 n, isr_t handler) {
130
    interrupt_handlers[n] = handler;
131
}
132
133
void irq_handler(registers_t r) {
134
    /* After every interrupt we need to send an EOI to the PICs
135
     * or they will not send another interrupt again */
136
    if (r.int_no >= 40) port_byte_out(0xA0, 0x20); /* slave */
137
    port_byte_out(0x20, 0x20); /* master */
138
139
    /* Handle the interrupt in a more modular way */
140
    if (interrupt_handlers[r.int_no] != 0) {
141
        isr_t handler = interrupt_handlers[r.int_no];
142
        handler(r);
143
    }
144
}
145
146
void irq_install() {
147
    /* Enable interruptions */
148
    asm volatile("sti");
149
    /* IRQ0: timer */
150
    init_timer(50);
151
    /* IRQ1: keyboard */
152
    init_keyboard();
153
}

+ 89 - 0
cpu/isr.h

@ -0,0 +1,89 @@
1
#ifndef ISR_H
2
#define ISR_H
3
4
#include "types.h"
5
6
/* ISRs reserved for CPU exceptions */
7
extern void isr0();
8
extern void isr1();
9
extern void isr2();
10
extern void isr3();
11
extern void isr4();
12
extern void isr5();
13
extern void isr6();
14
extern void isr7();
15
extern void isr8();
16
extern void isr9();
17
extern void isr10();
18
extern void isr11();
19
extern void isr12();
20
extern void isr13();
21
extern void isr14();
22
extern void isr15();
23
extern void isr16();
24
extern void isr17();
25
extern void isr18();
26
extern void isr19();
27
extern void isr20();
28
extern void isr21();
29
extern void isr22();
30
extern void isr23();
31
extern void isr24();
32
extern void isr25();
33
extern void isr26();
34
extern void isr27();
35
extern void isr28();
36
extern void isr29();
37
extern void isr30();
38
extern void isr31();
39
/* IRQ definitions */
40
extern void irq0();
41
extern void irq1();
42
extern void irq2();
43
extern void irq3();
44
extern void irq4();
45
extern void irq5();
46
extern void irq6();
47
extern void irq7();
48
extern void irq8();
49
extern void irq9();
50
extern void irq10();
51
extern void irq11();
52
extern void irq12();
53
extern void irq13();
54
extern void irq14();
55
extern void irq15();
56
57
#define IRQ0 32
58
#define IRQ1 33
59
#define IRQ2 34
60
#define IRQ3 35
61
#define IRQ4 36
62
#define IRQ5 37
63
#define IRQ6 38
64
#define IRQ7 39
65
#define IRQ8 40
66
#define IRQ9 41
67
#define IRQ10 42
68
#define IRQ11 43
69
#define IRQ12 44
70
#define IRQ13 45
71
#define IRQ14 46
72
#define IRQ15 47
73
74
/* Struct which aggregates many registers */
75
typedef struct {
76
   u32 ds; /* Data segment selector */
77
   u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
78
   u32 int_no, err_code; /* Interrupt number and error code (if applicable) */
79
   u32 eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */
80
} registers_t;
81
82
void isr_install();
83
void isr_handler(registers_t r);
84
void irq_install();
85
86
typedef void (*isr_t)(registers_t);
87
void register_interrupt_handler(u8 n, isr_t handler);
88
89
#endif

+ 37 - 0
cpu/ports.c

@ -0,0 +1,37 @@
1
#include "ports.h"
2
3
/**
4
 * Read a byte from the specified port
5
 */
6
u8 port_byte_in (u16 port) {
7
    u8 result;
8
    /* Inline assembler syntax
9
     * !! Notice how the source and destination registers are switched from NASM !!
10
     *
11
     * '"=a" (result)'; set '=' the C variable '(result)' to the value of register e'a'x
12
     * '"d" (port)': map the C variable '(port)' into e'd'x register
13
     *
14
     * Inputs and outputs are separated by colons
15
     */
16
    __asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
17
    return result;
18
}
19
20
void port_byte_out (u16 port, u8 data) {
21
    /* Notice how here both registers are mapped to C variables and
22
     * nothing is returned, thus, no equals '=' in the asm syntax 
23
     * However we see a comma since there are two variables in the input area
24
     * and none in the 'return' area
25
     */
26
    __asm__ __volatile__("out %%al, %%dx" : : "a" (data), "d" (port));
27
}
28
29
u16 port_word_in (u16 port) {
30
    u16 result;
31
    __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
32
    return result;
33
}
34
35
void port_word_out (u16 port, u16 data) {
36
    __asm__ __volatile__("out %%ax, %%dx" : : "a" (data), "d" (port));
37
}

+ 11 - 0
cpu/ports.h

@ -0,0 +1,11 @@
1
#ifndef PORTS_H
2
#define PORTS_H
3
4
#include "../cpu/types.h"
5
6
unsigned char port_byte_in (u16 port);
7
void port_byte_out (u16 port, u8 data);
8
unsigned short port_word_in (u16 port);
9
void port_word_out (u16 port, u16 data);
10
11
#endif

+ 26 - 0
cpu/timer.c

@ -0,0 +1,26 @@
1
#include "timer.h"
2
#include "isr.h"
3
#include "ports.h"
4
#include "../libc/function.h"
5
6
u32 tick = 0;
7
8
static void timer_callback(registers_t regs) {
9
    tick++;
10
    UNUSED(regs);
11
}
12
13
void init_timer(u32 freq) {
14
    /* Install the function we just wrote */
15
    register_interrupt_handler(IRQ0, timer_callback);
16
17
    /* Get the PIT value: hardware clock at 1193180 Hz */
18
    u32 divisor = 1193180 / freq;
19
    u8 low  = (u8)(divisor & 0xFF);
20
    u8 high = (u8)( (divisor >> 8) & 0xFF);
21
    /* Send the command */
22
    port_byte_out(0x43, 0x36); /* Command port */
23
    port_byte_out(0x40, low);
24
    port_byte_out(0x40, high);
25
}
26

+ 8 - 0
cpu/timer.h

@ -0,0 +1,8 @@
1
#ifndef TIMER_H
2
#define TIMER_H
3
4
#include "types.h"
5
6
void init_timer(u32 freq);
7
8
#endif

+ 16 - 0
cpu/types.h

@ -0,0 +1,16 @@
1
#ifndef TYPES_H
2
#define TYPES_H
3
4
/* Instead of using 'chars' to allocate non-character bytes,
5
 * we will use these new type with no semantic meaning */
6
typedef unsigned int   u32;
7
typedef          int   s32;
8
typedef unsigned short u16;
9
typedef          short s16;
10
typedef unsigned char  u8;
11
typedef          char  s8;
12
13
#define low_16(address) (u16)((address) & 0xFFFF)
14
#define high_16(address) (u16)(((address) >> 16) & 0xFFFF)
15
16
#endif

+ 10 - 0
drivers/floppy.c

@ -0,0 +1,10 @@
1
#include "floppy.h"
2
#include "../cpu/ports.h"
3
4
// Obviously you'd have this return the data, start drivers or something.
5
int floppy_detect_drives() {
6
7
   port_byte_out(0x70, 0x10);
8
   return port_word_in(0x71);
9
10
}

+ 17 - 0
drivers/floppy.h

@ -0,0 +1,17 @@
1
#ifndef floppy
2
    #define floppy
3
4
    /*static const char * drive_types[8] = {
5
        "none",
6
        "360kB 5.25\"",
7
        "1.2MB 5.25\"",
8
        "720kB 3.5\"",
9
10
        "1.44MB 3.5\"",
11
        "2.88MB 3.5\"",
12
        "unknown type",
13
        "unknown type"
14
    };*/
15
16
    int floppy_detect_drives();
17
#endif

+ 83 - 0
drivers/keyboard.c

@ -0,0 +1,83 @@
1
#include "keyboard.h"
2
#include "../cpu/ports.h"
3
#include "../cpu/isr.h"
4
#include "screen.h"
5
#include "../libc/string.h"
6
#include "../libc/function.h"
7
#include "../kernel/kernel.h"
8
#include "../util/terminal.h"
9
10
#define BACKSPACE 0x0E
11
#define ENTER 0x1C
12
#define LSHIFT 0x2A
13
#define RSHIFT 0x36
14
15
static char key_buffer[256];
16
static u8 uppercase = 0;
17
18
#define SC_MAX 57
19
const char *sc_name[] = { "ERROR", "Esc", "1", "2", "3", "4", "5", "6",
20
    "7", "8", "9", "0", "-", "=", "Backspace", "Tab", "Q", "W", "E",
21
        "R", "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Lctrl",
22
        "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "`",
23
        "LShift", "\\", "Z", "X", "C", "V", "B", "N", "M", ",", ".",
24
        "/", "RShift", "Keypad *", "LAlt", "Spacebar"};
25
const char sc_ascii[] = { '?', '?', '1', '2', '3', '4', '5', '6',
26
    '7', '8', '9', '0', '-', '=', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y',
27
        'U', 'I', 'O', 'P', '[', ']', '?', '?', 'A', 'S', 'D', 'F', 'G',
28
        'H', 'J', 'K', 'L', ';', '\'', '`', '?', '\\', 'Z', 'X', 'C', 'V',
29
        'B', 'N', 'M', ',', '.', '/', '?', '*', '?', ' '};
30
31
const char sc_shift_below[] = { '?', '?', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '?', '?'};
32
const char sc_shift_middle[] = { ':', '"', '~', '?', '|'}; //0x27 to 0x2B
33
const char sc_shift_above[] = { '<', '>', '?', '?', '*', '?', ' '}; //0x33 to 0x39
34
35
static void keyboard_callback(registers_t regs) {
36
    /* The PIC leaves us the scancode in port 0x60 */
37
    u8 scancode = port_byte_in(0x60);
38
39
    if (scancode > SC_MAX) { //Key being released
40
        scancode -= 0x80; //Difference between release code and press code
41
        if (scancode == LSHIFT || scancode == RSHIFT)
42
        {
43
            uppercase = 0;
44
        }
45
    }
46
    else {
47
        if (scancode == LSHIFT || scancode == RSHIFT) {
48
            uppercase = 1;
49
        } else if (scancode == BACKSPACE) {
50
            if (strlen(key_buffer) > 0) {
51
                backspace(key_buffer);
52
                delete_last();
53
            }
54
        } else if (scancode == ENTER) {
55
            newline();
56
            user_input(key_buffer); /* kernel-controlled function */
57
            key_buffer[0] = '\0';
58
        } else {
59
            char letter = sc_ascii[(int)scancode];
60
            if (letter > 65 && letter < 90) {
61
                letter += 32 * !uppercase; //Remove 32 from letter(make it lower case) if uppercase is false
62
            }
63
            else if (uppercase) {
64
                if (scancode < 0x10) {
65
                    letter = sc_shift_below[scancode];
66
                } else if (scancode >= 0x27 && scancode <= 0x2B) {
67
                    letter = sc_shift_middle[scancode - 0x27];
68
                } else if (scancode >= 0x33 && scancode <= 0x39) {
69
                    letter = sc_shift_above[scancode - 0x33];
70
                }
71
            }
72
            /* Remember that kprint only accepts char[] */
73
            char str[2] = {letter, '\0'};
74
            append(key_buffer, letter);
75
            print(str);
76
        }
77
    }
78
    UNUSED(regs);
79
}
80
81
void init_keyboard() {
82
   register_interrupt_handler(IRQ1, keyboard_callback);
83
}

+ 3 - 0
drivers/keyboard.h

@ -0,0 +1,3 @@
1
#include "../cpu/types.h"
2
3
void init_keyboard();

+ 180 - 0
drivers/screen.c

@ -0,0 +1,180 @@
1
#include "screen.h"
2
#include "../cpu/ports.h"
3
#include "../libc/mem.h"
4
#include "../util/font.h"
5
6
u32 VIDEO_ADDRESS = 0;
7
u8 COLOR_BYTES = 0;
8
u16 SCN_WIDTH;
9
u16 SCN_HEIGHT;
10
u16 SCN_PITCH;
11
12
/* Declaration of private functions */
13
int get_cursor_offset();
14
void set_cursor_offset(int offset);
15
int print_char(char c, int col, int row, char attr);
16
int get_offset(int col, int row);
17
int get_offset_row(int offset);
18
int get_offset_col(int offset);
19
20
/**********************************************************
21
 * Public Kernel API functions                            *
22
 **********************************************************/
23
24
/**
25
 * Print a message on the specified location
26
 * If col, row, are negative, we will use the current offset
27
 */
28
void kprint_at(char *message, int col, int row) {
29
    /* Set cursor if col/row are negative */
30
    int offset;
31
    if (col >= 0 && row >= 0)
32
        offset = get_offset(col, row);
33
    else {
34
        offset = get_cursor_offset();
35
        row = get_offset_row(offset);
36
        col = get_offset_col(offset);
37
    }
38
39
    /* Loop through message and print it */
40
    int i = 0;
41
    while (message[i] != 0) {
42
        offset = print_char(message[i++], col, row, WHITE_ON_BLACK);
43
        /* Compute row/col for next iteration */
44
        row = get_offset_row(offset);
45
        col = get_offset_col(offset);
46
    }
47
}
48
49
void kprint(char *message) {
50
    kprint_at(message, -1, -1);
51
}
52
53
void kprintln(char *message) {
54
    kprint(message);
55
    kprint("\n");
56
}
57
58
void kprint_backspace() {
59
    int offset = get_cursor_offset()-2;
60
    int row = get_offset_row(offset);
61
    int col = get_offset_col(offset);
62
    print_char(0x08, col, row, WHITE_ON_BLACK);
63
}
64
65
void putpixel(int x, int y, int r, int b, int g) {
66
    unsigned where = x*COLOR_BYTES + y*SCN_PITCH; //TODO: Should come from above function
67
    u8 *screen = (u8*) VIDEO_ADDRESS;
68
    screen[where] = b;              // BLUE
69
    screen[where + 1] = g;   // GREEN
70
    screen[where + 2] = r;  // RED
71
}
72
73
void fillrect(int x, int y, unsigned char r, unsigned char g, unsigned char b, int w, int h) {
74
    unsigned where = x*COLOR_BYTES + y*SCN_PITCH;
75
    u8 *screen = (u8*) VIDEO_ADDRESS;
76
    int i, j;
77
78
    for (i = 0; i < w; i++) {
79
        for (j = 0; j < h; j++) {
80
            screen[where + j*3] = b;
81
            screen[where + j*3 + 1] = g;
82
            screen[where + j*3 + 2] = r;
83
        }
84
        where += SCN_PITCH;
85
    }
86
}
87
88
/**********************************************************
89
 * Private kernel functions                               *
90
 **********************************************************/
91
92
93
/**
94
 * Innermost print function for our kernel, directly accesses the video memory
95
 *
96
 * If 'col' and 'row' are negative, we will print at current cursor location
97
 * If 'attr' is zero it will use 'white on black' as default
98
 * Returns the offset of the next character
99
 * Sets the video cursor to the returned offset
100
 */
101
102
int print_char(char c, int col, int row, char attr) {
103
    u8 *vidmem = (u8*) VIDEO_ADDRESS;
104
    if (!attr) attr = WHITE_ON_BLACK;
105
106
    /* Error control: print a red 'E' if the coords aren't right */
107
    if (col >= MAX_COLS || row >= MAX_ROWS) {
108
        vidmem[2*(MAX_COLS)*(MAX_ROWS)-2] = 'E';
109
        vidmem[2*(MAX_COLS)*(MAX_ROWS)-1] = RED_ON_WHITE;
110
        return get_offset(col, row);
111
    }
112
113
    int offset;
114
    if (col >= 0 && row >= 0) offset = get_offset(col, row);
115
    else offset = get_cursor_offset();
116
117
    if (c == '\n') {
118
        row = get_offset_row(offset);
119
        offset = get_offset(0, row+1);
120
    } else if (c == 0x08) { /* Backspace */
121
        vidmem[offset] = ' ';
122
        vidmem[offset+1] = attr;
123
    } else {
124
        vidmem[offset] = c;
125
        vidmem[offset+1] = attr;
126
        offset += 2;
127
    }
128
129
    /* Check if the offset is over screen size and scroll */
130
    if (offset >= MAX_ROWS * MAX_COLS * 2) {
131
        int i;
132
        for (i = 1; i < MAX_ROWS; i++)
133
            memory_copy((u8*)(get_offset(0, i) + VIDEO_ADDRESS),
134
                        (u8*)(get_offset(0, i-1) + VIDEO_ADDRESS),
135
                        MAX_COLS * 2);
136
137
        /* Blank last line */
138
        char *last_line = (char*) (get_offset(0, MAX_ROWS-1) + (u8*) VIDEO_ADDRESS);
139
        for (i = 0; i < MAX_COLS * 2; i++) last_line[i] = 0;
140
141
        offset -= 2 * MAX_COLS;
142
    }
143
144
    set_cursor_offset(offset);
145
    return offset;
146
}
147
148
int get_cursor_offset() {
149
    /* Use the VGA ports to get the current cursor position
150
     * 1. Ask for high byte of the cursor offset (data 14)
151
     * 2. Ask for low byte (data 15)
152
     */
153
    port_byte_out(REG_SCREEN_CTRL, 14);
154
    int offset = port_byte_in(REG_SCREEN_DATA) << 8; /* High byte: << 8 */
155
    port_byte_out(REG_SCREEN_CTRL, 15);
156
    offset += port_byte_in(REG_SCREEN_DATA);
157
    return offset * 2; /* Position * size of character cell */
158
}
159
160
void set_cursor_offset(int offset) {
161
    /* Similar to get_cursor_offset, but instead of reading we write data */
162
    offset /= 2;
163
    port_byte_out(REG_SCREEN_CTRL, 14);
164
    port_byte_out(REG_SCREEN_DATA, (u8)(offset >> 8));
165
    port_byte_out(REG_SCREEN_CTRL, 15);
166
    port_byte_out(REG_SCREEN_DATA, (u8)(offset & 0xff));
167
}
168
169
void setup_video() {
170
    struct vbe_mode_info_structure *vbe_info = (struct vbe_mode_info_structure *)0x900;
171
    VIDEO_ADDRESS = vbe_info->framebuffer;
172
    COLOR_BYTES = vbe_info->bpp / 8;
173
    SCN_WIDTH = vbe_info->width;
174
    SCN_HEIGHT = vbe_info->height;
175
    SCN_PITCH = vbe_info->pitch;
176
}
177
178
int get_offset(int col, int row) { return 2 * (row * MAX_COLS + col); }
179
int get_offset_row(int offset) { return offset / (2 * MAX_COLS); }
180
int get_offset_col(int offset) { return (offset - (get_offset_row(offset)*2*MAX_COLS))/2; }

+ 70 - 0
drivers/screen.h

@ -0,0 +1,70 @@
1
#ifndef SCREEN_H
2
#define SCREEN_H
3
4
#include "../cpu/types.h"
5
6
#define MAX_ROWS 25
7
#define MAX_COLS 80
8
#define WHITE_ON_BLACK 0x0f
9
#define RED_ON_WHITE 0xf4
10
11
/* Screen i/o ports */
12
#define REG_SCREEN_CTRL 0x3d4
13
#define REG_SCREEN_DATA 0x3d5
14
15
#define uint8 u8
16
#define uint16 u16
17
#define uint32 u32
18
//A struct
19
struct vbe_mode_info_structure {
20
	u16 attributes;		// deprecated, only bit 7 should be of interest to you, and it indicates the mode supports a linear frame buffer.
21
	uint8 window_a;			// deprecated
22
	uint8 window_b;			// deprecated
23
	uint16 granularity;		// deprecated; used while calculating bank numbers
24
	uint16 window_size;
25
	uint16 segment_a;
26
	uint16 segment_b;
27
	uint32 win_func_ptr;		// deprecated; used to switch banks from protected mode without returning to real mode
28
	uint16 pitch;			// number of bytes per horizontal line
29
	uint16 width;			// width in pixels
30
	uint16 height;			// height in pixels
31
	uint8 w_char;			// unused...
32
	uint8 y_char;			// ...
33
	uint8 planes;
34
	uint8 bpp;			// bits per pixel in this mode
35
	uint8 banks;			// deprecated; total number of banks in this mode
36
	uint8 memory_model;
37
	uint8 bank_size;		// deprecated; size of a bank, almost always 64 KB but may be 16 KB...
38
	uint8 image_pages;
39
	uint8 reserved0;
40
41
	uint8 red_mask;
42
	uint8 red_position;
43
	uint8 green_mask;
44
	uint8 green_position;
45
	uint8 blue_mask;
46
	uint8 blue_position;
47
	uint8 reserved_mask;
48
	uint8 reserved_position;
49
	uint8 direct_color_attributes;
50
51
	uint32 framebuffer;		// physical address of the linear frame buffer; write here to draw to the screen
52
	uint32 off_screen_mem_off;
53
	uint16 off_screen_mem_size;	// size of memory in the framebuffer but not being displayed on the screen
54
	uint8 reserved1[206];
55
} __attribute__ ((packed));
56
57
/* Public kernel API */
58
void kprint_at(char *message, int col, int row);
59
void kprint(char *message);
60
void kprintln(char *message);
61
void kprint_backspace();
62
void putpixel(int x, int y, int r, int g, int b); // 0-255 for each
63
void fillrect(int x, int y, unsigned char r, unsigned char g, unsigned char b, int w, int h);
64
void setup_video();
65
66
u8 COLOR_BYTES;
67
u16 SCN_WIDTH;
68
u16 SCN_HEIGHT;
69
70
#endif

+ 53 - 0
kernel/kernel.c

@ -0,0 +1,53 @@
1
#include "../cpu/isr.h"
2
#include "../drivers/screen.h"
3
#include "kernel.h"
4
#include "../libc/string.h"
5
#include "../programs/texteditor.h"
6
#include "../util/font.h"
7
#include "../util/terminal.h"
8
#include "../drivers/floppy.h"
9
10
void main() {
11
    isr_install();
12
    irq_install();
13
14
    setup_video();
15
16
    set_background(0, 100, 100);
17
    clear_screen();
18
19
    print_centered(SCN_WIDTH, 8, "_______ _________ _______           _______  _______  _______ ");
20
    print_centered(SCN_WIDTH, 16,"(  ____ \\\\__   __/(  ____ \\|\\     /|(  ____ \\(  ___  )(  ____ \\");
21
    print_centered(SCN_WIDTH, 24,"| (    \\/   ) (   | (    \\/| )   ( || (    \\/| (   ) || (    \\/");
22
    print_centered(SCN_WIDTH, 32, "| (_____    | |   | (__    | |   | || (__    | |   | || (_____ ");
23
    print_centered(SCN_WIDTH, 40, "(_____  )   | |   |  __)   ( (   ) )|  __)   | |   | |(_____  )");
24
    print_centered(SCN_WIDTH, 48, "      ) |   | |   | (       \\ \\_/ / | (      | |   | |      ) |");
25
    print_centered(SCN_WIDTH, 56, "/\\____) |   | |   | (____/\\  \\   /  | (____/\\| (___) |/\\____) |");
26
    print_centered(SCN_WIDTH, 64, "\\_______)   )_(   (_______/   \\_/   (_______/(_______)\\_______)");
27
    set_offset(0, 80);
28
29
    println("STEVEOS V0.0.2");
30
    println("WRITTEN BY STEPHEN DOWNWARD");
31
    println("TYPE \"HELP\" FOR HELP.");
32
    print("> ");
33
    //char bbp[5];
34
    //int_to_ascii(SCN_WIDTH, bbp);
35
    //print(bbp);
36
}
37
38
void user_input(char *input) {
39
    if (strcmp(input, "SHUTDOWN") == 0) {
40
        print("Stopping the CPU.\n");
41
        asm volatile("hlt");
42
    }
43
    else if (strcmp(input, "help") == 0) {
44
        println("not implemented");
45
    }
46
    else if (strcmp(input, "edit") == 0) {
47
        editor(); //Start the editor
48
    }
49
    else {
50
        println("Command not found.");
51
    }
52
    print("> ");
53
}

+ 6 - 0
kernel/kernel.h

@ -0,0 +1,6 @@
1
#ifndef KERNEL_H
2
#define KERNEL_H
3
4
void user_input(char *input);
5
6
#endif

+ 8 - 0
libc/function.h

@ -0,0 +1,8 @@
1
#ifndef FUNCTION_H
2
#define FUNCTION_H
3
4
/* Sometimes we want to keep parameters to a function for later use
5
 * and this is a solution to avoid the 'unused parameter' compiler warning */
6
#define UNUSED(x) (void)(x)
7
8
#endif

+ 13 - 0
libc/mem.c

@ -0,0 +1,13 @@
1
#include "mem.h"
2
3
void memory_copy(u8 *source, u8 *dest, int nbytes) {
4
    int i;
5
    for (i = 0; i < nbytes; i++) {
6
        *(dest + i) = *(source + i);
7
    }
8
}
9
10
void memory_set(u8 *dest, u8 val, u32 len) {
11
    u8 *temp = (u8 *)dest;
12
    for ( ; len != 0; len--) *temp++ = val;
13
}

+ 9 - 0
libc/mem.h

@ -0,0 +1,9 @@
1
#ifndef MEM_H
2
#define MEM_H
3
4
#include "../cpu/types.h"
5
6
void memory_copy(u8 *source, u8 *dest, int nbytes);
7
void memory_set(u8 *dest, u8 val, u32 len);
8
9
#endif

+ 59 - 0
libc/string.c

@ -0,0 +1,59 @@
1
#include "string.h"
2
3
/**
4
 * K&R implementation
5
 */
6
void int_to_ascii(int n, char str[]) {
7
    int i, sign;
8
    if ((sign = n) < 0) n = -n;
9
    i = 0;
10
    do {
11
        str[i++] = n % 10 + '0';
12
    } while ((n /= 10) > 0);
13
14
    if (sign < 0) str[i++] = '-';
15
    str[i] = '\0';
16
17
    reverse(str);
18
}
19
20
/* K&R */
21
void reverse(char s[]) {
22
    int c, i, j;
23
    for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
24
        c = s[i];
25
        s[i] = s[j];
26
        s[j] = c;
27
    }
28
}
29
30
/* K&R */
31
int strlen(char s[]) {
32
    int i = 0;
33
    while (s[i] != '\0') ++i;
34
    return i;
35
}
36
37
void append(char s[], char n) {
38
    int len = strlen(s);
39
    s[len] = n;
40
    s[len+1] = '\0';
41
}
42
43
void backspace(char s[]) {
44
    int len = strlen(s);
45
    s[len-1] = '\0';
46
}
47
48
/* K&R
49
 * Returns <0 if s1<s2, 0 if s1==s2, >0 if s1>s2 */
50
int strcmp(char s1[], char s2[]) {
51
    int i;
52
    for (i = 0; s1[i] == s2[i]; i++) {
53
        if (s1[i] == '\0') return 0;
54
    }
55
    return s1[i] - s2[i];
56
}
57
58
//New stuff
59

+ 11 - 0
libc/string.h

@ -0,0 +1,11 @@
1
#ifndef STRINGS_H
2
#define STRINGS_H
3
4
void int_to_ascii(int n, char str[]);
5
void reverse(char s[]);
6
int strlen(char s[]);
7
void backspace(char s[]);
8
void append(char s[], char n);
9
int strcmp(char s1[], char s2[]);
10
11
#endif

+ 10 - 0
makeiso.sh

@ -0,0 +1,10 @@
1
rm -rf flp
2
3
#Pad os-image.bin
4
dd if=/dev/null of=os-image.bin bs=1 count=0 seek=1474560
5
6
mkdir flp
7
cp os-image.bin flp/os-image.bin
8
9
#Generate iso
10
mkisofs -b os-image.bin -o steveos.iso flp

+ 31 - 0
programs/texteditor.c

@ -0,0 +1,31 @@
1
#include "texteditor.h"
2
#include "../util/terminal.h"
3
#include "../drivers/screen.h"
4
#include "../libc/string.h"
5
6
void gen_padding(char *menu) {
7
    kprint("=");
8
    for(u8 i = 0; i < strlen(menu); i++) {
9
        if (menu[i] != '|')
10
            print("=");
11
        else
12
            print("|");
13
    }
14
    println("=");
15
}
16
17
void gen_menu(char *menu) {
18
    gen_padding(menu);
19
    print("|");
20
    print(menu);
21
    println("|");
22
    gen_padding(menu);
23
}
24
25
void editor() {
26
    //Clear screen
27
    clear_screen();
28
29
    //Menu setup
30
    gen_menu("File|Edit");
31
}

+ 4 - 0
programs/texteditor.h

@ -0,0 +1,4 @@
1
#ifndef texteditor_h
2
#define texteditor_h
3
void editor();
4
#endif

+ 14 - 0
util/bitmap.c

@ -0,0 +1,14 @@
1
#include "bitmap.h"
2
3
struct bitmap {
4
    int height;
5
    int width;
6
    char *R, *B, *G;
7
};
8
9
/*bitmap get_Tux() {
10
    struct bitmap tux;
11
    tux.height = 860;
12
    tux.width = 712;
13
    *tux.R = ;
14
}*/

+ 0 - 0
util/bitmap.h


+ 109 - 0
util/font.c

@ -0,0 +1,109 @@
1
#include "font.h"
2
#include "../drivers/screen.h"
3
#include "../libc/string.h"
4
5
u16 characters[26 * 8 + 31 * 8 + 16*8] = {
6
    24,24,0,24,60,60,126,126,
7
    0,0,0,0,108,108,108,108,
8
    108,254,254,108,108,254,254,108,
9
    16,124,124,16,8,124,124,16,
10
    198,206,28,56,112,224,198,6,
11
    16,124,64,124,64,64,124,16,
12
    0,0,0,0,6,6,6,6,
13
    24,30,14,6,6,14,30,24,
14
    6,30,28,24,24,28,30,6,
15
    146,84,56,254,56,84,146,16,
16
    0,24,24,126,126,24,24,0,
17
    28,56,48,0,0,0,0,0,
18
    0,0,0,252,252,0,0,0,
19
    14,14,14,0,0,0,0,0,
20
    6,14,28,56,112,224,192,0,
21
    254,254,206,222,246,230,254,254,
22
    254,254,48,48,48,62,60,56,
23
    254,254,28,56,118,230,254,254,
24
    254,254,192,254,254,192,254,254,
25
    48,48,48,254,254,54,54,54,
26
    254,254,198,192,254,6,254,254,
27
    254,254,198,254,254,6,254,254,
28
    48,48,48,48,48,48,62,62,
29
    124,238,198,254,124,198,238,124,
30
    192,192,254,254,198,198,254,254,
31
    24,24,0,0,0,0,24,24,
32
    12,28,56,48,0,0,48,48,
33
    48,56,28,14,14,28,56,48,
34
    0,0,254,254,0,254,254,0,
35
    24,56,112,224,224,112,56,24,
36
    24,24,0,120,120,96,120,120,
37
    254,254,6,246,246,198,254,254,
38
    198,198,254,254,198,238,124,56,
39
    62,126,102,126,126,102,126,62,
40
    126,126,6,6,6,6,126,126,
41
    62,126,230,198,198,230,126,62,
42
    254,254,6,30,30,6,254,254,
43
    6,6,126,126,6,6,254,254,
44
    254,254,198,246,246,6,254,254,
45
    198,198,198,254,254,198,198,198,
46
    126,126,24,24,24,24,126,126,
47
    62,62,54,54,48,48,48,48,
48
    102,118,62,30,30,62,118,102,
49
    62,62,6,6,6,6,6,6,
50
    198,198,198,214,254,254,238,198,
51
    198,198,246,246,222,222,198,198,
52
    254,254,198,198,198,198,254,254,
53
    6,6,62,126,102,102,126,62,
54
    62,126,246,246,198,198,254,254,
55
    230,118,62,126,102,102,126,62,
56
    126,126,112,56,28,14,126,126,
57
    24,24,24,24,24,24,126,126,
58
    254,254,198,198,198,198,198,198,
59
    24,60,126,102,102,102,102,102,
60
    198,238,254,254,214,198,198,198,
61
    198,238,124,56,56,124,238,198,
62
    24,24,24,24,60,126,102,102,
63
    126,126,12,28,56,48,126,126,
64
    30,30,6,6,6,6,30,30,
65
    192,224,112,56,28,14,6,0,
66
    30,30,24,24,24,24,30,30,
67
    0,0,0,132,204,252,120,48,
68
    254,254,0,0,0,0,0,0,
69
    0,0,0,0,0,12,14,6,
70
    192,254,254,198,198,254,254,192,
71
    62,126,102,102,126,62,6,6,
72
    62,62,6,62,62,0,0,0,
73
    254,254,246,254,254,192,192,192,
74
    254,254,6,246,246,198,254,254,
75
    24,126,126,24,216,216,248,248,
76
    126,64,126,126,102,102,126,126,
77
    102,102,126,126,6,6,6,6,
78
    6,6,6,6,6,0,6,6
79
};
80
81
void draw_char(int x, int y, char c) {
82
    if (c >= 106) {
83
        c -= 32;
84
    }
85
    //We now know c is a letter we have. Subtract 65 to get a number we can use in the above array.
86
    c -= 33;
87
    for(int r = 0; r < 8; r++) {//Rows
88
        uint16 row = characters[c * 8 + r];
89
        for (int i = 0; i < 8; i++) {
90
            if (row&(1 << i)) {
91
                putpixel(x + i, y - r, 255, 255, 255); //TODO: CHANGE THIS
92
            }
93
        }
94
    }
95
}
96
97
void print_at(int x, int y, char *c) {
98
    int i = 0;
99
    while (c[i] != 0) {
100
        draw_char(x + i * 8, y, c[i]);
101
        i++;
102
    }
103
}
104
105
//X is where the middle character goes
106
void print_centered(int scn_width, int y, char *c) {
107
    int x_left = (scn_width - (strlen(c) * 8)) / 2;
108
    print_at(x_left, y, c);
109
}

+ 7 - 0
util/font.h

@ -0,0 +1,7 @@
1
#ifndef font
2
    #define font
3
    void draw_char(int x, int y, char c);
4
    void print_at(int x, int y, char *c);
5
    void print_centered(int scn_width, int y, char *c);
6
7
#endif

+ 63 - 0
util/terminal.c

@ -0,0 +1,63 @@
1
#include "terminal.h"
2
#include "font.h"
3
#include "../drivers/screen.h"