Compare commits
1 Commits
main
...
dev-tasks-
Author | SHA1 | Date | |
---|---|---|---|
|
6142b085cd |
4
Makefile
4
Makefile
@ -1,8 +1,8 @@
|
|||||||
objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o gdt.o\
|
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\
|
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
|
progs.o hexedit.o textedit.o
|
||||||
CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding\
|
CFLAGS = -target "i386-elf" -m32 -mgeneral-regs-only -ffreestanding\
|
||||||
-march=i686 -fno-stack-protector -Wno-int-conversion -nostdlib -c
|
-march=i386 -fno-stack-protector -Wno-int-conversion -nostdlib -c
|
||||||
LFLAGS = -Wl,--gc-sections -Wl,--print-gc-sections -m32 -nostartfiles -nostdlib
|
LFLAGS = -Wl,--gc-sections -Wl,--print-gc-sections -m32 -nostartfiles -nostdlib
|
||||||
|
|
||||||
ifeq ($(OUTFILE),)
|
ifeq ($(OUTFILE),)
|
||||||
|
21
fault.nasm
21
fault.nasm
@ -70,10 +70,13 @@ jmp _fault_coda
|
|||||||
_gpf_old_ds: dw 0
|
_gpf_old_ds: dw 0
|
||||||
extern get_key
|
extern get_key
|
||||||
extern get_scancode
|
extern get_scancode
|
||||||
|
extern get_key_no_wait
|
||||||
|
extern get_scancode_no_wait
|
||||||
extern task_ptr
|
extern task_ptr
|
||||||
extern _enter_v86_internal_no_task
|
extern _enter_v86_internal_no_task
|
||||||
extern return_prev_task
|
extern return_prev_task
|
||||||
extern v86Interrupt
|
extern v86Interrupt
|
||||||
|
extern TIMERVAL
|
||||||
gpf_handler_32:
|
gpf_handler_32:
|
||||||
push eax
|
push eax
|
||||||
mov eax, dword [esp+8] ; EIP
|
mov eax, dword [esp+8] ; EIP
|
||||||
@ -91,9 +94,25 @@ jne .s1
|
|||||||
call get_key
|
call get_key
|
||||||
jmp .return_to_offender
|
jmp .return_to_offender
|
||||||
.s1: cmp al, 0x01 ; get scancode
|
.s1: cmp al, 0x01 ; get scancode
|
||||||
jne .s86
|
jne .s2
|
||||||
call get_scancode
|
call get_scancode
|
||||||
jmp .return_to_offender
|
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
|
.s86: cmp al, 0x86 ; v86 interrupt call
|
||||||
je .v86int
|
je .v86int
|
||||||
cmp ax, 0x86D8 ; get v86 data pointer
|
cmp ax, 0x86D8 ; get v86 data pointer
|
||||||
|
73
handler.nasm
73
handler.nasm
@ -1,71 +1,38 @@
|
|||||||
oldscancodesToAscii: db 0, 0 ; 0x00 - 0x01
|
global PROC_SWITCH
|
||||||
db "1234567890" ; 0x02 - 0x0B
|
PROC_SWITCH: dw 0
|
||||||
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 TIMERVAL
|
global TIMERVAL
|
||||||
|
global TIMERVAL_FRAC
|
||||||
TIMERVAL: dd 0
|
TIMERVAL: dd 0
|
||||||
|
TIMERVAL_FRAC: dd 0
|
||||||
global timerHandler
|
global timerHandler
|
||||||
timerHandler:
|
timerHandler:
|
||||||
push eax
|
push eax
|
||||||
push ds
|
push ds
|
||||||
mov ax, 0x10
|
mov ax, 0x10
|
||||||
mov ds, ax
|
mov ds, ax
|
||||||
;inc byte [(0xb8000 + (80*8*2))]
|
; Value from PITPgrm
|
||||||
inc dword [TIMERVAL]
|
add dword [TIMERVAL_FRAC], 0xfffdb8d0
|
||||||
|
adc dword [TIMERVAL], 0
|
||||||
mov al, 0x20
|
mov al, 0x20
|
||||||
out 0x20, al
|
out 0x20, al
|
||||||
|
; Check task switch
|
||||||
|
movzx eax, word [PROC_SWITCH]
|
||||||
|
test eax, eax
|
||||||
|
jnz task_switch
|
||||||
pop ds
|
pop ds
|
||||||
pop eax
|
pop eax
|
||||||
iret
|
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
|
global picInit
|
||||||
picInit:
|
picInit:
|
||||||
mov al, 0x11 ; initialization sequence
|
mov al, 0x11 ; initialization sequence
|
||||||
|
22
kbd.c
22
kbd.c
@ -1,6 +1,11 @@
|
|||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "kbd.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] =
|
uint8_t scancodesToAscii[0x3B] =
|
||||||
"\0\0" // 0x00 - 0x01
|
"\0\0" // 0x00 - 0x01
|
||||||
"1234567890" // 0x02 - 0x0B
|
"1234567890" // 0x02 - 0x0B
|
||||||
@ -69,6 +74,8 @@ void keyboardHandler(struct interrupt_frame *frame) {
|
|||||||
"mov %%ax, %%ds\n"
|
"mov %%ax, %%ds\n"
|
||||||
::"a"(old_ds)
|
::"a"(old_ds)
|
||||||
);
|
);
|
||||||
|
if (key == KEY_F12) PROC_SWITCH = 1;
|
||||||
|
if (key == KEY_F11) ret_current_task_int();
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute((__no_caller_saved_registers__))
|
__attribute((__no_caller_saved_registers__))
|
||||||
@ -106,3 +113,18 @@ uint16_t get_scancode() {
|
|||||||
return k;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
68
kernel.c
68
kernel.c
@ -190,9 +190,11 @@ Protected Only (1MB+)
|
|||||||
280000 - 300000 Disk Cache (512kB)
|
280000 - 300000 Disk Cache (512kB)
|
||||||
300000 - 310000 Task Stack (64kB)
|
300000 - 310000 Task Stack (64kB)
|
||||||
310000 - 320000 Interrupt Stack (64kB)
|
310000 - 320000 Interrupt Stack (64kB)
|
||||||
320000 - 400000 Kernel Stack (896kB)
|
320000 - 400000 Free (896kB)
|
||||||
400000 - 700000 Usermode Code (3mB)
|
400000 - 700000 Free (3mB)
|
||||||
700000 - 800000 Usermode Stack (1mB)
|
700000 - 800000 Kernel Stack (1mB)
|
||||||
|
800000 - F00000 Usermode Code (7mB)
|
||||||
|
F00000 - 1000000 Usermode Stack (1mB)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void DrawScreen(uint16_t *vga) {
|
void DrawScreen(uint16_t *vga) {
|
||||||
@ -247,13 +249,8 @@ void RestoreVGA() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t fileCount, fileOffset;
|
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;
|
extern char _USERMODE;
|
||||||
dirent *const DirEntries = (dirent*)&_USERMODE;
|
dirent *const DirEntries = (dirent*)0x400000;
|
||||||
#define MAXDISPFILES 16
|
#define MAXDISPFILES 16
|
||||||
void PrintFileList(uint16_t *vga) {
|
void PrintFileList(uint16_t *vga) {
|
||||||
uint16_t *vga_text = &((uint16_t *)vga)[80*6+3];
|
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++)
|
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
|
||||||
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
|
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
|
||||||
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
|
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);
|
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;
|
current_path[current_path_end] = 0;
|
||||||
RestoreVGA();
|
RestoreVGA();
|
||||||
reload = 1;
|
reload = 1;
|
||||||
@ -388,7 +398,18 @@ void FileSelect() {
|
|||||||
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
|
for (int i = 0; i < DirEntries[fileHovered].namelen; i++)
|
||||||
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
|
current_path[current_path_end + i] = DirEntries[fileHovered].name[i];
|
||||||
current_path[current_path_end + DirEntries[fileHovered].namelen] = 0;
|
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);
|
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;
|
current_path[current_path_end] = 0;
|
||||||
RestoreVGA();
|
RestoreVGA();
|
||||||
reload = 1;
|
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);
|
int MakeSystemVolume(uint8_t sysPartition);
|
||||||
void MakeMBRPartitions();
|
void MakeMBRPartitions();
|
||||||
void SystemRun(uint8_t sysPartition) {
|
void SystemRun(uint8_t sysPartition) {
|
||||||
@ -463,6 +512,7 @@ void SystemRun(uint8_t sysPartition) {
|
|||||||
DrawScreen((uint16_t*)0xb8000);
|
DrawScreen((uint16_t*)0xb8000);
|
||||||
|
|
||||||
InitDisk();
|
InitDisk();
|
||||||
|
PITPgrm();
|
||||||
|
|
||||||
// Check for FAT partition
|
// Check for FAT partition
|
||||||
{
|
{
|
||||||
|
95
paging.c
95
paging.c
@ -1,7 +1,7 @@
|
|||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
|
|
||||||
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
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() {
|
void enable_paging() {
|
||||||
asm(
|
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
|
// Each page is 4K, Each page table is 4M
|
||||||
uintptr_t page_dir_entry = page >> 10;
|
uintptr_t page_dir_entry = page >> 10;
|
||||||
if (page_dir_entry >= 4) return;
|
|
||||||
uintptr_t page_index = page & 0x3ff;
|
uintptr_t page_index = page & 0x3ff;
|
||||||
if (page_index + num_pages > 1024) return;
|
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;
|
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
|
// User, R/W, Present
|
||||||
#define USERACCESS (4|2|1)
|
#define USERACCESS (4|2|1)
|
||||||
// Supervisor, R/W, Present
|
// Supervisor, R/W, Present
|
||||||
#define SUPERACCESS (2|1)
|
#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() {
|
void init_paging() {
|
||||||
for (int i = 0; i < 1024; i++)
|
for (int i = 0; i < 1024; i++)
|
||||||
// Supervisor, R/W, Not Present
|
// Supervisor, R/W, Not Present
|
||||||
@ -51,13 +132,15 @@ void init_paging() {
|
|||||||
// Next 4MB: Kernel
|
// Next 4MB: Kernel
|
||||||
map_pages(0x00400000 >> 12, 1024, 0x00400000, SUPERACCESS);
|
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
|
// We aren't using page directory permissions
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
page_directory[i] = ((uintptr_t)&page_tables[i]) | USERACCESS;
|
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();
|
enable_paging();
|
||||||
}
|
}
|
||||||
|
3
paging.h
3
paging.h
@ -1,3 +1,6 @@
|
|||||||
#include <stdint.h>
|
#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();
|
void init_paging();
|
||||||
|
26
progs.c
26
progs.c
@ -1,21 +1,23 @@
|
|||||||
#include "progs.h"
|
#include "progs.h"
|
||||||
|
#include "paging.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
|
||||||
extern char _USERMODE, _USERMODE_END;
|
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, ...);
|
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;
|
uint16_t *vga_text = (uint16_t *)0xb8000;
|
||||||
for (int i = 0; i < 80*25; i++)
|
for (int i = 0; i < 80*25; i++)
|
||||||
vga_text[i] = 0x0f00;
|
vga_text[i] = 0x0f00;
|
||||||
uint32_t successcount;
|
uint32_t successcount;
|
||||||
|
|
||||||
uint8_t *diskReadBuf = (uint8_t *)&_USERMODE;
|
uint8_t *diskReadBuf = (uint8_t *)&_USERMODE;
|
||||||
{
|
{
|
||||||
uint32_t err;
|
uint32_t err;
|
||||||
dirent de;
|
dirent de;
|
||||||
err = path_getinfo(path, &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);
|
vga_text += printStr("File too large or error.", vga_text);
|
||||||
kbd_wait();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FILE file;
|
FILE file;
|
||||||
@ -45,7 +47,8 @@ void ProgramLoadTest(char *path) {
|
|||||||
vga_text = nextLine(vga_text,(uint16_t*)0xb8000);
|
vga_text = nextLine(vga_text,(uint16_t*)0xb8000);
|
||||||
vga_text += printStr("Press any key to run.", vga_text);
|
vga_text += printStr("Press any key to run.", vga_text);
|
||||||
kbd_wait();
|
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;
|
union V86Regs_t regs;
|
||||||
regs.w.ax = 3; // text mode
|
regs.w.ax = 3; // text mode
|
||||||
V8086Int(0x10, ®s);
|
V8086Int(0x10, ®s);
|
||||||
@ -57,5 +60,18 @@ void ProgramLoadTest(char *path) {
|
|||||||
vga_text += printStr(" (0x", vga_text);
|
vga_text += printStr(" (0x", vga_text);
|
||||||
vga_text += printDword(res, vga_text);
|
vga_text += printDword(res, vga_text);
|
||||||
vga_text += printStr("). Press any key to exit.", 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);
|
||||||
}
|
}
|
||||||
|
98
task.nasm
98
task.nasm
@ -5,9 +5,8 @@ ltr ax
|
|||||||
ret
|
ret
|
||||||
|
|
||||||
global task_ptr
|
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, ...);
|
; extern void create_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
|
||||||
global create_child
|
global create_child
|
||||||
create_child:
|
create_child:
|
||||||
@ -60,6 +59,101 @@ push 0x18 | 3
|
|||||||
push eax
|
push eax
|
||||||
iret
|
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 address in EAX
|
||||||
; return stack in ECX
|
; return stack in ECX
|
||||||
; we can modify EAX, ECX, EDX
|
; we can modify EAX, ECX, EDX
|
||||||
|
12
tests.c
12
tests.c
@ -1,4 +1,5 @@
|
|||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
#include "paging.h"
|
||||||
|
|
||||||
extern char *user_test();
|
extern char *user_test();
|
||||||
extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
|
extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...);
|
||||||
@ -26,8 +27,17 @@ void ReloadUser() {
|
|||||||
*d++ = *s++;
|
*d++ = *s++;
|
||||||
}
|
}
|
||||||
char TestUser() {
|
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();
|
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) {
|
if ((uintptr_t)vga != 0xA0000) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
4
tss.c
4
tss.c
@ -41,8 +41,8 @@ void write_tss() {
|
|||||||
tss_data->iomap_base = 0x80;
|
tss_data->iomap_base = 0x80;
|
||||||
|
|
||||||
// not technically TSS but set up task pointer
|
// not technically TSS but set up task pointer
|
||||||
uint32_t *current_task_ptr = (uint32_t*)(0x310000-4);
|
uint32_t *current_task_ptr = (uint32_t*)(0x310000);
|
||||||
*current_task_ptr = 0x310000-(20*4); // each task is 12 dwords, plus 1 for pointer
|
*current_task_ptr = 0x310000-(1*4); // each task is 12 dwords, plus 1 for pointer
|
||||||
/* TODO setup null recovery task at start */
|
/* TODO setup null recovery task at start */
|
||||||
}
|
}
|
||||||
extern void flushTSS();
|
extern void flushTSS();
|
||||||
|
@ -27,6 +27,8 @@ mov dword [0xb8000+800], 0x0f000f00 | 'g' | ':' << 16
|
|||||||
mov dword [0xb8004+800], 0x0f000f00 | ' ' | '#' << 16
|
mov dword [0xb8004+800], 0x0f000f00 | ' ' | '#' << 16
|
||||||
mov dword [0xb8008+800], 0x0f000f00 | 'G' | 'P' << 16
|
mov dword [0xb8008+800], 0x0f000f00 | 'G' | 'P' << 16
|
||||||
mov dword [0xb800C+800], 0x0f000f00 | 'F' | ' ' << 16
|
mov dword [0xb800C+800], 0x0f000f00 | 'F' | ' ' << 16
|
||||||
|
.busy:
|
||||||
|
jmp .busy
|
||||||
mov eax, 0 ; command = 00h, get key
|
mov eax, 0 ; command = 00h, get key
|
||||||
int 0x21 ; OS call
|
int 0x21 ; OS call
|
||||||
cmp al, 'd'
|
cmp al, 'd'
|
||||||
|
Loading…
Reference in New Issue
Block a user