Usermode now loads at 0x800000, Virtual 8086 loads consistent DS&ES for data access

This commit is contained in:
Lucia Ceionia 2023-02-17 01:41:30 -06:00
parent 5fe565b6f7
commit d0a5eb4c6f
12 changed files with 86 additions and 52 deletions

View File

@ -16,7 +16,7 @@ mov es, ax
mov ss, ax mov ss, ax
mov fs, ax mov fs, ax
mov gs, ax mov gs, ax
mov ebp, 0x400000 mov ebp, 0x800000
mov esp, ebp mov esp, ebp
mov eax, 0x1f001f00 mov eax, 0x1f001f00
mov ecx, (80*25)/2 mov ecx, (80*25)/2

View File

@ -83,6 +83,7 @@ je .int30
cmp eax, 0x21CD ; int 0x21 cmp eax, 0x21CD ; int 0x21
je .int21 je .int21
jmp gpf_unhandled jmp gpf_unhandled
.int21: .int21:
pop eax ; command pop eax ; command
cmp al, 0x00 ; get key cmp al, 0x00 ; get key
@ -94,7 +95,13 @@ jne .s86
call get_scancode call get_scancode
jmp .return_to_offender jmp .return_to_offender
.s86: cmp al, 0x86 ; v86 interrupt call .s86: cmp al, 0x86 ; v86 interrupt call
je .v86int
cmp ax, 0x86D8 ; get v86 data pointer
jne .return_to_offender jne .return_to_offender
mov eax, 0x30000 ; V86 Data
jmp .return_to_offender
.v86int:
add esp, 4 add esp, 4
add dword [esp+0], 2 add dword [esp+0], 2
; add a new task ; add a new task
@ -120,6 +127,7 @@ push eax ; cs
push 0xFF00 ; sp push 0xFF00 ; sp
push 0x8000 ; ss push 0x8000 ; ss
jmp _enter_v86_internal_no_task ; NOT a function call jmp _enter_v86_internal_no_task ; NOT a function call
.int30: .int30:
pop eax ; return value pop eax ; return value
jmp return_prev_task jmp return_prev_task

View File

@ -171,10 +171,11 @@ Real Mode Accessible (First MB)
01000 - 04000 Free (12kB) 01000 - 04000 Free (12kB)
04000 - 07C00 V86 Code (15kB) 04000 - 07C00 V86 Code (15kB)
07C00 - 08000 Boot & V86 Code (512B) 07C00 - 08000 Boot & V86 Code (512B)
08000 - 20000 V86 Code (96kB) 08000 - 20000 Free (96kB)
20000 - 30000 Disk Buffer (64kB) 20000 - 30000 Disk Buffer (64kB)
30000 - 80000 Free (320kB) 30000 - 40000 V86 Data (64kB)
80000 - 90000 Real Mode Stack (64kB) 40000 - 80000 Free (256kB)
80000 - 90000 V86 Stack (64kB)
90000 - A0000 Free (64kB) 90000 - A0000 Free (64kB)
A0000 - C0000 VGA (128kB) A0000 - C0000 VGA (128kB)
C0000 - FFFFF BIOS Area (256kB) C0000 - FFFFF BIOS Area (256kB)
@ -434,6 +435,8 @@ void SystemRun(uint8_t sysPartition) {
RestoreVGA(); RestoreVGA();
DrawScreen((uint16_t*)0xb8000); DrawScreen((uint16_t*)0xb8000);
InitDisk();
// Check for FAT partition // Check for FAT partition
{ {
// TODO Check partitions beyond 0 // TODO Check partitions beyond 0
@ -528,7 +531,6 @@ void start() {
setup_tss(); setup_tss();
init_paging(); init_paging();
backup_ivtbios(); backup_ivtbios();
InitDisk();
// DL contained disk number, DH contained active partition // DL contained disk number, DH contained active partition
uint8_t SystemPartition = boot_dx >> 8; uint8_t SystemPartition = boot_dx >> 8;

View File

@ -3,7 +3,8 @@ ENTRY(entry)
SECTIONS { SECTIONS {
. = 0x100000; . = 0x100000;
_USERMODE = 0x400000; _USERMODE = 0x800000;
_USERMODE_END = 0x1000000;
.text : { .text : {
*(.text); *(.text);

View File

@ -1,8 +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 first_page_table[1024] __attribute__((aligned(4096))); // 0x00000000 - 0x00400000 uint32_t page_tables[4][1024] __attribute__((aligned(4096)));
uint32_t second_page_table[1024] __attribute__((aligned(4096))); // 0x00400000 - 0x00800000
void enable_paging() { void enable_paging() {
asm( asm(
@ -13,38 +12,52 @@ void enable_paging() {
::"a"(page_directory)); ::"a"(page_directory));
} }
// TODO Add a function which can dynamically add and remove pages,
// that keeps track internally of what's already used?
// NOTE This function cannot cross 4MB (1024 page) boundaries
void map_pages(uintptr_t page, uintptr_t num_pages, uintptr_t phy_address, char access_flags) {
uintptr_t access = access_flags & 0x7;
// 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;
// Address must be 4K aligned
if (phy_address & 0x3ff) return;
for (int i = 0; i < num_pages; i++)
page_tables[page_dir_entry][page_index + i] = phy_address + (i * 0x1000) | access_flags;
}
// User, R/W, Present
#define USERACCESS (4|2|1)
// Supervisor, R/W, Present
#define SUPERACCESS (2|1)
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
page_directory[i] = 2; page_directory[i] = 2;
// First Page Table // 1024 Pages = 1MB
// First MB: Real Mode // First MB: Real Mode
{ // TODO Make some of this not accessible to usermode?
int i; map_pages(0x00000000 >> 12, 256, 0x00000000, USERACCESS);
// Up to 0xC0000
// TODO make some areas here Read Only
for (i = 0;i < 16*0xC; i++)
// User, R/W, Present
first_page_table[i] = (i * 0x1000) |4|2|1;
// Remainder of first MB BIOS Area (writable?)
for (;i < 256; i++)
// User, R/W, Present
first_page_table[i] = (i * 0x1000) |4|2|1;
}
// Next 3MB: Kernel // Next 3MB: Kernel
for (int i = 256; i < 1024; i++) map_pages(0x00100000 >> 12, 768, 0x00100000, SUPERACCESS);
// Supervisor, R/W, Present // Next 4MB: Kernel
first_page_table[i] = (i * 0x1000) |2|1; map_pages(0x00400000 >> 12, 1024, 0x00400000, SUPERACCESS);
// Usermode Page Table // Next 8MB: Usermode
for (int i = 0; i < 1024; i++) map_pages(0x00800000 >> 12, 1024, 0x00800000, USERACCESS);
// User, R/W, Present map_pages(0x00C00000 >> 12, 1024, 0x00C00000, USERACCESS);
second_page_table[i] = (i * 0x1000 + 0x400000) |4|2|1;
// User, R/W, Present // We aren't using page directory permissions
page_directory[0] = ((uintptr_t)first_page_table)|4|2|1; for (int i = 0; i < 4; i++)
page_directory[1] = ((uintptr_t)second_page_table)|4|2|1; page_directory[i] = ((uintptr_t)&page_tables[i]) | USERACCESS;
enable_paging(); enable_paging();
} }

View File

@ -1,9 +1,7 @@
#include "progs.h" #include "progs.h"
#include "file.h" #include "file.h"
// 400000 - 700000 Usermode Code (3mB) extern char _USERMODE, _USERMODE_END;
// 700000 - 800000 Usermode Stack (1mB)
extern char _USERMODE;
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, dirent *de) { void ProgramLoadTest(char *path, dirent *de) {
uint16_t *vga_text = (uint16_t *)0xb8000; uint16_t *vga_text = (uint16_t *)0xb8000;
@ -46,7 +44,7 @@ void ProgramLoadTest(char *path, dirent *de) {
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(0x800000, (uintptr_t)&_USERMODE, 0); uint32_t res = create_user_child((uintptr_t)&_USERMODE_END, (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, &regs); V8086Int(0x10, &regs);

View File

@ -152,17 +152,12 @@ mov ecx, esp ; return stack
call save_current_task call save_current_task
_enter_v86_internal_no_task: _enter_v86_internal_no_task:
mov ebp, esp ; save stack pointer mov ebp, esp ; save stack pointer
mov eax, dword [ebp+16] ; regs ; push v86 stuff for iret
test eax, eax mov eax, 0x3000
jz .no_regs push eax ; gs
; load regs: edi, esi, ebx, edx, ecx, eax push eax ; fs
mov edi, dword [eax+0] push eax ; ds
mov esi, dword [eax+4] push eax ; es
mov ebx, dword [eax+8]
mov edx, dword [eax+12]
mov ecx, dword [eax+16]
mov eax, dword [eax+20]
.no_regs:
push dword [ebp+0] ; ss push dword [ebp+0] ; ss
push dword [ebp+4] ; esp push dword [ebp+4] ; esp
pushfd ; eflags pushfd ; eflags
@ -170,6 +165,19 @@ or dword [esp], (1 << 17) ; set VM flags
;or dword [esp], (3 << 12) ; IOPL 3 ;or dword [esp], (3 << 12) ; IOPL 3
push dword [ebp+8] ; cs push dword [ebp+8] ; cs
push dword [ebp+12] ; eip push dword [ebp+12] ; eip
; check if we have regs
mov eax, dword [ebp+16] ; regs
test eax, eax
jz .no_regs
; load regs: ebp, edi, esi, ebx, edx, ecx, eax
mov ebp, dword [eax+0]
mov edi, dword [eax+4]
mov esi, dword [eax+8]
mov ebx, dword [eax+12]
mov edx, dword [eax+16]
mov ecx, dword [eax+20]
mov eax, dword [eax+24]
.no_regs:
iret iret
; return address in eax, return stack in ebp ; return address in eax, return stack in ebp

View File

@ -1,5 +1,5 @@
[BITS 32] [BITS 32]
[ORG 0x400000] [ORG 0x800000]
xchg bx,bx xchg bx,bx
mov edi, 0xB8000 mov edi, 0xB8000
mov ecx, 80*25 mov ecx, 80*25

View File

@ -16,7 +16,7 @@ void TestV86() {
uint16_t *vga_text = (uint16_t *)0xb8000 + (80*2); uint16_t *vga_text = (uint16_t *)0xb8000 + (80*2);
vga_text += printStr("Done.", vga_text); vga_text += printStr("Done.", vga_text);
} }
extern char _USERMODE; extern char _USERMODE, _USERMODE_END;
extern char _binary_usermode_bin_start, _binary_usermode_bin_end; extern char _binary_usermode_bin_start, _binary_usermode_bin_end;
void ReloadUser() { void ReloadUser() {
// Put Usermode code in proper place based on linker // Put Usermode code in proper place based on linker
@ -27,7 +27,7 @@ void ReloadUser() {
} }
char TestUser() { char TestUser() {
ReloadUser(); ReloadUser();
char *vga = (char *)(uintptr_t)create_user_child(0x800000, (uintptr_t)&_USERMODE, 0); char *vga = (char *)(uintptr_t)create_user_child((uintptr_t)&_USERMODE_END, (uintptr_t)&_USERMODE, 0);
if ((uintptr_t)vga != 0xA0000) { if ((uintptr_t)vga != 0xA0000) {
return 1; return 1;
} }

View File

@ -1,5 +1,5 @@
[BITS 32] [BITS 32]
[ORG 0x400000] [ORG 0x800000]
global user_test global user_test
user_test: user_test:
mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16 mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16
@ -43,6 +43,7 @@ push 0x00000000 ; edx
push 0x00000000 ; ebx push 0x00000000 ; ebx
push 0x00000000 ; esi push 0x00000000 ; esi
push 0x00000000 ; edi push 0x00000000 ; edi
push 0x00000000 ; ebp
push esp ; regs push esp ; regs
push 0x10 ; interrupt push 0x10 ; interrupt
mov eax, 0x86 ; command = 86h, virtual 8086 call mov eax, 0x86 ; command = 86h, virtual 8086 call

View File

@ -14,6 +14,7 @@ extern void v86DiskReadCHS();
union __attribute((__packed__)) V86Regs_t { union __attribute((__packed__)) V86Regs_t {
struct dword_regs { struct dword_regs {
uint32_t ebp;
uint32_t edi; uint32_t edi;
uint32_t esi; uint32_t esi;
uint32_t ebx; uint32_t ebx;
@ -22,6 +23,7 @@ union __attribute((__packed__)) V86Regs_t {
uint32_t eax; uint32_t eax;
} d; } d;
struct word_regs { struct word_regs {
uint16_t bp, _upper_bp;
uint16_t di, _upper_di; uint16_t di, _upper_di;
uint16_t si, _upper_si; uint16_t si, _upper_si;
uint16_t bx, _upper_bx; uint16_t bx, _upper_bx;
@ -30,8 +32,9 @@ union __attribute((__packed__)) V86Regs_t {
uint16_t ax, _upper_ax; uint16_t ax, _upper_ax;
} w; } w;
struct byte_regs { struct byte_regs {
uint16_t di, _upper_di; uint32_t ebp;
uint16_t si, _upper_si; uint32_t edi;
uint32_t esi;
uint8_t bl, bh; uint8_t bl, bh;
uint16_t _upper_bx; uint16_t _upper_bx;
uint8_t dl, dh; uint8_t dl, dh;

Binary file not shown.