Initial commit
This commit is contained in:
commit
0fd6a3e0d3
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.bin
|
||||
*.dis
|
||||
*.o
|
||||
*.elf
|
||||
*/*.o
|
43
Makefile
Normal file
43
Makefile
Normal file
@ -0,0 +1,43 @@
|
||||
C_SOURCES = $(wildcard kernel/*.c drivers/*.c libc/*.c)
|
||||
HEADERS = $(wildcard kernel/*.h drivers/*.h libc/*.h)
|
||||
OBJ = ${C_SOURCES:.c=.o drivers/interrupt.o}
|
||||
|
||||
CC = /usr/local/bin/i386-elf-gcc
|
||||
GDB = /usr/local/bin/i386-elf-gdb
|
||||
CFLAGS = -g
|
||||
|
||||
# First rule is run by default
|
||||
os-image.bin: boot/boot.bin kernel.bin
|
||||
cat $^ > os-image.bin
|
||||
|
||||
# '--oformat binary' deletes all symbols as a collateral, so we don't need
|
||||
# to 'strip' them manually on this case
|
||||
kernel.bin: boot/kernel_entry.o ${OBJ}
|
||||
i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
|
||||
|
||||
# Used for debugging purposes
|
||||
kernel.elf: boot/kernel_entry.o ${OBJ}
|
||||
i386-elf-ld -o $@ -Ttext 0x1000 $^
|
||||
|
||||
run: os-image.bin
|
||||
qemu-system-i386 -fda os-image.bin
|
||||
|
||||
# Open the connection to qemu and load our kernel-object file with symbols
|
||||
debug: os-image.bin kernel.elf
|
||||
qemu-system-i386 -s -fda os-image.bin &
|
||||
${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"
|
||||
|
||||
# Generic rules for wildcards
|
||||
# To make an object, always compile from its .c
|
||||
%.o: %.c ${HEADERS}
|
||||
${CC} ${CFLAGS} -ffreestanding -c $< -o $@
|
||||
|
||||
%.o: %.asm
|
||||
nasm $< -f elf -o $@
|
||||
|
||||
%.bin: %.asm
|
||||
nasm $< -f bin -o $@
|
||||
|
||||
clean:
|
||||
rm -rf *.bin *.dis *.o os-image.bin *.elf
|
||||
rm -rf */*.o
|
57
bochsrc.txt
Normal file
57
bochsrc.txt
Normal file
@ -0,0 +1,57 @@
|
||||
# configuration file generated by Bochs
|
||||
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, iodebug=1
|
||||
config_interface: textconfig
|
||||
display_library: sdl2
|
||||
memory: host=32, guest=32
|
||||
romimage: file="/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest", address=0x0, options=none
|
||||
vgaromimage: file="/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest"
|
||||
boot: floppy
|
||||
floppy_bootsig_check: disabled=0
|
||||
floppya: type=1_44, 1_44="os-image.bin", status=inserted, write_protected=0
|
||||
# no floppyb
|
||||
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||
ata0-master: type=none
|
||||
ata0-slave: type=none
|
||||
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
|
||||
ata1-master: type=none
|
||||
ata1-slave: type=none
|
||||
ata2: enabled=0
|
||||
ata3: enabled=0
|
||||
optromimage1: file=none
|
||||
optromimage2: file=none
|
||||
optromimage3: file=none
|
||||
optromimage4: file=none
|
||||
optramimage1: file=none
|
||||
optramimage2: file=none
|
||||
optramimage3: file=none
|
||||
optramimage4: file=none
|
||||
pci: enabled=1, chipset=i440fx
|
||||
vga: extension=vbe, update_freq=5, realtime=1
|
||||
cpu: count=1:1:1, ips=4000000, quantum=16, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
|
||||
cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string=" Intel(R) Pentium(R) 4 CPU "
|
||||
cpuid: mmx=1, apic=xapic, simd=sse2, sse4a=0, misaligned_sse=0, sep=1, movbe=0, adx=0
|
||||
cpuid: aes=0, sha=0, xsave=0, xsaveopt=0, avx_f16c=0, avx_fma=0, bmi=0, xop=0, fma4=0
|
||||
cpuid: tbm=0, x86_64=1, 1g_pages=0, pcid=0, fsgsbase=0, smep=0, smap=0, mwait=1, vmx=1
|
||||
print_timestamps: enabled=0
|
||||
debugger_log: -
|
||||
magic_break: enabled=0
|
||||
port_e9_hack: enabled=0
|
||||
private_colormap: enabled=0
|
||||
clock: sync=none, time0=local, rtc_sync=0
|
||||
# no cmosimage
|
||||
# no loader
|
||||
log: -
|
||||
logprefix: %t%e%d
|
||||
debug: action=ignore
|
||||
info: action=report
|
||||
error: action=report
|
||||
panic: action=ask
|
||||
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
|
||||
mouse: type=ps2, enabled=0, toggle=ctrl+mbutton
|
||||
speaker: enabled=1, mode=gui
|
||||
parport1: enabled=1, file=none
|
||||
parport2: enabled=0
|
||||
com1: enabled=1, mode=null
|
||||
com2: enabled=0
|
||||
com3: enabled=0
|
||||
com4: enabled=0
|
57
boot/32bit-gdt.asm
Normal file
57
boot/32bit-gdt.asm
Normal file
@ -0,0 +1,57 @@
|
||||
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 kernel code segment. base = 0x00000000, length = 0xfffff
|
||||
; for flags, refer to os-dev.pdf document, page 36
|
||||
gdt_kern_code:
|
||||
dw 0x0000 ; 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 11000001b ; flags (4 bits) + segment length, bits 16-19
|
||||
db 0x0 ; segment base, bits 24-31
|
||||
|
||||
; GDT for kernel data segment. base and length identical to code segment
|
||||
; some flags changed, again, refer to os-dev.pdf
|
||||
gdt_kern_data:
|
||||
dw 0x0000
|
||||
dw 0x0
|
||||
db 0x0
|
||||
db 10010010b
|
||||
db 11000001b
|
||||
db 0x0
|
||||
|
||||
; GDT for user code segment. base = 0x01000000, length = 0xfffff
|
||||
; for flags, refer to os-dev.pdf document, page 36
|
||||
gdt_usr_code:
|
||||
dw 0xffff ; segment length, bits 0-15
|
||||
dw 0x0 ; segment base, bits 0-15
|
||||
db 0x0 ; segment base, bits 16-23
|
||||
db 11111010b ; flags (8 bits)
|
||||
db 11001111b ; flags (4 bits) + segment length, bits 16-19
|
||||
db 0x0 ; segment base, bits 24-31
|
||||
|
||||
; GDT for user data segment. base and length identical to code segment
|
||||
; some flags changed, again, refer to os-dev.pdf
|
||||
gdt_usr_data:
|
||||
dw 0xffff
|
||||
dw 0x0
|
||||
db 0x0
|
||||
db 11110010b
|
||||
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_kern_code - gdt_start
|
||||
DATA_SEG equ gdt_kern_data - gdt_start
|
||||
USR_CODE_SEG equ gdt_usr_code - gdt_start
|
||||
USR_DATA_SEG equ gdt_usr_data - gdt_start
|
21
boot/32bit-switch.asm
Normal file
21
boot/32bit-switch.asm
Normal file
@ -0,0 +1,21 @@
|
||||
[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
|
41
boot/boot.asm
Normal file
41
boot/boot.asm
Normal file
@ -0,0 +1,41 @@
|
||||
[org 0x7c00]
|
||||
KERNEL_OFFSET equ 0x1000 ; The same one we used when linking the kernel
|
||||
|
||||
mov [BOOT_DRIVE], dl ; Remember that the BIOS sets us the boot drive in 'dl' on boot
|
||||
mov bp, 0x9000
|
||||
mov sp, bp
|
||||
|
||||
|
||||
call load_kernel ; read the kernel from disk
|
||||
call switch_to_pm ; disable interrupts, load GDT, etc. Finally jumps to 'BEGIN_PM'
|
||||
jmp $ ; Never executed
|
||||
|
||||
%include "boot/print.asm"
|
||||
%include "boot/print_hex.asm"
|
||||
%include "boot/disk.asm"
|
||||
%include "boot/32bit-gdt.asm"
|
||||
%include "boot/32bit-switch.asm"
|
||||
|
||||
[bits 16]
|
||||
load_kernel:
|
||||
mov bx, MSG_LOAD_KERNEL
|
||||
call print
|
||||
call print_nl
|
||||
mov bx, KERNEL_OFFSET ; Read from disk and store in 0x1000
|
||||
mov dh, 20
|
||||
mov dl, [BOOT_DRIVE]
|
||||
call disk_load
|
||||
ret
|
||||
|
||||
[bits 32]
|
||||
BEGIN_PM:
|
||||
call KERNEL_OFFSET ; Give control to the kernel
|
||||
jmp $ ; Stay here when the kernel returns control to us (if ever)
|
||||
|
||||
|
||||
BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
|
||||
MSG_LOAD_KERNEL db "Loading kernel into memory", 0
|
||||
|
||||
; padding
|
||||
times 510 - ($-$$) db 0
|
||||
dw 0xaa55
|
46
boot/disk.asm
Executable file
46
boot/disk.asm
Executable file
@ -0,0 +1,46 @@
|
||||
; load 'dh' sectors from drive 'dl' into ES:BX
|
||||
disk_load:
|
||||
pusha
|
||||
; reading from disk requires setting specific values in all registers
|
||||
; so we will overwrite our input parameters from 'dx'. Let's save it
|
||||
; to the stack for later use.
|
||||
push dx
|
||||
|
||||
mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
|
||||
mov al, dh ; al <- number of sectors to read (0x01 .. 0x80)
|
||||
mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
|
||||
; 0x01 is our boot sector, 0x02 is the first 'available' sector
|
||||
mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
|
||||
; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
|
||||
; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
|
||||
mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)
|
||||
|
||||
; [es:bx] <- pointer to buffer where the data will be stored
|
||||
; caller sets it up for us, and it is actually the standard location for int 13h
|
||||
int 0x13 ; BIOS interrupt
|
||||
jc disk_error ; if error (stored in the carry bit)
|
||||
|
||||
pop dx
|
||||
cmp al, dh ; BIOS also sets 'al' to the # of sectors read. Compare it.
|
||||
jne sectors_error
|
||||
popa
|
||||
ret
|
||||
|
||||
|
||||
disk_error:
|
||||
mov bx, DISK_ERROR
|
||||
call print
|
||||
call print_nl
|
||||
mov dh, ah ; ah = error code, dl = disk drive that dropped the error
|
||||
call print_hex ; check out the code at http://stanislavs.org/helppc/int_13-1.html
|
||||
jmp disk_loop
|
||||
|
||||
sectors_error:
|
||||
mov bx, SECTORS_ERROR
|
||||
call print
|
||||
|
||||
disk_loop:
|
||||
jmp $
|
||||
|
||||
DISK_ERROR: db "Disk read error", 0
|
||||
SECTORS_ERROR: db "Incorrect number of sectors read", 0
|
4
boot/kernel_entry.asm
Normal file
4
boot/kernel_entry.asm
Normal 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
boot/print.asm
Executable file
37
boot/print.asm
Executable 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
boot/print_hex.asm
Executable file
46
boot/print_hex.asm
Executable 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
|
20
drivers/idt.c
Normal file
20
drivers/idt.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include "idt.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define low_16(address) (uint16_t)((address) & 0xFFFF)
|
||||
#define high_16(address) (uint16_t)(((address) >> 16) & 0xFFFF)
|
||||
|
||||
void set_idt_gate(int n,uint32_t 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=(uint32_t) &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
drivers/idt.h
Normal file
39
drivers/idt.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef IDT_H
|
||||
#define IDT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Segment selectors */
|
||||
#define KERNEL_CS 0x08
|
||||
|
||||
/* How every interrupt gate (handler) is defined */
|
||||
typedef struct {
|
||||
uint16_t low_offset; /* Lower 16 bits of handler function address */
|
||||
uint16_t sel; /* Kernel segment selector */
|
||||
uint8_t 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" */
|
||||
uint8_t flags;
|
||||
uint16_t 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 {
|
||||
uint16_t limit;
|
||||
uint32_t 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,uint32_t handler);
|
||||
void set_idt();
|
||||
|
||||
#endif
|
424
drivers/interrupt.asm
Normal file
424
drivers/interrupt.asm
Normal file
@ -0,0 +1,424 @@
|
||||
; 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
|
146
drivers/isr.c
Normal file
146
drivers/isr.c
Normal file
@ -0,0 +1,146 @@
|
||||
#include "isr.h"
|
||||
#include "idt.h"
|
||||
#include "vga.h"
|
||||
#include "../libc/string.h"
|
||||
#include <stdint.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,(uint32_t)isr0);
|
||||
set_idt_gate(1,(uint32_t)isr1);
|
||||
set_idt_gate(2,(uint32_t)isr2);
|
||||
set_idt_gate(3,(uint32_t)isr3);
|
||||
set_idt_gate(4,(uint32_t)isr4);
|
||||
set_idt_gate(5,(uint32_t)isr5);
|
||||
set_idt_gate(6,(uint32_t)isr6);
|
||||
set_idt_gate(7,(uint32_t)isr7);
|
||||
set_idt_gate(8,(uint32_t)isr8);
|
||||
set_idt_gate(9,(uint32_t)isr9);
|
||||
set_idt_gate(10,(uint32_t)isr10);
|
||||
set_idt_gate(11,(uint32_t)isr11);
|
||||
set_idt_gate(12,(uint32_t)isr12);
|
||||
set_idt_gate(13,(uint32_t)isr13);
|
||||
set_idt_gate(14,(uint32_t)isr14);
|
||||
set_idt_gate(15,(uint32_t)isr15);
|
||||
set_idt_gate(16,(uint32_t)isr16);
|
||||
set_idt_gate(17,(uint32_t)isr17);
|
||||
set_idt_gate(18,(uint32_t)isr18);
|
||||
set_idt_gate(19,(uint32_t)isr19);
|
||||
set_idt_gate(20,(uint32_t)isr20);
|
||||
set_idt_gate(21,(uint32_t)isr21);
|
||||
set_idt_gate(22,(uint32_t)isr22);
|
||||
set_idt_gate(23,(uint32_t)isr23);
|
||||
set_idt_gate(24,(uint32_t)isr24);
|
||||
set_idt_gate(25,(uint32_t)isr25);
|
||||
set_idt_gate(26,(uint32_t)isr26);
|
||||
set_idt_gate(27,(uint32_t)isr27);
|
||||
set_idt_gate(28,(uint32_t)isr28);
|
||||
set_idt_gate(29,(uint32_t)isr29);
|
||||
set_idt_gate(30,(uint32_t)isr30);
|
||||
set_idt_gate(31,(uint32_t)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,(uint32_t)irq0);
|
||||
set_idt_gate(33,(uint32_t)irq1);
|
||||
set_idt_gate(34,(uint32_t)irq2);
|
||||
set_idt_gate(35,(uint32_t)irq3);
|
||||
set_idt_gate(36,(uint32_t)irq4);
|
||||
set_idt_gate(37,(uint32_t)irq5);
|
||||
set_idt_gate(38,(uint32_t)irq6);
|
||||
set_idt_gate(39,(uint32_t)irq7);
|
||||
set_idt_gate(40,(uint32_t)irq8);
|
||||
set_idt_gate(41,(uint32_t)irq9);
|
||||
set_idt_gate(42,(uint32_t)irq10);
|
||||
set_idt_gate(43,(uint32_t)irq11);
|
||||
set_idt_gate(44,(uint32_t)irq12);
|
||||
set_idt_gate(45,(uint32_t)irq13);
|
||||
set_idt_gate(46,(uint32_t)irq14);
|
||||
set_idt_gate(47,(uint32_t)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) {
|
||||
write_string("Received interrupt no ");
|
||||
char s[3];
|
||||
int_to_ascii(r.int_no, s);
|
||||
write_string(s);
|
||||
write_string(". (");
|
||||
write_string(exception_messages[r.int_no]);
|
||||
write_string(")\n");
|
||||
asm volatile("hlt");
|
||||
}
|
||||
|
||||
|
||||
void register_interrupt_handler(uint8_t 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);
|
||||
}
|
||||
}
|
88
drivers/isr.h
Normal file
88
drivers/isr.h
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef ISR_H
|
||||
#define ISR_H
|
||||
|
||||
#include <stdint.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 {
|
||||
uint32_t ds; /* Data segment selector */
|
||||
uint32_t edi,esi,ebp,esp,ebx,edx,ecx,eax; /* Pushed by pusha. */
|
||||
uint32_t int_no,err_code; /* Interrupt number and error code (if applicable) */
|
||||
uint32_t eip,cs,eflags,useresp,ss; /* Pushed by the processor automatically */
|
||||
} registers_t;
|
||||
|
||||
void isr_install();
|
||||
void isr_handler(registers_t r);
|
||||
|
||||
typedef void (*isr_t)(registers_t);
|
||||
void register_interrupt_handler(uint8_t n,isr_t handler);
|
||||
|
||||
#endif
|
19
drivers/ports.c
Normal file
19
drivers/ports.c
Normal file
@ -0,0 +1,19 @@
|
||||
unsigned char port_byte_in(unsigned short port) {
|
||||
unsigned char result;
|
||||
asm("in %%dx, %%al":"=a"(result):"d"(port));
|
||||
return result;
|
||||
}
|
||||
|
||||
void port_byte_out(unsigned short port,unsigned char data) {
|
||||
asm("out %%al, %%dx":: "a"(data),"d"(port));
|
||||
}
|
||||
|
||||
unsigned short port_word_in(unsigned short port) {
|
||||
unsigned short result;
|
||||
asm("in %%dx, %%ax":"=a"(result):"d"(port));
|
||||
return result;
|
||||
}
|
||||
|
||||
void port_word_out(unsigned short port,unsigned short data) {
|
||||
asm("out %%ax, %%dx":: "a" (data), "d" (port));
|
||||
}
|
9
drivers/ports.h
Normal file
9
drivers/ports.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef PORTS_H
|
||||
#define PORTS_H
|
||||
|
||||
unsigned char port_byte_in(unsigned short port);
|
||||
void port_byte_out(unsigned short port,unsigned char data);
|
||||
unsigned short port_word_in(unsigned short port);
|
||||
void port_word_out(unsigned short port,unsigned short data);
|
||||
|
||||
#endif
|
99
drivers/vga.c
Normal file
99
drivers/vga.c
Normal file
@ -0,0 +1,99 @@
|
||||
#include "ports.h"
|
||||
#include "vga.h"
|
||||
#include "../libc/memory.h"
|
||||
#define SCREEN_CTRL 0x3d4
|
||||
#define SCREEN_DATA 0x3d5
|
||||
#define VIDEO_MEMORY 0xb8000
|
||||
static char* video_memory;
|
||||
static char x;
|
||||
static char y;
|
||||
static char color;
|
||||
|
||||
|
||||
int get_cursor_offset();
|
||||
void set_cursor_offset(int offset);
|
||||
|
||||
int get_offset(int x,int y) {
|
||||
return 2*(y*VGA_WIDTH+x);
|
||||
}
|
||||
int get_offset_y(int offset) {
|
||||
return offset/(2*VGA_WIDTH);
|
||||
}
|
||||
|
||||
int get_offset_x(int offset) {
|
||||
return (offset-(get_offset_y(offset)*2*VGA_WIDTH))/2;
|
||||
}
|
||||
|
||||
void init_vga(VGA_COLOR txt,VGA_COLOR bg) {
|
||||
video_memory=(char*)VIDEO_MEMORY;
|
||||
x=0;
|
||||
y=0;
|
||||
color=(int)bg;
|
||||
color=color<<4;
|
||||
color=color|txt;
|
||||
clear_screen();
|
||||
}
|
||||
|
||||
void write_string(const char *string) {
|
||||
char c;
|
||||
while(*string!=0) {
|
||||
c=*string;
|
||||
string++;
|
||||
if (c=='\n') {
|
||||
x=0;
|
||||
y++;
|
||||
continue;
|
||||
}
|
||||
if (x==80) {
|
||||
x=0;
|
||||
y++;
|
||||
}
|
||||
if (y==25) {
|
||||
for (int i=1;i<VGA_HEIGHT;i++) {
|
||||
memory_copy(get_offset(0,i)+VIDEO_MEMORY,get_offset(0,i-1)+VIDEO_MEMORY,VGA_WIDTH*2);
|
||||
}
|
||||
char *last_line=get_offset(0,VGA_HEIGHT-1)+VIDEO_MEMORY;
|
||||
for(int i=0;i<VGA_WIDTH*2;i++) {
|
||||
last_line[i]=0;
|
||||
}
|
||||
y-=2;
|
||||
}
|
||||
video_memory[get_offset(x,y)]=c;
|
||||
video_memory[get_offset(x,y)+1]=color;
|
||||
x++;
|
||||
set_cursor_offset(get_offset(x,y));
|
||||
}
|
||||
}
|
||||
|
||||
void clear_screen() {
|
||||
int x=0;
|
||||
int y=0;
|
||||
while (y<25) {
|
||||
video_memory[get_offset(x,y)]=' ';
|
||||
video_memory[get_offset(x,y)]=BLACK;
|
||||
x++;
|
||||
if(x==80) {
|
||||
x=0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
x=0;
|
||||
y=0;
|
||||
set_cursor_offset(0);
|
||||
}
|
||||
|
||||
int get_cursor_offset() {
|
||||
// port_byte_out(SCREEN_CTRL,14);
|
||||
// int offset=port_byte_in(SCREEN_DATA)<<8;
|
||||
// port_byte_out(SCREEN_CTRL,15);
|
||||
// offset+=port_byte_in(SCREEN_DATA);
|
||||
// return offset*2;
|
||||
}
|
||||
|
||||
void set_cursor_offset(int offset) {
|
||||
// offset/=2;
|
||||
// port_byte_out(SCREEN_CTRL,14);
|
||||
// port_byte_out(SCREEN_DATA,(unsigned char)(offset>>8));
|
||||
// port_byte_out(SCREEN_CTRL,15);
|
||||
// port_byte_out(SCREEN_DATA,(unsigned char)(offset&0xff));
|
||||
}
|
30
drivers/vga.h
Normal file
30
drivers/vga.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef VGA_H
|
||||
#define VGA_H
|
||||
|
||||
typedef enum {
|
||||
BLACK=0,
|
||||
BLUE=1,
|
||||
GREEN=2,
|
||||
CYAN=3,
|
||||
RED=4,
|
||||
PURPLE=5,
|
||||
BROWN=6,
|
||||
GRAY=7,
|
||||
DARK_GRAY=8,
|
||||
LIGHT_BLUE=9,
|
||||
LIGHT_GREEN=10,
|
||||
LIGHT_CYAN=11,
|
||||
LIGHT_RED=12,
|
||||
LIGHT_PURPLE=13,
|
||||
YELLOW=14,
|
||||
WHITE=15
|
||||
} VGA_COLOR;
|
||||
|
||||
#define VGA_WIDTH 80
|
||||
#define VGA_HEIGHT 25
|
||||
|
||||
void init_vga(VGA_COLOR txt,VGA_COLOR bg);
|
||||
void write_string(const char *string);
|
||||
void clear_screen();
|
||||
|
||||
#endif
|
37
kernel/kernel.c
Normal file
37
kernel/kernel.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include "../drivers/vga.h"
|
||||
#include "../drivers/isr.h"
|
||||
#include "../drivers/idt.h"
|
||||
/*
|
||||
pop %eax; \
|
||||
or $0x200,%eax; \
|
||||
push %eax; \
|
||||
*/
|
||||
void switch_to_user_mode() {
|
||||
// Set up a stack structure for switching to user mode.
|
||||
asm volatile(" \
|
||||
cli; \
|
||||
mov $0x23, %ax; \
|
||||
mov %ax, %ds; \
|
||||
mov %ax, %es; \
|
||||
mov %ax, %fs; \
|
||||
mov %ax, %gs; \
|
||||
mov %esp, %eax; \
|
||||
pushl $0x23; \
|
||||
pushl %eax; \
|
||||
pushf; \
|
||||
pushl $0x1B; \
|
||||
push $1f; \
|
||||
iret; \
|
||||
1: \
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
init_vga(GRAY,BLACK);
|
||||
write_string("Initialized VGA\n");
|
||||
isr_install();
|
||||
asm volatile("sti");
|
||||
write_string("Setup interrupts\n");
|
||||
switch_to_user_mode();
|
||||
}
|
6
libc/memory.c
Normal file
6
libc/memory.c
Normal file
@ -0,0 +1,6 @@
|
||||
void memory_copy(char *source,char *dest,int nbytes) {
|
||||
int i;
|
||||
for(i=0;i<nbytes;i++) {
|
||||
*(dest+i)=*(source+i);
|
||||
}
|
||||
}
|
6
libc/memory.h
Normal file
6
libc/memory.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
void memory_copy(char *source,char *dest,int nbytes);
|
||||
|
||||
#endif
|
34
libc/string.c
Normal file
34
libc/string.c
Normal file
@ -0,0 +1,34 @@
|
||||
int strlen(char* str) {
|
||||
int i;
|
||||
for (i=0;str[i]!='\0';i++) {
|
||||
continue;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void reverse(char* str) {
|
||||
char chr;
|
||||
int j;
|
||||
for (int i=0,j=strlen(str)-1;i<j;i++,j--) {
|
||||
chr=str[i];
|
||||
str[i]=str[j];
|
||||
str[j]=chr;
|
||||
}
|
||||
}
|
||||
|
||||
void int_to_ascii(int n,char* str) {
|
||||
int i;
|
||||
int 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);
|
||||
}
|
8
libc/string.h
Normal file
8
libc/string.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
|
||||
int strlen(char* str);
|
||||
void reverse(char* str);
|
||||
void int_to_ascii(int n,char* str);
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user