From d0a5eb4c6f2a9c08f3c0c8ea91eda76940f9e8cb Mon Sep 17 00:00:00 2001 From: Lucia Ceionia Date: Fri, 17 Feb 2023 01:41:30 -0600 Subject: [PATCH] Usermode now loads at 0x800000, Virtual 8086 loads consistent DS&ES for data access --- entry.nasm | 2 +- fault.nasm | 8 ++++++ kernel.c | 10 +++++--- link.ld | 3 ++- paging.c | 63 +++++++++++++++++++++++++++++------------------- progs.c | 6 ++--- task.nasm | 30 ++++++++++++++--------- testpgrm.nasm | 2 +- tests.c | 4 +-- usermode.nasm | 3 ++- v86defs.h | 7 ++++-- virtdisk.bin.ex | Bin 33554432 -> 33554432 bytes 12 files changed, 86 insertions(+), 52 deletions(-) diff --git a/entry.nasm b/entry.nasm index 41c1f8b..20dc30f 100644 --- a/entry.nasm +++ b/entry.nasm @@ -16,7 +16,7 @@ mov es, ax mov ss, ax mov fs, ax mov gs, ax -mov ebp, 0x400000 +mov ebp, 0x800000 mov esp, ebp mov eax, 0x1f001f00 mov ecx, (80*25)/2 diff --git a/fault.nasm b/fault.nasm index cf2ef21..9f1170f 100644 --- a/fault.nasm +++ b/fault.nasm @@ -83,6 +83,7 @@ je .int30 cmp eax, 0x21CD ; int 0x21 je .int21 jmp gpf_unhandled + .int21: pop eax ; command cmp al, 0x00 ; get key @@ -94,7 +95,13 @@ jne .s86 call get_scancode jmp .return_to_offender .s86: cmp al, 0x86 ; v86 interrupt call +je .v86int +cmp ax, 0x86D8 ; get v86 data pointer jne .return_to_offender +mov eax, 0x30000 ; V86 Data +jmp .return_to_offender + +.v86int: add esp, 4 add dword [esp+0], 2 ; add a new task @@ -120,6 +127,7 @@ push eax ; cs push 0xFF00 ; sp push 0x8000 ; ss jmp _enter_v86_internal_no_task ; NOT a function call + .int30: pop eax ; return value jmp return_prev_task diff --git a/kernel.c b/kernel.c index 38d72b7..8fe20f1 100644 --- a/kernel.c +++ b/kernel.c @@ -171,10 +171,11 @@ Real Mode Accessible (First MB) 01000 - 04000 Free (12kB) 04000 - 07C00 V86 Code (15kB) 07C00 - 08000 Boot & V86 Code (512B) - 08000 - 20000 V86 Code (96kB) + 08000 - 20000 Free (96kB) 20000 - 30000 Disk Buffer (64kB) - 30000 - 80000 Free (320kB) - 80000 - 90000 Real Mode Stack (64kB) + 30000 - 40000 V86 Data (64kB) + 40000 - 80000 Free (256kB) + 80000 - 90000 V86 Stack (64kB) 90000 - A0000 Free (64kB) A0000 - C0000 VGA (128kB) C0000 - FFFFF BIOS Area (256kB) @@ -434,6 +435,8 @@ void SystemRun(uint8_t sysPartition) { RestoreVGA(); DrawScreen((uint16_t*)0xb8000); + InitDisk(); + // Check for FAT partition { // TODO Check partitions beyond 0 @@ -528,7 +531,6 @@ void start() { setup_tss(); init_paging(); backup_ivtbios(); - InitDisk(); // DL contained disk number, DH contained active partition uint8_t SystemPartition = boot_dx >> 8; diff --git a/link.ld b/link.ld index be57bc8..a86b17e 100644 --- a/link.ld +++ b/link.ld @@ -3,7 +3,8 @@ ENTRY(entry) SECTIONS { . = 0x100000; - _USERMODE = 0x400000; + _USERMODE = 0x800000; + _USERMODE_END = 0x1000000; .text : { *(.text); diff --git a/paging.c b/paging.c index 7ce635e..c752793 100644 --- a/paging.c +++ b/paging.c @@ -1,8 +1,7 @@ #include "paging.h" uint32_t page_directory[1024] __attribute__((aligned(4096))); -uint32_t first_page_table[1024] __attribute__((aligned(4096))); // 0x00000000 - 0x00400000 -uint32_t second_page_table[1024] __attribute__((aligned(4096))); // 0x00400000 - 0x00800000 +uint32_t page_tables[4][1024] __attribute__((aligned(4096))); void enable_paging() { asm( @@ -13,38 +12,52 @@ void enable_paging() { ::"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() { for (int i = 0; i < 1024; i++) // Supervisor, R/W, Not Present page_directory[i] = 2; - // First Page Table + // 1024 Pages = 1MB // First MB: Real Mode - { - int i; - // 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; - } + // TODO Make some of this not accessible to usermode? + map_pages(0x00000000 >> 12, 256, 0x00000000, USERACCESS); // Next 3MB: Kernel - for (int i = 256; i < 1024; i++) - // Supervisor, R/W, Present - first_page_table[i] = (i * 0x1000) |2|1; + map_pages(0x00100000 >> 12, 768, 0x00100000, SUPERACCESS); + // Next 4MB: Kernel + map_pages(0x00400000 >> 12, 1024, 0x00400000, SUPERACCESS); - // Usermode Page Table - for (int i = 0; i < 1024; i++) - // User, R/W, Present - second_page_table[i] = (i * 0x1000 + 0x400000) |4|2|1; + // Next 8MB: Usermode + map_pages(0x00800000 >> 12, 1024, 0x00800000, USERACCESS); + map_pages(0x00C00000 >> 12, 1024, 0x00C00000, USERACCESS); - // User, R/W, Present - page_directory[0] = ((uintptr_t)first_page_table)|4|2|1; - page_directory[1] = ((uintptr_t)second_page_table)|4|2|1; + // We aren't using page directory permissions + for (int i = 0; i < 4; i++) + page_directory[i] = ((uintptr_t)&page_tables[i]) | USERACCESS; enable_paging(); } diff --git a/progs.c b/progs.c index 5d0cabd..cbbebbd 100644 --- a/progs.c +++ b/progs.c @@ -1,9 +1,7 @@ #include "progs.h" #include "file.h" -// 400000 - 700000 Usermode Code (3mB) -// 700000 - 800000 Usermode Stack (1mB) -extern char _USERMODE; +extern char _USERMODE, _USERMODE_END; extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...); void ProgramLoadTest(char *path, dirent *de) { 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 += printStr("Press any key to run.", vga_text); 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; regs.w.ax = 3; // text mode V8086Int(0x10, ®s); diff --git a/task.nasm b/task.nasm index f4f2711..654c1c2 100644 --- a/task.nasm +++ b/task.nasm @@ -152,17 +152,12 @@ mov ecx, esp ; return stack call save_current_task _enter_v86_internal_no_task: mov ebp, esp ; save stack pointer -mov eax, dword [ebp+16] ; regs -test eax, eax -jz .no_regs -; load regs: edi, esi, ebx, edx, ecx, eax -mov edi, dword [eax+0] -mov esi, dword [eax+4] -mov ebx, dword [eax+8] -mov edx, dword [eax+12] -mov ecx, dword [eax+16] -mov eax, dword [eax+20] -.no_regs: +; push v86 stuff for iret +mov eax, 0x3000 +push eax ; gs +push eax ; fs +push eax ; ds +push eax ; es push dword [ebp+0] ; ss push dword [ebp+4] ; esp pushfd ; eflags @@ -170,6 +165,19 @@ or dword [esp], (1 << 17) ; set VM flags ;or dword [esp], (3 << 12) ; IOPL 3 push dword [ebp+8] ; cs 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 ; return address in eax, return stack in ebp diff --git a/testpgrm.nasm b/testpgrm.nasm index 47e21df..eb0dfab 100644 --- a/testpgrm.nasm +++ b/testpgrm.nasm @@ -1,5 +1,5 @@ [BITS 32] -[ORG 0x400000] +[ORG 0x800000] xchg bx,bx mov edi, 0xB8000 mov ecx, 80*25 diff --git a/tests.c b/tests.c index 68ec4e0..03dbd7d 100644 --- a/tests.c +++ b/tests.c @@ -16,7 +16,7 @@ void TestV86() { uint16_t *vga_text = (uint16_t *)0xb8000 + (80*2); vga_text += printStr("Done.", vga_text); } -extern char _USERMODE; +extern char _USERMODE, _USERMODE_END; extern char _binary_usermode_bin_start, _binary_usermode_bin_end; void ReloadUser() { // Put Usermode code in proper place based on linker @@ -27,7 +27,7 @@ void ReloadUser() { } char TestUser() { 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) { return 1; } diff --git a/usermode.nasm b/usermode.nasm index 81ad030..3d75ccd 100644 --- a/usermode.nasm +++ b/usermode.nasm @@ -1,5 +1,5 @@ [BITS 32] -[ORG 0x400000] +[ORG 0x800000] global user_test user_test: mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16 @@ -43,6 +43,7 @@ push 0x00000000 ; edx push 0x00000000 ; ebx push 0x00000000 ; esi push 0x00000000 ; edi +push 0x00000000 ; ebp push esp ; regs push 0x10 ; interrupt mov eax, 0x86 ; command = 86h, virtual 8086 call diff --git a/v86defs.h b/v86defs.h index f8937d1..9d2f3dd 100644 --- a/v86defs.h +++ b/v86defs.h @@ -14,6 +14,7 @@ extern void v86DiskReadCHS(); union __attribute((__packed__)) V86Regs_t { struct dword_regs { + uint32_t ebp; uint32_t edi; uint32_t esi; uint32_t ebx; @@ -22,6 +23,7 @@ union __attribute((__packed__)) V86Regs_t { uint32_t eax; } d; struct word_regs { + uint16_t bp, _upper_bp; uint16_t di, _upper_di; uint16_t si, _upper_si; uint16_t bx, _upper_bx; @@ -30,8 +32,9 @@ union __attribute((__packed__)) V86Regs_t { uint16_t ax, _upper_ax; } w; struct byte_regs { - uint16_t di, _upper_di; - uint16_t si, _upper_si; + uint32_t ebp; + uint32_t edi; + uint32_t esi; uint8_t bl, bh; uint16_t _upper_bx; uint8_t dl, dh; diff --git a/virtdisk.bin.ex b/virtdisk.bin.ex index d44344b3844480b163fec7292214d0e99bc78bf2..eb4a47c618c7306b0d51663ed392e46deac4e98d 100644 GIT binary patch delta 3239 zcmeHIT}&KR6u$FAnT4TqOE+eXs~O@XQlKrQMx~)xU`=U4?E+=_vlQf~>|`l+cWL#- zUA%+kvJzur^tI_rjp>_aAsX9-UBQ~HNhK0U)s$+RT?SJcq|j0r&+wD<-PfJuJNMpm z?)lEootYa92651Y#%Qd@X}p%E?b6aUL9=KXTBasyS=w$*((vbd1lBOVVc183XQ$b( zb$|ClwTnYn5JKhcs2BCX#4se3WjynkD#KvBs1Ny&AMHnA_rRhZxltQ9Ay6McHFdS8 z_E&vaRB`fzjQHx3YFD)jA#>yr&qM5Yk9|>@{UQ_m@}H=dLYpT{)t); zQf6(vi!9isuwN;Z!VaZC8hI>*e;vCkjNK6|i*%0UAkxMI1Vld&X*H&0*2yv(#t5mn zdGuo-sjiLZkeEPX_Leiv(b25Mt75!R->3uX{)KC>VYC%$8Ho6$u1Sr*h612ENFuEM z&vg{cL^m$Odf20g{Tr7*%|w2wzRs0sXAvSXk=f9b>Qn>xW=rA0@3|oAvV4M?!0V_! zUlfVwl$`HdB^`>4K-f)TGlkU@*c2j~bSTPRh_I6_O$N3TR!dvdLk&f@)#sXuZn~U_ zr47SqXjBiJQS(}gZkDM>PSg2%SK{|A^_xv9+gMYRh;J>q#!cgmtrg!0Bx-4c69}D& zuQ!#WKS9(V5XwN;k1|lrTAKeDSyM(G|HLr=2iOoDBXc%dr3iGE%smb5S(zbsY@6AS@x>2(Z-f{yVhAft&C>}O#i{!s zv1OXRP9}LW#?x_qn$EypF(gpQ)J1rGk+UnXjVE)QnJSYkj{7V_djo@Y=&cHUiNvg% zRV816*V8P`89JrNP?#Nd+aRYW(go)VWW-TX8GcouW5o}BX@k#~=__-BWx$hlqK-X6K8&*#tCCp*2JKA(JE_V>!2@4Nl-;Y0Oax8Hs4tbFmH zTz>pyt?WK0pY^uA*X?fi$vwRtov;NV9y)6UaDZcP*P*h3NS;xXmoJtMeKy|Od}aE# zuUd~2hP}kF48R;Y01rq5>;j|%1b_vQ0muZ1fGoi75r&nFb%NPT7zi*BU?9LifPnx5 z0R{pL1Q-Y~5MUs{K!AY&0|92G#S}rR2dVcU^)00S2dRHz>R$N&cOzV?S@Gn5P76|Q delta 2099 zcmZo@Xb@-s;TFagrWWQFmKN3)wifmljuy@qt`_bVo)+E~z83x#fhmF