Browse Source

First

remotes/origin/commandhandler
Stephen Downward 2 years 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 View File

@@ -32,3 +32,10 @@
# Debug files
*.dSYM/

#Customs
flp
Other
*~
*.bin
*.o
*.iso

+ 48
- 0
Makefile View File

@@ -0,0 +1,48 @@
C_SOURCES = $(wildcard kernel/*.c drivers/*.c cpu/*.c libc/*.c programs/*.c util/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h cpu/*.h libc/*.h programs/*.h util/*.c)
# Nice syntax for file extension replacement
OBJ = ${C_SOURCES:.c=.o cpu/interrupt.o}

# Change this if your cross-compiler is somewhere else
CC = /home/stephen/opt/cross/bin/i686-elf-gcc
GDB = /home/stephen/opt/cross/bin/i686-elf-gdb
# -g: Use debugging symbols in gcc
CFLAGS = -g -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs \
-Wall -Wextra -Werror

# First rule is run by default
os-image.bin: boot/bootsect.bin boot/bootsect2.bin kernel.bin
cat $^ > os-image.bin
#Pad os-image.bin
dd if=/dev/null of=os-image.bin bs=1 count=0 seek=1474560
# '--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}
i686-elf-ld -o $@ -Ttext 0x1800 $^ --oformat binary

# Used for debugging purposes
kernel.elf: boot/kernel_entry.o ${OBJ}
i686-elf-ld -o $@ -Ttext 0x1800 $^

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 -d guest_errors,int &
${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 cpu/*.o libc/*.o

+ 26
- 0
boot/32bit_print.asm View File

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

+ 75
- 0
boot/bootsect.asm View File

@@ -0,0 +1,75 @@
[org 0x7c00]
[bits 16]
BOOTLOADER_OFFSET equ 0x1000 ; Second stage of bootloader

mov [BOOT_DRIVE], dl ; Remember that the BIOS sets us the boot drive in 'dl' on boot
mov bp, 0x9000
mov sp, bp

mov al, 0x0002
call load_bootloader ; read the kernel (and the rest of the bootloader) from disk
jmp BOOTLOADER_OFFSET
jmp $ ; Should never be called

%include "boot/disk.asm"
%include "boot/print.asm"
%include "boot/print_hex.asm"

load_bootloader:
pusha
mov bx, [CURRENT_MEM_LOAD] ; Read from disk and store into ax
mov dh, [HEAD_COUNT] ; dh <- head number (0x0 .. 0xF) //Redundant?
mov cl, al
mov al, 1 ;Num sectors
mov ch, [CYL_COUNT] ;Cylinder number
mov dl, [BOOT_DRIVE]
call disk_load
popa

;Increment CURRENT_MEM_LOAD
mov cx, [CURRENT_MEM_LOAD]
add cx, 0x200
mov [CURRENT_MEM_LOAD], cx


cmp al, 0x12 ; If al >= 0x11, increment cylinder 18 = 0x12
jge inc_head

mov ch, [CYL_COUNT]
cmp ch, 1
jge done_load

;Increment sector ID
inc al
jmp load_bootloader

inc_head:
mov dh, [HEAD_COUNT]
cmp dh, 1
jge inc_cyl
inc dh
mov [HEAD_COUNT], dh
mov al, 1
jmp load_bootloader

inc_cyl:
mov ch, [CYL_COUNT]
inc ch
mov [CYL_COUNT], ch
;Reset head count
mov dh, 0
mov [HEAD_COUNT], dh
;Reset sector count
mov al, 1
jmp load_bootloader

done_load:
ret;jmp BOOTLOADER_OFFSET ;ret

CYL_COUNT db 0
HEAD_COUNT db 0
CURRENT_MEM_LOAD dw 0x1000
BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
; padding
times 510 - ($-$$) db 0
dw 0xaa55

+ 59
- 0
boot/bootsect2.asm View File

@@ -0,0 +1,59 @@
[bits 16]
[org 0x1000]
KERNEL_OFFSET equ 0x1800
VBE_INFO equ 0x900

;TODO: What are these for?
;MOV AX, CS ; initialize
;MOV DS, AX ; segments
;MOV ES, AX ; correctly, ALWAYS gen

mov ax, 0x4F02 ;VBD mode
mov bx, 0x4118 ;1024x768x? TODO: Query BIOS to find out supported modes
int 0x10 ; switch to VGA 640x480
cmp ax, 0x004F ; test for error
jne error

;Get VBE mode
mov esi, 0
mov di, VBE_INFO
mov ax, 0x4f01
mov cx, 0x4118 ;Redundant for now
int 0x10
cmp ax, 0x004F ; test for error
jne error


mov bx, MSG_REAL_MODE
call print
call print_nl

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/gdt.asm"
%include "boot/32bit_print.asm"
%include "boot/switch_pm.asm"

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
MSG_RETURNED_KERNEL db "Returned from kernel. Error?", 0
MSG_VIDEO_ERROR db "VESA_ERR", 0

[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)

error:
mov ebx, MSG_VIDEO_ERROR
call print_string_pm
jmp $

times 2048 - ($-$$) db 0 ; This second stage can be up to 2KB, for now

+ 45
- 0
boot/disk.asm View File

@@ -0,0 +1,45 @@
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 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)

; [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
retry:
int 0x13 ; BIOS interrupt
jc disk_error ; if error (stored in the carry bit)

pop dx
cmp al, 1 ; 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
jmp retry ;Try again. Forever.

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

+ 35
- 0
boot/gdt.asm View File

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

+ 4
- 0
boot/kernel_entry.asm View File

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

+ 37
- 0
boot/print.asm View File

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

+ 46
- 0
boot/print_hex.asm View File

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

+ 22
- 0
boot/switch_pm.asm View File

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

+ 16
- 0
cpu/idt.c View File

@@ -0,0 +1,16 @@
#include "idt.h"

void set_idt_gate(int n, u32 handler) {
idt[n].low_offset = low_16(handler);
idt[n].sel = KERNEL_CS;
idt[n].always0 = 0;
idt[n].flags = 0x8E;
idt[n].high_offset = high_16(handler);
}

void set_idt() {
idt_reg.base = (u32) &idt;
idt_reg.limit = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
/* Don't make the mistake of loading &idt -- always load &idt_reg */
__asm__ __volatile__("lidtl (%0)" : : "r" (&idt_reg));
}

+ 39
- 0
cpu/idt.h View File

@@ -0,0 +1,39 @@
#ifndef IDT_H
#define IDT_H

#include "types.h"

/* Segment selectors */
#define KERNEL_CS 0x08

/* How every interrupt gate (handler) is defined */
typedef struct {
u16 low_offset; /* Lower 16 bits of handler function address */
u16 sel; /* Kernel segment selector */
u8 always0;
/* First byte
* Bit 7: "Interrupt is present"
* Bits 6-5: Privilege level of caller (0=kernel..3=user)
* Bit 4: Set to 0 for interrupt gates
* Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */
u8 flags;
u16 high_offset; /* Higher 16 bits of handler function address */
} __attribute__((packed)) idt_gate_t ;

/* A pointer to the array of interrupt handlers.
* Assembly instruction 'lidt' will read it */
typedef struct {
u16 limit;
u32 base;
} __attribute__((packed)) idt_register_t;

#define IDT_ENTRIES 256
idt_gate_t idt[IDT_ENTRIES];
idt_register_t idt_reg;


/* Functions implemented in idt.c */
void set_idt_gate(int n, u32 handler);
void set_idt();

#endif

+ 425
- 0
cpu/interrupt.asm View File

@@ -0,0 +1,425 @@
; Defined in isr.c
[extern isr_handler]
[extern irq_handler]

; Common ISR code
isr_common_stub:
; 1. Save CPU state
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; 2. Call C handler
call isr_handler
; 3. Restore state
pop eax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
popa
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
sti
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP

; Common IRQ code. Identical to ISR code except for the 'call'
; and the 'pop ebx'
irq_common_stub:
pusha
mov ax, ds
push eax
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call irq_handler ; Different than the ISR code
pop ebx ; Different than the ISR code
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popa
add esp, 8
sti
iret
; We don't get information about which interrupt was caller
; when the handler is run, so we will need to have a different handler
; for every interrupt.
; Furthermore, some interrupts push an error code onto the stack but others
; don't, so we will push a dummy error code for those which don't, so that
; we have a consistent stack for all of them.

; First make the ISRs global
global isr0
global isr1
global isr2
global isr3
global isr4
global isr5
global isr6
global isr7
global isr8
global isr9
global isr10
global isr11
global isr12
global isr13
global isr14
global isr15
global isr16
global isr17
global isr18
global isr19
global isr20
global isr21
global isr22
global isr23
global isr24
global isr25
global isr26
global isr27
global isr28
global isr29
global isr30
global isr31
; IRQs
global irq0
global irq1
global irq2
global irq3
global irq4
global irq5
global irq6
global irq7
global irq8
global irq9
global irq10
global irq11
global irq12
global irq13
global irq14
global irq15

; 0: Divide By Zero Exception
isr0:
cli
push byte 0
push byte 0
jmp isr_common_stub

; 1: Debug Exception
isr1:
cli
push byte 0
push byte 1
jmp isr_common_stub

; 2: Non Maskable Interrupt Exception
isr2:
cli
push byte 0
push byte 2
jmp isr_common_stub

; 3: Int 3 Exception
isr3:
cli
push byte 0
push byte 3
jmp isr_common_stub

; 4: INTO Exception
isr4:
cli
push byte 0
push byte 4
jmp isr_common_stub

; 5: Out of Bounds Exception
isr5:
cli
push byte 0
push byte 5
jmp isr_common_stub

; 6: Invalid Opcode Exception
isr6:
cli
push byte 0
push byte 6
jmp isr_common_stub

; 7: Coprocessor Not Available Exception
isr7:
cli
push byte 0
push byte 7
jmp isr_common_stub

; 8: Double Fault Exception (With Error Code!)
isr8:
cli
push byte 8
jmp isr_common_stub

; 9: Coprocessor Segment Overrun Exception
isr9:
cli
push byte 0
push byte 9
jmp isr_common_stub

; 10: Bad TSS Exception (With Error Code!)
isr10:
cli
push byte 10
jmp isr_common_stub

; 11: Segment Not Present Exception (With Error Code!)
isr11:
cli
push byte 11
jmp isr_common_stub

; 12: Stack Fault Exception (With Error Code!)
isr12:
cli
push byte 12
jmp isr_common_stub

; 13: General Protection Fault Exception (With Error Code!)
isr13:
cli
push byte 13
jmp isr_common_stub

; 14: Page Fault Exception (With Error Code!)
isr14:
cli
push byte 14
jmp isr_common_stub

; 15: Reserved Exception
isr15:
cli
push byte 0
push byte 15
jmp isr_common_stub

; 16: Floating Point Exception
isr16:
cli
push byte 0
push byte 16
jmp isr_common_stub

; 17: Alignment Check Exception
isr17:
cli
push byte 0
push byte 17
jmp isr_common_stub

; 18: Machine Check Exception
isr18:
cli
push byte 0
push byte 18
jmp isr_common_stub

; 19: Reserved
isr19:
cli
push byte 0
push byte 19
jmp isr_common_stub

; 20: Reserved
isr20:
cli
push byte 0
push byte 20
jmp isr_common_stub

; 21: Reserved
isr21:
cli
push byte 0
push byte 21
jmp isr_common_stub

; 22: Reserved
isr22:
cli
push byte 0
push byte 22
jmp isr_common_stub

; 23: Reserved
isr23:
cli
push byte 0
push byte 23
jmp isr_common_stub

; 24: Reserved
isr24:
cli
push byte 0
push byte 24
jmp isr_common_stub

; 25: Reserved
isr25:
cli
push byte 0
push byte 25
jmp isr_common_stub

; 26: Reserved
isr26:
cli
push byte 0
push byte 26
jmp isr_common_stub

; 27: Reserved
isr27:
cli
push byte 0
push byte 27
jmp isr_common_stub

; 28: Reserved
isr28:
cli
push byte 0
push byte 28
jmp isr_common_stub

; 29: Reserved
isr29:
cli
push byte 0
push byte 29
jmp isr_common_stub

; 30: Reserved
isr30:
cli
push byte 0
push byte 30
jmp isr_common_stub

; 31: Reserved
isr31:
cli
push byte 0
push byte 31
jmp isr_common_stub

; IRQ handlers
irq0:
cli
push byte 0
push byte 32
jmp irq_common_stub

irq1:
cli
push byte 1
push byte 33
jmp irq_common_stub

irq2:
cli
push byte 2
push byte 34
jmp irq_common_stub

irq3:
cli
push byte 3
push byte 35
jmp irq_common_stub

irq4:
cli
push byte 4
push byte 36
jmp irq_common_stub

irq5:
cli
push byte 5
push byte 37
jmp irq_common_stub

irq6:
cli
push byte 6
push byte 38
jmp irq_common_stub

irq7:
cli
push byte 7
push byte 39
jmp irq_common_stub

irq8:
cli
push byte 8
push byte 40
jmp irq_common_stub

irq9:
cli
push byte 9
push byte 41
jmp irq_common_stub

irq10:
cli
push byte 10
push byte 42
jmp irq_common_stub

irq11:
cli
push byte 11
push byte 43
jmp irq_common_stub

irq12:
cli
push byte 12
push byte 44
jmp irq_common_stub

irq13:
cli
push byte 13
push byte 45
jmp irq_common_stub

irq14:
cli
push byte 14
push byte 46
jmp irq_common_stub

irq15:
cli
push byte 15
push byte 47
jmp irq_common_stub


+ 153
- 0
cpu/isr.c View File

@@ -0,0 +1,153 @@
#include "isr.h"
#include "idt.h"
#include "../drivers/screen.h"
#include "../drivers/keyboard.h"
#include "../libc/string.h"
#include "timer.h"
#include "ports.h"

isr_t interrupt_handlers[256];

/* Can't do this with a loop because we need the address
* of the function names */
void isr_install() {
set_idt_gate(0, (u32)isr0);
set_idt_gate(1, (u32)isr1);
set_idt_gate(2, (u32)isr2);
set_idt_gate(3, (u32)isr3);
set_idt_gate(4, (u32)isr4);
set_idt_gate(5, (u32)isr5);
set_idt_gate(6, (u32)isr6);
set_idt_gate(7, (u32)isr7);
set_idt_gate(8, (u32)isr8);
set_idt_gate(9, (u32)isr9);
set_idt_gate(10, (u32)isr10);
set_idt_gate(11, (u32)isr11);
set_idt_gate(12, (u32)isr12);
set_idt_gate(13, (u32)isr13);
set_idt_gate(14, (u32)isr14);
set_idt_gate(15, (u32)isr15);
set_idt_gate(16, (u32)isr16);
set_idt_gate(17, (u32)isr17);
set_idt_gate(18, (u32)isr18);
set_idt_gate(19, (u32)isr19);
set_idt_gate(20, (u32)isr20);
set_idt_gate(21, (u32)isr21);
set_idt_gate(22, (u32)isr22);
set_idt_gate(23, (u32)isr23);
set_idt_gate(24, (u32)isr24);
set_idt_gate(25, (u32)isr25);
set_idt_gate(26, (u32)isr26);
set_idt_gate(27, (u32)isr27);
set_idt_gate(28, (u32)isr28);
set_idt_gate(29, (u32)isr29);
set_idt_gate(30, (u32)isr30);
set_idt_gate(31, (u32)isr31);

// Remap the PIC
port_byte_out(0x20, 0x11);
port_byte_out(0xA0, 0x11);
port_byte_out(0x21, 0x20);
port_byte_out(0xA1, 0x28);
port_byte_out(0x21, 0x04);
port_byte_out(0xA1, 0x02);
port_byte_out(0x21, 0x01);
port_byte_out(0xA1, 0x01);
port_byte_out(0x21, 0x0);
port_byte_out(0xA1, 0x0);

// Install the IRQs
set_idt_gate(32, (u32)irq0);
set_idt_gate(33, (u32)irq1);
set_idt_gate(34, (u32)irq2);
set_idt_gate(35, (u32)irq3);
set_idt_gate(36, (u32)irq4);
set_idt_gate(37, (u32)irq5);
set_idt_gate(38, (u32)irq6);
set_idt_gate(39, (u32)irq7);
set_idt_gate(40, (u32)irq8);
set_idt_gate(41, (u32)irq9);
set_idt_gate(42, (u32)irq10);
set_idt_gate(43, (u32)irq11);
set_idt_gate(44, (u32)irq12);
set_idt_gate(45, (u32)irq13);
set_idt_gate(46, (u32)irq14);
set_idt_gate(47, (u32)irq15);

set_idt(); // Load with ASM
}

/* To print the message which defines every exception */
char *exception_messages[] = {
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",

"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",

"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",

"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};

void isr_handler(registers_t r) {
kprint("received interrupt: ");
char s[3];
int_to_ascii(r.int_no, s);
kprint(s);
kprint("\n");
kprint(exception_messages[r.int_no]);
kprint("\n");
}

void register_interrupt_handler(u8 n, isr_t handler) {
interrupt_handlers[n] = handler;
}

void irq_handler(registers_t r) {
/* After every interrupt we need to send an EOI to the PICs
* or they will not send another interrupt again */
if (r.int_no >= 40) port_byte_out(0xA0, 0x20); /* slave */
port_byte_out(0x20, 0x20); /* master */

/* Handle the interrupt in a more modular way */
if (interrupt_handlers[r.int_no] != 0) {
isr_t handler = interrupt_handlers[r.int_no];
handler(r);
}
}

void irq_install() {
/* Enable interruptions */
asm volatile("sti");
/* IRQ0: timer */
init_timer(50);
/* IRQ1: keyboard */
init_keyboard();
}

+ 89
- 0
cpu/isr.h View File

@@ -0,0 +1,89 @@
#ifndef ISR_H
#define ISR_H

#include "types.h"

/* ISRs reserved for CPU exceptions */
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();
/* IRQ definitions */
extern void irq0();
extern void irq1();
extern void irq2();
extern void irq3();
extern void irq4();
extern void irq5();
extern void irq6();
extern void irq7();
extern void irq8();
extern void irq9();
extern void irq10();
extern void irq11();
extern void irq12();
extern void irq13();
extern void irq14();
extern void irq15();

#define IRQ0 32
#define IRQ1 33
#define IRQ2 34
#define IRQ3 35
#define IRQ4 36
#define IRQ5 37
#define IRQ6 38
#define IRQ7 39
#define IRQ8 40
#define IRQ9 41
#define IRQ10 42
#define IRQ11 43
#define IRQ12 44
#define IRQ13 45
#define IRQ14 46
#define IRQ15 47

/* Struct which aggregates many registers */
typedef struct {
u32 ds; /* Data segment selector */
u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
u32 int_no, err_code; /* Interrupt number and error code (if applicable) */
u32 eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */
} registers_t;

void isr_install();
void isr_handler(registers_t r);
void irq_install();

typedef void (*isr_t)(registers_t);
void register_interrupt_handler(u8 n, isr_t handler);

#endif

+ 37
- 0
cpu/ports.c View File

@@ -0,0 +1,37 @@
#include "ports.h"

/**
* Read a byte from the specified port
*/
u8 port_byte_in (u16 port) {
u8 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 (u16 port, u8 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__ __volatile__("out %%al, %%dx" : : "a" (data), "d" (port));
}

u16 port_word_in (u16 port) {
u16 result;
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
return result;
}

void port_word_out (u16 port, u16 data) {
__asm__ __volatile__("out %%ax, %%dx" : : "a" (data), "d" (port));
}

+ 11
- 0
cpu/ports.h View File

@@ -0,0 +1,11 @@
#ifndef PORTS_H
#define PORTS_H

#include "../cpu/types.h"

unsigned char port_byte_in (u16 port);
void port_byte_out (u16 port, u8 data);
unsigned short port_word_in (u16 port);
void port_word_out (u16 port, u16 data);

#endif

+ 26
- 0
cpu/timer.c View File

@@ -0,0 +1,26 @@
#include "timer.h"
#include "isr.h"
#include "ports.h"
#include "../libc/function.h"

u32 tick = 0;

static void timer_callback(registers_t regs) {
tick++;
UNUSED(regs);
}

void init_timer(u32 freq) {
/* Install the function we just wrote */
register_interrupt_handler(IRQ0, timer_callback);

/* Get the PIT value: hardware clock at 1193180 Hz */
u32 divisor = 1193180 / freq;
u8 low = (u8)(divisor & 0xFF);
u8 high = (u8)( (divisor >> 8) & 0xFF);
/* Send the command */
port_byte_out(0x43, 0x36); /* Command port */
port_byte_out(0x40, low);
port_byte_out(0x40, high);
}


+ 8
- 0
cpu/timer.h View File

@@ -0,0 +1,8 @@
#ifndef TIMER_H
#define TIMER_H

#include "types.h"

void init_timer(u32 freq);

#endif

+ 16
- 0
cpu/types.h View File

@@ -0,0 +1,16 @@
#ifndef TYPES_H
#define TYPES_H

/* Instead of using 'chars' to allocate non-character bytes,
* we will use these new type with no semantic meaning */
typedef unsigned int u32;
typedef int s32;
typedef unsigned short u16;
typedef short s16;
typedef unsigned char u8;
typedef char s8;

#define low_16(address) (u16)((address) & 0xFFFF)
#define high_16(address) (u16)(((address) >> 16) & 0xFFFF)

#endif

+ 10
- 0
drivers/floppy.c View File

@@ -0,0 +1,10 @@
#include "floppy.h"
#include "../cpu/ports.h"

// Obviously you'd have this return the data, start drivers or something.
int floppy_detect_drives() {

port_byte_out(0x70, 0x10);
return port_word_in(0x71);

}

+ 17
- 0
drivers/floppy.h View File

@@ -0,0 +1,17 @@
#ifndef floppy
#define floppy

/*static const char * drive_types[8] = {
"none",
"360kB 5.25\"",
"1.2MB 5.25\"",
"720kB 3.5\"",

"1.44MB 3.5\"",
"2.88MB 3.5\"",
"unknown type",
"unknown type"
};*/

int floppy_detect_drives();
#endif

+ 83
- 0
drivers/keyboard.c View File

@@ -0,0 +1,83 @@
#include "keyboard.h"
#include "../cpu/ports.h"
#include "../cpu/isr.h"
#include "screen.h"
#include "../libc/string.h"
#include "../libc/function.h"
#include "../kernel/kernel.h"
#include "../util/terminal.h"

#define BACKSPACE 0x0E
#define ENTER 0x1C
#define LSHIFT 0x2A
#define RSHIFT 0x36

static char key_buffer[256];
static u8 uppercase = 0;

#define SC_MAX 57
const char *sc_name[] = { "ERROR", "Esc", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "0", "-", "=", "Backspace", "Tab", "Q", "W", "E",
"R", "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Lctrl",
"A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "`",
"LShift", "\\", "Z", "X", "C", "V", "B", "N", "M", ",", ".",
"/", "RShift", "Keypad *", "LAlt", "Spacebar"};
const char sc_ascii[] = { '?', '?', '1', '2', '3', '4', '5', '6',
'7', '8', '9', '0', '-', '=', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y',
'U', 'I', 'O', 'P', '[', ']', '?', '?', 'A', 'S', 'D', 'F', 'G',
'H', 'J', 'K', 'L', ';', '\'', '`', '?', '\\', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', ',', '.', '/', '?', '*', '?', ' '};

const char sc_shift_below[] = { '?', '?', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '?', '?'};
const char sc_shift_middle[] = { ':', '"', '~', '?', '|'}; //0x27 to 0x2B
const char sc_shift_above[] = { '<', '>', '?', '?', '*', '?', ' '}; //0x33 to 0x39

static void keyboard_callback(registers_t regs) {
/* The PIC leaves us the scancode in port 0x60 */
u8 scancode = port_byte_in(0x60);

if (scancode > SC_MAX) { //Key being released
scancode -= 0x80; //Difference between release code and press code
if (scancode == LSHIFT || scancode == RSHIFT)
{
uppercase = 0;
}
}
else {
if (scancode == LSHIFT || scancode == RSHIFT) {
uppercase = 1;
} else if (scancode == BACKSPACE) {
if (strlen(key_buffer) > 0) {
backspace(key_buffer);
delete_last();
}
} else if (scancode == ENTER) {
newline();
user_input(key_buffer); /* kernel-controlled function */
key_buffer[0] = '\0';
} else {
char letter = sc_ascii[(int)scancode];
if (letter > 65 && letter < 90) {
letter += 32 * !uppercase; //Remove 32 from letter(make it lower case) if uppercase is false
}
else if (uppercase) {
if (scancode < 0x10) {
letter = sc_shift_below[scancode];
} else if (scancode >= 0x27 && scancode <= 0x2B) {
letter = sc_shift_middle[scancode - 0x27];
} else if (scancode >= 0x33 && scancode <= 0x39) {
letter = sc_shift_above[scancode - 0x33];
}
}
/* Remember that kprint only accepts char[] */
char str[2] = {letter, '\0'};
append(key_buffer, letter);
print(str);
}
}
UNUSED(regs);
}

void init_keyboard() {
register_interrupt_handler(IRQ1, keyboard_callback);
}

+ 3
- 0
drivers/keyboard.h View File

@@ -0,0 +1,3 @@
#include "../cpu/types.h"

void init_keyboard();

+ 180
- 0
drivers/screen.c View File

@@ -0,0 +1,180 @@
#include "screen.h"
#include "../cpu/ports.h"
#include "../libc/mem.h"
#include "../util/font.h"

u32 VIDEO_ADDRESS = 0;
u8 COLOR_BYTES = 0;
u16 SCN_WIDTH;
u16 SCN_HEIGHT;
u16 SCN_PITCH;

/* Declaration of private functions */
int get_cursor_offset();
void set_cursor_offset(int offset);
int print_char(char c, int col, int row, char attr);
int get_offset(int col, int row);
int get_offset_row(int offset);
int get_offset_col(int offset);

/**********************************************************
* Public Kernel API functions *
**********************************************************/

/**
* Print a message on the specified location
* If col, row, are negative, we will use the current offset
*/
void kprint_at(char *message, int col, int row) {
/* Set cursor if col/row are negative */
int offset;
if (col >= 0 && row >= 0)
offset = get_offset(col, row);
else {
offset = get_cursor_offset();
row = get_offset_row(offset);
col = get_offset_col(offset);
}

/* Loop through message and print it */
int i = 0;
while (message[i] != 0) {
offset = print_char(message[i++], col, row, WHITE_ON_BLACK);
/* Compute row/col for next iteration */
row = get_offset_row(offset);
col = get_offset_col(offset);
}
}

void kprint(char *message) {
kprint_at(message, -1, -1);
}

void kprintln(char *message) {
kprint(message);
kprint("\n");
}

void kprint_backspace() {
int offset = get_cursor_offset()-2;
int row = get_offset_row(offset);
int col = get_offset_col(offset);
print_char(0x08, col, row, WHITE_ON_BLACK);
}

void putpixel(int x, int y, int r, int b, int g) {
unsigned where = x*COLOR_BYTES + y*SCN_PITCH; //TODO: Should come from above function
u8 *screen = (u8*) VIDEO_ADDRESS;
screen[where] = b; // BLUE
screen[where + 1] = g; // GREEN
screen[where + 2] = r; // RED
}

void fillrect(int x, int y, unsigned char r, unsigned char g, unsigned char b, int w, int h) {
unsigned where = x*COLOR_BYTES + y*SCN_PITCH;
u8 *screen = (u8*) VIDEO_ADDRESS;
int i, j;

for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
screen[where + j*3] = b;
screen[where + j*3 + 1] = g;
screen[where + j*3 + 2] = r;
}
where += SCN_PITCH;
}
}

/**********************************************************
* Private kernel functions *
**********************************************************/


/**
* Innermost print function for our kernel, directly accesses the video memory
*
* If 'col' and 'row' are negative, we will print at current cursor location
* If 'attr' is zero it will use 'white on black' as default
* Returns the offset of the next character
* Sets the video cursor to the returned offset
*/

int print_char(char c, int col, int row, char attr) {
u8 *vidmem = (u8*) VIDEO_ADDRESS;
if (!attr) attr = WHITE_ON_BLACK;

/* Error control: print a red 'E' if the coords aren't right */
if (col >= MAX_COLS || row >= MAX_ROWS) {
vidmem[2*(MAX_COLS)*(MAX_ROWS)-2] = 'E';
vidmem[2*(MAX_COLS)*(MAX_ROWS)-1] = RED_ON_WHITE;
return get_offset(col, row);
}

int offset;
if (col >= 0 && row >= 0) offset = get_offset(col, row);
else offset = get_cursor_offset();

if (c == '\n') {
row = get_offset_row(offset);
offset = get_offset(0, row+1);
} else if (c == 0x08) { /* Backspace */
vidmem[offset] = ' ';
vidmem[offset+1] = attr;
} else {
vidmem[offset] = c;
vidmem[offset+1] = attr;
offset += 2;
}

/* Check if the offset is over screen size and scroll */
if (offset >= MAX_ROWS * MAX_COLS * 2) {
int i;
for (i = 1; i < MAX_ROWS; i++)
memory_copy((u8*)(get_offset(0, i) + VIDEO_ADDRESS),
(u8*)(get_offset(0, i-1) + VIDEO_ADDRESS),
MAX_COLS * 2);

/* Blank last line */
char *last_line = (char*) (get_offset(0, MAX_ROWS-1) + (u8*) VIDEO_ADDRESS);
for (i = 0; i < MAX_COLS * 2; i++) last_line[i] = 0;

offset -= 2 * MAX_COLS;
}

set_cursor_offset(offset);
return offset;
}

int get_cursor_offset() {
/* Use the VGA ports to get the current cursor position
* 1. Ask for high byte of the cursor offset (data 14)
* 2. Ask for low byte (data 15)
*/
port_byte_out(REG_SCREEN_CTRL, 14);
int offset = port_byte_in(REG_SCREEN_DATA) << 8; /* High byte: << 8 */
port_byte_out(REG_SCREEN_CTRL, 15);
offset += port_byte_in(REG_SCREEN_DATA);
return offset * 2; /* Position * size of character cell */
}

void set_cursor_offset(int offset) {
/* Similar to get_cursor_offset, but instead of reading we write data */
offset /= 2;
port_byte_out(REG_SCREEN_CTRL, 14);
port_byte_out(REG_SCREEN_DATA, (u8)(offset >> 8));
port_byte_out(REG_SCREEN_CTRL, 15);
port_byte_out(REG_SCREEN_DATA, (u8)(offset & 0xff));
}

void setup_video() {
struct vbe_mode_info_structure *vbe_info = (struct vbe_mode_info_structure *)0x900;
VIDEO_ADDRESS = vbe_info->framebuffer;
COLOR_BYTES = vbe_info->bpp / 8;
SCN_WIDTH = vbe_info->width;
SCN_HEIGHT = vbe_info->height;
SCN_PITCH = vbe_info->pitch;
}

int get_offset(int col, int row) { return 2 * (row * MAX_COLS + col); }
int get_offset_row(int offset) { return offset / (2 * MAX_COLS); }
int get_offset_col(int offset) { return (offset - (get_offset_row(offset)*2*MAX_COLS))/2; }

+ 70
- 0
drivers/screen.h View File

@@ -0,0 +1,70 @@
#ifndef SCREEN_H
#define SCREEN_H

#include "../cpu/types.h"

#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

#define uint8 u8
#define uint16 u16
#define uint32 u32
//A struct
struct vbe_mode_info_structure {
u16 attributes; // deprecated, only bit 7 should be of interest to you, and it indicates the mode supports a linear frame buffer.
uint8 window_a; // deprecated
uint8 window_b; // deprecated
uint16 granularity; // deprecated; used while calculating bank numbers
uint16 window_size;
uint16 segment_a;
uint16 segment_b;
uint32 win_func_ptr; // deprecated; used to switch banks from protected mode without returning to real mode
uint16 pitch; // number of bytes per horizontal line
uint16 width; // width in pixels
uint16 height; // height in pixels
uint8 w_char; // unused...
uint8 y_char; // ...
uint8 planes;
uint8 bpp; // bits per pixel in this mode
uint8 banks; // deprecated; total number of banks in this mode
uint8 memory_model;
uint8 bank_size; // deprecated; size of a bank, almost always 64 KB but may be 16 KB...
uint8 image_pages;
uint8 reserved0;

uint8 red_mask;
uint8 red_position;
uint8 green_mask;
uint8 green_position;
uint8 blue_mask;
uint8 blue_position;
uint8 reserved_mask;
uint8 reserved_position;
uint8 direct_color_attributes;

uint32 framebuffer; // physical address of the linear frame buffer; write here to draw to the screen
uint32 off_screen_mem_off;
uint16 off_screen_mem_size; // size of memory in the framebuffer but not being displayed on the screen
uint8 reserved1[206];
} __attribute__ ((packed));

/* Public kernel API */
void kprint_at(char *message, int col, int row);
void kprint(char *message);
void kprintln(char *message);
void kprint_backspace();
void putpixel(int x, int y, int r, int g, int b); // 0-255 for each
void fillrect(int x, int y, unsigned char r, unsigned char g, unsigned char b, int w, int h);
void setup_video();

u8 COLOR_BYTES;
u16 SCN_WIDTH;
u16 SCN_HEIGHT;

#endif

+ 53
- 0
kernel/kernel.c View File

@@ -0,0 +1,53 @@
#include "../cpu/isr.h"
#include "../drivers/screen.h"
#include "kernel.h"
#include "../libc/string.h"
#include "../programs/texteditor.h"
#include "../util/font.h"
#include "../util/terminal.h"
#include "../drivers/floppy.h"

void main() {
isr_install();
irq_install();

setup_video();

set_background(0, 100, 100);
clear_screen();

print_centered(SCN_WIDTH, 8, "_______ _________ _______ _______ _______ _______ ");
print_centered(SCN_WIDTH, 16,"( ____ \\\\__ __/( ____ \\|\\ /|( ____ \\( ___ )( ____ \\");
print_centered(SCN_WIDTH, 24,"| ( \\/ ) ( | ( \\/| ) ( || ( \\/| ( ) || ( \\/");
print_centered(SCN_WIDTH, 32, "| (_____ | | | (__ | | | || (__ | | | || (_____ ");
print_centered(SCN_WIDTH, 40, "(_____ ) | | | __) ( ( ) )| __) | | | |(_____ )");
print_centered(SCN_WIDTH, 48, " ) | | | | ( \\ \\_/ / | ( | | | | ) |");
print_centered(SCN_WIDTH, 56, "/\\____) | | | | (____/\\ \\ / | (____/\\| (___) |/\\____) |");
print_centered(SCN_WIDTH, 64, "\\_______) )_( (_______/ \\_/ (_______/(_______)\\_______)");
set_offset(0, 80);

println("STEVEOS V0.0.2");
println("WRITTEN BY STEPHEN DOWNWARD");
println("TYPE \"HELP\" FOR HELP.");
print("> ");
//char bbp[5];
//int_to_ascii(SCN_WIDTH, bbp);
//print(bbp);
}

void user_input(char *input) {
if (strcmp(input, "SHUTDOWN") == 0) {
print("Stopping the CPU.\n");
asm volatile("hlt");
}
else if (strcmp(input, "help") == 0) {
println("not implemented");
}
else if (strcmp(input, "edit") == 0) {
editor(); //Start the editor
}
else {
println("Command not found.");
}
print("> ");
}

+ 6
- 0
kernel/kernel.h View File

@@ -0,0 +1,6 @@
#ifndef KERNEL_H
#define KERNEL_H

void user_input(char *input);

#endif

+ 8
- 0
libc/function.h View File

@@ -0,0 +1,8 @@
#ifndef FUNCTION_H
#define FUNCTION_H

/* Sometimes we want to keep parameters to a function for later use
* and this is a solution to avoid the 'unused parameter' compiler warning */
#define UNUSED(x) (void)(x)

#endif

+ 13
- 0
libc/mem.c View File

@@ -0,0 +1,13 @@
#include "mem.h"

void memory_copy(u8 *source, u8 *dest, int nbytes) {
int i;
for (i = 0; i < nbytes; i++) {
*(dest + i) = *(source + i);
}
}

void memory_set(u8 *dest, u8 val, u32 len) {
u8 *temp = (u8 *)dest;
for ( ; len != 0; len--) *temp++ = val;
}

+ 9
- 0
libc/mem.h View File

@@ -0,0 +1,9 @@
#ifndef MEM_H
#define MEM_H

#include "../cpu/types.h"

void memory_copy(u8 *source, u8 *dest, int nbytes);
void memory_set(u8 *dest, u8 val, u32 len);

#endif

+ 59
- 0
libc/string.c View File

@@ -0,0 +1,59 @@
#include "string.h"

/**
* K&R implementation
*/
void int_to_ascii(int n, char str[]) {
int i, sign;
if ((sign = n) < 0) n = -n;
i = 0;
do {
str[i++] = n % 10 + '0';
} while ((n /= 10) > 0);

if (sign < 0) str[i++] = '-';
str[i] = '\0';

reverse(str);
}

/* K&R */
void reverse(char s[]) {
int c, i, j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}

/* K&R */
int strlen(char s[]) {
int i = 0;
while (s[i] != '\0') ++i;
return i;
}

void append(char s[], char n) {
int len = strlen(s);
s[len] = n;
s[len+1] = '\0';
}

void backspace(char s[]) {
int len = strlen(s);
s[len-1] = '\0';
}

/* K&R
* Returns <0 if s1<s2, 0 if s1==s2, >0 if s1>s2 */
int strcmp(char s1[], char s2[]) {
int i;
for (i = 0; s1[i] == s2[i]; i++) {
if (s1[i] == '\0') return 0;
}
return s1[i] - s2[i];
}

//New stuff


+ 11
- 0
libc/string.h View File

@@ -0,0 +1,11 @@
#ifndef STRINGS_H
#define STRINGS_H

void int_to_ascii(int n, char str[]);
void reverse(char s[]);
int strlen(char s[]);
void backspace(char s[]);
void append(char s[], char n);
int strcmp(char s1[], char s2[]);

#endif

+ 10
- 0
makeiso.sh View File

@@ -0,0 +1,10 @@
rm -rf flp

#Pad os-image.bin
dd if=/dev/null of=os-image.bin bs=1 count=0 seek=1474560

mkdir flp
cp os-image.bin flp/os-image.bin

#Generate iso
mkisofs -b os-image.bin -o steveos.iso flp

+ 31
- 0
programs/texteditor.c View File

@@ -0,0 +1,31 @@
#include "texteditor.h"
#include "../util/terminal.h"
#include "../drivers/screen.h"
#include "../libc/string.h"

void gen_padding(char *menu) {
kprint("=");
for(u8 i = 0; i < strlen(menu); i++) {
if (menu[i] != '|')
print("=");
else
print("|");
}
println("=");
}

void gen_menu(char *menu) {
gen_padding(menu);
print("|");
print(menu);
println("|");
gen_padding(menu);
}

void editor() {
//Clear screen
clear_screen();

//Menu setup
gen_menu("File|Edit");
}

+ 4
- 0
programs/texteditor.h View File

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

+ 14
- 0
util/bitmap.c View File

@@ -0,0 +1,14 @@
#include "bitmap.h"

struct bitmap {
int height;
int width;
char *R, *B, *G;
};

/*bitmap get_Tux() {
struct bitmap tux;
tux.height = 860;
tux.width = 712;
*tux.R = ;
}*/

+ 0
- 0
util/bitmap.h View File


+ 109
- 0
util/font.c View File

@@ -0,0 +1,109 @@
#include "font.h"
#include "../drivers/screen.h"
#include "../libc/string.h"

u16 characters[26 * 8 + 31 * 8 + 16*8] = {
24,24,0,24,60,60,126,126,
0,0,0,0,108,108,108,108,
108,254,254,108,108,254,254,108,
16,124,124,16,8,124,124,16,
198,206,28,56,112,224,198,6,
16,124,64,124,64,64,124,16,
0,0,0,0,6,6,6,6,
24,30,14,6,6,14,30,24,
6,30,28,24,24,28,30,6,
146,84,56,254,56,84,146,16,
0,24,24,126,126,24,24,0,
28,56,48,0,0,0,0,0,
0,0,0,252,252,0,0,0,
14,14,14,0,0,0,0,0,
6,14,28,56,112,224,192,0,
254,254,206,222,246,230,254,254,
254,254,48,48,48,62,60,56,
254,254,28,56,118,230,254,254,
254,254,192,254,254,192,254,254,
48,48,48,254,254,54,54,54,
254,254,198,192,254,6,254,254,
254,254,198,254,254,6,254,254,
48,48,48,48,48,48,62,62,
124,238,198,254,124,198,238,124,
192,192,254,254,198,198,254,254,
24,24,0,0,0,0,24,24,
12,28,56,48,0,0,48,48,
48,56,28,14,14,28,56,48,
0,0,254,254,0,254,254,0,
24,56,112,224,224,112,56,24,
24,24,0,120,120,96,120,120,
254,254,6,246,246,198,254,254,
198,198,254,254,198,238,124,56,
62,126,102,126,126,102,126,62,
126,126,6,6,6,6,126,126,
62,126,230,198,198,230,126,62,
254,254,6,30,30,6,254,254,
6,6,126,126,6,6,254,254,
254,254,198,246,246,6,254,254,
198,198,198,254,254,198,198,198,
126,126,24,24,24,24,126,126,
62,62,54,54,48,48,48,48,
102,118,62,30,30,62,118,102,
62,62,6,6,6,6,6,6,
198,198,198,214,254,254,238,198,
198,198,246,246,222,222,198,198,
254,254,198,198,198,198,254,254,
6,6,62,126,102,102,126,62,
62,126,246,246,198,198,254,254,
230,118,62,126,102,102,126,62,
126,126,112,56,28,14,126,126,
24,24,24,24,24,24,126,126,
254,254,198,198,198,198,198,198,
24,60,126,102,102,102,102,102,
198,238,254,254,214,198,198,198,
198,238,124,56,56,124,238,198,
24,24,24,24,60,126,102,102,
126,126,12,28,56,48,126,126,
30,30,6,6,6,6,30,30,
192,224,112,56,28,14,6,0,
30,30,24,24,24,24,30,30,
0,0,0,132,204,252,120,48,
254,254,0,0,0,0,0,0,
0,0,0,0,0,12,14,6,
192,254,254,198,198,254,254,192,
62,126,102,102,126,62,6,6,
62,62,6,62,62,0,0,0,
254,254,246,254,254,192,192,192,
254,254,6,246,246,198,254,254,
24,126,126,24,216,216,248,248,
126,64,126,126,102,102,126,126,
102,102,126,126,6,6,6,6,
6,6,6,6,6,0,6,6
};

void draw_char(int x, int y, char c) {
if (c >= 106) {
c -= 32;
}
//We now know c is a letter we have. Subtract 65 to get a number we can use in the above array.
c -= 33;
for(int r = 0; r < 8; r++) {//Rows
uint16 row = characters[c * 8 + r];
for (int i = 0; i < 8; i++) {
if (row&(1 << i)) {
putpixel(x + i, y - r, 255, 255, 255); //TODO: CHANGE THIS
}
}
}
}

void print_at(int x, int y, char *c) {
int i = 0;
while (c[i] != 0) {
draw_char(x + i * 8, y, c[i]);
i++;
}
}

//X is where the middle character goes
void print_centered(int scn_width, int y, char *c) {
int x_left = (scn_width - (strlen(c) * 8)) / 2;
print_at(x_left, y, c);
}

+ 7
- 0
util/font.h View File

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

#endif

+ 63
- 0
util/terminal.c View File

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

int offset_x = 0;
int offset_y = 8; //Higher numbers really means lower on screen
int bg[3] = {0, 0, 0};

void newline() {
offset_x = 0;
offset_y += char_height;
}

void print(char *c) {
int i = 0;
while (c[i] != 0) {
if (c[i] >= 97 && c[i] <= 122) { //UPPERCASE because my lowercase font sucks
c[i] -= 32;
}
if (c[i] == '\n') {
newline();
} else {
if (offset_x + 8 > SCN_WIDTH) {
offset_x = 0;
offset_y += char_height;
}
draw_char(offset_x, offset_y, c[i]);
offset_x += 8;
}
i++;
}
}

void println(char *c) {
print(c);
newline();
}

void delete_last() {
offset_x -= 8;
if (offset_x < 0) {
offset_x = SCN_WIDTH - 8;
offset_y -= char_height;
}
fillrect(offset_x, offset_y - 7, 0, 100, 100, 8, char_height);
}

void clear_screen() {
fillrect(0, 0, bg[0], bg[1], bg[2], SCN_HEIGHT, SCN_WIDTH); //Background
offset_x = 0;
offset_y = 8;
}

void set_background(int r, int g, int b) {
bg[0] = r;
bg[1] = g;
bg[2] = b;
}

void set_offset(int x, int y) {
offset_x = x;
offset_y = y;
}

+ 15
- 0
util/terminal.h View File

@@ -0,0 +1,15 @@
#ifndef terminal

#define terminal

#define char_height 12

void print(char *c);
void println(char *c);
void newline();
void delete_last();
void clear_screen();
void set_background(int r, int g, int b);
void set_offset();

#endif

Loading…
Cancel
Save