modified: README.md

modified:   compiler/create_crosscompiler.sh
	deleted:    notes
	modified:   src/.gdb_history
	deleted:    src/amd64_vol2.pdf
	modified:   src/bootloader/bios_functions/bios_disk.asm
	modified:   src/bootloader/bios_functions/print.asm
	modified:   src/bootloader/bootloader.asm
	modified:   src/bootloader/cpu_check.asm
	modified:   src/bootloader/enter_kernel.asm
	deleted:    src/bootloader/enter_kernel_backup
	modified:   src/bootloader/gdt.asm
	deleted:    src/bootloader/multicore.asm
	deleted:    src/bootloader/notes
	new file:   src/debug/gdbinit.gdb
	deleted:    src/indigo_os
	modified:   src/kernel/include/libc.h
	modified:   src/kernel/include/paging.h
	modified:   src/kernel/include/video.h
	modified:   src/kernel/kernel.c
	modified:   src/kernel/libs/acpi.c
	modified:   src/kernel/libs/drivers/serial.c
	modified:   src/kernel/libs/drivers/video.c
	modified:   src/kernel/libs/libc.c
	modified:   src/kernel/libs/page.c
	modified:   src/link.ld
	modified:   src/makefile
	new file:   tools/README.md
	modified:   tools/page/page.py
This commit is contained in:
Brett Weiland 2021-03-24 15:36:54 -05:00
parent 13000d6f44
commit 14b109ea24
29 changed files with 453 additions and 495 deletions

@ -1,17 +1,12 @@
# IndigoOS
This project is in it's infancy. There's a lot to clean up (bootloader), and this is for my own entertainment. I'll likely be working on it on and off, and only updating the branch after major steps forward.
IndigoOS (name likely to change) will be a unix-like operating system for x86-64 computers. I'm hoping to impliment many things a modern operating system would have, including a desktop enviornment, pre-emptive multithreading, ASLR, and memory protection. I'd also like to port games such as DOOM.
##Questions and answers
### Why are you already parsing APCI tables?
When I first started this project, it was intended to be a bare metal mandelbrotset, then an operating system. This way I could set up an enviornment and become comftorable with the x86 architecture. I was going to have a pretty simple multi-core SMP setup to acheive a higher speed. However, as I worked more and more, I realized that this plan was counter productive. The main reason for this is that I'd be doing a lot of "static" work (for lack of a better word). It would be too hard to modify an existing project into an operating system, due to all the code I'd need to discard.
This project is in it's infancy. However, I'm making quick progress. I'll only commit major changes to keep the commit history clean.
### Will you support UEFI?
Maybe some day. What I have so far of the bootloader was a lot of work, so I need to take a break on it for now.
##Cleaning list
## Cleaning list
- [] clean RSDP v1 vs v2+ ugly unison code
- [] clean static paging code if possible
- [] clean static paging code
- [] fallback to best compatable video mode if not found
- [] find out when and why checksum of binary vs debug binary stripped is occationally diffrent (maybe linker script?)
@ -19,7 +14,7 @@ Maybe some day. What I have so far of the bootloader was a lot of work, so I nee
##debugging
- [x] get debugging into into a seperate elf for GDB
- [] md5sum of striped binary is the same as one built without debugging info
_Almost_ always, there was one time when it wasn't. Can't seem to reproduce. Check linker sizes.
_Almost_ always, there was one time when it wasn't. Can't seem to reproduce. Check linker sizes and included sections.
##bootloader
- [x] make USB bootable as floppy
@ -34,14 +29,15 @@ _Almost_ always, there was one time when it wasn't. Can't seem to reproduce. Che
- [x] boot into kernel long mode
##kernel (listed in order of dependency)
###Memory
- [x] static page mapping
- [] dynamic page allocation - 3/24/21, almost done, will likely finish soon.
- [] remap paging to higher/more available physical address
- [] remap kernel to higher virtual address
###ACPI
- [x] find, check, and parse RSDP
- [x] find, check, and parse RSDT or XSDT
- [x] static page mapping
- [] remap paging to higher/more available physical address
- [] remap kernel to higher virtual address
- [] re-create page tables to accomidate amount of ram in system without becoming too big
- [] dynamic page allocation
###multicpu
- [] boot cpus

@ -18,7 +18,8 @@ mkdir src/build_gcc
lftp -c "set xfer:clobber on; connect ftp.gnu.org; get -O src/packs/ gnu/binutils/$(lftp -c 'connect ftp.gnu.org; ls gnu/binutils/binutils*.tar.gz' | awk '{print $NF}' | sort -V | tail -n 1)"
#download gcc
#yes, I know, I'm making too many connections, I'm tired as fuck rn
# TODO clean up this script so we only need one connection
latest_gcc=$(lftp -c 'connect ftp.gnu.org; ls -d gnu/gcc/gcc-*' | grep -E "^d" | awk '{print $NF}' | sort -V | tail -1)
lftp -c "set xfer:clobber on; connect ftp.gnu.org; get -O src/packs/ gnu/gcc/$latest_gcc/$latest_gcc.tar.gz"

23
notes

@ -1,23 +0,0 @@
| type start end size |
| 1 1 0x0000000000000000 0x000000000009FC00 0x000000000009FC00 |
| 2 1 0x000000000009FC00 0x00000000000A0000 0x0000000000000400 |
| 2 1 0x00000000000E0000 0x0000000000100000 0x0000000000020000 |
| 1 1 0x0000000000100000 0x00000000BA6E4000 0x00000000BA5E4000 |
| 2 1 0x00000000BA6E4000 0x00000000BA868000 0x0000000000184000 |
| 3 1 0x00000000BA868000 0x00000000BA878000 0x0000000000010000 |
| 4 1 0x00000000BA878000 0x00000000BB67A000 0x0000000000E02000 |
| 2 1 0x00000000BB67A000 0x00000000BCA37000 0x00000000013BD000 |
| 1 1 0x00000000BCA37000 0x00000000BCA38000 0x0000000000001000 |
| 4 1 0x00000000BCA38000 0x00000000BCC3E000 0x0000000000206000 |
| 1 1 0x00000000BCC3E000 0x00000000BD083000 0x0000000000445000 |
| 2 1 0x00000000BD083000 0x00000000BD7F4000 0x0000000000771000 |
| 1 1 0x00000000BD7F4000 0x00000000BD800000 0x000000000000C000 |
| 1 1 0x0000000100001000 0x000000043F000000 0x000000033EFFF000 |
| 2 1 0x00000000F8000000 0x00000000FC000000 0x0000000004000000 |
| 2 1 0x00000000FEC00000 0x00000000FEC01000 0x0000000000001000 |
| 2 1 0x00000000FEC10000 0x00000000FEC11000 0x0000000000001000 |
| 2 1 0x00000000FEC20000 0x00000000FEC21000 0x0000000000001000 |
| 2 1 0x00000000FED00000 0x00000000FED01000 0x0000000000001000 |
| 2 1 0x00000000FED61000 0x00000000FED71000 0x0000000000010000 |
| 2 1 0x00000000FED80000 0x00000000FED90000 0x0000000000010000 |
| 2 1 0x00000000FEF00000 0x0000000100000000 0x0000000001100000 |

@ -1,256 +1,256 @@
x 0x7FFE1667
x 0x7FFE1667
x 0x200000
quit
break main
x 0x1
next
break bzero
c
next
stepi
condition 3 i == 98268
quit
quit
break bzero
c
c
quit
break panic
c
quit
break map_page
c
next
break bzero
d 2
c
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
stack
quit
break main
quit
break bzero
c
page_table *table = (page_table *)PAGEMAP_LOCATION
print page_table *table = (page_table *)PAGEMAP_LOCATION
print (page_table *)PAGEMAP_LOCATION
print (page_table *)0x4000
print *(page_table *)0x4000
print (page_table *)0x4000.pml4
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[2]
print ((page_table *)0x4000).pml4e[3]
print ((page_table *)0x4000).pml4e[4]
print ((page_table *)0x4000).pml4e[1]
print ((page_table *)0x4000).pml4e[1]
print ((page_table *)0x4000).pml4e[1]
print ((page_table *)0x4000).pml4e[1]
print ((page_table *)0x4000).pml4e[0]
print ((page_table *)0x4000).pde[0]
print ((page_table *)0x4000).pde[1]
print ((page_table *)0x4000).pde[0]
print ((page_table *)0x4000).pde[20]
print ((page_table *)0x4000).pde[10]
print ((page_table *)0x4000).pde[0]
print ((page_table *)0x4000).pde[1]
print ((page_table *)0x4000).pde[2]
print ((page_table *)0x4000).pde[0]
print ((page_table *)0x4000).pde[1]
print ((page_table *)0x4000).pde[0]
print ((page_table *)0x4000).pde[1]
print ((page_table *)0x4000).pde[2]
print ((page_table *)0x4000).pde[2]
print ((page_table *)0x4000).pde[21]
print ((page_table *)0x4000).pde[1]
c
next
print rsdp.v1.rsdt_addr
print (void*)rsdp.v1.rsdt_addr
break bzero
c
c
next
watch i
c
info breakpoints
d 4 3 2
info watchpoitns
info watchpoints
watch i
c
c
info breakpoints
c
d 5
next
watch i
c
condition 6 i == 9999999
c
x 0
x 1
nexti
break bzero
c
next
watch i
condition 8 i == 16359
c
x 0x1fffb8
next
print p1[o]i]
print p1[i]
print p1
stack
quit
break bzero
c
next
watch i
condition i == 16359
c
condition 3 i == 16359
c
x 0
print p1
print p1[i]
print &p1[i]
print &(p1[i])
x p1
x p1[i]
nexti
next
quit
c
quit
c
quit
quit
quit
quit
next
break mina
break main
c
break main
c
quit
break bzero
c
next
next
quit
break bzero
c
next
print p1
next
nexti
info reg rax
next
c
quit
c
quit
break bzero
c
next
watch i
condition 3 i == 1000000
c
quit
break bzero
c
next
watch i
condition 3 i == 100000
c
quit
break bzero
c
next
watch i
condition 3 i == 100000
c
x 0x0000000000204000
info reg
info reg rip
quit
break bzero
c
next
watch i
condition 3 i == 20454
c
quit
break bzer
break bzero
c
next
condition i = 16360
condition 3 i == 16360
watch i
condition 3 i == 16360
c
print (struct page_table)0x5000
print (page_table)0x5000
print (page_table *)0x5000
print (page_table *)0x4000
print (page_table *)0x4000.pml4e[0]
print (page_table *)0x4000->pml4e[0]
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).pde[0]
print ((page_table *)0x4000).pde[1]
print ((page_table *)0x4000).pde[0]
print ((page_table *)0x4000).pde[2]
print ((page_table *)0x4000).pde[1]
print ((page_table *)0x4000).pde[0]
print ((page_table *)0x4000).pde[1]
print ((page_table *)0x4000).pde[0]
print ((page_table *)0x4000).pde[1]
print ((page_table *)0x4000).pde[2]
print ((page_table *)0x4000).pde[3]
quit
break mod_page_pde
break map_page
c
next
print table->pde
print table->pde[1]
next
print table->pde[1]
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]
mext
next
print table->pde[pde_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
break map_page
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)
print table->pde[pde_i]
next
quit
break panic
c
prit apic
print apic
print acpi
print *acpi
print acpi
print acpi.sig
quit
break main
break map_page
c
next
print apic
ptype apic_header
quit
ptype acpi
ptype acpi_header
break main
break init_memory
c
next
print apic
print acpi
print acpi.*
context
print apic
quit
break main
next
break map_page
c
return
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
pirnt map
quit

Binary file not shown.

@ -3,6 +3,8 @@ bios_disk:
pusha
mov es, dx
; TODO when our kernel gets to big to fit in one track, we need to just switch over to LHS with extended bios functions.
mov ah, 0x02 ; read disc sectors
mov ch, 0x00 ; track 0
mov dh, 0x00 ; head 0

@ -1,25 +1,24 @@
;TODO fix null problem, allow direct passes
;TODO fix null problem, allow passing value insted of pointer
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
mov ah, 0x0e
.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
mov al, [bx]
cmp al, 0
je .fini
test cx, cx ; if cx is zero, ascii, otherwise hex string
jne .print_hex
int 0x10 ; bios call, actually prints the char
int 0x10
.print_hex_ret:
inc bx ; adds to the pointer
jmp .print_loop ; goes back to loop start
inc bx
jmp .print_loop
.fini:
mov al, 0xd ; \r
mov al, 0xd
int 0x10
mov al, 0xa ; \n
mov al, 0xa
int 0x10
popa
ret
@ -32,7 +31,7 @@ int 0x10
mov al, 'x'
int 0x10
mov al, [bx] ; shift bits to get first nibble
mov al, [bx]
shr al, 4
call .bios_print_nibble
@ -47,13 +46,13 @@ jmp .print_hex_ret
.bios_print_nibble:
cmp al, 9 ; see if letter worthy
cmp al, 9
ja .print_hex_letter
add al, 0x30 ;'1'
add al, 0x30
int 0x10
ret
.print_hex_letter:
add al, 0x57 ;'a'
add al, 0x57
int 0x10
ret

@ -3,7 +3,6 @@
[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)
@ -59,7 +58,6 @@ 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
@ -94,9 +92,10 @@ mov cr0, eax
pop ds
sti
;we are now in unreal mode
mov cl, 5 ; starting sector TODO automate this
mov cl, 5
mov edi, _kernel_loc
.loop:
mov al, 0x1 ; sector count
@ -114,10 +113,6 @@ mov ecx, 512
a32 rep movsb
nop
mov bx, boot_msg.debugmsg
mov cx, 0
call bios_print
pop cx
cmp cl, _kernel_size
@ -142,4 +137,5 @@ jmp $
%include "bootloader/cpu_check.asm"
%include "bootloader/video.asm"
%include "bootloader/enter_kernel.asm"
times 2048 - ($ - $$) db 0

@ -1,38 +1,41 @@
; 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.
; detect CPUID
pushfd
pushfd
xor dword [esp], 0x00200000
pop eax
xor eax, [esp]
popfd
and eax, 0x00200000
jz .print_cpuid_error
; detect long mode
mov eax, 0x80000001
cpuid ;cpuid returns into edx
and edx, 0x0020000000 ; the 21st bit is cpuid.
cpuid
and edx, 0x0020000000
jz .print_long_error
; APIC
mov eax, 0x00000001
cpuid
and edx, 0x00000200
test edx, 0x00000200
jz .print_apic_error
; SSE (you might be able to remove this, I think it's a standard requirement)
test edx, 0x2000000
jz .print_sse_error
mov bx, .no_error
mov cx, 0
call bios_print
;mapping memory
; get memory mappings
mov ax, 0
mov es, ax
mov ax, _meminfo_loc
@ -71,7 +74,7 @@ call bios_print
jmp $
.print_long_error:
mov bx, .arch_error ; lets just test for now
mov bx, .arch_error
mov cx, 0
call bios_print
jmp $
@ -80,11 +83,19 @@ jmp $
mov bx, .apic_error
mov cx, 0
call bios_print
jmp $
.print_mem_error:
mov bx, .mem_error
mov cx, 0
call bios_print
jmp $
.print_sse_error:
mov bx, .sse_error
mov cx, 0
call bios_print
jmp $
.cpuid_error:
@ -95,6 +106,8 @@ call bios_print
db "No apic support", 0x0
.mem_error:
db "Could not get information on memory!", 0x0
.sse_error:
db "This OS requires SSE", 0x0
.no_error:
db "CPU info gathered!", 0x0

@ -1,5 +1,6 @@
[extern main]
[extern _kernel_stack_loc]
[extern _stage1_pagetable]
enter_longmode:
cli
@ -29,7 +30,7 @@ mov es, ax
mov fs, ax
mov gs, ax
mov edi, 0x4000 ; 0x3000
mov edi, _stage1_pagetable ; 0x3000
mov cr3, edi
mov eax, 0
mov ecx, 0xc00 ; 0x1000
@ -37,14 +38,14 @@ rep stosd
mov edi, cr3
mov DWORD [edi], 0x5003 ; pml4e[0] = pdpe
mov DWORD [edi], _stage1_pagetable + 0x1003 ; pml4e[0] = pdpe
add edi, 0x1000
mov DWORD [edi], 0x6003 ; pdpe[0] = pde
mov DWORD [edi], _stage1_pagetable + 0x2003 ; pdpe[0] = pde
add edi, 0x1000
mov DWORD [edi], 0x83 ; pde[0] = pte
mov eax, cr4
or eax, 1 << 5
or eax, 0x620
mov cr4, eax
;end of setting up pages
@ -65,9 +66,11 @@ or eax, 1 << 8
wrmsr
mov eax, cr0
or eax, 1 << 31
and ax, 0xfffb
or eax, 0x80000002
mov cr0, eax
lgdt [long_gdt.descriptor]
jmp LONG_CODE_SEGMENT:enter_kernel

@ -1,87 +0,0 @@
[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

@ -49,8 +49,6 @@ db 10011010b ;1st flags and type. The first four bits (1010) are type, and the
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

@ -1,10 +0,0 @@
multicore_boot:
jmp $
mov ecx, 0x0000001b
rdmsr
;mov [apic_register] dx:ax
apic_register: dq 0
multicore_msg1: db "CPUs available: ", 0

4
src/debug/gdbinit.gdb Normal file

@ -0,0 +1,4 @@
target remote localhost:1234
symbol-file debug/debug_syms.o
break *0x7c00
continue

Binary file not shown.

@ -7,4 +7,6 @@ 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);
void bzero(const void *dest, size_t size);
int ceil(float n1);
#endif

@ -24,7 +24,7 @@ typedef struct __attribute__((packed)) {
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;
unsigned int sign:11;
} page_entry;
@ -35,11 +35,11 @@ typedef struct __attribute__((packed)) {
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 MEM_AVAILABLE 1
#define MEM_RESERVED 2
#define MEM_APCI_RECLAIMABLE 3
#define MEM_APCI_NVS 4
#define MEM_BAD 5
#define PAGE_SIZE_4K 12
#define PAGE_SIZE_2M 21
@ -49,12 +49,23 @@ struct memory_table {
uint64_t base;
uint64_t length;
uint32_t type;
uint32_t ACPI; //we'll never use this
uint32_t ACPI;
} __attribute__((packed));
struct phys_map {
uint64_t map_size; //this way we won't have to calculate it every time
void *chunk_start;
uint64_t chunk_size;
uint64_t *buddies;
} __attribute__((packed));
extern void* _meminfo_loc;
extern void* _stage2_pagetable;
bool map_page(uintptr_t virtual_addr, uintptr_t physical_addr, uint8_t PAGE_SIZE);
bool map_page(void *virtual_addr, void *physical_addr, uint8_t PAGE_SIZE);
void debug_print_memory();
void create_pagetable_stage2(uint64_t free_mem);
void init_memory();
#endif

@ -47,3 +47,5 @@ struct vbe_infoblock {
uint32_t videomodeptr;
uint16_t total_memory;
} __attribute__((packed));
extern void *_vbe_infoblock;

@ -15,28 +15,20 @@ 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");
printf("Couldn't find the RSDP... 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");
dump_video();
debug_print_memory();
init_memory();
panic();
}

@ -31,16 +31,13 @@ static int RSDP_verify(void *rsdp_pointer) {
return 1;
}
// TODO: move these when you gain your sanity
rsdp_t *find_RSDP() { // finds root descriptor
rsdp_t *find_RSDP() {
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)) {

@ -1,10 +1,6 @@
#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)
);
@ -19,14 +15,14 @@ static inline uint8_t inb(uint16_t port) {
}
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, 0x80);
outb(port + 0, 0x06);
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 + 3, 0x03);
outb(port + 2, 0xc7);
outb(port + 4, 0x0b);
outb(port + 4, 0x1e);
outb(port + 0, 0xae); // test char
@ -38,6 +34,6 @@ int init_serial(uint16_t port) {
}
void _putchar_serial(uint16_t port, char msg) {
while(!(inb(port + 5) & 0x20)); //wait for transmit to be doneroni
while(!(inb(port + 5) & 0x20)); //wait for transmit to be done
outb(port, msg);
}

@ -1,5 +1,8 @@
#include <printf.h>
#include <video.h>
//to be implimented when paging is set up
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);

@ -1,7 +1,6 @@
#include <stddef.h>
#include <stdint.h>
//#include <printf.h>
// you need to sort all these into diffrent files! TODO
// TODO clean up variable names
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++) {
@ -23,7 +22,7 @@ int strcmp(const char *s1, const char *s2) {
}
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 *p1 = s1;
const unsigned char *p2 = s2;
int i;
for(i = 0; i < n; i++) {
@ -45,3 +44,17 @@ void memcpy(char *dest, char *src, size_t n) {
dest[i] = src[i];
}
}
void bzero(void *dest, size_t size) {
unsigned char *p1 = dest;
for(uint64_t i = 0; i < size; i++) {
p1[i] = 0;
}
}
//TODO move this function to a seperate math library
int ceil(float n) {
int low_n = (int)n;
if(n == (float)low_n) return(low_n);
return(low_n + 1);
}

@ -1,14 +1,7 @@
#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.
#include <libc.h>
void debug_print_memory() {
struct memory_table *memtable = (struct memory_table *)&_meminfo_loc;
@ -22,33 +15,89 @@ void debug_print_memory() {
}
//uses buddy system allocation
void init_memory() {
struct memory_table *memtable = (struct memory_table *)&_meminfo_loc;
struct phys_map *map = (struct phys_map*)0x200000;
uintptr_t onpage = 0x200000;
unsigned int i, x, buddy_size, buddy_bitsize, prev_buddy_bsize;
uint64_t *buddy_ptr;
map_page((void*)0x200000, (void*)0x200000, PAGE_SIZE_2M);
void *next_page = (void *)onpage + 0x200000;
// at this point, we are declaring our header and kernel itself as free (so don't forget to fix that!)
for(i = 0; memtable[i].length > 0; i++) {
if((memtable[i].type == MEM_AVAILABLE) && (memtable[i].ACPI & 1)) {
map->chunk_start = (void*)memtable[i].base;
map->chunk_size = memtable[i].length;
buddy_ptr = (void*)&map->buddies;
for(x = 0; x < 8; x++) {
buddy_bitsize = memtable[i].length / (0x1000 * (1 << x));
buddy_size = ceil(buddy_bitsize / (float)8);
if((void *)buddy_ptr + buddy_size >= next_page) {
map_page(next_page, next_page, PAGE_SIZE_2M);
next_page += 0x200000;
}
bzero(buddy_ptr, buddy_size); //meant to be /8?
if((buddy_bitsize * 2) != prev_buddy_bsize) {
buddy_ptr[-1] |= (1 << ((prev_buddy_bsize % 8) - 1));
}
buddy_ptr += buddy_size;
prev_buddy_bsize = buddy_bitsize;
}
map->map_size = buddy_ptr - (uint64_t*)map;
map = (struct phys_map *)map + map->map_size;
if((void *)map + 24 >= next_page) {
map_page(next_page, next_page, PAGE_SIZE_2M);
next_page += 0x200000;
}
}
}
}
//TODO this function was deleted due to it being wrong.
//I'll create it once I have the physical paging prerequisite set up.
void create_pagetable_stage2(uint64_t free_mem) {
}
/**
* 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/
* BIG TODO:
* Paging turned out to be simpler then I thought. I've temporarily fixed the code, but needs to be rewritten/simplified.
* Let's get rid of those nasty GOTOs if we can.
* Also, once we get physical memory allocator up and running, impliment that in this function.
**/
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))) {
bool map_page(void *virtual_addr, void *physical_addr, uint8_t size) {
//printf("map page called\n");
uintptr_t va_ptr = (uintptr_t)virtual_addr;
uintptr_t pa_ptr = (uintptr_t)physical_addr;
if((va_ptr % (1 << size)) || (pa_ptr % (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);
int pte_i = (va_ptr >> 12) & 0x1ff;
int pde_i = (va_ptr >> 21) & 0x1ff;
int pdpe_i = (va_ptr >> 30) & 0x1ff;
int pml4e_i = (va_ptr >> 39) & 0x1ff;
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)
if(table->pdpe[pdpe_i].base_ptr == (uintptr_t)pa_ptr >> 30 & 0x1ff)
return true;
goto error;
}
@ -56,13 +105,13 @@ bool map_page(uintptr_t virtual_addr, uintptr_t physical_addr, uint8_t size) {
if(table->pde[pde_i].present) {
if(size == PAGE_SIZE_2M) {
if(table->pde[pde_i].base_ptr == (uintptr_t)physical_addr >> 21 & 0x1ff)
if(table->pde[pde_i].base_ptr == (uintptr_t)pa_ptr >> 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;
if(table->pte[pte_i].base_ptr != ((pa_ptr >> 12) & 0x1ff)) goto error;
return true;
}
else goto mod_page_pte;
@ -77,9 +126,10 @@ bool map_page(uintptr_t virtual_addr, uintptr_t physical_addr, uint8_t size) {
table->pml4e[pml4e_i].present = 1;
mod_page_pdpe:
table->pdpe[pdpe_i].read_write = 1;
//TODO you just found out things are a lot more simple then you thought!
if(size == PAGE_SIZE_1G) {
table->pdpe[pdpe_i].size = 1;
table->pdpe[pdpe_i].base_ptr = physical_addr >> 30;
table->pdpe[pdpe_i].base_ptr = pa_ptr >> 12;
table->pdpe[pdpe_i].present = 1;
return true;
}
@ -89,14 +139,14 @@ 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].base_ptr = pa_ptr >> 12;
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].base_ptr = pa_ptr >> 12;
table->pte[pte_i].read_write = 1;
table->pte[pte_i].present = 1;
return true;

@ -11,12 +11,12 @@ 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_stack_loc = 0x200000 - 8;
_kernel_loc = 0x100000;
_meminfo_loc = 0x7000;
_vbe_infoblock = 0x500; /* this does not account for segmentation to get over 0xffff*/
_vbe_infoblock = 0x500;
_stage2_pagetable = 0x200000;
_stage1_pagetable = 0x4000;
SECTIONS
{

@ -4,11 +4,10 @@ OBJCPY=../compiler/indigo_gcc/bin/x86_64-elf-objcopy
INC=-Ikernel/include
EMU_CORES=4
EMU_RAM=2G
EMU_RAM=4G
XRES=1024
YRES=768
#TODO clean up make vs debug
make:
nasm -g -felf64 bootloader/bootloader.asm -o objects/bootloader.o
@ -32,15 +31,15 @@ endif
run:
qemu-system-x86_64 -smp $(EMU_CORES) -m $(EMU_RAM) -nographic -drive format=raw,file=./indigo_os
qemu-system-x86_64 -smp $(EMU_CORES) -m $(EMU_RAM) -nographic -no-reboot -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)"\;\
tmux new-session -s os_gdb "qemu-system-x86_64 -smp $(EMU_CORES) -nographic -no-reboot -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 &\
qemu-system-x86_64 -S -s -smp $(EMU_CORES) -m $(EMU_RAM) -no-reboot -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:
@ -50,4 +49,3 @@ clean:
rm -f debug/debug_syms.o
rm -f debug/serial.in
rm -f debug/serial.out
rm -f indigo_os.elf

2
tools/README.md Normal file

@ -0,0 +1,2 @@
# You can probably ignore this directory for now.
These were just tools I used to check my sanity in the early stages of my bootloader.

@ -24,6 +24,6 @@ def get_table_size(addr):
return((pte_cnt + pde_cnt + pdpe_cnt + pml4_cnt) * 8)
ts = get_table_size(68719476736)
print(hex(ts))
ts = get_table_size(34359738368)
print(ts)