Move to git

This commit is contained in:
Mid
2025-05-22 22:16:46 +03:00
commit c4d808833a
74 changed files with 11870 additions and 0 deletions

41
src/boot0.asm Normal file
View File

@@ -0,0 +1,41 @@
cpu 386
bits 16
org 0x7C00
start:
jmp 0:cseg
cseg:
cld
mov ax, 0xB800
mov fs, ax
mov ax, 0x3000
mov es, ax
mov ax, 0x0200 | ((BOOT1_SIZE + 511) / 512)
mov cx, 0x0002
mov dh, 0
mov bx, 0
int 0x13
setc al
add al, '0'
mov [fs:0], al
xor ax, ax
mov es, ax
mov ax, 0x3000
mov ds, ax
mov ax, 0x4000 ;Apparently Bochs' BIOS bugs out if below 0x7C00 linear
mov ss, ax
xor sp, sp
jmp 0x3000:0
db "Yo waddup"
times 446 - ($ - $$) db 0

864
src/boot1.asm Normal file
View File

@@ -0,0 +1,864 @@
cpu 386
bits 16
org 0
%define BIT_READWRITE (1 << 1)
%define BIT_EXECUTABLE (1 << 3)
%define BIT_ISCODEORDATA (1 << 4)
%define BIT_PRESENT (1 << 7)
%define PBIT_PRESENT 1
%define PBIT_WRITABLE 2
%define PBIT_USERLEVEL 4
%define PBIT_WRITETHROUGH 8
%define PBIT_CACHEDISABLE 16
%define PBIT_ACCESSED 32
MALLOC_MEM equ 0x520
BOOT1_SEGMENT equ 0x3000
BOOT1_ADDR equ (BOOT1_SEGMENT * 0x10)
start:
mov [ld_lba.drive + 1], dl
mov ah, 8
mov di, 0
int 0x13
mov dl, dh
mov dh, 0
inc dx
mov [lba2chs.numheads + 1], dx
and cl, 0x3F
mov ch, 0
mov [lba2chs.spt + 1], cx
mov eax, [es:0x7C00 + 0x1BE + 8]
mov [get_inode.abs1], eax
mov [read_inode.abs1], eax
mov ecx, 40 * 25
mov edi, 0
.lup:
mov [fs:edi + ecx * 4 - 4], dword 0x0F000F00
dec ecx
jnz .lup
mov si, MSG_START
mov ax, MSG_START.end - MSG_START
call print16
mov edi, MALLOC_MEM ;Bump allocator pointer
add edi, 4096
mov [TSS.esp0], edi ;End of stack ~ beginning of memory map!!
a20:
cli
call .waito
mov al, 0xAD
out 0x64, al
call .waito
mov al, 0xD0
out 0x64, al
.waiti:
in al, 0x64
test al, 1
jz .waiti
in al, 0x60
push ax
call .waito
mov al, 0xD1
out 0x64, al
call .waito
pop ax
or al, 2
out 0x60, al
call .waito
mov al, 0xAE
out 0x64, al
call .waito
sti
jmp ramdetect
.waito:
in al, 0x64
test al, 2
jnz .waito
ret
ramdetect: ;Currently only detects RAM below 16MB, which will be enough for a while.
clc
int 0x12
jc .fail
mov [es:di + 0], dword 0
mov [es:di + 4], dword 0
movzx ecx, ax
shr cx, 2
mov [es:di + 8], ecx
mov [es:di + 12], byte 0
add di, 13
mov al, 0
add cx, 7
shr cx, 3
rep stosb
xor cx, cx
xor dx, dx
mov ax, 0xE801
int 0x15
jc .fail
cmp ah, 0x86
je .fail
cmp ah, 0x80
je .fail
jcxz .useax
mov ax, cx
mov bx, dx
.useax:
mov [es:di + 0], dword 0x100000
mov [es:di + 4], dword 0
movzx ecx, ax
shr ecx, 2
mov [es:di + 8], ecx
mov [es:di + 12], byte 0
add di, 13
mov al, 0
shr ecx, 3
rep stosb
jmp .foundMMap
.fail:
mov si, MSG_FAIL
mov ax, MSG_FAIL.end - MSG_FAIL
call print16
jmp $
.foundMMap:
mov si, MSG_DETECTED_MEMORY_MAP
mov ax, MSG_DETECTED_MEMORY_MAP.end - MSG_DETECTED_MEMORY_MAP
call print16
pg:
; Create page directory
add edi, 4095
and edi, ~4095
mov cr3, edi ;In advance
lea eax, [edi + 4096]
or eax, PBIT_PRESENT | PBIT_WRITABLE
mov [es:edi], eax
add edi, 4
mov eax, 0
mov ecx, 1023
rep stosd
mov ecx, 192
mov edx, PBIT_PRESENT | PBIT_WRITABLE
.lup:
mov [es:edi], edx
add edi, 4
add edx, 4096
dec ecx
jnz .lup
mov ecx, 1024 - 192
mov eax, 0
rep stosd
mov eax, cr3 ;Back to the page directory
mov [es:eax + 4092], edi
or dword [es:eax + 4092], PBIT_PRESENT | PBIT_WRITABLE
mov [es:edi + 4092], edi
or dword [es:edi + 4092], PBIT_PRESENT | PBIT_WRITABLE
add edi, 4096
mov esi, MSG_STEP3s
mov eax, MSG_STEP3s.end - MSG_STEP3s
call print16
loadkernel:
mov eax, 2 ;root
call get_inode
mov bx, di
call read_inode
mov eax, edi
mov esi, KERNEL_FILE
mov ecx, KERNEL_FILE.end - KERNEL_FILE
call find_in_dirnode
test eax, eax
jnz .found
mov si, MSG_STEP5f
mov ax, MSG_STEP5f.end - MSG_STEP5f
call print16
jmp $
.found:
call get_inode
mov bx, di
call read_inode
; Now edi is kernel location, ebx is after kernel.
call fix_module_addresses
mov [inPE.KERNEL_START], edi
mov edi, ebx ;Allocate modules after kernel
;~ mov [inPE.MODULES_START], edi
loadmods:
mov eax, 2
call get_inode
mov esi, [endSector + 32] ;filesize
push es
push ds
pop es
mov bx, endSector + 0x200 ;Will break if root directory is larger than 1KB.
call read_inode
pop es
mov eax, endSector + 0x200
.lup: ;Loop over files, the names of which end with ".mod"
movzx ecx, word [eax + 10] ;Length of name
lea edx, [eax + 12] ;Get name string
cmp ecx, 4 ;Test if shorter than 4 characters
jb .cont
.testext:
cmp [eax + ecx + 12 - 4], dword ".mod"
jne .cont
.testkrnl:
cmp [eax + 12], dword "krnl"
je .cont
.ismod:
inc dword [inPE.MOD_COUNT]
push eax
mov eax, [eax] ;inode
call get_inode
call page_align_es_edi
push esi
mov esi, cr3
mov cx, 1024
push ds
push word 0
pop ds
rep movsd ;Copy page directory to one local to process
pop ds
pop esi
mov bx, di
call read_inode ;edi = start, ebx = end
mov di, bx
pop eax
.cont:
movzx ecx, byte [eax + 9]
shl cx, 4
add eax, ecx
sub esi, ecx
jnz .lup
.end:
mov di, es
shl edi, 4
add edi, 4095
and edi, ~4095
mov [inPE.IMPORTANT_MEM_END], edi
xor ax, ax
mov es, ax
add ebx, edi
fixmmap: ; Make all module memories "used"
lea ecx, [es:ebx + 4095]
shr ecx, 12
mov ebx, ecx
and ebx, 7
shr ecx, 3
mov edi, [TSS.esp0]
add edi, 13
push edi
mov al, -1
rep stosb
mov ecx, ebx
mov al, 1
shl al, cl
dec al
mov [es:edi], al
pop edi
or [es:edi + (BOOT1_ADDR / 4096 / 8)], byte 3 ; TODO: Let boot1 get overwritten after load
modex:
mov ax, 0x13
int 0x10
mov dx, 0x3C4
mov al, 4
out dx, al
inc dx
mov al, 6
out dx, al
mov dx, 0x3D4
mov al, 0x14
out dx, al
inc dx
xor al, al
out dx, al
dec dx
mov al, 0x17
out dx, al
inc dx
mov al, 0xE3
out dx, al
dec dx
mov al, 0x11
out dx, al
inc dx
mov al, 0x2C
out dx, al
dec dx
mov al, 0x06
out dx, al
inc dx
mov al, 0x0D
out dx, al
dec dx
mov al, 0x07
out dx, al
inc dx
mov al, 0x3E
out dx, al
dec dx
mov al, 0x10
out dx, al
inc dx
mov al, 0xEA
out dx, al
dec dx
mov al, 0x11
out dx, al
inc dx
mov al, 0xAC
out dx, al
dec dx
mov al, 0x12
out dx, al
inc dx
mov al, 0xDF
out dx, al
dec dx
mov al, 0x15
out dx, al
inc dx
mov al, 0xE7
out dx, al
dec dx
mov al, 0x16
out dx, al
inc dx
mov al, 0x06
out dx, al
; ESP should be zero here.
push strict dword BOOT1_ADDR + inPE
mov esp, BOOT1_ADDR + 0x10000 + 0xFFFC
jmp enterPM
enterPM:
cli
or [GDT.R0CSLIMFLAGS], byte 64 ;Make 32-bit
lgdt [GDT]
mov eax, cr0
or eax, 1 | (1 << 31)
mov cr0, eax
jmp 8:dword BOOT1_ADDR + .inPM
.inPM:
bits 32
mov eax, 0x23
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov al, 0x10
mov ss, ax
ret
enterRM:
and [GDT.R0CSLIMFLAGS], byte ~64 ;Make 16-bit
lgdt [GDT]
jmp 8:.in16
.in16:
bits 16
mov eax, cr0
and eax, ~(1 | (1 << 31))
mov cr0, eax
jmp 0:.inRM
.inRM:
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
sti
ret
; Makes es:edi a normalized far pointer
normalize_es_edi:
push eax
push edi
mov ax, es
shr di, 4
add ax, di
mov es, ax
pop edi
and edi, 15
pop eax
ret
page_align_es_edi:
push eax
xor eax, eax
mov ax, es
shl eax, 4
add eax, edi
add eax, 4095
and eax, ~4095
shr eax, 4
mov es, ax
pop eax
xor edi, edi
ret
print16:
push di
push cx
push ax
.ind:
mov di, 0
mov cx, ax
.lup:
mov al, [ds:si]
mov [fs:di], al
inc si
inc di
inc di
dec cx
jnz .lup
mov [.ind + 1], di ;SMC
pop ax
pop cx
pop di
ret
ld_lba:
pushad
call lba2chs
mov ch, al
mov dh, dl
.drive:
mov dl, 0
mov ah, 2
mov al, 1
int 0x13
popad
ret
; In: AX = lba
; Out: CX = sector, AX = cylinder, DX = head
lba2chs:
push bx
.spt:
mov bx, 0xF157
xor dx, dx
div bx
mov cx, dx
inc cx
.numheads:
mov bx, 0x9001
xor dx, dx
div bx
pop bx
ret
; In: EAX = inode
; Out: *BOOT1_SEGMENT:endSector = inode struct
get_inode:
push eax
push ebx
.abs1 equ ($ + 2)
add eax, strict dword 0xABCDEF42
push es
push ds
pop es
mov bx, endSector
call ld_lba
pop es
pop ebx
pop eax
ret
; In: *BOOT1_SEGMENT:endSector = inode struct
; Out: *ES:BX = data
read_inode:
push edx
push ecx
push eax
push esi
push edi
push ebx
mov dl, [endSector + 8] ;extent count
mov ecx, endSector + 104 ;extent starts
.lup:
mov eax, [ecx] ;start
mov esi, [ecx + 48] ;size of extent
.abs1 equ ($ + 2)
add eax, strict dword 0x12345678
.lup2:
call ld_lba
add bx, 512
inc eax
dec esi
jnz .lup2
add ecx, 8
dec dl
jnz .lup
mov edi, [esp] ;dest address
lea esi, [edi + 176]
test dword [endSector + 28], 1 << 19
jz .doesntHaveInline
add esi, 512 - 176
.doesntHaveInline:
mov ecx, [endSector + 32] ;filesize
push ds
push es
pop ds
rep movsb
pop ds
add esp, 4 ;ignore old ebx, because read_inode should return the addr after
pop edi
pop esi
pop eax
pop ecx
pop edx
ret
; In: *ES:EAX = directory content buffer, *ESI = name to test, ECX = name length
; Out: EAX = inode or 0 if not found
find_in_dirnode:
push ebx
push edx
push edi
mov edi, [endSector + 32] ;filesize
.lup:
movzx edx, word [es:eax + 10] ;record name length
cmp dx, cx
.lup2:
dec dx
mov bl, [es:eax + 12 + edx]
cmp bl, [esi + edx]
jne .next
test dx, dx
jnz .lup2
jmp .found
.next:
movzx edx, byte [es:eax + 9] ;record length
shl dx, 4
add eax, edx
sub edi, edx
jnz .lup
mov eax, 0
jmp .end
.found:
mov eax, [es:eax]
.end:
pop edi
pop edx
pop ebx
ret
fix_module_addresses:
push esi
push ecx
push eax
push ebx
movzx ecx, word [es:edi + 4] ;amount of syms
lea esi, [es:edi + 12 + ecx * 4]
lea esi, [es:esi + ecx * 2]
movzx ecx, word [es:edi + 6] ;amount of relocs
mov eax, esi ;ptr to relocs
lea esi, [esi + ecx * 4] ;ptr to data
add esi, 15
and esi, ~15
mov [es:edi], esi ;Replace the MOD\0 magic header with the base address
test ecx, ecx ;If none, end
jz .end
.lup:
; Apply relocation
mov ebx, [es:eax]
add ebx, esi
add [es:ebx], esi
add eax, 4
dec ecx
jnz .lup
.end:
pop ebx
pop eax
pop ecx
pop esi
ret
bits 32
inPE:
mov [BOOT1_ADDR + TSS.ss0], dword 0x10
mov esp, [BOOT1_ADDR + TSS.esp0]
mov eax, 40
ltr ax
mov ax, [BOOT1_ADDR + print16.ind + 1]
mov [BOOT1_ADDR + print32.LAST], ax
mov esi, BOOT1_ADDR + MSG_STEP2s
mov eax, MSG_STEP2s.end - MSG_STEP2s
call print32
.KERNEL_START equ ($ + 1)
mov edi, strict dword 0
lea ebx, [edi + 14]
; Sym 0: ppm_Bitmap
mov eax, [ebx]
add eax, [edi] ;Base address that used to be magic header
push dword [BOOT1_ADDR + TSS.esp0] ;As said before, end of stack ~ beginning of mmap!
pop dword [eax]
add ebx, 6
; Sym 1: vpm_init
mov eax, [ebx]
add eax, [edi]
.IMPORTANT_MEM_END equ ($ + 1)
push strict dword 0
call eax
add esp, 4
add ebx, 6
; Sym 2: vpm_map
mov eax, [ebx]
add eax, [edi]
mov [BOOT1_ADDR + .VPM_MAP_ENTRY], eax
add ebx, 6
; Sym 3: canal_init
mov eax, [ebx]
add eax, [edi]
call eax
add ebx, 6
; Sym 4: pci_init
mov eax, [ebx]
add eax, [edi]
call eax
add ebx, 6
; Sym 5: scheduler_init
mov eax, [ebx]
add eax, [edi]
call eax
add ebx, 6
; Sym 6: scheduler_spawn
mov eax, [ebx]
add eax, [edi]
mov [BOOT1_ADDR + .SCHEDULER_SPAWN_ENTRY], eax
add ebx, 6
; Sym 7: scheduler_start
mov eax, [ebx]
add eax, [edi]
mov [BOOT1_ADDR + .SCHEDULER_START_ENTRY], eax
.MOD_COUNT equ ($ + 1)
mov ebp, strict dword 0
.modspawnlup:
; Find next module
movzx ecx, word [edi + 4]
lea eax, [edi + ecx * 4]
lea eax, [eax + ecx * 2]
movzx ecx, word [edi + 6]
lea eax, [eax + ecx * 4]
add eax, 15
and eax, ~15
mov ecx, [edi + 8]
lea eax, [eax + ecx]
add eax, 4096 + 4095
and eax, ~4095
mov edi, eax
mov ebx, 0x40000000
call rebase_module32
sub edx, edi
push strict dword edx
push strict dword edi
push strict dword 0x40000000
push strict dword 1 ;user
lea eax, [edi - 4096] ; cr3
push eax
.VPM_MAP_ENTRY equ ($ + 1)
mov eax, strict dword 0
call eax
add esp, 20
push strict dword 0
.SCHEDULER_SPAWN_ENTRY equ ($ + 1)
mov eax, strict dword 0
call eax
add esp, 4
lea ebx, [edi - 4096]
mov [eax + 46], ebx ;cr3
mov ebx, [edi + 14] ;get sym 0 (modentry)
add ebx, [edi] ;add data offset
mov [eax + 34], ebx ;eip
dec ebp
jnz .modspawnlup
.SCHEDULER_START_ENTRY equ ($ + 1)
mov eax, strict dword 0
jmp eax
print32:
push ebx
push eax
push ecx
movzx ebx, word [BOOT1_ADDR + .LAST]
mov ecx, eax
.lup:
mov al, [esi]
mov [0xB8000 + ebx], al
inc esi
inc ebx
inc ebx
dec ecx
jnz .lup
mov [BOOT1_ADDR + .LAST], bx
pop ecx
pop eax
pop ebx
ret
.LAST: dw 0
; In: EDI = module pointer, EBX = rebase address
; Out: EDX = physical module end
rebase_module32:
push ecx
push eax
push ebx
push ebp
movzx ecx, word [edi + 4]
lea eax, [edi + 12 + ecx * 2]
lea eax, [eax + ecx * 4] ; eax = relocations pointer
movzx ecx, word [edi + 6] ;ecx = amount of relocations
lea edx, [eax + ecx * 4] ; edx = data pointer
add edx, 15
and edx, ~15
mov [edi], edx ;Store offset of data buffer in
sub [edi], edi ;file in place of magic header
add [edi], ebx ;
mov ebx, [edi]
test ecx, ecx
jz .end
.lup:
mov ebp, [eax]
add [edx + ebp], ebx
add eax, 4
dec ecx
jnz .lup
.end:
add edx, [edi + 8]
pop ebp
pop ebx
pop eax
pop ecx
ret
MSG_FAIL: db "Failed to detect memory map. "
.end:
MSG_START: db "Starting eklernel. "
.end:
MSG_DETECTED_MEMORY_MAP: db "Found memory map. "
.end:
MSG_STEP2s: db "Entered protected mode. "
.end:
MSG_STEP3s: db "Generated paging structures. "
.end:
MSG_STEP4f: db "Boot filesystem must have block size of 1024. "
.end:
KERNEL_FILE: db "krnl.mod"
.end:
MSG_STEP5f: db "Kernel not found; aborting boot. "
.end:
GDT:
dw (GDT.END - GDT) - 1 ;GDT descriptor in the null entry
dd BOOT1_ADDR + GDT
dw 0
dw 0xFFFF, 0x0000
db 0x00, BIT_READWRITE | BIT_EXECUTABLE | BIT_ISCODEORDATA | BIT_PRESENT | (0 << 5)
.R0CSLIMFLAGS:
db (128 | 64) | 0xF
db 0
dw 0xFFFF, 0x0000
db 0x00, BIT_READWRITE | BIT_ISCODEORDATA | BIT_PRESENT | (0 << 5)
db (128 | 64) | 0xF
db 0
dw 0xFFFF, 0x0000
db 0x00, BIT_READWRITE | BIT_EXECUTABLE | BIT_ISCODEORDATA | BIT_PRESENT | (3 << 5)
db (128 | 64) | 0xF
db 0
dw 0xFFFF, 0x0000
db 0x00, BIT_READWRITE | BIT_ISCODEORDATA | BIT_PRESENT | (3 << 5)
db (128 | 64) | 0xF
db 0
dw (TSS.END - TSS) - 1
dw TSS
db BOOT1_ADDR / 0x10000, 1 | 8 | 128
db 0, 0
.END:
TSS:
dd 0
.esp0: dd 0
.ss0: dd 0
times 23 dd 0
.END:
end:
times (end - start + 511) / 512 * 512 - ($ - $$) db 0
endSector:

181
src/kernel/arch/x86/canal.c Normal file
View File

@@ -0,0 +1,181 @@
#include"canal.h"
#include"vpm.h"
#include"mem.h"
#include"scheduler.h"
#include"ppm.h"
static inline void pr(int c) {
asm volatile("outb %%al, $0xE9" :: "a"(c) :);
}
static inline void pri(size_t num) {
char buf[16] = {};
int i = 16;
do {
buf[--i] = num % 10;
num /= 10;
} while(num);
for(; i < 16; i++) {
pr(buf[i] + '0');
}
}
static inline void prcs(const char *str) {
while(*str) {
pr(*str);
str++;
}
}
static Canal *canals = 0;
static Link *links = 0;
void canal_init() {
uint32_t cr3;
asm volatile("movl %%cr3, %0" : "=r"(cr3) :);
canals = vpm_map(cr3, VPM_KERNEL, -1, -1, 4096);
kmemw1(canals, 0, 4096);
links = vpm_map(cr3, VPM_KERNEL, -1, -1, 4096);
kmemw1(links, 0xFF, 4096);
}
uint32_t canal_create(uint64_t name, uint16_t hostProcessId) {
Process *hostProcess = scheduler_find(hostProcessId);
for(int i = 0; i < 4096 / sizeof(Canal); i++) {
if(canals[i].name == name) return -2;
if(canals[i].name == 0) {
canals[i].name = name;
canals[i].hostProcess = hostProcess;
canals[i].links = NULL;
canals[i].ownedNext = hostProcess->ownedCanal;
hostProcess->ownedCanal = &canals[i];
return i;
}
}
return -1;
}
uint32_t link_create(uint64_t canalName, uint16_t guestProcessId, uint32_t areaSize) {
int canalId = -1;
for(int i = 0; i < 4096 / sizeof(Canal); i++) {
if(canals[i].name == canalName) {
canalId = i;
break;
}
}
Process *guest = scheduler_find(guestProcessId);
if(canalId == -1) return -1;
if(canals[canalId].hostProcess == guest) return -1;
uint32_t hostCR3 = canals[canalId].hostProcess->ctx.cr3;
uint32_t hostAreaVirtAddr = vpm_find_free(hostCR3, VPM_USER, areaSize);
uint32_t guestCR3 = guest->ctx.cr3;
uint32_t guestAreaVirtAddr = vpm_find_free(guestCR3, VPM_USER, areaSize);
/* TODO: Fail if areas not found. */
for(int i = 0; i < 4096 / sizeof(Link); i++) {
if(links[i].canalId == -1) {
links[i].canalId = canalId;
links[i].guestProcess = guest;
links[i].hostVirtAddr = hostAreaVirtAddr;
links[i].guestVirtAddr = guestAreaVirtAddr;
links[i].flags = 0;
uint32_t pages = (areaSize + 4095) / 4096;
uint32_t phys = ppm_alloc(pages);
vpm_map(hostCR3, VPM_USER, hostAreaVirtAddr, phys, areaSize);
vpm_map(guestCR3, VPM_USER, guestAreaVirtAddr, phys, areaSize);
canals[canalId].hostProcess->eventsRequest++;
links[i].nextInCanal = canals[canalId].links;
canals[canalId].links = &links[i];
links[i].nextGuestLink = guest->guestLinks;
guest->guestLinks = &links[i];
return guestAreaVirtAddr;
}
}
return -1;
}
uint32_t canal_accept(uint16_t hostProcessId, uint32_t canalId) {
for(int i = 0; i < 4096 / sizeof(Link); i++) {
if(links[i].canalId != -1 && canals[links[i].canalId].hostProcess->id == hostProcessId && (canalId == (uint32_t)-1 || links[i].canalId == canalId) && !(links[i].flags & LINK_FLAG_ACCEPTED)) {
links[i].flags = links[i].flags | LINK_FLAG_ACCEPTED;
prcs("RETURNING ");
pri(links[i].hostVirtAddr);
pr('\n');
return links[i].hostVirtAddr;
}
}
return -1;
}
void link_send_signal_from(uint16_t processId, uint32_t processAreaAddr, uint32_t meta) {
for(int i = 0; i < 4096 / sizeof(Link); i++) {
if(links[i].guestProcess->id == processId && links[i].guestVirtAddr == processAreaAddr) {
if(!(links[i].flags & LINK_FLAG_G2H)) {
canals[links[i].canalId].hostProcess->eventsSignal++;
links[i].flags |= LINK_FLAG_G2H;
}
links[i].metaG2H = meta;
return;
} else if(canals[links[i].canalId].hostProcess->id == processId && links[i].hostVirtAddr == processAreaAddr) {
if(!(links[i].flags & LINK_FLAG_H2G)) {
links[i].guestProcess->eventsSignal++;
links[i].flags |= LINK_FLAG_H2G;
}
links[i].metaH2G = meta;
return;
}
}
}
uint32_t is_signal_awaiting_to_concerning_link(uint16_t processId, uint32_t area, uint32_t *metaOut, uint32_t *canalId) {
for(int i = 0; i < 4096 / sizeof(Link); i++) {
if((links[i].guestProcess->id == processId && (area == -1 || links[i].guestVirtAddr == area) && (links[i].flags & LINK_FLAG_H2G))
|| (canals[links[i].canalId].hostProcess->id == processId && (area == -1 || area == links[i].hostVirtAddr) && (links[i].flags & LINK_FLAG_G2H))) {
*canalId = links[i].canalId;
return signal_accept(scheduler_find(processId), &links[i], metaOut);
}
}
return -1;
}
uint32_t signal_accept(Process *p, Link *l, uint32_t *meta) {
p->eventsSignal--;
if(l->guestProcess == p) {
l->flags &= ~LINK_FLAG_H2G;
*meta = l->metaH2G;
return l->guestVirtAddr;
} else {
l->flags &= ~LINK_FLAG_G2H;
*meta = l->metaG2H;
return l->hostVirtAddr;
}
}

View File

@@ -0,0 +1,42 @@
#ifndef _CANAL_H
#define _CANAL_H
#include<stdint.h>
#define LINK_FLAG_ACCEPTED 1
#define LINK_FLAG_G2H 2
#define LINK_FLAG_H2G 4
struct Process;
struct Link;
typedef struct Canal {
uint64_t name;
struct Process *hostProcess;
struct Canal *ownedNext;
struct Link *links;
} __attribute__((packed)) Canal;
typedef struct Link {
uint32_t canalId;
uint32_t hostVirtAddr;
struct Process *guestProcess;
uint32_t guestVirtAddr;
uint32_t metaG2H;
uint32_t metaH2G;
uint8_t flags;
struct Link *nextInCanal;
struct Link *nextGuestLink;
} __attribute__((packed)) Link;
uint32_t canal_create(uint64_t name, uint16_t hostProcessId);
uint32_t link_create(uint64_t canal, uint16_t guestProcessId, uint32_t areaSize);
uint32_t canal_accept(uint16_t hostProcessId, uint32_t canalId);
void link_send_signal_from(uint16_t processId, uint32_t processAreaAddr, uint32_t meta);
uint32_t link_get_oldest_signal_to(uint16_t processId);
uint32_t is_signal_awaiting_to_concerning_link(uint16_t processId, uint32_t area, uint32_t *metaOut, uint32_t *canalId);
uint32_t signal_accept(struct Process *p, Link *l, uint32_t *meta);
#endif

View File

@@ -0,0 +1,20 @@
#ifndef _X86_CONSTS_H
#define _X86_CONSTS_H
#define EFLAGS_IOPL_0 (0 << 12)
#define EFLAGS_IOPL_1 (1 << 12)
#define EFLAGS_IOPL_2 (2 << 12)
#define EFLAGS_IOPL_3 (3 << 12)
#define EFLAGS_IF (1 << 9)
#define EFLAGS_RESET 2
#define RPL_0 0
#define RPL_1 1
#define RPL_2 2
#define RPL_3 3
#define PAGE_BIT_PRESENT 1
#define PAGE_BIT_WRITABLE 2
#define PAGE_BIT_USER 4
#endif

View File

@@ -0,0 +1,827 @@
cpu 386
bits 32
TIMER_FREQUENCY equ 250;Hz
; TODO: perform IO waits
section .text
extern scheduler_switch
extern scheduler_CurrentProcess
pit_handler:
extern scheduler_Tick
inc dword [scheduler_Tick]
push eax
mov al, 0x20
out 0x20, al
pop eax
ctx_switch:
push eax
mov eax, [scheduler_CurrentProcess]
test eax, eax
jnz .a
add esp, 16
jmp .b
.a:
pop dword [eax + 2] ;eax
pop dword [eax + 34] ;eip
pop dword [eax + 42] ;cs
pop dword [eax + 38] ;eflags
mov [eax + 6], ebx
mov [eax + 10], ecx
mov [eax + 14], edx
mov [eax + 18], esi
mov [eax + 22], edi
mov [eax + 26], ebp
cmp dword [eax + 42], 8 ;CS 8 implies ring 0
jne .isR3
mov [eax + 30], esp
jmp .b
.isR3:
pop dword [eax + 30] ;esp
add esp, 4 ;ss
.b:
call scheduler_switch
jmp jump_to_process
global jump_to_process
jump_to_process:
mov eax, [scheduler_CurrentProcess]
test eax, eax
jnz .c
; No next process, goto hlt loop.
push dword 0x202
push dword 8
push haltLoop
iretd
.c:
mov ebx, [eax + 46]
mov cr3, ebx
mov ebx, [eax + 6]
mov ecx, [eax + 10]
mov edx, [eax + 14]
mov esi, [eax + 18]
mov edi, [eax + 22]
mov ebp, [eax + 26]
cmp dword [eax + 42], 8
je .isR0
push dword 32 | 3
push dword [eax + 30]
jmp .b
.isR0:
mov esp, [eax + 30]
.b:
push dword [eax + 38] ;eflags
push dword [eax + 42] ;cs
push dword [eax + 34] ;eip
mov eax, [eax + 2]
iretd
set_bit:
push edx
push ebx
push ecx
push eax
shl ebx, 1
mov dx, 0x3C4
mov al, 2
out dx, al
mov ecx, ebx
and ecx, 3
mov eax, 1
shl eax, cl
mov dx, 0x3C5
out dx, al
mov ecx, ebx
sar ecx, 2
pop eax
mov [0xA0000 + ecx], byte al
pop ecx
pop ebx
pop edx
ret
write_dword:
push eax
push ecx
mov ecx, 32
.lup:
rol eax, 1
push eax
and eax, 1
shl eax, 4
add eax, 20
call set_bit
pop eax
.nz:
inc ebx
dec ecx
jnz .lup
pop ecx
pop eax
ret
clear_screen:
push eax
push ecx
push edx
push edi
mov dx, 0x3C4
mov al, 2
out dx, al
inc dx
mov al, 15
out dx, al
mov edi, 0xA0000
mov ecx, 4800
mov eax, 0
rep stosd
pop edi
pop edx
pop ecx
pop eax
ret
pgf_handler:
call clear_screen
pop eax ;error code
mov ebx, 0
call write_dword
inc ebx
mov eax, cr2 ;accessed address
call write_dword
inc ebx
pop eax ;instruction cause of exception
call write_dword
add ebx, 100
mov eax, [eax] ;instruction data
call write_dword
.LOUP:
hlt
jmp .LOUP
dbf_handler:
add esp, 4
mov [0xA0000], dword "D_F_"
.LOUP:
hlt
jmp .LOUP
gpf_handler:
pop eax
movzx ebx, al
and bl, 0xF
mov bl, [.tbl + ebx]
mov [0xB800E], bl
movzx ebx, al
shr bl, 4
mov bl, [.tbl + ebx]
mov [0xB800C], bl
shr eax, 8
movzx ebx, al
and bl, 0xF
mov bl, [.tbl + ebx]
mov [0xB800A], bl
movzx ebx, al
shr bl, 4
mov bl, [.tbl + ebx]
mov [0xB8008], bl
shr eax, 8
movzx ebx, al
and bl, 0xF
mov bl, [.tbl + ebx]
mov [0xB8006], bl
movzx ebx, al
shr bl, 4
mov bl, [.tbl + ebx]
mov [0xB8004], bl
shr eax, 8
movzx ebx, al
and bl, 0xF
mov bl, [.tbl + ebx]
mov [0xB8002], bl
movzx ebx, al
shr bl, 4
mov bl, [.tbl + ebx]
mov [0xB8000], bl
shr eax, 8
.LOUP:
hlt
jmp .LOUP
.tbl: db "0123456789ABCDEF"
spur_handler:
iret
syscall_int_entry:
cmp eax, (.tblend - .tbl) / 4
jae .invalid
jmp [.tbl + eax * 4]
.invalid:
mov eax, 0
iret
.tbl:
dd .sys_vpm_map, .sys_canal_create, .sys_link_create, .sys_canal_accept, .sys_signal_send, .sys_signal_wait, .sys_pci_claim, .sys_pci_read, .sys_vpm_unmap, .sys_vpm_get_phys, .sys_sleep, .sys_pci_write_1, .sys_pci_write_2, .sys_pci_write_4, .sys_irq_claim, .sys_wait_for_irq, .sys_create_thread, .sys_spawn, .sys_abuse_map, .sys_release, .sys_abuse_state, .sys_exit, .sys_event_wait
.tblend:
.sys_vpm_map:
push ecx
push edx
push esi
push edi
push 1 ;USER mapping
mov eax, cr3
push eax
extern vpm_map
call vpm_map
add esp, 16
pop edx
pop ecx
iret
.sys_canal_create:
push ecx
push edx
mov eax, [scheduler_CurrentProcess]
movzx eax, word [eax] ;process ID
push eax
push esi
push edi
extern canal_create
call canal_create
add esp, 12
pop edx
pop ecx
iret
.sys_link_create:
push ecx
push edx
mov eax, [scheduler_CurrentProcess]
movzx eax, word [eax]
push eax
push esi
push edi
extern link_create
call link_create
add esp, 12
pop edx
pop ecx
iret
.sys_canal_accept:
push ecx
push edx
push edi
mov eax, [scheduler_CurrentProcess]
movzx eax, word [eax] ;id
push eax
extern canal_accept
call canal_accept
add esp, 8
pop edx
pop ecx
iret
.sys_signal_send:
push ecx
push edx
push esi
push edi
mov eax, [scheduler_CurrentProcess]
movzx eax, word [eax] ;id
push eax
extern link_send_signal_from
call link_send_signal_from
pop eax
add esp, 8
pop edx
pop ecx
iret
.sys_signal_wait:
push eax
mov eax, [scheduler_CurrentProcess]
mov [eax + 50], byte 1
mov [eax + 51], edi
pop eax
jmp ctx_switch
.sys_pci_claim:
push ecx
push edx
push edi
extern pci_claim
call pci_claim
pop edx
pop edx
pop ecx
iret
.sys_pci_read:
push ecx
push edx
push esi
push edi
extern pci_read
call pci_read
add esp, 8
pop edx
pop ecx
iret
.sys_vpm_unmap:
push eax
push ecx
push edx
push esi
push edi
mov eax, cr3
push eax
extern vpm_unmap
call vpm_unmap
add esp, 12
pop edx
pop ecx
pop eax
iret
.sys_vpm_get_phys:
push ecx
push edx
push edi
mov eax, cr3
push eax
extern vpm_get_phys
call vpm_get_phys
add esp, 8
pop edx
pop ecx
iret
.sys_sleep:
push edx
push ebx
push eax
xor edx, edx
mov eax, edi
mov ebx, 1000 / TIMER_FREQUENCY
div ebx
add eax, [scheduler_Tick]
mov ebx, [scheduler_CurrentProcess]
mov byte [ebx + 50], 2
mov [ebx + 51], eax
pop eax
pop ebx
pop edx
jmp ctx_switch
.sys_pci_write_1:
push eax
push ecx
push edx
push esi
push edi
extern pci_write_1
call pci_write_1
add esp, 8
pop edx
pop ecx
pop eax
iret
.sys_pci_write_2:
push eax
push ecx
push edx
push esi
push edi
extern pci_write_2
call pci_write_2
add esp, 8
pop edx
pop ecx
pop eax
iret
.sys_pci_write_4:
push eax
push ecx
push edx
push esi
push edi
extern pci_write_4
call pci_write_4
add esp, 8
pop edx
pop ecx
pop eax
iret
.sys_irq_claim:
push ecx
push edx
call irq_claim
pop edx
pop ecx
iret
.sys_wait_for_irq:
push ecx
mov ecx, edi
; TODO: check privilege
call toggle_irq_mask
mov ecx, [scheduler_CurrentProcess]
mov [ecx + 50], byte 3 ; Wait type IRQ
pop ecx
jmp ctx_switch
.sys_create_thread:
push eax
push ecx
push edx
extern scheduler_spawn
call scheduler_spawn
mov ecx, cr3
mov [eax + 46], ecx ;cr3
mov [eax + 34], edi ;eip
pop edx
pop ecx
pop eax
mov eax, 1
iret
.sys_spawn:
push ecx
push edx
call scheduler_spawn
test eax, eax
jnz .sys_spawn_spawned
pop edx
pop ecx
iret
.sys_spawn_spawned:
push eax
mov eax, [scheduler_CurrentProcess]
movzx eax, word [eax] ;proc ID
push eax
extern scheduler_enslave
call scheduler_enslave
add esp, 8
pop edx
pop ecx
iret
.sys_abuse_map:
push ecx
push edx
push edi
call scheduler_find
add esp, 4
pop edx
pop ecx
test eax, eax
jz .notfound
push ecx
push edx
push ebx
push ecx
push edx
push esi
push dword [eax + 46] ;cr3
mov eax, cr3
push eax
extern vpm_double_map
call vpm_double_map
add esp, 24
pop edx
pop ecx
iret
.notfound:
mov eax, -1
iret
.sys_release:
push ecx
push edx
push edi
extern scheduler_unslave
call scheduler_unslave
pop edi
pop edx
pop ecx
iret
.sys_abuse_state:
push ecx
push edx
push edi
call scheduler_find
add esp, 4
pop edx
pop ecx
test eax, eax
jz .notfound2
push ecx
push edx
push edx
push esi
push eax
extern process_abuse_state
call process_abuse_state
add esp, 12
pop edx
pop ecx
iret
.notfound2:
mov eax, -1
iret
.sys_exit:
iret
.sys_event_wait:
push eax
push ecx
push edx
push edi
push dword [scheduler_CurrentProcess]
extern process_search_event
call process_search_event
add esp, 8
pop edx
pop ecx
pop eax
iret
global scheduler_start:
scheduler_start:
.pic_init:
mov al, 0x10 | 0x01
out 0x20, al
out 0xA0, al
mov al, 32
out 0x21, al
mov al, 40
out 0xA1, al
mov al, 4
out 0x21, al
mov al, 2
out 0xA1, al
mov al, 0x01
out 0x21, al
out 0xA1, al
.pic_mask:
mov al, ~1 ;PIT
out 0x21, al
mov al, ~0
out 0xA1, al
.idt:
; Page fault handler
mov eax, pgf_handler
and eax, 0x0000FFFF
or eax, 0x00080000
mov [idt + 14 * 8], eax
mov eax, pgf_handler
and eax, 0xFFFF0000
or eax, (14 << 8) | (1 << 15)
mov [idt + 14 * 8 + 4], eax
; Double fault handler
mov eax, dbf_handler
and eax, 0x0000FFFF
or eax, 0x00080000
mov [idt + 8 * 8], eax
mov eax, dbf_handler
and eax, 0xFFFF0000
or eax, (14 << 8) | (1 << 15)
mov [idt + 8 * 8 + 4], eax
; General protection fault handler
mov eax, gpf_handler
and eax, 0x0000FFFF
or eax, 0x00080000
mov [idt + 13 * 8], eax
mov eax, gpf_handler
and eax, 0xFFFF0000
or eax, (14 << 8) | (1 << 15)
mov [idt + 13 * 8 + 4], eax
; Timer scheduler handler
mov eax, pit_handler
and eax, 0x0000FFFF
or eax, 0x00080000
mov [idt + 32 * 8], eax
mov eax, pit_handler
and eax, 0xFFFF0000
or eax, (14 << 8) | (1 << 15)
mov [idt + 32 * 8 + 4], eax
; Spurious interrupt handler
mov eax, spur_handler
and eax, 0x0000FFFF
or eax, 0x00080000
mov [idt + 39 * 8], eax
mov eax, spur_handler
and eax, 0xFFFF0000
or eax, (14 << 8) | (1 << 15)
mov [idt + 39 * 8 + 4], eax
; Software interrupt syscall entry point
mov eax, syscall_int_entry
and eax, 0x0000FFFF
or eax, 0x00080000
mov [idt + 0xEC * 8], eax
mov eax, syscall_int_entry
and eax, 0xFFFF0000
or eax, (14 << 8) | (1 << 15) | (3 << 13)
mov [idt + 0xEC * 8 + 4], eax
push idt
push (idt.end - idt - 1) << 16
lidt [esp + 2]
add esp, 8
.pit:
mov al, (2 << 1) | (2 << 4)
out 0x43, al
mov al, (1193182 / TIMER_FREQUENCY) % 256
out 0x40, al
mov al, (1193182 / TIMER_FREQUENCY) / 256
out 0x40, al
sti
haltLoop:
hlt
jmp haltLoop
; ecx = id
toggle_irq_mask:
push ecx
push ebx
push edx
push eax
mov dx, 0x21
cmp cl, 8
jl .lower
sub cl, 8
mov dx, 0xA1
.lower:
mov bl, 1
shl bl, cl
in al, dx
xor al, bl
out dx, al
pop eax
pop edx
pop ebx
pop ecx
ret
irq_claim:
test edi, edi
jnz .notTimer
xor eax, eax
ret
.notTimer:
mov eax, [scheduler_CurrentProcess]
mov bx, [eax] ;id
lea eax, [edi * 8]
lea eax, [eax * 2 + edi] ;17x
lea eax, [eax + irqhandlers - 17]
mov [eax + 2], esi ;mov edi, handler
mov [eax + 7], bx ;mov esi, process id
mov ecx, edi
mov [eax + 12], cl
push eax
and eax, 0x0000FFFF
or eax, 0x00080000
mov [idt + edi * 8 + 256], eax
pop eax
and eax, 0xFFFF0000
or eax, (14 << 8) | (1 << 15)
mov [idt + edi * 8 + 256 + 4], eax
mov eax, 1
ret
irqhandlers:
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
jmp strict word irqhandler
pushad
mov edi, strict dword 0
mov esi, strict dword 0
mov cl, strict byte 0
irqhandler:
call toggle_irq_mask
mov al, 0x20
out 0x20, al
push esi
extern scheduler_find
call scheduler_find
add esp, 4
mov [eax + 55], edi
popad
iret
idt:
times 256 dq 0
.end:

View File

@@ -0,0 +1,67 @@
section .data
section .text
global klogc
klogc:
mov eax, [esp + 4]
out 0xE9, al
ret
global klogs
klogs:
mov ecx, [esp + 4]
.lup:
mov al, [ecx]
test al, al
jz .end
out 0xE9, al
inc ecx
jmp .lup
.end:
ret
;~ global klogp
;~ klogp:
;~ push eax
;~ mov edx, [esp + 12]
;~ mov eax, edx
;~ shr eax, 28
;~ call .logh
;~ mov eax, edx
;~ shr eax, 24
;~ and al, 0x0F
;~ call .logh
;~ mov eax, edx
;~ shr eax, 20
;~ and al, 0x0F
;~ call .logh
;~ mov eax, edx
;~ shr eax, 16
;~ and al, 0x0F
;~ call .logh
;~ mov eax, edx
;~ shr eax, 12
;~ and al, 0x0F
;~ call .logh
;~ mov eax, edx
;~ shr eax, 8
;~ and al, 0x0F
;~ call .logh
;~ mov eax, edx
;~ shr eax, 4
;~ and al, 0x0F
;~ call .logh
;~ mov eax, edx
;~ and al, 0x0F
;~ call .logh
;~ pop eax
;~ ret
;~ .logh:
;~ add al, '0'
;~ cmp al, '0' + 9
;~ jle .p
;~ add al, 7
;~ .p:
;~ out 0xE9, al
;~ ret

15
src/kernel/arch/x86/mem.c Normal file
View File

@@ -0,0 +1,15 @@
#include"mem.h"
void kmemw1(void *_ptr, uint8_t val, size_t amount) {
uint8_t *ptr = _ptr;
for(size_t i = 0; i < amount; i++) {
*(ptr++) = val;
}
}
void kmemw4(void *_ptr, uint32_t val, size_t amount) {
uint32_t *ptr = _ptr;
for(size_t i = 0; i < amount; i++) {
*(ptr++) = val;
}
}

10
src/kernel/arch/x86/mem.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef _MEM_H
#define _MEM_H
#include<stdint.h>
#include<stddef.h>
void kmemw1(void *ptr, uint8_t val, size_t amount);
void kmemw4(void *ptr, uint32_t val, size_t amount);
#endif

60
src/kernel/arch/x86/pci.c Normal file
View File

@@ -0,0 +1,60 @@
#include"pci.h"
#include<stddef.h>
#include"vpm.h"
size_t claimedCount = 0;
uint32_t *claimed;
void pci_init() {
uint32_t cr3;
asm volatile("movl %%cr3, %0" : "=r" (cr3) :);
claimed = vpm_map(cr3, VPM_KERNEL, -1, -1, 4096);
}
uint32_t pci_claim(uint32_t cscp) {
for(int b = 0; b < 256; b++) {
for(int d = 0; d < 32; d++) {
for(int f = 0; f < 8; f++) {
uint32_t id = (b << 16) | (d << 11) | (f << 8);
if((pci_read(id, 8) & 0xFFFFFF00) == cscp) {
for(size_t i = 0; i < claimedCount; i++) {
if(claimed[i] == id) {
goto cont;
}
}
claimed[claimedCount++] = id;
return id;
}
cont:;
}
}
}
return -1;
}
uint32_t pci_read(uint32_t id, uint8_t offset) {
asm volatile("outl %%eax, %%dx" : : "a"(0x80000000 | id | offset), "d"(0xCF8));
uint32_t ret;
asm volatile("inl %%dx, %%eax" : "=a"(ret) : "d"(0xCFC));
return ret;
}
void pci_write_1(uint32_t id, uint8_t offset, uint8_t val) {
asm volatile("outl %%eax, %%dx" : : "a"(0x80000000 | id | offset), "d"(0xCF8));
asm volatile("outb %%al, %%dx" : : "a"(val), "d"(0xCFC + (offset & 3)));
}
void pci_write_2(uint32_t id, uint8_t offset, uint16_t val) {
asm volatile("outl %%eax, %%dx" : : "a"(0x80000000 | id | offset), "d"(0xCF8));
asm volatile("outw %%ax, %%dx" : : "a"(val), "d"(0xCFC + (offset & 2)));
}
void pci_write_4(uint32_t id, uint8_t offset, uint32_t val) {
asm volatile("outl %%eax, %%dx" : : "a"(0x80000000 | id | offset), "d"(0xCF8));
asm volatile("outl %%eax, %%dx" : : "a"(val), "d"(0xCFC));
}

13
src/kernel/arch/x86/pci.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef _PCI_H
#define _PCI_H
#include<stdint.h>
void pci_init();
uint32_t pci_claim(uint32_t);
uint32_t pci_read(uint32_t, uint8_t);
void pci_write_1(uint32_t, uint8_t, uint8_t);
void pci_write_2(uint32_t, uint8_t, uint16_t);
void pci_write_4(uint32_t, uint8_t, uint32_t);
#endif

64
src/kernel/arch/x86/ppm.c Normal file
View File

@@ -0,0 +1,64 @@
#include"ppm.h"
#include<stdint.h>
typedef struct __attribute__((packed)) {
uint64_t start;
uint32_t length;
uint8_t flags;
uint8_t data[];
} PPMBitmap;
PPMBitmap *ppm_Bitmap;
static int availability_test(PPMBitmap *bm, size_t pg, size_t len) {
if(pg > bm->length - len) {
return 0;
}
while(len--) {
if(bm->data[pg / 8] & (1 << (pg % 8))) {
return 0;
}
pg++;
}
return 1;
}
static int mark(PPMBitmap *bm, size_t pg, size_t len) {
if(pg > bm->length - len) {
return 0;
}
while(len--) {
bm->data[pg / 8] |= 1 << (pg % 8);
pg++;
}
return 1;
}
uint64_t ppm_alloc(size_t len) {
PPMBitmap *bm = ppm_Bitmap;
for(int bmid = 0; bmid < 2; bmid++) {
if(bm->length < len) {
continue;
}
for(size_t pg = 0; pg <= bm->length - len; pg++) {
if(availability_test(bm, pg, len)) {
if(mark(bm, pg, len)) {
return bm->start + pg * 4096;
}
}
}
bm = (PPMBitmap*) ((uintptr_t) bm + sizeof(*bm) + (bm->length + 7) / 8);
}
return 0;
}

View File

@@ -0,0 +1,9 @@
#ifndef _PPM_H
#define _PPM_H
#include<stddef.h>
#include<stdint.h>
uint64_t ppm_alloc(size_t len);
#endif

View File

@@ -0,0 +1,46 @@
#ifndef _PROCESS_H
#define _PROCESS_H
#include<stdint.h>
struct Canal;
struct Link;
typedef struct __attribute__((packed)) {
uint32_t eax; //0
uint32_t ebx; //4
uint32_t ecx; //8
uint32_t edx; //12
uint32_t esi; //16
uint32_t edi; //20
uint32_t ebp; //24
uint32_t esp; //28
uint32_t eip; //32
uint32_t eflags; //36
uint32_t cs; //40
uint32_t cr3; //44
} Context;
#define WAIT_TYPE_NONE 0
#define WAIT_TYPE_SIGNAL 1
#define WAIT_TYPE_TIME 2
#define WAIT_TYPE_IRQ 3
#define WAIT_TYPE_MINOR 4
typedef struct __attribute__((packed)) Process {
uint16_t id;
Context ctx;
uint8_t waitType;
uint32_t waitValue;
uint32_t irqWaiting;
uint8_t minipriority;
struct Process *next;
uint16_t ownerId;
uint8_t eventsRequest;
uint8_t eventsSignal;
uint8_t eventsClosed;
struct Canal *ownedCanal;
struct Link *guestLinks;
} Process;
#endif

View File

@@ -0,0 +1,301 @@
#include"scheduler.h"
#include"vpm.h"
#include"mem.h"
#include<kernel/arch/x86/consts.h>
#include"canal.h"
#define PROCESS_ZONE_SIZE 4096
#define HANDLE_ZONE_SIZE 4096
Process *scheduler_ProcessZone = 0;
Process *scheduler_ProcessQueues[TOTAL_PRIORITIES];
static int scheduler_CurrentPriority;
volatile Process *scheduler_CurrentProcess = 0;
uint32_t scheduler_Tick;
void klogs(const char *str);
void klogc(int c);
static void klogp(void *p) {
static char hex[16]="0123456789ABCDEF";
uintptr_t i = (uintptr_t) p;
klogc(hex[(i >> 28) & 0xF]);
klogc(hex[(i >> 24) & 0xF]);
klogc(hex[(i >> 20) & 0xF]);
klogc(hex[(i >> 16) & 0xF]);
klogc(hex[(i >> 12) & 0xF]);
klogc(hex[(i >> 8) & 0xF]);
klogc(hex[(i >> 4) & 0xF]);
klogc(hex[(i >> 0) & 0xF]);
}
void scheduler_init() {
uint32_t cr3;
asm volatile("movl %%cr3, %0" : "=r" (cr3) :);
scheduler_ProcessZone = vpm_map(cr3, VPM_KERNEL, -1, -1, PROCESS_ZONE_SIZE);
kmemw1(scheduler_ProcessZone, 0, PROCESS_ZONE_SIZE);
}
static int consider_switch(Process *p) {
if(p->waitType == WAIT_TYPE_SIGNAL) {
uint32_t meta = 0;
uint32_t canalId = -1;
uint32_t which = is_signal_awaiting_to_concerning_link(p->id, p->waitValue, &meta, &canalId);
if(which != 0xFFFFFFFF) {
p->waitType = WAIT_TYPE_NONE;
p->ctx.eax = which;
p->ctx.edx = meta;
p->ctx.ebx = canalId;
} else return 0;
} else if(p->waitType == WAIT_TYPE_TIME) {
if(p->waitValue <= scheduler_Tick) {
p->waitType = WAIT_TYPE_NONE;
} else return 0;
} else if(p->waitType == WAIT_TYPE_IRQ) {
if(p->irqWaiting) {
p->waitType = WAIT_TYPE_NONE;
p->ctx.eip = p->irqWaiting;
p->irqWaiting = 0;
} else return 0;
} else if(p->waitType == WAIT_TYPE_MINOR) {
//asm("xchg %bx, %bx");
return 0;
}
/*static char hex[16]="0123456789ABCDEF";
klogc('0' + p->id);
klogc(' ');
klogc(hex[p->priority / PRIORITY_UNIT]);
klogc('\n');*/
scheduler_CurrentPriority = p->minipriority / PRIORITY_UNIT;
scheduler_CurrentProcess = p;
return 1;
}
void scheduler_switch() {
if(scheduler_CurrentProcess == 0) {
for(int p = 0; p < TOTAL_PRIORITIES; p++) {
Process *q = scheduler_ProcessQueues[p];
while(q) {
if(consider_switch(q)) {
return;
}
q = q->next;
}
}
scheduler_CurrentProcess = 0;
return;
}
for(int p = 0; p < scheduler_CurrentPriority; p++) {
Process *q = scheduler_ProcessQueues[p];
while(q) {
if(consider_switch(q)) {
return;
}
q = q->next;
}
}
Process *p = scheduler_CurrentProcess;
do {
p = p->next;
if(!p) {
p = scheduler_ProcessQueues[scheduler_CurrentPriority];
}
if(consider_switch(p)) {
return;
}
} while(p != scheduler_CurrentProcess);
for(int p = scheduler_CurrentPriority + 1; p < TOTAL_PRIORITIES; p++) {
Process *q = scheduler_ProcessQueues[p];
while(q) {
if(consider_switch(q)) {
return;
}
q = q->next;
}
}
scheduler_CurrentProcess = 0;
}
Process *scheduler_find(uint16_t id) {
for(int p = 0; p < TOTAL_PRIORITIES; p++) {
Process *q = scheduler_ProcessQueues[p];
while(q) {
if(q->id == id) {
return q;
}
q = q->next;
}
}
return NULL;
}
static uint16_t next_free_id() {
for(uint32_t id = 1; id < 65536; id++) {
if(!scheduler_find(id)) {
return id;
}
}
return 0;
}
Process *scheduler_spawn(int minipriority) {
int found = 0;
Process *p = scheduler_ProcessZone;
for(size_t i = 0; i < PROCESS_ZONE_SIZE / sizeof(Process); i++) {
if(p->id == 0) {
found = 1;
break;
}
p++;
}
if(!found) {
return NULL;
}
kmemw1(p, 0, sizeof(*p));
p->id = next_free_id();
p->ctx.eflags = EFLAGS_RESET | EFLAGS_IF | EFLAGS_IOPL_3;
p->ctx.cs = 24 | RPL_3;
p->waitType = WAIT_TYPE_NONE;
p->irqWaiting = 0;
p->minipriority = minipriority;
p->next = scheduler_ProcessQueues[minipriority / PRIORITY_UNIT];
p->eventsRequest = 0;
p->eventsSignal = 0;
p->eventsClosed = 0;
p->ownedCanal = NULL;
p->guestLinks = NULL;
scheduler_ProcessQueues[minipriority / PRIORITY_UNIT] = p;
return p;
}
size_t scheduler_enslave(uint16_t ownerId, Process *child) {
child->waitType = WAIT_TYPE_MINOR;
child->ownerId = ownerId;
// Should not be how it works.
child->ctx.cr3 = vpm_create_space();
return child->id;
}
int scheduler_unslave(size_t handle) {
struct Process *proc = scheduler_find(handle);
if(proc && proc->waitType == WAIT_TYPE_MINOR) {
proc->waitType = WAIT_TYPE_NONE;
return 0;
}
return -1;
}
#define SYS_STATE_X86_EIP 0
int process_abuse_state(struct Process *proc, size_t type, uintmax_t val) {
switch(type) {
case SYS_STATE_X86_EIP:
proc->ctx.eip = val;
break;
default:
return -1;
}
return 0;
}
#define KEV_TYPE_NONE 0
#define KEV_TYPE_LINK_REQUEST 1
#define KEV_TYPE_LINK_SIGNAL 2
#define KEV_TYPE_LINK_CLOSE 3
typedef struct __attribute__((packed)) {
uint8_t type;
uint32_t canalId;
void *area;
uint32_t meta;
} KEvent;
int process_search_event(Process *proc, KEvent *kev) {
if(proc->eventsRequest) {
kev->type = KEV_TYPE_LINK_REQUEST;
Canal *c = proc->ownedCanal;
while(c) {
Link *l = c->links;
while(l) {
if(!(l->flags & LINK_FLAG_ACCEPTED)) {
kev->canalId = l->canalId;
return 1;
}
l = l->nextInCanal;
}
c = c->ownedNext;
}
}
if(proc->eventsSignal) {
kev->type = KEV_TYPE_LINK_SIGNAL;
Link *l = proc->guestLinks;
while(l) {
if(l->flags & LINK_FLAG_H2G) {
kev->area = signal_accept(proc, l, &kev->meta);
return 1;
}
l = l->nextGuestLink;
}
}
if(proc->eventsSignal) {
kev->type = KEV_TYPE_LINK_SIGNAL;
Canal *c = proc->ownedCanal;
while(c) {
Link *l = c->links;
while(l) {
if(l->flags & LINK_FLAG_G2H) {
kev->area = signal_accept(proc, l, &kev->meta);
return 1;
}
l = l->nextInCanal;
}
c = c->ownedNext;
}
}
kev->type = KEV_TYPE_NONE;
return 0;
}

View File

@@ -0,0 +1,22 @@
#ifndef _SCHEDULER_H
#define _SCHEDULER_H
#include"process.h"
#include<stddef.h>
void scheduler_init();
void scheduler_switch();
Process *scheduler_spawn();
size_t scheduler_create_handle(uint16_t ownerId, Process *child);
Process *scheduler_find(uint16_t procId);
#define MAX_MINIPRIORITY 255
#define TOTAL_PRIORITIES 16
#define PRIORITY_UNIT ((MAX_MINIPRIORITY + 1) / TOTAL_PRIORITIES)
//extern size_t scheduler_ProcessCount;
extern Process *scheduler_ProcessZone;
extern Process *scheduler_ProcessQueues[TOTAL_PRIORITIES];
#endif

268
src/kernel/arch/x86/vpm.c Normal file
View File

@@ -0,0 +1,268 @@
#include"vpm.h"
#include"ppm.h"
#include"mem.h"
extern void *_kernel_end;
void set_temporary_mapping(uint32_t addr) {
if((addr & 0xFFF) != 0) asm volatile("xchgw %bx, %bx");
*(volatile uint32_t*) 0xFFFFFFF8 = addr | 3;
asm volatile("invlpg 0xFFFFE000" : : : "memory");
}
static uint32_t nextAllocs[2] = {[VPM_KERNEL] = 0, [VPM_USER] = 1 * 1024 * 1024 * 1024};
void vpm_init(uint32_t kernelEnd) {
nextAllocs[VPM_KERNEL] = (kernelEnd + 4095) & ~4095;
}
/* TODO: Make better. */
uint32_t vpm_find_free(uint32_t addrspace, AllocationOwner owner, size_t lenBytes) {
size_t len = (lenBytes + 4095) / 4096;
uint32_t ret = nextAllocs[owner];
for(size_t i = 0; i < len;) {
uint32_t pdeid = (ret + i * 4096) >> 22;
uint32_t pteid = ((ret + i * 4096) >> 12) & 1023;
set_temporary_mapping(addrspace);
volatile uint32_t *pde = &((volatile uint32_t*) 0xFFFFE000)[pdeid];
if((*pde & 1) == 0) {
i += 4096;
} else {
set_temporary_mapping(*pde & ~0xFFF);
if((((volatile uint32_t*) 0xFFFFE000)[pteid] & 1) == 0) {
i++;
} else {
ret += (i + 1) * 4096;
i = 0;
}
}
}
return ret;
}
/* If phys is -1, map to uncontiguous physical pages anywhere, else map contiguous span of physical memory. */
/* If phys is -2, automatically find contiguous span of physical memory */
/* If virt is -1, find free space, else overwrite. */
void *vpm_map(uint32_t addrspace, AllocationOwner owner, uint32_t virt, uint32_t phys, size_t len) {
uint32_t thisspace;
asm volatile("movl %%cr3, %0" : "=r" (thisspace) :);
//if(len == 32768)asm("xchg %%bx, %%bx":::);
if(virt == -1) {
virt = vpm_find_free(addrspace, owner, len);
}
len = (len + 4095) / 4096;
if(phys == -2) {
phys = ppm_alloc(len);
if(!phys) {
goto error;
}
}
for(size_t i = 0; i < len; i++) {
set_temporary_mapping(addrspace);
uint32_t pdeid = (virt + i * 4096) >> 22;
uint32_t pteid = ((virt + i * 4096) >> 12) & 1023;
volatile uint32_t *pde = &((volatile uint32_t*) 0xFFFFE000)[pdeid];
if((*pde & 1) == 0) {
uint64_t physpag = ppm_alloc(1);
if(physpag) {
*pde = physpag | 3 | (owner == VPM_USER ? 4 : 0);
} else {
goto error;
}
}
set_temporary_mapping(*pde & ~0xFFF);
volatile uint32_t *pte = &((volatile uint32_t*) 0xFFFFE000)[pteid];
if(phys == -1) {
*pte = ppm_alloc(1);
if(!*pte) goto error;
} else {
*pte = phys + i * 4096;
}
*pte |= 3 | (owner == VPM_USER ? 4 : 0);
if(thisspace == addrspace) {
//~ asm volatile("xchg %bx, %bx");
asm volatile("invlpg %0" : : "m"(*(char*) (virt + i * 4096)) : "memory");
}
}
return (void*) virt;
error:
// TODO: Deallocate physical pages.
return 0;
}
int vpm_double_map(uint32_t cr3a, uint32_t cr3b, uint32_t *va, uint32_t *vb, uintptr_t phys, size_t len) {
uint32_t thisspace;
asm volatile("movl %%cr3, %0" : "=r" (thisspace) :);
if(*va == -1) {
*va = vpm_find_free(cr3a, VPM_USER, len);
}
if(*vb == -1) {
*vb = vpm_find_free(cr3b, VPM_USER, len);
}
len = (len + 4095) / 4096;
if(phys == -2) {
phys = ppm_alloc(len);
}
for(size_t i = 0; i < len; i++) {
uint32_t backend;
if(phys == -1) {
backend = ppm_alloc(1);
if(!backend) goto error;
} else {
backend = phys + i * 4096;
}
{
set_temporary_mapping(cr3a);
uint32_t pdeid = (*va + i * 4096) >> 22;
uint32_t pteid = ((*va + i * 4096) >> 12) & 1023;
volatile uint32_t *pde = &((volatile uint32_t*) 0xFFFFE000)[pdeid];
if((*pde & 1) == 0) {
uintptr_t physpag = ppm_alloc(1);
if(physpag) {
*pde = physpag | 3 | 4;
} else {
goto error;
}
}
set_temporary_mapping(*pde & ~0xFFF);
volatile uint32_t *pte = &((volatile uint32_t*) 0xFFFFE000)[pteid];
*pte = backend | 3 | 4;
if(thisspace == cr3a) {
asm volatile("invlpg %0" : : "m"(*(char*) (*va + i * 4096)) : "memory");
}
}
{
set_temporary_mapping(cr3b);
uint32_t pdeid = (*vb + i * 4096) >> 22;
uint32_t pteid = ((*vb + i * 4096) >> 12) & 1023;
volatile uint32_t *pde = &((volatile uint32_t*) 0xFFFFE000)[pdeid];
if((*pde & 1) == 0) {
uintptr_t physpag = ppm_alloc(1);
if(physpag) {
*pde = physpag | 3 | 4;
} else {
goto error;
}
}
set_temporary_mapping(*pde & ~0xFFF);
volatile uint32_t *pte = &((volatile uint32_t*) 0xFFFFE000)[pteid];
*pte = backend | 3 | 4;
if(thisspace == cr3b) {
asm volatile("invlpg %0" : : "m"(*(char*) (*vb + i * 4096)) : "memory");
}
}
}
return 1;
error:
return 0;
}
uint32_t vpm_create_space() {
uint32_t curPD;
asm volatile("movl %%cr3, %0" : "=r"(curPD) :);
set_temporary_mapping(curPD);
uint32_t pde0000 = *(volatile uint32_t*) 0xFFFFE000;
uint32_t pde1023 = *(volatile uint32_t*) 0xFFFFEFFC;
uint32_t newPD = ppm_alloc(1);
set_temporary_mapping(newPD);
*(volatile uint32_t*) 0xFFFFE000 = pde0000;
kmemw4((void*) 0xFFFFE004, 0, 1022);
*(volatile uint32_t*) 0xFFFFEFFC = pde1023;
return newPD;
}
void vpm_set_space(uint32_t cr3) {
asm volatile("movl %0, %%cr3" : : "r"(cr3));
}
uint32_t vpm_get_phys(uint32_t cr3, uint32_t v) {
uint32_t offset = v & 4095;
uint32_t pdeid = v >> 22;
uint32_t pteid = (v >> 12) & 1023;
set_temporary_mapping(cr3);
set_temporary_mapping(((uint32_t*) 0xFFFFE000)[pdeid] & ~0xFFF);
return (((uint32_t*) 0xFFFFE000)[pteid] & ~0xFFF) + offset;
}
void vpm_unmap(uint32_t cr3, uint32_t virt, size_t len) {
uint32_t thisspace;
asm volatile("movl %%cr3, %0" : "=r"(thisspace) :);
len = (len + 4095) / 4096;
for(size_t i = 0; i < len; i++) {
set_temporary_mapping(cr3);
uint32_t pdeid = (virt + i * 4096) >> 22;
uint32_t pteid = ((virt + i * 4096) >> 12) & 1023;
volatile uint32_t *pde = &((volatile uint32_t*) 0xFFFFE000)[pdeid];
if((*pde & 1) == 0) {
continue;
}
set_temporary_mapping(*pde & ~0xFFF);
((volatile uint32_t*) 0xFFFFE000)[pteid] = 0;
if(thisspace == cr3) {
asm volatile("invlpg %0" : : "m"(*(char*) (virt + i * 4096)) : "memory");
}
}
}

24
src/kernel/arch/x86/vpm.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef _VPM_H
#define _VPM_H
#include<stdint.h>
#include<stddef.h>
typedef struct {
uint32_t from, to;
} SharedRange;
typedef enum {
VPM_KERNEL, VPM_USER
} AllocationOwner;
void set_temporary_mapping(uint32_t addr);
uint32_t vpm_find_free(uint32_t addrspace, AllocationOwner owner, size_t len);
void *vpm_map(uint32_t cr3, AllocationOwner owner, uint32_t virt, uint32_t phys, size_t len);
uint32_t vpm_create_space();
void vpm_set_space(uint32_t cr3);
uint32_t vpm_get_phys(uint32_t cr3, uint32_t);
void vpm_unmap(uint32_t cr3, uint32_t virt, size_t len);
#endif