summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrett Weiland <brett_weiland@bpcspace.com>2021-03-19 10:54:25 -0500
committerBrett Weiland <brett_weiland@bpcspace.com>2021-03-19 10:54:25 -0500
commit66289aa8ecfa07b20bad424eb9860b196641ef52 (patch)
tree9fb3915b5cb18d9f2c1f4648d3bf3fb56396509f /src
first commit
Diffstat (limited to 'src')
-rw-r--r--src/.gdb_history256
-rw-r--r--src/amd64_vol2.pdfbin0 -> 3511027 bytes
-rw-r--r--src/bootloader/bios_functions/bios_disk.asm38
-rw-r--r--src/bootloader/bios_functions/print.asm59
-rw-r--r--src/bootloader/bootloader.asm145
-rw-r--r--src/bootloader/cpu_check.asm100
-rw-r--r--src/bootloader/enter_kernel.asm80
-rw-r--r--src/bootloader/enter_kernel_backup87
-rw-r--r--src/bootloader/gdt.asm70
-rw-r--r--src/bootloader/multicore.asm10
-rw-r--r--src/bootloader/notes0
-rw-r--r--src/bootloader/video.asm179
-rw-r--r--src/debug/.gdb_history4
-rwxr-xr-xsrc/indigo_osbin0 -> 15312 bytes
-rw-r--r--src/kernel/include/acpi.h39
-rw-r--r--src/kernel/include/libc.h10
-rw-r--r--src/kernel/include/paging.h60
-rw-r--r--src/kernel/include/printf.h117
-rw-r--r--src/kernel/include/serial.h16
-rw-r--r--src/kernel/include/video.h49
-rw-r--r--src/kernel/kernel.c42
-rw-r--r--src/kernel/libs/acpi.c61
-rw-r--r--src/kernel/libs/drivers/serial.c43
-rw-r--r--src/kernel/libs/drivers/video.c6
-rw-r--r--src/kernel/libs/libc.c47
-rw-r--r--src/kernel/libs/page.c107
-rw-r--r--src/kernel/libs/printf.c924
-rw-r--r--src/kernel/libs/printf.h117
-rw-r--r--src/link.ld37
-rw-r--r--src/makefile53
30 files changed, 2756 insertions, 0 deletions
diff --git a/src/.gdb_history b/src/.gdb_history
new file mode 100644
index 0000000..f627526
--- /dev/null
+++ b/src/.gdb_history
@@ -0,0 +1,256 @@
+x 0x7FFE1667
+x 0x7FFE1667
+x 0x200000
+quit
+break main
+c
+next
+stepi
+next
+x 0x200000
+return
+next
+x 0x20000
+x 0x20000 4096
+dq 0x20000 (4096/8)
+dq 0x20000 1
+dq 0x20000 2
+dq 0x20000 3
+dq 0x200000 3
+print rsdp.v1->rsdp
+print rsdp->v1.rsdt_addr
+print (void*)rsdp->v1.rsdt_addr
+print (page table*)0x4000
+print (page_table*)0x4000
+print (page_table*)0x4000->pml4e
+print (page_table*)0x4000.pml4e
+print (page_table*)0x4000->pml4e
+print *(page_table*)0x4000->pml4e
+print (page_table*)0x4000.pml4e
+print (page_table*)0x4000.pml4e[0]
+print (page_table*)0x4000->pml4e[0]
+print (page_table*)0x4000.pml4e[0]
+print (page_table*)0x4000.pdpe
+print (page_table*)0x4000.pde
+print (page_table*)0x4000
+print *(page_table*)0x4000
+print *((page_table*)0x4000)
+print *((page_table*)0x4000).pde
+print *((page_table*)0x4000).pml4e
+print *((page_table*)0x3000).pml4e
+print *((page_table*)0x4000).pml4e
+print *((page_table*)0x4000).pde
+print *((page_table*)0x4000).pte
+print rsdp.v1.base_addr
+print rsdp.v1.rsdt_addr
+print (void*)rsdp.v1.rsdt_addr
+print *((page_table*)0x4000).pte
+print *((page_table*)0x4000).pte[1]
+print *((page_table*)0x4000).pte
+print *((page_table*)0x4000)->pte[1]
+print *((page_table*)0x4000).pte
+print *((page_table*)0x4000).pte[0]
+print ((page_table*)0x4000).pte
+print ((page_table*)0x4000)->pte
+print ((page_table*)0x4000)->pte[0]
+print ((page_table*)0x4000)->pte[1]
+print ((page_table*)0x4000)->pte[2]
+print ((page_table*)0x4000)->pte[3]
+print ((page_table*)0x4000)->pte[4]
+print ((page_table*)0x4000)->pte[5]
+print ((page_table*)0x4000)->pte[10]
+print ((page_table*)0x4000)->pte[1512]
+print ((page_table*)0x4000)->pte[512]
+print ((page_table*)0x4000)->pte[513]
+print ((page_table*)0x4000)->pte[512]
+print ((page_table*)0x4000)->pte[511]
+print ((page_table*)0x4000)->pte[510]
+print ((page_table*)0x4000)->pte
+quit
+break main
+c
+next
+print rsdp.v1.rsdt_addr
+print (void*)rsdp.v1.rsdt_addr
+quit
+break map_page
+c
+next
+print size
+next
+print table->pde[pde_i]
+next
+print table->pde[pde_i]
+next
+print table->pde[pde_i]
+next
+print table->pde[pde_i]
+print table->pte[pte_i]
+next
+print table->pte[pte_i]
+next
+x 0x20000
+dq 0x20000 30
+dq 0x20000 40
+print table->pte[pte_i]
+context
+quit
+break map_page
+c
+next
+print table->pte[pte_i0
+print table->pte[pte_i]
+quit
+r
+c
+quit
+c
+quit
+break panic
+c
+x 0x7ffe1000
+quit
+break panic
+c
+x 0x200000
+dq 0x200000
+dq 0x200000 4
+dq 0x200000 8
+search -4 FACP
+search -4 FACP
+search -4 'FACP'
+search -s 'FACP'
+search -s 'ACPI'
+search -s 'RSDT'
+x 0x200000 + 0x667
+dq 0x200000 + 0x667
+dq (0x200000 + 0x667)
+x 0x200000 + 0x667
+x/20i 0x200000 + 0x667
+x/20x 0x200000 + 0x667
+x/100x 0x200000 + 0x667
+x/400x 0x200000 + 0x667
+x/400x 0x200000 + 0x1000
+x/400x 0x200000 + (0x1000)
+x/400x 0x200000 + (0x1000-8)
+x/400x 0x200000 + (0x1000-8)
+quit
+break panic
+c
+x 0x2000
+x 0x20000
+x 0x200000
+x 0x2000000
+x 0x200000
+x 0x2000000
+x 0x200000
+x 0x202000
+x 0x20b000
+x 0x20b000+8
+x 0x20b000
+x 0x202000
+x 0x201000
+x 0x200000
+x 0x201000
+x 0x201000-8
+x 0x200000-8
+x 0x200000
+quit
+break panic
+c
+0x200000
+x 0x200000
+x/s 0x200000
+quit
+break panic
+c
+quit
+break panic
+c
+quit
+break panic
+c
+quit
+break panic
+c
+x 0x20000
+x 0x21667
+x 0x20667
+x 0x200000
+x 0x200667
+x 0x200667
+x/s 0x200667
+quit
+break panic
+c
+x apic
+quit
+break main
+c
+next
+pirnt apic
+print apic
+print rsdp
+print apic
+print *apic
+(struct apic_header *)((uint64_t)0x200000 + (rsdp->v1.rsdt_addr % 0x1000)
+print (struct apic_header *)((uint64_t)0x200000 + (rsdp->v1.rsdt_addr % 0x1000)
+quit
+break panic
+c
+prit apic
+print apic
+print acpi
+print *acpi
+print acpi
+print acpi.sig
+quit
+break main
+c
+next
+print apic
+ptype apic_header
+quit
+ptype acpi
+ptype acpi_header
+break main
+c
+next
+print apic
+print acpi
+print acpi.*
+context
+print apic
+quit
+break main
+c
+next
+print apic
+print apci_header
+ptype apci_header
+ptype apci_header
+quit
+break main
+c
+next
+print acpi
+next
+print acpi
+quit
+print acpi
+break main
+c
+print acpi
+next
+print acpi
+next
+print acpi
+next
+print acpi
+next
+print acpi
+ptype acpi_header
+quit
+quit
+quit
+quit
diff --git a/src/amd64_vol2.pdf b/src/amd64_vol2.pdf
new file mode 100644
index 0000000..edcafc6
--- /dev/null
+++ b/src/amd64_vol2.pdf
Binary files differ
diff --git a/src/bootloader/bios_functions/bios_disk.asm b/src/bootloader/bios_functions/bios_disk.asm
new file mode 100644
index 0000000..28fc74d
--- /dev/null
+++ b/src/bootloader/bios_functions/bios_disk.asm
@@ -0,0 +1,38 @@
+bios_disk:
+.load_sectors:
+pusha
+mov es, dx
+
+mov ah, 0x02 ; read disc sectors
+mov ch, 0x00 ; track 0
+mov dh, 0x00 ; head 0
+mov dl, [stage0.boot_device]
+
+int 0x13
+
+jc .failed
+
+mov ah, 0
+popa
+ret
+
+.failed:
+
+mov bx, .loadsectors_error
+mov cx, 0
+call bios_print
+
+push 0
+mov al, ah
+mov ah, 0 ; you need to clean up the bios print function!
+push ax
+mov cx, 1
+mov bx, sp
+call bios_print
+
+
+mov ah, 1
+popa
+ret
+
+.loadsectors_error: db "Error loading sectors: ", 0
diff --git a/src/bootloader/bios_functions/print.asm b/src/bootloader/bios_functions/print.asm
new file mode 100644
index 0000000..d071cd9
--- /dev/null
+++ b/src/bootloader/bios_functions/print.asm
@@ -0,0 +1,59 @@
+;TODO fix null problem, allow direct passes
+bios_print:
+;push ax ; we need to use ax, so let's push it in case whoever called needs it
+pusha
+mov ah, 0x0e ; tells bios we're in tty mode
+
+.print_loop:
+mov al, [bx] ; al is the char MEANT TO BE CX
+cmp al, 0 ; compare the char we're about to print with null
+je .fini ; if it is null, we gonna scoot the fuck outta here
+
+test cx, cx ; if cx is zero, ascii, otherwise hex string
+jne .print_hex
+int 0x10 ; bios call, actually prints the char
+.print_hex_ret:
+inc bx ; adds to the pointer
+jmp .print_loop ; goes back to loop start
+
+.fini:
+mov al, 0xd ; \r
+int 0x10
+mov al, 0xa ; \n
+int 0x10
+popa
+ret
+
+
+.print_hex:
+mov al, '0'
+int 0x10
+
+mov al, 'x'
+int 0x10
+
+mov al, [bx] ; shift bits to get first nibble
+shr al, 4
+call .bios_print_nibble
+
+mov al, [bx]
+and al, 0x0f
+call .bios_print_nibble
+
+mov al, ' '
+int 0x10
+
+jmp .print_hex_ret
+
+
+.bios_print_nibble:
+cmp al, 9 ; see if letter worthy
+ja .print_hex_letter
+add al, 0x30 ;'1'
+int 0x10
+ret
+
+.print_hex_letter:
+add al, 0x57 ;'a'
+int 0x10
+ret
diff --git a/src/bootloader/bootloader.asm b/src/bootloader/bootloader.asm
new file mode 100644
index 0000000..14116db
--- /dev/null
+++ b/src/bootloader/bootloader.asm
@@ -0,0 +1,145 @@
+[bits 16]
+[extern _kernel_size]
+[extern _bootloader_stage1_size]
+[extern _kernel_loc]
+
+;TODO clean up unreal mode
+jmp stage0
+times 3-($-$$) db 0x90 ; a temporary dirty fix to emulate a floppy disk insted of a hard risk
+times 59 db 0 ; (TODO support hard disks)
+
+stage0:
+
+jmp 0:.entry
+.entry:
+
+mov ax, 0
+mov ds, ax
+mov bp, ax
+
+mov ds, ax
+mov es, ax
+
+mov ax, 0x8fc0
+mov ss, ax
+mov ax, 0xfffe
+mov sp, ax
+
+mov al, 0x92
+or al, 2
+out 0x92, al
+
+mov [.boot_device], dl
+
+mov bx, .loadstage2_msg
+mov cx, 0
+call bios_print
+
+; TODO put in an error message and a maximum fail count
+.load_stage1:
+mov al, _bootloader_stage1_size
+mov cl, 0x2 ; read sector 2
+mov dx, 0x0 ; dest segment 0
+mov bx, 0x7e00 ; dest offst 0
+call bios_disk.load_sectors
+
+
+jmp mbr_end.entry
+
+.boot_device: db 0
+
+.loadstage2_msg: db "Loading (stage 2) bootloader...", 0
+
+%include "bootloader/bios_functions/bios_disk.asm"
+%include "bootloader/bios_functions/print.asm"
+
+times 510 - ($-$$) db 0
+dw 0xaa55
+
+%include "bootloader/gdt.asm"
+
+boot_msg:
+.debugmsg: db "debugeroni", 0
+.kernel_loaded: db `Kernel loaded!\r\nBooting to protected, then long mode...`, 0
+.stage2_loaded: db `Done loading bootloader!\r\nLoading kernel...`, 0
+
+
+
+
+mbr_end:
+.entry:
+; entering unreal mode
+mov bx, boot_msg.stage2_loaded
+mov cx, 0
+call bios_print
+
+
+cli
+push ds
+
+lgdt [protected_gdt.descriptor]
+
+mov eax, cr0
+or al, 1
+mov cr0, eax
+
+jmp $+2
+
+mov bx, 0x10 ; descriptor 2, the data descriptor
+mov ds, bx ; put it into the segment register
+mov es, bx ;
+
+and al, 0xfe
+mov cr0, eax
+
+pop ds
+sti
+;we are now in unreal mode
+
+mov cl, 5 ; starting sector TODO automate this
+mov edi, _kernel_loc
+.loop:
+mov al, 0x1 ; sector count
+mov dx, 0x0 ; dest addr segment
+mov bx, 0x500 ; dest addr offset
+call bios_disk.load_sectors
+
+
+inc cl
+
+push cx
+
+mov esi, 0x500
+mov ecx, 512
+a32 rep movsb
+nop
+
+mov bx, boot_msg.debugmsg
+mov cx, 0
+call bios_print
+
+pop cx
+
+cmp cl, _kernel_size
+je .loop_end
+
+jmp .loop
+
+.loop_end:
+
+mov bx, boot_msg.kernel_loaded
+mov cx, 0
+call bios_print
+
+
+call detect_arch
+call vbe_init
+done:
+
+call enter_longmode
+jmp $
+
+%include "bootloader/cpu_check.asm"
+%include "bootloader/video.asm"
+%include "bootloader/enter_kernel.asm"
+times 2048 - ($ - $$) db 0
diff --git a/src/bootloader/cpu_check.asm b/src/bootloader/cpu_check.asm
new file mode 100644
index 0000000..ffdd908
--- /dev/null
+++ b/src/bootloader/cpu_check.asm
@@ -0,0 +1,100 @@
+; TODO move this file to something like "system_check", now that we do ram checks here
+[extern _meminfo_loc]
+detect_arch:
+; todo: figure out how to just handle invalid opcode exceptions, it would be faster and (maybe?) easier
+; todo: digest this part a little better when it's _not_ 1am.
+pushfd ; pushes eflags to stack
+pushfd ; pushes eflags to stack a second time
+xor dword [esp], 0x00200000 ; inverses the ID bit to see if cpuid is a thing
+pop eax ;gets our modified cpuid back
+xor eax, [esp] ; checks with the first time we pushed it; the OG eflag
+popfd ; pops the flags back I guess?
+and eax, 0x00200000 ; checks to see if the bit was inverted
+jz .print_cpuid_error
+;now we detect if we support long slong (aka 64 bit)
+
+;https://www.amd.com/system/files/TechDocs/25481.pdf page 21
+;So apperently some dumbass engineers thought it would be funny to sell CPUs that have the long mode bit set without it being supported, dispite including it in their own documentation.
+;there's a work around by checking other bits, and it's a low priority TODO. However, I really think us coming accross this will be extremely rare.
+mov eax, 0x80000001
+cpuid ;cpuid returns into edx
+and edx, 0x0020000000 ; the 21st bit is cpuid.
+jz .print_long_error
+
+mov eax, 0x00000001
+cpuid
+and edx, 0x00000200
+jz .print_apic_error
+
+
+mov bx, .no_error
+mov cx, 0
+call bios_print
+
+
+;mapping memory
+mov ax, 0
+mov es, ax
+mov ax, _meminfo_loc
+mov di, ax
+
+mov eax, 0xe820
+mov ebx, 0
+mov ecx, 24
+mov edx, 0x534d4150
+int 0x15
+
+jc .print_mem_error
+cmp eax, 0x534D4150
+jne .print_mem_error
+
+.mem_detect_loop:
+add di, 24
+mov [di + 20], dword 1
+mov eax, 0xe820
+mov ecx, 24
+
+int 0x15
+jc .mem_detected
+cmp ebx, 0
+je .mem_detected
+jmp .mem_detect_loop
+.mem_detected:
+
+ret
+
+
+.print_cpuid_error:
+mov bx, .cpuid_error
+mov cx, 0
+call bios_print
+jmp $
+
+.print_long_error:
+mov bx, .arch_error ; lets just test for now
+mov cx, 0
+call bios_print
+jmp $
+
+.print_apic_error:
+mov bx, .apic_error
+mov cx, 0
+call bios_print
+
+.print_mem_error:
+mov bx, .mem_error
+mov cx, 0
+call bios_print
+
+
+.cpuid_error:
+ db "No CPUID capabilitity", 0x0
+.arch_error:
+ db "This operating system was compiled to run in 64 bit mode!", 0x0
+.apic_error:
+ db "No apic support", 0x0
+.mem_error:
+ db "Could not get information on memory!", 0x0
+.no_error:
+ db "CPU info gathered!", 0x0
+
diff --git a/src/bootloader/enter_kernel.asm b/src/bootloader/enter_kernel.asm
new file mode 100644
index 0000000..c9991e3
--- /dev/null
+++ b/src/bootloader/enter_kernel.asm
@@ -0,0 +1,80 @@
+[extern main]
+[extern _kernel_stack_loc]
+enter_longmode:
+cli
+
+; TODO check if a20 is already set
+mov al, 0x92
+or al, 2
+out 0x92, al
+
+lgdt [protected_gdt.descriptor]
+mov eax, cr0
+or eax, 0x1
+mov cr0, eax
+
+mov eax, 0x8
+mov ds, eax
+
+jmp 0x8:init_longmode
+
+bits 32
+init_longmode:
+mov ebp, 0xffff
+mov esp, ebp
+mov ax, PROTECTED_DATA_SEGMENT
+mov ds, ax
+mov ss, ax
+mov es, ax
+mov fs, ax
+mov gs, ax
+
+mov edi, 0x4000 ; 0x3000
+mov cr3, edi
+mov eax, 0
+mov ecx, 0xc00 ; 0x1000
+rep stosd
+mov edi, cr3
+
+
+mov DWORD [edi], 0x5003 ; pml4e[0] = pdpe
+add edi, 0x1000
+mov DWORD [edi], 0x6003 ; pdpe[0] = pde
+add edi, 0x1000
+mov DWORD [edi], 0x83 ; pde[0] = pte
+
+mov eax, cr4
+or eax, 1 << 5
+mov cr4, eax
+
+;end of setting up pages
+
+mov ecx, 0xc0000080
+rdmsr
+or eax, 1 << 8
+wrmsr
+
+mov eax, cr0
+or eax, 1 << 31 | 1 << 0 ; this is where we set paging and protected mode (respectively)!
+mov cr0, eax
+
+
+mov ecx, 0xc0000080
+rdmsr
+or eax, 1 << 8
+wrmsr
+
+mov eax, cr0
+or eax, 1 << 31
+mov cr0, eax
+
+lgdt [long_gdt.descriptor]
+
+jmp LONG_CODE_SEGMENT:enter_kernel
+enter_kernel:
+bits 64
+mov rbp, _kernel_stack_loc
+mov rsp, _kernel_stack_loc
+call main ; where we actually call the kernel
+jmp $
+ret
diff --git a/src/bootloader/enter_kernel_backup b/src/bootloader/enter_kernel_backup
new file mode 100644
index 0000000..7631f20
--- /dev/null
+++ b/src/bootloader/enter_kernel_backup
@@ -0,0 +1,87 @@
+[extern main]
+[extern _kernel_stack_loc]
+enter_longmode:
+cli
+
+; TODO check if a20 is already set
+mov al, 0x92
+or al, 2
+out 0x92, al
+
+lgdt [protected_gdt.descriptor]
+mov eax, cr0
+or eax, 0x1
+mov cr0, eax
+
+mov eax, 0x8
+mov ds, eax
+
+jmp 0x8:init_longmode
+
+bits 32
+init_longmode:
+mov ebp, 0xffff
+mov esp, ebp
+mov ax, PROTECTED_DATA_SEGMENT
+mov ds, ax
+mov ss, ax
+mov es, ax
+mov fs, ax
+mov gs, ax
+
+mov edi, 0x3000 ; this is where our page tables will be
+mov cr3, edi
+mov eax, 0 ; what we'll be putting there
+mov ecx, 4096 ; how many times we'll put it there
+rep stosd ; kinda like memset(&edi, ecx, edi)
+mov edi, cr3
+
+mov DWORD [edi], 0x4003 ; pml4e[0] = pdpe
+add edi, 0x1000
+mov DWORD [edi], 0x5003 ; pdpe[0] = pde
+add edi, 0x1000
+mov DWORD [edi], 0x6003 ; pde[0] = pte
+add edi, 0x1000
+
+mov ebx, 0x00000003 ; the flags
+mov ecx, 512; the loop counter, will map 2 mib
+
+.idmap_pte_loop:
+mov DWORD [edi], ebx
+add ebx, 0x1000 ; physical address. Should leave us at 0x7000
+add edi, 8 ; position in page table
+loop .idmap_pte_loop
+
+mov eax, cr4
+or eax, 1 << 5
+mov cr4, eax
+
+mov ecx, 0xc0000080
+rdmsr
+or eax, 1 << 8
+wrmsr
+
+mov eax, cr0
+or eax, 1 << 31 | 1 << 0 ; this is where we set paging and protected mode (respectively)!
+mov cr0, eax
+
+
+mov ecx, 0xc0000080
+rdmsr
+or eax, 1 << 8
+wrmsr
+
+mov eax, cr0
+or eax, 1 << 31
+mov cr0, eax
+
+lgdt [long_gdt.descriptor]
+
+jmp LONG_CODE_SEGMENT:enter_kernel
+enter_kernel:
+bits 64
+mov rbp, _kernel_stack_loc
+mov rsp, _kernel_stack_loc
+call main ; where we actually call the kernel
+jmp $
+ret
diff --git a/src/bootloader/gdt.asm b/src/bootloader/gdt.asm
new file mode 100644
index 0000000..d506cdf
--- /dev/null
+++ b/src/bootloader/gdt.asm
@@ -0,0 +1,70 @@
+protected_gdt:
+.gdt_start: ; we need to start with a null gdt
+dd 0
+dd 0
+
+.gdt_code:
+dw 0xffff
+dw 0x0000
+db 0x00
+db 10011010b
+db 11001111b
+db 0x0000
+
+
+.gdt_data:
+dw 0xffff
+dw 0x0000
+db 0x00
+db 10010010b
+db 11001111b
+db 0x0000
+
+.gdt_end:
+
+.descriptor:
+ dw .gdt_end - .gdt_start - 1
+dq .gdt_start
+
+PROTECTED_CODE_SEGMENT equ .gdt_code - .gdt_start
+PROTECTED_DATA_SEGMENT equ .gdt_data - .gdt_start
+
+
+long_gdt:
+.gdt_start:
+;and now we set up a temporary GDT creating a 1:1 mapping
+dw 0xffff
+dw 0
+db 0 ;this is the invalid GDT
+db 0
+db 1
+db 0
+
+;now for the code GDT:
+.gdt_code:
+dw 0 ; segment limit 15:00 (I don't think this matters in 64 bit mode!)
+dw 0 ; base address 15:00
+db 0 ; base address 23:16
+db 10011010b ;1st flags and type. The first four bits (1010) are type, and the last are flags. See https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf
+db 10101111b ;1111 is segment limit continued. 0: available, 0: 64 bit (change?), 1: 32 bit segment, 1: granularity (shifts 3 hex didgets to get all of memory)
+db 0
+
+; the data GDT is the exact same, and it overlaps. We don't care, we'll be booting into long mode right after then programming in C
+; TODO: clarify once you figure out what you're doing
+.gdt_data:
+dw 0
+dw 0
+db 0
+db 10010010b
+db 00000000b
+db 0
+
+.gdt_end: ; later calculates offset in defs below
+
+
+.descriptor:
+ dw .gdt_end - .gdt_start - 1
+dq .gdt_start
+
+LONG_CODE_SEGMENT equ .gdt_code - .gdt_start
+LONG_DATA_SEGMENT equ .gdt_data - .gdt_start
diff --git a/src/bootloader/multicore.asm b/src/bootloader/multicore.asm
new file mode 100644
index 0000000..fa33ea5
--- /dev/null
+++ b/src/bootloader/multicore.asm
@@ -0,0 +1,10 @@
+multicore_boot:
+jmp $
+
+mov ecx, 0x0000001b
+rdmsr
+;mov [apic_register] dx:ax
+
+apic_register: dq 0
+multicore_msg1: db "CPUs available: ", 0
+
diff --git a/src/bootloader/notes b/src/bootloader/notes
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/bootloader/notes
diff --git a/src/bootloader/video.asm b/src/bootloader/video.asm
new file mode 100644
index 0000000..5b292c2
--- /dev/null
+++ b/src/bootloader/video.asm
@@ -0,0 +1,179 @@
+[extern _vbe_infoblock]
+vbe_init:
+.init_video:
+;getting edid
+
+mov ax, 0
+mov es, ax
+mov di, 0x500
+
+mov ax, 0x4f15
+mov bx, 0x1
+mov cx, 0
+mov dx, 0
+
+int 0x10
+
+cmp al, 0x4f
+jne .vbe_unsupported
+cmp ah, 0x00
+jne .edid_error
+
+
+mov ah, [0x500+58]
+shr ah, 4
+mov al, [0x500+56]
+push ax
+
+mov ah, [0x500+61]
+shr ah, 4
+mov al, [0x500+59]
+push ax
+
+mov al, BYTE [0x500+20]
+test al, 0x80
+jz .res_unsupported ; uses an analog signal
+
+shr al, 4
+and al, 7
+
+.cdp_6:
+cmp al, 0b001
+jne .cdp_8
+mov ax, 18
+jmp .colordepth_found
+
+.cdp_8:
+cmp al, 0b010
+jne .cdp_10
+mov ax, 24
+jmp .colordepth_found
+
+.cdp_10:
+cmp al, 0b011
+jne .cdp_12
+mov ax, 30
+jmp .colordepth_found
+
+.cdp_12:
+cmp al, 0b100
+jne .cdp_14
+mov ax, 36
+jmp .colordepth_found
+
+.cdp_14:
+cmp al, 0b101
+jne .cdp_16
+mov ax, 42
+jmp .colordepth_found
+
+.cdp_16:
+cmp al, 0b110
+jne .cdp_undefined
+mov ax, 48
+jmp .colordepth_found
+
+.cdp_undefined:
+mov ax, 24
+; TODO print warning, this only happens when we can't find bitdepth
+
+.colordepth_found:
+push ax
+
+
+
+
+; _______________________________________________________________________________________________________
+
+; When we get things sorted out, some time you should come back here and find a good resolution that isn't
+; native as a fallback.
+; Maybe redo this part in C?
+
+;getting available modes
+mov ax, 0
+mov es, ax
+mov ax, 0x500
+mov di, ax
+
+;get vbe capabilities
+mov ax, 0x4f00
+int 0x10
+cmp ax, 0x4f
+jne .vbe_generic_error
+cmp DWORD [0x500], "VESA"
+jne .vbe_generic_error
+
+; now we loop through the modes
+mov ebx, [0x500+14] ; pointer to modes
+mov di, 0x600
+mov ax, 0
+mov es, ax
+.mode_loop:
+mov ax, 0x4f01
+mov cx, [ebx]
+cmp cx, 0xffff
+je .res_unsupported
+
+int 0x10
+
+mov ax, [esp]
+cmp al, BYTE [0x600+25] ; might be wrong
+jne .mode_loop_next
+
+; width (1920)
+mov ax, [esp+4]
+cmp ax, [0x600+18]
+jne .mode_loop_next
+
+; height
+mov ax, [esp+2]
+cmp ax, [0x600+20]
+jne .mode_loop_next
+
+
+
+jmp .mode_found
+
+.mode_loop_next:
+add ebx, 2
+jmp .mode_loop
+
+.mode_found:
+mov ax, 0x4f02
+mov bx, cx
+int 0x10
+;getting rid of stack
+pop ax
+pop ax
+pop ax
+ret
+; ________________________________________________________________________________________________________
+
+.vbe_unsupported:
+mov bx, .unsupported_msg
+mov cx, 0
+call bios_print
+jmp $
+
+.vbe_generic_error:
+mov bx, .lazyerror_msg
+mov cx, 0
+call bios_print
+jmp $
+
+.edid_error:
+mov bx, .ediderror_msg
+mov cx, 0
+call bios_print
+jmp $
+
+.res_unsupported:
+mov bx, .res_unsupported_msg
+mov cx, 0
+call bios_print
+jmp $
+
+.unsupported_msg: db "Your BIOS doesn't support VESA. It's probably time to get a new computer!", 0
+.lazyerror_msg: db "A VESA error has occured.", 0
+.ediderror_msg: db "EDID error", 0
+.res_unsupported_msg: db "Native resolution not supported!", 0
diff --git a/src/debug/.gdb_history b/src/debug/.gdb_history
new file mode 100644
index 0000000..e513052
--- /dev/null
+++ b/src/debug/.gdb_history
@@ -0,0 +1,4 @@
+quit
+quit
+c
+quit
diff --git a/src/indigo_os b/src/indigo_os
new file mode 100755
index 0000000..b1d65ea
--- /dev/null
+++ b/src/indigo_os
Binary files differ
diff --git a/src/kernel/include/acpi.h b/src/kernel/include/acpi.h
new file mode 100644
index 0000000..c15e044
--- /dev/null
+++ b/src/kernel/include/acpi.h
@@ -0,0 +1,39 @@
+#include <stdint.h>
+#include <libc.h>
+
+struct rsdp_v1 {
+ char sig[8];
+ uint8_t checksum;
+ char OEMID[6];
+ uint8_t version;
+ uint32_t rsdt_addr;
+
+} __attribute__((packed));
+
+struct rsdp_v2 {
+ struct rsdp_v1 v1;
+ uint32_t len;
+ uint64_t xsdt_addr;
+ uint8_t extended_checksum;
+ uint8_t reserved[3];
+} __attribute__((packed));
+
+
+typedef union rsdp_t {
+ struct rsdp_v1 v1;
+ struct rsdp_v2 v2;
+} rsdp_t;
+
+struct acpi_header {
+ char sig[4];
+ uint32_t length;
+ uint8_t revision;
+ uint8_t checksum;
+ char OEMID[6];
+ char OEMTableID[8];
+ uint32_t OEMRevision;
+ uint32_t creator_id;
+ uint32_t creator_revision;
+} __attribute__((packed));
+
+rsdp_t *find_RSDP();
diff --git a/src/kernel/include/libc.h b/src/kernel/include/libc.h
new file mode 100644
index 0000000..7e837ae
--- /dev/null
+++ b/src/kernel/include/libc.h
@@ -0,0 +1,10 @@
+#ifndef _STRING_H_
+#define _STRING_H_
+#include <stddef.h>
+
+int strcmp(const char *str1, const char *str2);
+int strncmp(const char *str1, const char *str2, size_t n);
+void strcpy(char *dest, char *src);
+void memcpy(void *dest, void *src, size_t n); //TODO
+int memcmp(const void *s1, const void *s2, size_t n);
+#endif
diff --git a/src/kernel/include/paging.h b/src/kernel/include/paging.h
new file mode 100644
index 0000000..3b89af9
--- /dev/null
+++ b/src/kernel/include/paging.h
@@ -0,0 +1,60 @@
+#include <stdbool.h>
+//paging errors
+#define PAGEMAP_LOCATION 0x4000
+#ifndef _PAGE_H_
+#define _PAGE_H_
+#include <stdint.h>
+
+#define PAGE_VIRT_UNALIGNED 0x01
+#define PAGE_PHYS_UNALIGNED 0x02
+#define PAGE_PHYS_INVALID 0x03
+#define PAGE_VIRT_INVALID 0x04
+
+//*
+typedef struct __attribute__((packed)) {
+ unsigned int present : 1; // present, must be one when accessed.
+ unsigned int read_write : 1; // if set to one, read and write is set
+ unsigned int user : 1; // another bit we'll never use, for seperating CPL 0-2 and 3+
+ unsigned int writethrough_cache : 1; // honestly maybe I should look into caching
+ unsigned int cachable : 1; // hardware chaching. 0 is enabled, whats the worst that could happen?
+ unsigned int accessed : 1; // we'll never use any of these!
+ unsigned int zg0 : 1; // needs to be (and will be) zero'd
+ unsigned int size : 1;
+ unsigned int zg1 : 1; // needs to be (and will be) zero'd
+ unsigned int software_marks : 3; // available for our own use, I doubt we'll use it in such a simple thing
+
+ uintptr_t base_ptr : 40;
+ unsigned int available:11;
+} page_entry;
+
+
+typedef struct __attribute__((packed)) {
+ page_entry pml4e[512];
+ page_entry pdpe[512];
+ page_entry pde[512];
+ page_entry pte[512];
+} page_table;
+
+#define MEM_AVAILABLE 0
+#define MEM_RESERVED 1
+#define MEM_APCI_RECLAIMABLE 2
+#define MEM_APCI_NVS 3
+#define MEM_BAD 4
+
+#define PAGE_SIZE_4K 12
+#define PAGE_SIZE_2M 21
+#define PAGE_SIZE_1G 30
+
+struct memory_table {
+ uint64_t base;
+ uint64_t length;
+ uint32_t type;
+ uint32_t ACPI; //we'll never use this
+} __attribute__((packed));
+
+
+extern void* _meminfo_loc;
+
+bool map_page(uintptr_t virtual_addr, uintptr_t physical_addr, uint8_t PAGE_SIZE);
+void debug_print_memory();
+#endif
diff --git a/src/kernel/include/printf.h b/src/kernel/include/printf.h
new file mode 100644
index 0000000..6104ccf
--- /dev/null
+++ b/src/kernel/include/printf.h
@@ -0,0 +1,117 @@
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+// 2014-2019, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
+// embedded systems with a very limited resources.
+// Use this instead of bloated standard/newlib printf.
+// These routines are thread safe and reentrant.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _PRINTF_H_
+#define _PRINTF_H_
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Output a character to a custom device like UART, used by the printf() function
+ * This function is declared here only. You have to write your custom implementation somewhere
+ * \param character Character to output
+ */
+void _putchar(char character);
+
+
+/**
+ * Tiny printf implementation
+ * You have to implement _putchar if you use printf()
+ * To avoid conflicts with the regular printf() API it is overridden by macro defines
+ * and internal underscore-appended functions like printf_() are used
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are written into the array, not counting the terminating null character
+ */
+#define printf printf_
+int printf_(const char* format, ...);
+
+
+/**
+ * Tiny sprintf implementation
+ * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
+ * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
+ */
+#define sprintf sprintf_
+int sprintf_(char* buffer, const char* format, ...);
+
+
+/**
+ * Tiny snprintf/vsnprintf implementation
+ * \param buffer A pointer to the buffer where to store the formatted string
+ * \param count The maximum number of characters to store in the buffer, including a terminating null character
+ * \param format A string that specifies the format of the output
+ * \param va A value identifying a variable arguments list
+ * \return The number of characters that COULD have been written into the buffer, not counting the terminating
+ * null character. A value equal or larger than count indicates truncation. Only when the returned value
+ * is non-negative and less than count, the string has been completely written.
+ */
+#define snprintf snprintf_
+#define vsnprintf vsnprintf_
+int snprintf_(char* buffer, size_t count, const char* format, ...);
+int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
+
+
+/**
+ * Tiny vprintf implementation
+ * \param format A string that specifies the format of the output
+ * \param va A value identifying a variable arguments list
+ * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
+ */
+#define vprintf vprintf_
+int vprintf_(const char* format, va_list va);
+
+
+/**
+ * printf with output function
+ * You may use this as dynamic alternative to printf() with its fixed _putchar() output
+ * \param out An output function which takes one character and an argument pointer
+ * \param arg An argument pointer for user data passed to output function
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are sent to the output function, not counting the terminating null character
+ */
+int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _PRINTF_H_
diff --git a/src/kernel/include/serial.h b/src/kernel/include/serial.h
new file mode 100644
index 0000000..824e245
--- /dev/null
+++ b/src/kernel/include/serial.h
@@ -0,0 +1,16 @@
+//these com values are just guesses! Figure out how to find em later if you want
+#ifndef _SERIAL_H_
+#define _SERIAL_H_
+
+#include <stdint.h>
+#define COM1 0x3f8
+#define COM2 0x2f8
+#define COM3 0x3e8
+#define COM4 0x2e8
+
+
+int init_serial(uint16_t port);
+void serial_out(uint16_t port, char *string);
+void _putchar_serial(uint16_t port, char character);
+
+#endif
diff --git a/src/kernel/include/video.h b/src/kernel/include/video.h
new file mode 100644
index 0000000..6f702b1
--- /dev/null
+++ b/src/kernel/include/video.h
@@ -0,0 +1,49 @@
+#include <stdint.h>
+void dump_video();
+
+//this struct was stolen from wiki.osdev.org
+struct mode_info {
+ uint16_t attributes;
+ uint8_t window_a;
+ uint8_t window_b;
+ uint16_t granularity;
+ uint16_t window_size;
+ uint16_t segment_a;
+ uint16_t segment_b;
+ uint32_t win_func_ptr;
+ uint16_t pitch;
+ uint16_t width;
+ uint16_t height;
+ uint8_t w_char;
+ uint8_t y_char;
+ uint8_t planes;
+ uint8_t bpp;
+ uint8_t banks;
+ uint8_t memory_model;
+ uint8_t bank_size;
+ uint8_t image_pages;
+ uint8_t reserved0;
+ uint8_t red_mask;
+ uint8_t red_position;
+ uint8_t green_mask;
+ uint8_t green_position;
+ uint8_t blue_mask;
+ uint8_t blue_position;
+ uint8_t reserved_mask;
+ uint8_t reserved_position;
+ uint8_t direct_color_attributes;
+
+ uint32_t framebuffer;
+ uint32_t off_screen_mem_off;
+ uint16_t off_screen_mem_size;
+ uint8_t reserved1[206];
+} __attribute__((packed));
+
+struct vbe_infoblock {
+ char vbe_signature[4];
+ uint16_t vbe_version;
+ uint16_t oem_ptr[2];
+ uint8_t capabilities[4];
+ uint32_t videomodeptr;
+ uint16_t total_memory;
+} __attribute__((packed));
diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c
new file mode 100644
index 0000000..8db2e50
--- /dev/null
+++ b/src/kernel/kernel.c
@@ -0,0 +1,42 @@
+#include <stdbool.h>
+#include <serial.h>
+#include <printf.h>
+#include <paging.h>
+#include <video.h>
+#include <acpi.h>
+
+void panic() { // will fill with debugging info latter
+ printf("Kernel panic!\n");
+ for(;;);
+}
+
+
+void main() {
+ if(!(init_serial(COM1))) {
+ printf("\nKernal started on CPU 1!\n"); // will detect cpu later
+ }
+
+ rsdp_t *rsdp;
+ struct memory_table *table = (struct memory_table *)&_meminfo_loc;
+ struct vbe_infoblock *vbe_info = (struct vbe_infoblock *)0x500;
+ debug_print_memory();
+
+ rsdp = find_RSDP();
+ if(!(rsdp)) {
+ printf("Couldn't find the RSDP... uhh, not sure what to do now.\n");
+ panic();
+ }
+ dump_video();
+
+ if(rsdp->v1.version) {
+ map_page(0x200000, (rsdp->v2.xsdt_addr / 0x1000) * 0x1000, PAGE_SIZE_4K);
+ }
+ else {
+ map_page(0x200000, (rsdp->v1.rsdt_addr / 0x1000) * 0x1000, PAGE_SIZE_4K);
+ struct acpi_header *acpi = (struct acpi_header *)((uint64_t)0x200000 + (rsdp->v1.rsdt_addr % 0x1000));
+ }
+
+ printf("kernel is done, you can ignore this panic\n");
+ panic();
+
+}
diff --git a/src/kernel/libs/acpi.c b/src/kernel/libs/acpi.c
new file mode 100644
index 0000000..8bc6a56
--- /dev/null
+++ b/src/kernel/libs/acpi.c
@@ -0,0 +1,61 @@
+#include <acpi.h>
+#include <stdint.h>
+#include <printf.h>
+
+static int RSDP_verify(void *rsdp_pointer) {
+ printf("Verifying potential RSDP at address 0x%p... ", rsdp_pointer);
+ union rsdp_t *rsdp = rsdp_pointer;
+ uint8_t checksum = 0;
+ char *rsdp_csm_ptr = rsdp_pointer;
+ int i;
+ if(checksum) return 0;
+ if(rsdp->v1.version) {
+ printf("APCI revision > 2.\n");
+ checksum = 0;
+ printf("len : %i\n", rsdp->v2.len);
+ for(i = 0; i < rsdp->v2.len; i++) {
+ checksum += rsdp_csm_ptr[i];
+ }
+ }
+ else {
+ printf("APCI revision 1.\n");
+ for(i = 0; i <= 20; i++) {
+ checksum += rsdp_csm_ptr[i];
+ }
+ }
+ if(checksum) {
+ return 0;
+ printf("Invalid, searching on.\n");
+ }
+ printf("RSDP Verified!\n");
+ return 1;
+}
+
+// TODO: move these when you gain your sanity
+rsdp_t *find_RSDP() { // finds root descriptor
+ const char sig[9] = "RSD PTR ";
+ uintptr_t *p = (void *)0x040e;
+ uintptr_t *ebda_unshifted = (void *)p;
+
+ // TODO you REALLY need to verify this.
+ void *ebda = (void *)((uintptr_t)ebda_unshifted << (uintptr_t)4 & (uintptr_t)0xfffff);
+
+
+ for(void *i = ebda; i <= ebda + 64000; i += 16) {
+ if(!(memcmp(sig, i, 8))) {
+ if(RSDP_verify(i)) {
+ return(i);
+ }
+ }
+ }
+
+ for(void *i = (void *)0xe0000; i <= (void *)0xfffff; i += 16) {
+ if(!(memcmp(sig, i, 8))) {
+ if(RSDP_verify(i)) {
+ return(i);
+ }
+ }
+ }
+}
+
+
diff --git a/src/kernel/libs/drivers/serial.c b/src/kernel/libs/drivers/serial.c
new file mode 100644
index 0000000..665f06c
--- /dev/null
+++ b/src/kernel/libs/drivers/serial.c
@@ -0,0 +1,43 @@
+#include <stdint.h>
+#include <serial.h>
+//you can add more options if you need to later
+// PORT + 3: values are from bit zero (right) to left
+// dlab(1) | misteryyy bone(1) | paraty(3) | stop bits (1) | character length (2)
+static inline void outb(uint16_t port, uint8_t value) {
+ //here "a" is the a register, and "Nd" is inteter (I think?) in the d register
+ asm volatile(
+ "outb %0, %1" :: "a"(value), "Nd"(port)
+ );
+}
+
+static inline uint8_t inb(uint16_t port) {
+ uint8_t ret;
+ asm volatile(
+ "inb %1, %0" : "=a"(ret) : "Nd"(port)
+ );
+ return(ret);
+}
+
+int init_serial(uint16_t port) {
+ outb(port + 1, 0x00); // disable them fuckin interupts
+ outb(port + 3, 0x80); // sets dlab, allowing custom serial speeds
+ outb(port + 0, 0x06); // speed is 115200/6
+ outb(port + 1, 0x00);
+ outb(port + 3, 0x03); // disables dlab, as well as 8 bit char len, 1 stop bit, no paraty, no mystery
+ outb(port + 2, 0xc7); // I have no fucking clue what this means
+ outb(port + 4, 0x0b); // don't know what this means eather... delete if you can
+ outb(port + 4, 0x1e); // loopback mode (where the hell is this documented????)
+
+ outb(port + 0, 0xae); // test char
+
+ if(inb(port + 0) != 0xae)
+ return 1;
+
+ outb(port + 4, 0x0f); // dissable interupts
+ return 0;
+}
+
+void _putchar_serial(uint16_t port, char msg) {
+ while(!(inb(port + 5) & 0x20)); //wait for transmit to be doneroni
+ outb(port, msg);
+}
diff --git a/src/kernel/libs/drivers/video.c b/src/kernel/libs/drivers/video.c
new file mode 100644
index 0000000..9bb4187
--- /dev/null
+++ b/src/kernel/libs/drivers/video.c
@@ -0,0 +1,6 @@
+#include <printf.h>
+#include <video.h>
+void dump_video() {
+ struct mode_info *video = (struct mode_info *)0x600;
+ printf("Video info:\nx:\t%u\ny:\t%u\nbbp:\t%u\nloc:\t0x%p\n", video->width, video->height, video->bpp, video->framebuffer);
+}
diff --git a/src/kernel/libs/libc.c b/src/kernel/libs/libc.c
new file mode 100644
index 0000000..31580ff
--- /dev/null
+++ b/src/kernel/libs/libc.c
@@ -0,0 +1,47 @@
+#include <stddef.h>
+#include <stdint.h>
+//#include <printf.h>
+// you need to sort all these into diffrent files! TODO
+int strncmp(const char *s1, const char *s2, unsigned int n) {
+ int i;
+ for(i = 0; ((i <= n) && (s1[i] != '\0') && (s2[i] != '\0')); i++) {
+ if(s1[i] != s2[i]) {
+ return(s1[i] - s2[i]);
+ }
+ }
+ return(s1[i] - s2[i]);
+}
+
+int strcmp(const char *s1, const char *s2) {
+ int i;
+ for(i = 0; ((s1[i] != '\0') && (s2[i] != '\0')); i++) {
+ if(s1[i] != s2[i]) {
+ return(s1[i] - s2[i]);
+ }
+ }
+ return(s1[i] - s2[i]);
+}
+
+int memcmp(const void *s1, const void *s2, size_t n) {
+ const unsigned char *p1 = s1; // Why is c such a bitch?
+ const unsigned char *p2 = s2;
+ int i;
+ for(i = 0; i < n; i++) {
+ if(p1[i] != p2[i]) {
+ return(p1[i] - p2[i]);
+ }
+ }
+ return(p1[n-1] - p2[n-1]);
+}
+
+void strcpy(char *dest, char *src) {
+ for(unsigned int i = 0; src[i] != '\0'; i++){
+ dest[i] = src[i];
+ }
+}
+
+void memcpy(char *dest, char *src, size_t n) {
+ for(unsigned int i = 0; i <= n; i++) {
+ dest[i] = src[i];
+ }
+}
diff --git a/src/kernel/libs/page.c b/src/kernel/libs/page.c
new file mode 100644
index 0000000..88d0c2f
--- /dev/null
+++ b/src/kernel/libs/page.c
@@ -0,0 +1,107 @@
+#include <printf.h>
+#include <paging.h>
+#include <stdint.h>
+
+// for now, this will always remain the same.
+// If this ever isn't the case, we'll add paramaters to the paging functions.
+// We will also never need to mess with many bits,
+// as we are not implimenting security for a bare metal fractal generator.
+// Also, is this really the cleanest way to do things?
+
+//after we get paging working, we can probably remove these structs and replace them with plain old uint_16ts.
+
+void debug_print_memory() {
+ struct memory_table *memtable = (struct memory_table *)&_meminfo_loc;
+ printf(" __________________________________________________________________________\n");
+ printf("| type\tstart\t\t\tend\t\t\tsize\t\t |\n");
+ printf("|--------------------------------------------------------------------------|\n");
+ for(unsigned int i = 0; memtable[i].length > 0; i++) {
+ printf("| %u %u\t0x%p\t0x%p\t0x%p |\n", memtable[i].type, memtable[i].ACPI, memtable[i].base, (memtable[i].base + memtable[i].length), memtable[i].length);
+ }
+ printf("----------------------------------------------------------------------------\n");
+}
+
+
+/**
+ * You can critisise the quality of this function all you want, it's messy due to planning mistakes
+ * and I'm planning on sanatising it.
+ * BUT, don't critisise it _just_ for using goto, that's bullshit. See the following links.
+ *
+ * https://www.kernel.org/doc/html/v4.17/process/coding-style.html "goto" section
+ * https://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/
+**/
+
+bool map_page(uintptr_t virtual_addr, uintptr_t physical_addr, uint8_t size) {
+ printf("map page called\n");
+ if((virtual_addr % (1 << size)) || (physical_addr % (1 << size))) {
+ return 0;
+ }
+ page_table *table = (page_table *)PAGEMAP_LOCATION;
+ int pte_i = (virtual_addr >> 12) & 0x1ff;
+ int pde_i = (virtual_addr >> 21) & 0x1ff;
+ int pdpe_i = (virtual_addr >> 30) & 0x1ff;
+ int pml4e_i = (virtual_addr >> 39) & 0x1ff;
+ //TODO remove this debugging info
+ printf("Virtual offsets:\npte:\t\t%i\npde:\t\t%i\npdpe:\t\t%i\npml4e\t\t%i\n", pte_i, pde_i, pdpe_i, pml4e_i);
+
+ if(table->pml4e[pml4e_i].present) {
+ if(table->pml4e[pml4e_i].base_ptr != (uintptr_t)&table->pdpe[pdpe_i] >> 12) goto error;
+ if(table->pdpe[pdpe_i].present) {
+ if(size == PAGE_SIZE_1G) {
+ if(table->pdpe[pdpe_i].base_ptr == (uintptr_t)physical_addr >> 30 & 0x1ff)
+ return true;
+ goto error;
+ }
+ if(table->pdpe[pdpe_i].base_ptr != (uintptr_t)&table->pde[pde_i] >> 12) goto error;
+
+ if(table->pde[pde_i].present) {
+ if(size == PAGE_SIZE_2M) {
+ if(table->pde[pde_i].base_ptr == (uintptr_t)physical_addr >> 21 & 0x1ff)
+ return true;
+ goto error;
+ }
+ if(table->pde[pde_i].base_ptr != (uintptr_t)&table->pte[pte_i] >> 12) goto error;
+ if(table->pte[pte_i].present) {
+ if(table->pte[pte_i].base_ptr != ((physical_addr >> 12) & 0x1ff)) goto error;
+ return true;
+ }
+ else goto mod_page_pte;
+ }
+ else goto mod_page_pde;
+ }
+ else goto mod_page_pdpe;
+ }
+ else {
+ table->pml4e[pml4e_i].base_ptr = (uintptr_t)&table->pdpe[pdpe_i] >> 12;
+ table->pdpe[pml4e_i].read_write = 1;
+ table->pml4e[pml4e_i].present = 1;
+mod_page_pdpe:
+ table->pdpe[pdpe_i].read_write = 1;
+ if(size == PAGE_SIZE_1G) {
+ table->pdpe[pdpe_i].size = 1;
+ table->pdpe[pdpe_i].base_ptr = physical_addr >> 30;
+ table->pdpe[pdpe_i].present = 1;
+ return true;
+ }
+ table->pdpe[pdpe_i].base_ptr = (uintptr_t)&table->pde[pde_i] >> 12;
+ table->pdpe[pdpe_i].present = 1;
+mod_page_pde:
+ table->pde[pde_i].read_write = 1;
+ if(size == PAGE_SIZE_2M) {
+ table->pde[pde_i].size = 1;
+ table->pde[pde_i].base_ptr = physical_addr >> 21;
+ table->pde[pde_i].present = 1;
+ return true;
+ }
+ table->pde[pde_i].base_ptr = (uintptr_t)&table->pte[pte_i] >> 12;
+ table->pde[pde_i].present = 1;
+mod_page_pte:
+ table->pte[pte_i].base_ptr = (physical_addr >> 12);
+ table->pte[pte_i].read_write = 1;
+ table->pte[pte_i].present = 1;
+ return true;
+ }
+error:
+ printf("Page allocation error!\n");
+ return false;
+}
diff --git a/src/kernel/libs/printf.c b/src/kernel/libs/printf.c
new file mode 100644
index 0000000..14c897d
--- /dev/null
+++ b/src/kernel/libs/printf.c
@@ -0,0 +1,924 @@
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+// 2014-2019, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
+// embedded systems with a very limited resources. These routines are thread
+// safe and reentrant!
+// Use this instead of the bloated standard/newlib printf cause these use
+// malloc for printf (and may not be thread safe).
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "printf.h"
+
+//this is my own ugly library
+#include <serial.h>
+
+//and my options
+#define PRINTF_DISABLE_SUPPORT_FLOAT
+#define PRINTF_DISABLE_SUPPORT_EXPONENTIAL
+#define PRINTF_DISABLE_SUPPORT_LONG_LONG
+#define PRINTF_DISABLE_SUPPORT_PTRDIFF_T
+
+
+// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
+// printf_config.h header file
+// default: undefined
+#ifdef PRINTF_INCLUDE_CONFIG_H
+#include "printf_config.h"
+#endif
+
+
+// 'ntoa' conversion buffer size, this must be big enough to hold one converted
+// numeric number including padded zeros (dynamically created on stack)
+// default: 32 byte
+#ifndef PRINTF_NTOA_BUFFER_SIZE
+#define PRINTF_NTOA_BUFFER_SIZE 32U
+#endif
+
+// 'ftoa' conversion buffer size, this must be big enough to hold one converted
+// float number including padded zeros (dynamically created on stack)
+// default: 32 byte
+#ifndef PRINTF_FTOA_BUFFER_SIZE
+#define PRINTF_FTOA_BUFFER_SIZE 32U
+#endif
+
+// support for the floating point type (%f)
+// default: activated
+#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
+#define PRINTF_SUPPORT_FLOAT
+#endif
+
+// support for exponential floating point notation (%e/%g)
+// default: activated
+#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
+#define PRINTF_SUPPORT_EXPONENTIAL
+#endif
+
+// define the default floating point precision
+// default: 6 digits
+#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
+#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
+#endif
+
+// define the largest float suitable to print with %f
+// default: 1e9
+#ifndef PRINTF_MAX_FLOAT
+#define PRINTF_MAX_FLOAT 1e9
+#endif
+
+// support for the long long types (%llu or %p)
+// default: activated
+#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
+#define PRINTF_SUPPORT_LONG_LONG
+#endif
+
+// support for the ptrdiff_t type (%t)
+// ptrdiff_t is normally defined in <stddef.h> as long or long long type
+// default: activated
+#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
+#define PRINTF_SUPPORT_PTRDIFF_T
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+// internal flag definitions
+#define FLAGS_ZEROPAD (1U << 0U)
+#define FLAGS_LEFT (1U << 1U)
+#define FLAGS_PLUS (1U << 2U)
+#define FLAGS_SPACE (1U << 3U)
+#define FLAGS_HASH (1U << 4U)
+#define FLAGS_UPPERCASE (1U << 5U)
+#define FLAGS_CHAR (1U << 6U)
+#define FLAGS_SHORT (1U << 7U)
+#define FLAGS_LONG (1U << 8U)
+#define FLAGS_LONG_LONG (1U << 9U)
+#define FLAGS_PRECISION (1U << 10U)
+#define FLAGS_ADAPT_EXP (1U << 11U)
+
+
+// import float.h for DBL_MAX
+#if defined(PRINTF_SUPPORT_FLOAT)
+#include <float.h>
+#endif
+
+
+// output function type
+typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
+
+
+// wrapper (used as buffer) for output function type
+typedef struct {
+ void (*fct)(char character, void* arg);
+ void* arg;
+} out_fct_wrap_type;
+
+
+// internal buffer output
+static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
+{
+ if (idx < maxlen) {
+ ((char*)buffer)[idx] = character;
+ }
+}
+
+
+// internal null output
+static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
+{
+ (void)character; (void)buffer; (void)idx; (void)maxlen;
+}
+
+
+// internal _putchar wrapper
+static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
+{
+ (void)buffer; (void)idx; (void)maxlen;
+ if (character) {
+ _putchar_serial(COM1, character); // later we should figure out a way to not specifify exclusively com1
+
+ }
+}
+
+
+// internal output function wrapper
+static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
+{
+ (void)idx; (void)maxlen;
+ if (character) {
+ // buffer is the output fct pointer
+ ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
+ }
+}
+
+
+// internal secure strlen
+// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
+static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
+{
+ const char* s;
+ for (s = str; *s && maxsize--; ++s);
+ return (unsigned int)(s - str);
+}
+
+
+// internal test if char is a digit (0-9)
+// \return true if char is a digit
+static inline bool _is_digit(char ch)
+{
+ return (ch >= '0') && (ch <= '9');
+}
+
+
+// internal ASCII string to unsigned int conversion
+static unsigned int _atoi(const char** str)
+{
+ unsigned int i = 0U;
+ while (_is_digit(**str)) {
+ i = i * 10U + (unsigned int)(*((*str)++) - '0');
+ }
+ return i;
+}
+
+
+// output the specified string in reverse, taking care of any zero-padding
+static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
+{
+ const size_t start_idx = idx;
+
+ // pad spaces up to given width
+ if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
+ for (size_t i = len; i < width; i++) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+
+ // reverse string
+ while (len) {
+ out(buf[--len], buffer, idx++, maxlen);
+ }
+
+ // append pad spaces up to given width
+ if (flags & FLAGS_LEFT) {
+ while (idx - start_idx < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+
+ return idx;
+}
+
+
+// internal itoa format
+static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ // pad leading zeros
+ if (!(flags & FLAGS_LEFT)) {
+ if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
+ width--;
+ }
+ while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = '0';
+ }
+ while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = '0';
+ }
+ }
+
+ // handle hash
+ if (flags & FLAGS_HASH) {
+ if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
+ len--;
+ if (len && (base == 16U)) {
+ len--;
+ }
+ }
+ if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = 'x';
+ }
+ else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = 'X';
+ }
+ else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = 'b';
+ }
+ if (len < PRINTF_NTOA_BUFFER_SIZE) {
+ buf[len++] = '0';
+ }
+ }
+
+ if (len < PRINTF_NTOA_BUFFER_SIZE) {
+ if (negative) {
+ buf[len++] = '-';
+ }
+ else if (flags & FLAGS_PLUS) {
+ buf[len++] = '+'; // ignore the space if the '+' exists
+ }
+ else if (flags & FLAGS_SPACE) {
+ buf[len++] = ' ';
+ }
+ }
+
+ return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
+}
+
+
+// internal itoa for 'long' type
+static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ char buf[PRINTF_NTOA_BUFFER_SIZE];
+ size_t len = 0U;
+
+ // no hash for 0 values
+ if (!value) {
+ flags &= ~FLAGS_HASH;
+ }
+
+ // write if precision != 0 and value is != 0
+ if (!(flags & FLAGS_PRECISION) || value) {
+ do {
+ const char digit = (char)(value % base);
+ buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
+ value /= base;
+ } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
+ }
+
+ return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
+}
+
+
+// internal itoa for 'long long' type
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ char buf[PRINTF_NTOA_BUFFER_SIZE];
+ size_t len = 0U;
+
+ // no hash for 0 values
+ if (!value) {
+ flags &= ~FLAGS_HASH;
+ }
+
+ // write if precision != 0 and value is != 0
+ if (!(flags & FLAGS_PRECISION) || value) {
+ do {
+ const char digit = (char)(value % base);
+ buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
+ value /= base;
+ } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
+ }
+
+ return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
+}
+#endif // PRINTF_SUPPORT_LONG_LONG
+
+
+#if defined(PRINTF_SUPPORT_FLOAT)
+
+#if defined(PRINTF_SUPPORT_EXPONENTIAL)
+// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
+static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
+#endif
+
+
+// internal ftoa for fixed decimal floating point
+static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ char buf[PRINTF_FTOA_BUFFER_SIZE];
+ size_t len = 0U;
+ double diff = 0.0;
+
+ // powers of 10
+ static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+
+ // test for special values
+ if (value != value)
+ return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
+ if (value < -DBL_MAX)
+ return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
+ if (value > DBL_MAX)
+ return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
+
+ // test for very large values
+ // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
+ if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
+#if defined(PRINTF_SUPPORT_EXPONENTIAL)
+ return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
+#else
+ return 0U;
+#endif
+ }
+
+ // test for negative
+ bool negative = false;
+ if (value < 0) {
+ negative = true;
+ value = 0 - value;
+ }
+
+ // set default precision, if not set explicitly
+ if (!(flags & FLAGS_PRECISION)) {
+ prec = PRINTF_DEFAULT_FLOAT_PRECISION;
+ }
+ // limit precision to 9, cause a prec >= 10 can lead to overflow errors
+ while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
+ buf[len++] = '0';
+ prec--;
+ }
+
+ int whole = (int)value;
+ double tmp = (value - whole) * pow10[prec];
+ unsigned long frac = (unsigned long)tmp;
+ diff = tmp - frac;
+
+ if (diff > 0.5) {
+ ++frac;
+ // handle rollover, e.g. case 0.99 with prec 1 is 1.0
+ if (frac >= pow10[prec]) {
+ frac = 0;
+ ++whole;
+ }
+ }
+ else if (diff < 0.5) {
+ }
+ else if ((frac == 0U) || (frac & 1U)) {
+ // if halfway, round up if odd OR if last digit is 0
+ ++frac;
+ }
+
+ if (prec == 0U) {
+ diff = value - (double)whole;
+ if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
+ // exactly 0.5 and ODD, then round up
+ // 1.5 -> 2, but 2.5 -> 2
+ ++whole;
+ }
+ }
+ else {
+ unsigned int count = prec;
+ // now do fractional part, as an unsigned number
+ while (len < PRINTF_FTOA_BUFFER_SIZE) {
+ --count;
+ buf[len++] = (char)(48U + (frac % 10U));
+ if (!(frac /= 10U)) {
+ break;
+ }
+ }
+ // add extra 0s
+ while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
+ buf[len++] = '0';
+ }
+ if (len < PRINTF_FTOA_BUFFER_SIZE) {
+ // add decimal
+ buf[len++] = '.';
+ }
+ }
+
+ // do whole part, number is reversed
+ while (len < PRINTF_FTOA_BUFFER_SIZE) {
+ buf[len++] = (char)(48 + (whole % 10));
+ if (!(whole /= 10)) {
+ break;
+ }
+ }
+
+ // pad leading zeros
+ if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
+ if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
+ width--;
+ }
+ while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
+ buf[len++] = '0';
+ }
+ }
+
+ if (len < PRINTF_FTOA_BUFFER_SIZE) {
+ if (negative) {
+ buf[len++] = '-';
+ }
+ else if (flags & FLAGS_PLUS) {
+ buf[len++] = '+'; // ignore the space if the '+' exists
+ }
+ else if (flags & FLAGS_SPACE) {
+ buf[len++] = ' ';
+ }
+ }
+
+ return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
+}
+
+
+#if defined(PRINTF_SUPPORT_EXPONENTIAL)
+// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
+static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ // check for NaN and special values
+ if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
+ return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
+ }
+
+ // determine the sign
+ const bool negative = value < 0;
+ if (negative) {
+ value = -value;
+ }
+
+ // default precision
+ if (!(flags & FLAGS_PRECISION)) {
+ prec = PRINTF_DEFAULT_FLOAT_PRECISION;
+ }
+
+ // determine the decimal exponent
+ // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
+ union {
+ uint64_t U;
+ double F;
+ } conv;
+
+ conv.F = value;
+ int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
+ conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
+ // now approximate log10 from the log2 integer part and an expansion of ln around 1.5
+ int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
+ // now we want to compute 10^expval but we want to be sure it won't overflow
+ exp2 = (int)(expval * 3.321928094887362 + 0.5);
+ const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
+ const double z2 = z * z;
+ conv.U = (uint64_t)(exp2 + 1023) << 52U;
+ // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
+ conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
+ // correct for rounding errors
+ if (value < conv.F) {
+ expval--;
+ conv.F /= 10;
+ }
+
+ // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
+ unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
+
+ // in "%g" mode, "prec" is the number of *significant figures* not decimals
+ if (flags & FLAGS_ADAPT_EXP) {
+ // do we want to fall-back to "%f" mode?
+ if ((value >= 1e-4) && (value < 1e6)) {
+ if ((int)prec > expval) {
+ prec = (unsigned)((int)prec - expval - 1);
+ }
+ else {
+ prec = 0;
+ }
+ flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
+ // no characters in exponent
+ minwidth = 0U;
+ expval = 0;
+ }
+ else {
+ // we use one sigfig for the whole part
+ if ((prec > 0) && (flags & FLAGS_PRECISION)) {
+ --prec;
+ }
+ }
+ }
+
+ // will everything fit?
+ unsigned int fwidth = width;
+ if (width > minwidth) {
+ // we didn't fall-back so subtract the characters required for the exponent
+ fwidth -= minwidth;
+ } else {
+ // not enough characters, so go back to default sizing
+ fwidth = 0U;
+ }
+ if ((flags & FLAGS_LEFT) && minwidth) {
+ // if we're padding on the right, DON'T pad the floating part
+ fwidth = 0U;
+ }
+
+ // rescale the float value
+ if (expval) {
+ value /= conv.F;
+ }
+
+ // output the floating part
+ const size_t start_idx = idx;
+ idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
+
+ // output the exponent part
+ if (minwidth) {
+ // output the exponential symbol
+ out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
+ // output the exponent value
+ idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
+ // might need to right-pad spaces
+ if (flags & FLAGS_LEFT) {
+ while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
+ }
+ }
+ return idx;
+}
+#endif // PRINTF_SUPPORT_EXPONENTIAL
+#endif // PRINTF_SUPPORT_FLOAT
+
+
+// internal vsnprintf
+static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
+{
+ unsigned int flags, width, precision, n;
+ size_t idx = 0U;
+
+ if (!buffer) {
+ // use null output function
+ out = _out_null;
+ }
+
+ while (*format)
+ {
+ // format specifier? %[flags][width][.precision][length]
+ if (*format != '%') {
+ // no
+ out(*format, buffer, idx++, maxlen);
+ format++;
+ continue;
+ }
+ else {
+ // yes, evaluate it
+ format++;
+ }
+
+ // evaluate flags
+ flags = 0U;
+ do {
+ switch (*format) {
+ case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
+ case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
+ case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
+ case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
+ case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
+ default : n = 0U; break;
+ }
+ } while (n);
+
+ // evaluate width field
+ width = 0U;
+ if (_is_digit(*format)) {
+ width = _atoi(&format);
+ }
+ else if (*format == '*') {
+ const int w = va_arg(va, int);
+ if (w < 0) {
+ flags |= FLAGS_LEFT; // reverse padding
+ width = (unsigned int)-w;
+ }
+ else {
+ width = (unsigned int)w;
+ }
+ format++;
+ }
+
+ // evaluate precision field
+ precision = 0U;
+ if (*format == '.') {
+ flags |= FLAGS_PRECISION;
+ format++;
+ if (_is_digit(*format)) {
+ precision = _atoi(&format);
+ }
+ else if (*format == '*') {
+ const int prec = (int)va_arg(va, int);
+ precision = prec > 0 ? (unsigned int)prec : 0U;
+ format++;
+ }
+ }
+
+ // evaluate length field
+ switch (*format) {
+ case 'l' :
+ flags |= FLAGS_LONG;
+ format++;
+ if (*format == 'l') {
+ flags |= FLAGS_LONG_LONG;
+ format++;
+ }
+ break;
+ case 'h' :
+ flags |= FLAGS_SHORT;
+ format++;
+ if (*format == 'h') {
+ flags |= FLAGS_CHAR;
+ format++;
+ }
+ break;
+#if defined(PRINTF_SUPPORT_PTRDIFF_T)
+ case 't' :
+ flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+ format++;
+ break;
+#endif
+ case 'j' :
+ flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+ format++;
+ break;
+ case 'z' :
+ flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+ format++;
+ break;
+ default :
+ break;
+ }
+
+ // evaluate specifier
+ switch (*format) {
+ case 'd' :
+ case 'i' :
+ case 'u' :
+ case 'x' :
+ case 'X' :
+ case 'o' :
+ case 'b' : {
+ // set the base
+ unsigned int base;
+ if (*format == 'x' || *format == 'X') {
+ base = 16U;
+ }
+ else if (*format == 'o') {
+ base = 8U;
+ }
+ else if (*format == 'b') {
+ base = 2U;
+ }
+ else {
+ base = 10U;
+ flags &= ~FLAGS_HASH; // no hash for dec format
+ }
+ // uppercase
+ if (*format == 'X') {
+ flags |= FLAGS_UPPERCASE;
+ }
+
+ // no plus or space flag for u, x, X, o, b
+ if ((*format != 'i') && (*format != 'd')) {
+ flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
+ }
+
+ // ignore '0' flag when precision is given
+ if (flags & FLAGS_PRECISION) {
+ flags &= ~FLAGS_ZEROPAD;
+ }
+
+ // convert the integer
+ if ((*format == 'i') || (*format == 'd')) {
+ // signed
+ if (flags & FLAGS_LONG_LONG) {
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+ const long long value = va_arg(va, long long);
+ idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
+#endif
+ }
+ else if (flags & FLAGS_LONG) {
+ const long value = va_arg(va, long);
+ idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
+ }
+ else {
+ const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
+ idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
+ }
+ }
+ else {
+ // unsigned
+ if (flags & FLAGS_LONG_LONG) {
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+ idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
+#endif
+ }
+ else if (flags & FLAGS_LONG) {
+ idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
+ }
+ else {
+ const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
+ idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
+ }
+ }
+ format++;
+ break;
+ }
+#if defined(PRINTF_SUPPORT_FLOAT)
+ case 'f' :
+ case 'F' :
+ if (*format == 'F') flags |= FLAGS_UPPERCASE;
+ idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
+ format++;
+ break;
+#if defined(PRINTF_SUPPORT_EXPONENTIAL)
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
+ if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
+ idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
+ format++;
+ break;
+#endif // PRINTF_SUPPORT_EXPONENTIAL
+#endif // PRINTF_SUPPORT_FLOAT
+ case 'c' : {
+ unsigned int l = 1U;
+ // pre padding
+ if (!(flags & FLAGS_LEFT)) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ // char output
+ out((char)va_arg(va, int), buffer, idx++, maxlen);
+ // post padding
+ if (flags & FLAGS_LEFT) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ format++;
+ break;
+ }
+
+ case 's' : {
+ const char* p = va_arg(va, char*);
+ unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
+ // pre padding
+ if (flags & FLAGS_PRECISION) {
+ l = (l < precision ? l : precision);
+ }
+ if (!(flags & FLAGS_LEFT)) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ // string output
+ while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
+ out(*(p++), buffer, idx++, maxlen);
+ }
+ // post padding
+ if (flags & FLAGS_LEFT) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ format++;
+ break;
+ }
+
+ case 'p' : {
+ width = sizeof(void*) * 2U;
+ flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+ const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
+ if (is_ll) {
+ idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
+ }
+ else {
+#endif
+ idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+ }
+#endif
+ format++;
+ break;
+ }
+
+ case '%' :
+ out('%', buffer, idx++, maxlen);
+ format++;
+ break;
+
+ default :
+ out(*format, buffer, idx++, maxlen);
+ format++;
+ break;
+ }
+ }
+
+ // termination
+ out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
+
+ // return written chars without terminating \0
+ return (int)idx;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+int printf_(const char* format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ char buffer[1];
+ const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
+ va_end(va);
+ return ret;
+}
+
+
+int sprintf_(char* buffer, const char* format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
+ va_end(va);
+ return ret;
+}
+
+
+int snprintf_(char* buffer, size_t count, const char* format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
+ va_end(va);
+ return ret;
+}
+
+
+int vprintf_(const char* format, va_list va)
+{
+ char buffer[1];
+ return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
+}
+
+
+int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
+{
+ return _vsnprintf(_out_buffer, buffer, count, format, va);
+}
+
+
+int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ const out_fct_wrap_type out_fct_wrap = { out, arg };
+ const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
+ va_end(va);
+ return ret;
+}
diff --git a/src/kernel/libs/printf.h b/src/kernel/libs/printf.h
new file mode 100644
index 0000000..6104ccf
--- /dev/null
+++ b/src/kernel/libs/printf.h
@@ -0,0 +1,117 @@
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+// 2014-2019, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
+// embedded systems with a very limited resources.
+// Use this instead of bloated standard/newlib printf.
+// These routines are thread safe and reentrant.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _PRINTF_H_
+#define _PRINTF_H_
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Output a character to a custom device like UART, used by the printf() function
+ * This function is declared here only. You have to write your custom implementation somewhere
+ * \param character Character to output
+ */
+void _putchar(char character);
+
+
+/**
+ * Tiny printf implementation
+ * You have to implement _putchar if you use printf()
+ * To avoid conflicts with the regular printf() API it is overridden by macro defines
+ * and internal underscore-appended functions like printf_() are used
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are written into the array, not counting the terminating null character
+ */
+#define printf printf_
+int printf_(const char* format, ...);
+
+
+/**
+ * Tiny sprintf implementation
+ * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
+ * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
+ */
+#define sprintf sprintf_
+int sprintf_(char* buffer, const char* format, ...);
+
+
+/**
+ * Tiny snprintf/vsnprintf implementation
+ * \param buffer A pointer to the buffer where to store the formatted string
+ * \param count The maximum number of characters to store in the buffer, including a terminating null character
+ * \param format A string that specifies the format of the output
+ * \param va A value identifying a variable arguments list
+ * \return The number of characters that COULD have been written into the buffer, not counting the terminating
+ * null character. A value equal or larger than count indicates truncation. Only when the returned value
+ * is non-negative and less than count, the string has been completely written.
+ */
+#define snprintf snprintf_
+#define vsnprintf vsnprintf_
+int snprintf_(char* buffer, size_t count, const char* format, ...);
+int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
+
+
+/**
+ * Tiny vprintf implementation
+ * \param format A string that specifies the format of the output
+ * \param va A value identifying a variable arguments list
+ * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
+ */
+#define vprintf vprintf_
+int vprintf_(const char* format, va_list va);
+
+
+/**
+ * printf with output function
+ * You may use this as dynamic alternative to printf() with its fixed _putchar() output
+ * \param out An output function which takes one character and an argument pointer
+ * \param arg An argument pointer for user data passed to output function
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are sent to the output function, not counting the terminating null character
+ */
+int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _PRINTF_H_
diff --git a/src/link.ld b/src/link.ld
new file mode 100644
index 0000000..a325c1a
--- /dev/null
+++ b/src/link.ld
@@ -0,0 +1,37 @@
+SEARCH_DIR(objects)
+
+INPUT(
+bootloader.o
+libc.o
+serial.o
+video.o
+printf.o
+page.o
+acpi.o
+kernel.o
+)
+
+/*while we do need to worry about the stack converging on our kernel,
+this is only temporary, and it will be more noticable then if it were to hit bios (we want to find bugs, not ignore them!)*/
+_kernel_stack_loc = 0x200000 - 16;
+_kernel_loc = 0x100000;
+_meminfo_loc = 0x7000;
+_vbe_infoblock = 0x500; /* this does not account for segmentation to get over 0xffff*/
+
+SECTIONS
+{
+ . = 0x0;
+ bootloader 0x7c00 :
+ {
+ bootloader.o(.text)
+ }
+ kernel _kernel_loc :
+ AT (ADDR(bootloader) + SIZEOF(bootloader))
+ /*ALIGN(4096)*/
+ {
+ EXCLUDE_FILE (*bootloader.o) *(.text .data .bss .rodata .comment .eh_frame)
+ }
+}
+
+_kernel_size = (SIZEOF(kernel) / 512) + (SIZEOF(bootloader) / 512) + 2;
+_bootloader_stage1_size = (SIZEOF(bootloader) / 512) - 1;
diff --git a/src/makefile b/src/makefile
new file mode 100644
index 0000000..93f5196
--- /dev/null
+++ b/src/makefile
@@ -0,0 +1,53 @@
+LD=../compiler/indigo_gcc/bin/x86_64-elf-ld
+CC=../compiler/indigo_gcc/bin/x86_64-elf-gcc
+OBJCPY=../compiler/indigo_gcc/bin/x86_64-elf-objcopy
+INC=-Ikernel/include
+
+EMU_CORES=4
+EMU_RAM=2G
+XRES=1024
+YRES=768
+
+#TODO clean up make vs debug
+
+make:
+ nasm -g -felf64 bootloader/bootloader.asm -o objects/bootloader.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/kernel.c -o objects/kernel.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/acpi.c -o objects/acpi.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/drivers/serial.c -o objects/serial.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/drivers/video.c -o objects/video.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/printf.c -o objects/printf.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/page.c -o objects/page.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/libc.c -o objects/libc.o
+ $(LD) -o indigo_os.elf --oformat=elf64-x86-64 -T link.ld
+ $(OBJCPY) --only-keep-debug indigo_os.elf debug/debug_syms.o
+ $(OBJCPY) -O binary --strip-all indigo_os.elf indigo_os
+ifneq ("$(wildcard $(./debug/serial.in))","")
+ mkfifo debug/serial.in
+endif
+ifneq ("$(wildcard $(./debug/serial.out))","")
+ mkfifo debug/serial.out
+endif
+ rm -f indigo_os.elf
+
+
+run:
+ qemu-system-x86_64 -smp $(EMU_CORES) -m $(EMU_RAM) -nographic -drive format=raw,file=./indigo_os
+
+
+gdb: indigo_os
+ tmux new-session -s os_gdb "qemu-system-x86_64 -smp $(EMU_CORES) -nographic -S -s -drive format=raw,file=./indigo_os -m $(EMU_RAM)"\;\
+ split-window -h "gdb -x debug/gdbinit.gdb; killall qemu-system-x86_64"
+
+run-graphical:
+ qemu-system-x86_64 -S -s -smp $(EMU_CORES) -serial pipe:debug/serial -device VGA,edid=on,xres=$(XRES),yres=$(YRES) -drive format=raw,file=./indigo_os &\
+ gdb -x debug/gdbinit.gdb; killall qemu-system-x86_64
+
+clean:
+ rm -f objects/*
+ rm -f indigo_os
+ rm -f bin/*
+ rm -f debug/debug_syms.o
+ rm -f debug/serial.in
+ rm -f debug/serial.out
+ rm -f indigo_os.elf