Compare commits

...

1 Commits

Author SHA1 Message Date
Lucia Ceionia
6142b085cd lots of in progress stuff 2024-01-07 22:33:27 -06:00
12 changed files with 349 additions and 83 deletions

View File

@ -1,8 +1,8 @@
objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o gdt.o\
paging.o fault.o tests.o kbd.o helper.o disk.o file.o fs.o dosfs/dosfs.o fs_dos.o\
progs.o hexedit.o textedit.o
CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding\
-march=i686 -fno-stack-protector -Wno-int-conversion -nostdlib -c
CFLAGS = -target "i386-elf" -m32 -mgeneral-regs-only -ffreestanding\
-march=i386 -fno-stack-protector -Wno-int-conversion -nostdlib -c
LFLAGS = -Wl,--gc-sections -Wl,--print-gc-sections -m32 -nostartfiles -nostdlib
ifeq ($(OUTFILE),)

View File

@ -70,10 +70,13 @@ jmp _fault_coda
_gpf_old_ds: dw 0
extern get_key
extern get_scancode
extern get_key_no_wait
extern get_scancode_no_wait
extern task_ptr
extern _enter_v86_internal_no_task
extern return_prev_task
extern v86Interrupt
extern TIMERVAL
gpf_handler_32:
push eax
mov eax, dword [esp+8] ; EIP
@ -91,9 +94,25 @@ jne .s1
call get_key
jmp .return_to_offender
.s1: cmp al, 0x01 ; get scancode
jne .s86
jne .s2
call get_scancode
jmp .return_to_offender
.s2: cmp al, 0x02 ; get key no wait
jne .s3
call get_key_no_wait
jmp .return_to_offender
.s3: cmp al, 0x03 ; get scancode no wait
jne .s4
call get_scancode_no_wait
jmp .return_to_offender
.s4: cmp al, 0x04 ; get timer
jne .s5
mov eax, dword [TIMERVAL]
jmp .return_to_offender
.s5: cmp al, 0x05 ; short wait (hlt)
jne .s86
hlt
jmp .return_to_offender
.s86: cmp al, 0x86 ; v86 interrupt call
je .v86int
cmp ax, 0x86D8 ; get v86 data pointer

View File

@ -1,71 +1,38 @@
oldscancodesToAscii: db 0, 0 ; 0x00 - 0x01
db "1234567890" ; 0x02 - 0x0B
db "-=" ; 0x0C - 0x0D
db 0, 0 ; 0x0E - 0x0F
db "qwertyuiop[]" ; 0x10 - 0x1B
db 0, 0 ; 0x1C - 0x1D
db "asdfghjkl;'`" ; 0x1E - 0x29
db 0 ; 0x2A
db "\zxcvbnm,./" ; 0x2B - 0x35
db 0 ; 0x36
db '*' ; 0x37
db 0 ; 0x38
db ' ' ; 0x39
db 'C'
scancodesToAsciiEnd:
cursorCurrent: dd 0xb8000 + (80*6*2)
global oldkeyboardHandler
oldkeyboardHandler:
push eax
push ebx
push ds
mov ax, 0x10
mov ds, ax
xor eax, eax
in al, 0x60
cmp eax, 0x3A
jg .done
mov al, [oldscancodesToAscii+eax]
test al, al
jz .done
mov ebx, [cursorCurrent]
mov byte [ebx], al
add dword [cursorCurrent], 2
mov byte [KBDWAIT], 1
.done:
mov al, 0x20
out 0x20, al
pop ds
pop ebx
pop eax
iret
KBDWAIT: db 0
oldkbd_wait:
mov byte [KBDWAIT], 0
.loop:
hlt
movzx eax, byte [KBDWAIT]
test eax, eax
jz .loop
ret
global PROC_SWITCH
PROC_SWITCH: dw 0
global TIMERVAL
global TIMERVAL_FRAC
TIMERVAL: dd 0
TIMERVAL_FRAC: dd 0
global timerHandler
timerHandler:
push eax
push ds
mov ax, 0x10
mov ds, ax
;inc byte [(0xb8000 + (80*8*2))]
inc dword [TIMERVAL]
; Value from PITPgrm
add dword [TIMERVAL_FRAC], 0xfffdb8d0
adc dword [TIMERVAL], 0
mov al, 0x20
out 0x20, al
; Check task switch
movzx eax, word [PROC_SWITCH]
test eax, eax
jnz task_switch
pop ds
pop eax
iret
extern save_current_task_int
task_switch:
mov word [PROC_SWITCH], 0
pop ds
pop eax
call save_current_task_int
iret
global picInit
picInit:
mov al, 0x11 ; initialization sequence

22
kbd.c
View File

@ -1,6 +1,11 @@
#include "interrupt.h"
#include "kbd.h"
extern uint16_t PROC_SWITCH;
__attribute__((__noreturn__))
__attribute__((__no_caller_saved_registers__))
extern void ret_current_task_int();
uint8_t scancodesToAscii[0x3B] =
"\0\0" // 0x00 - 0x01
"1234567890" // 0x02 - 0x0B
@ -69,6 +74,8 @@ void keyboardHandler(struct interrupt_frame *frame) {
"mov %%ax, %%ds\n"
::"a"(old_ds)
);
if (key == KEY_F12) PROC_SWITCH = 1;
if (key == KEY_F11) ret_current_task_int();
}
__attribute((__no_caller_saved_registers__))
@ -106,3 +113,18 @@ uint16_t get_scancode() {
return k;
}
__attribute((__no_caller_saved_registers__))
uint8_t get_key_no_wait() {
uint8_t k = _LSTKEY_ASCII;
_LSTKEY_ASCII = 0;
return k;
}
__attribute((__no_caller_saved_registers__))
uint16_t get_scancode_no_wait() {
uint16_t k = _LSTKEY_SCAN | (_LSTKEY_ASCII << 8);
_LSTKEY_SCAN = 0;
_LSTKEY_ASCII = 0;
return k;
}

View File

@ -190,9 +190,11 @@ Protected Only (1MB+)
280000 - 300000 Disk Cache (512kB)
300000 - 310000 Task Stack (64kB)
310000 - 320000 Interrupt Stack (64kB)
320000 - 400000 Kernel Stack (896kB)
400000 - 700000 Usermode Code (3mB)
700000 - 800000 Usermode Stack (1mB)
320000 - 400000 Free (896kB)
400000 - 700000 Free (3mB)
700000 - 800000 Kernel Stack (1mB)
800000 - F00000 Usermode Code (7mB)
F00000 - 1000000 Usermode Stack (1mB)
*/
void DrawScreen(uint16_t *vga) {
@ -247,13 +249,8 @@ void RestoreVGA() {
}
int32_t fileCount, fileOffset;
// We store dir entries in usermode space,
// which is nice because there's nothing after,
// but it does mean we need to reload the dir
// after every task called. This might be fine,
// since the task might have modified the directory.
extern char _USERMODE;
dirent *const DirEntries = (dirent*)&_USERMODE;
dirent *const DirEntries = (dirent*)0x400000;
#define MAXDISPFILES 16
void PrintFileList(uint16_t *vga) {
uint16_t *vga_text = &((uint16_t *)vga)[80*6+3];
@ -377,7 +374,20 @@ void FileSelect() {
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
{
// Give userspace mem (8MB)
uintptr_t process_page0 = add_pages(4|2|1);
uintptr_t process_page1 = add_pages(4|2|1);
asm("xchg %bx,%bx");
// Page blocks are 4MB
move_pages(process_page0 >> 22, (uintptr_t)&_USERMODE >> 22);
move_pages(process_page1 >> 22, ((uintptr_t)&_USERMODE >> 22) + 1);
asm("xchg %bx,%bx");
create_child(GetFreeStack(), (uintptr_t)HexEditor, 1, current_path);
// Free userspace mem
free_pages(process_page0 >> 22);
free_pages(process_page1 >> 22);
}
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
@ -388,7 +398,18 @@ void FileSelect() {
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
{
// Give userspace mem (8MB)
uintptr_t process_page0 = add_pages(4|2|1);
uintptr_t process_page1 = add_pages(4|2|1);
// Page blocks are 4MB
move_pages(process_page0 >> 22, (uintptr_t)&_USERMODE >> 22);
move_pages(process_page1 >> 22, ((uintptr_t)&_USERMODE >> 22) + 1);
create_child(GetFreeStack(), (uintptr_t)TextViewTest, 1, current_path);
// Free userspace mem
free_pages(process_page0 >> 22);
free_pages(process_page1 >> 22);
}
current_path[current_path_end] = 0;
RestoreVGA();
reload = 1;
@ -455,6 +476,34 @@ void FileSelect() {
}
}
// TODO Move this somewhere else, maybe configurable & with timer handler
void PITPgrm() {
const uint32_t base_clk = 3579545;
const uint16_t reload_v = 1194;
// (base_clk / 3) / reload_v = ~999.31463Hz
// 32.32 Fixed point
const uint64_t irq_ms = (uint64_t)reload_v * 3000LL * ((1LL << 42) / (uint64_t)base_clk / (1LL << 10));
// irq_ms = 4294818000 (0xfffdb8d0)
// We don't actually use this here, but in handler.nasm
// for now, eventually this should be in C
asm volatile(
"cli\n"
"movb $0b00110100, %%al\n"
"outb %%al, $0x43\n"
:::"%eax"
);
uint32_t clobber_eax;
asm volatile(
"outb %%al, $0x40\n"
"movb %%ah, %%al\n"
"outb %%al, $0x40\n"
"sti\n"
:"=a"(clobber_eax):"a"(reload_v)
);
}
int MakeSystemVolume(uint8_t sysPartition);
void MakeMBRPartitions();
void SystemRun(uint8_t sysPartition) {
@ -463,6 +512,7 @@ void SystemRun(uint8_t sysPartition) {
DrawScreen((uint16_t*)0xb8000);
InitDisk();
PITPgrm();
// Check for FAT partition
{

View File

@ -1,7 +1,7 @@
#include "paging.h"
uint32_t page_directory[1024] __attribute__((aligned(4096)));
uint32_t page_tables[4][1024] __attribute__((aligned(4096)));
uint32_t page_tables[128][1024] __attribute__((aligned(4096)));
void enable_paging() {
asm(
@ -21,7 +21,6 @@ void map_pages(uintptr_t page, uintptr_t num_pages, uintptr_t phy_address, char
// Each page is 4K, Each page table is 4M
uintptr_t page_dir_entry = page >> 10;
if (page_dir_entry >= 4) return;
uintptr_t page_index = page & 0x3ff;
if (page_index + num_pages > 1024) return;
@ -32,11 +31,93 @@ void map_pages(uintptr_t page, uintptr_t num_pages, uintptr_t phy_address, char
page_tables[page_dir_entry][page_index + i] = phy_address + (i * 0x1000) | access_flags;
}
// Marks a 4MB page directory index unused, *without* freeing physical memory
void mark_pages_unused(uint16_t page_dir_idx) {
if (page_dir_idx >= 1024) return;
// Supervisor, R/W, Not Present
page_directory[page_dir_idx] = 2;
}
// Bitmap of physical memory usage
uint8_t PhyMapArr[1024/8];
// Marks a 4MB page directory index unused, along with underlying physical memory
void free_pages(uint16_t page_dir_idx) {
// Get first entry of page table
uint32_t *page_table = (uint32_t*)(page_directory[page_dir_idx] != 2 ? (uintptr_t)page_directory[page_dir_idx] & 0xfffff000 : 0);
if (!page_table) return;
// Free physical memory
uint32_t phy_address = page_table[0] & 0xfffff000;
uint32_t phy_address_4mb = phy_address >> 22;
uint32_t map_idx = phy_address_4mb >> 3;
uint32_t bit_idx = phy_address_4mb & 7;
// Clear bit
PhyMapArr[map_idx] &= ~(1 << bit_idx);
// Mark unused
mark_pages_unused(page_dir_idx);
}
// Gets an unused 4MB page directory index. Return -1 if no free pages.
uint16_t get_unused_pages() {
for (int i = 0; i < 1024; i++)
if (page_directory[i] == 2) return i;
return -1;
}
// Gets physical address of 4MB unused area of physical memory. This will have to be mapped to virtual memory space to be used.
uint32_t get_phy_mem() {
for (int i = 0; i < sizeof(PhyMapArr); i++) {
// Fully used
if (PhyMapArr[i] == 0xff) continue;
// At least one bit must be free
uint8_t bits = PhyMapArr[i];
for (int j = 0; j < 8; j++)
if (!(bits & (1 << j))) return (i << 25) + (j << 22);
}
return -1;
}
// User, R/W, Present
#define USERACCESS (4|2|1)
// Supervisor, R/W, Present
#define SUPERACCESS (2|1)
// Returns a pointer to a newly mapped 4MB memory chunk
uintptr_t add_pages(char access_flags) {
// Get free physical space
uint32_t phy_mem = get_phy_mem();
if (phy_mem == -1) return -1;
// Get free virtual space
uint16_t free_ent = get_unused_pages();
if ((int16_t)free_ent == -1) return -1;
uintptr_t page = free_ent << 10;
// Mark page directory entry present, pointing to page table
page_directory[free_ent] = ((uintptr_t)&page_tables[free_ent]) | USERACCESS;
// Map pages to physical address
map_pages(page, 1024, phy_mem, access_flags);
// Mark physical memory used
uint32_t phy_address_4mb = phy_mem >> 22;
uint32_t map_idx = phy_address_4mb >> 3;
uint32_t bit_idx = phy_address_4mb & 7;
// Set bit
PhyMapArr[map_idx] |= 1 << bit_idx;
// Return virtual address
return page << 12;
}
// Copies 4MB groups of pages
void move_pages(uint16_t src_page_dir_idx, uint16_t dest_page_dir_idx) {
if (src_page_dir_idx >= 1024 || dest_page_dir_idx >= 1024) return;
page_directory[dest_page_dir_idx] = page_directory[src_page_dir_idx];
}
void init_paging() {
for (int i = 0; i < 1024; i++)
// Supervisor, R/W, Not Present
@ -51,13 +132,15 @@ void init_paging() {
// Next 4MB: Kernel
map_pages(0x00400000 >> 12, 1024, 0x00400000, SUPERACCESS);
// Next 8MB: Usermode
map_pages(0x00800000 >> 12, 1024, 0x00800000, USERACCESS);
map_pages(0x00C00000 >> 12, 1024, 0x00C00000, USERACCESS);
// We aren't using page directory permissions
for (int i = 0; i < 4; i++)
page_directory[i] = ((uintptr_t)&page_tables[i]) | USERACCESS;
// Mark all physical memory free TODO Check memory size
for (int i = 0; i < sizeof(PhyMapArr); i++)
PhyMapArr[i] = 0;
// Mark lowest 8MB as used
PhyMapArr[0] = 3;
enable_paging();
}

View File

@ -1,3 +1,6 @@
#include <stdint.h>
void free_pages(uint16_t page_dir_idx);
uintptr_t add_pages(char access_flags);
void move_pages(uint16_t src_page_dir_idx, uint16_t dest_page_dir_idx);
void init_paging();

26
progs.c
View File

@ -1,21 +1,23 @@
#include "progs.h"
#include "paging.h"
#include "file.h"
extern char _USERMODE, _USERMODE_END;
static uintptr_t USERMODE_STACK = (uintptr_t)&_USERMODE_END - 0x100000;
extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
void ProgramLoadTest(char *path) {
void programLoadTestInner(char *path) {
uint16_t *vga_text = (uint16_t *)0xb8000;
for (int i = 0; i < 80*25; i++)
vga_text[i] = 0x0f00;
uint32_t successcount;
uint8_t *diskReadBuf = (uint8_t *)&_USERMODE;
{
uint32_t err;
dirent de;
err = path_getinfo(path, &de);
if (de.size > 0x300000 || err) {
if (de.size > 0xE00000 || err) {
vga_text += printStr("File too large or error.", vga_text);
kbd_wait();
return;
}
FILE file;
@ -45,7 +47,8 @@ void ProgramLoadTest(char *path) {
vga_text = nextLine(vga_text,(uint16_t*)0xb8000);
vga_text += printStr("Press any key to run.", vga_text);
kbd_wait();
uint32_t res = create_user_child((uintptr_t)&_USERMODE_END, (uintptr_t)&_USERMODE, 0);
uint32_t res = create_user_child(USERMODE_STACK, (uintptr_t)&_USERMODE, 0);
union V86Regs_t regs;
regs.w.ax = 3; // text mode
V8086Int(0x10, &regs);
@ -57,5 +60,18 @@ void ProgramLoadTest(char *path) {
vga_text += printStr(" (0x", vga_text);
vga_text += printDword(res, vga_text);
vga_text += printStr("). Press any key to exit.", vga_text);
kbd_wait();
}
void ProgramLoadTest(char *path) {
// Get free memory (8MB)
uintptr_t process_page0 = add_pages(4|2|1);
uintptr_t process_page1 = add_pages(4|2|1);
// Map usermode memory
move_pages(process_page0 >> 22, (uintptr_t)&_USERMODE >> 22);
move_pages(process_page1 >> 22, ((uintptr_t)&_USERMODE >> 22) + 1);
// Inner program
programLoadTestInner(path);
kbd_wait();
// Free process memory
free_pages(process_page0 >> 22);
free_pages(process_page1 >> 22);
}

View File

@ -5,9 +5,8 @@ ltr ax
ret
global task_ptr
task_ptr: equ (0x310000-4)
task_ptr: equ (0x310000)
; TODO Is varargs too compiler dependent?
; extern void create_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
global create_child
create_child:
@ -60,6 +59,101 @@ push 0x18 | 3
push eax
iret
; save task
; stack contains caller, eip, cs, eflags(, esp, ss)
global save_current_task_new
save_current_task_new:
push ds
push ebx
push eax
push 0x10
pop ds
; 0 eax, 4 ebx, 8 ds, 12 caller, 16 eip, 20 cs, 24 eflags(, 28 esp, 32 ss)
; location to save task
mov ebx, dword [0x318000]
; code & stack
mov eax, dword [esp+16]
mov dword [ebx+0], eax ; eip
mov eax, dword [esp+20]
mov dword [ebx+4], eax ; cs
cmp ax, 0x08
; if we're not in code segment, save stack info
je .curr_stack
mov eax, dword [esp+24]
mov dword [ebx+8], eax ; eflags
mov eax, dword [esp+28]
mov dword [ebx+12], eax ; esp
mov eax, dword [esp+32]
mov dword [ebx+16], eax ; ss
jmp .seg_regs
; if we're in code segment, we save current info, minus interrupt stack
.curr_stack:
mov eax, dword [esp+24]
mov dword [ebx+8], eax ; eflags
lea eax, [esp+28]
mov dword [ebx+12], eax ; esp before interrupt
mov eax, ss
mov dword [ebx+16], eax
; segment regs
.seg_regs:
mov eax, dword [esp+8]
mov dword [ebx+20], eax ; ds
mov eax, es
mov dword [ebx+24], eax
mov eax, fs
mov dword [ebx+28], eax
mov eax, gs
mov dword [ebx+32], eax
; general regs besides esp
mov eax, dword [esp+0]
mov dword [ebx+36], eax ; eax
mov eax, dword [esp+4]
mov dword [ebx+40], eax ; ebx
mov dword [ebx+44], ecx
mov dword [ebx+48], edx
mov dword [ebx+52], esi
mov dword [ebx+56], edi
mov dword [ebx+60], ebp
pop eax
pop ebx
pop ds
xchg bx,bx
ret
; return to current task
global ret_current_task
ret_current_task:
xchg bx,bx
push 0x10
pop ds
; location to get task
mov ebx, dword [0x318000]
mov ebp, [ebx+60]
mov edi, [ebx+56]
mov esi, [ebx+52]
mov edx, [ebx+48]
mov ecx, [ebx+44]
mov gs, [ebx+32]
mov fs, [ebx+28]
mov es, [ebx+24]
mov ds, [ebx+20]
mov eax, [ebx+4] ; cs
cmp ax, 0x08
je .restore_stack
mov eax, [ebx+36]
mov esp, ebx
mov ebx, [ebx+40]
iret
.restore_stack:
mov esp, [ebx+12]
mov ss, [ebx+16]
mov eax, [ebx+36]
push dword [ebx+8]
push dword [ebx+4]
push dword [ebx]
mov ebx, [ebx+40]
iret
; return address in EAX
; return stack in ECX
; we can modify EAX, ECX, EDX

12
tests.c
View File

@ -1,4 +1,5 @@
#include "tests.h"
#include "paging.h"
extern char *user_test();
extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
@ -26,8 +27,17 @@ void ReloadUser() {
*d++ = *s++;
}
char TestUser() {
// Get free memory (8MB)
uintptr_t process_page0 = add_pages(4|2|1);
uintptr_t process_page1 = add_pages(4|2|1);
// Map usermode memory
move_pages(process_page0 >> 22, (uintptr_t)&_USERMODE >> 22);
move_pages(process_page1 >> 22, ((uintptr_t)&_USERMODE >> 22) + 1);
ReloadUser();
char *vga = (char *)(uintptr_t)create_user_child((uintptr_t)&_USERMODE_END, (uintptr_t)&_USERMODE, 0);
char *vga = (char *)(uintptr_t)create_user_child((uintptr_t)&_USERMODE_END - 0x100000, (uintptr_t)&_USERMODE, 0);
// Free process memory
free_pages(process_page0 >> 22);
free_pages(process_page1 >> 22);
if ((uintptr_t)vga != 0xA0000) {
return 1;
}

4
tss.c
View File

@ -41,8 +41,8 @@ void write_tss() {
tss_data->iomap_base = 0x80;
// not technically TSS but set up task pointer
uint32_t *current_task_ptr = (uint32_t*)(0x310000-4);
*current_task_ptr = 0x310000-(20*4); // each task is 12 dwords, plus 1 for pointer
uint32_t *current_task_ptr = (uint32_t*)(0x310000);
*current_task_ptr = 0x310000-(1*4); // each task is 12 dwords, plus 1 for pointer
/* TODO setup null recovery task at start */
}
extern void flushTSS();

View File

@ -27,6 +27,8 @@ mov dword [0xb8000+800], 0x0f000f00 | 'g' | ':' << 16
mov dword [0xb8004+800], 0x0f000f00 | ' ' | '#' << 16
mov dword [0xb8008+800], 0x0f000f00 | 'G' | 'P' << 16
mov dword [0xb800C+800], 0x0f000f00 | 'F' | ' ' << 16
.busy:
jmp .busy
mov eax, 0 ; command = 00h, get key
int 0x21 ; OS call
cmp al, 'd'