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

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