From 45ad970e6c7bd6b679bd96e99a8f24f5fc7a5dcc Mon Sep 17 00:00:00 2001 From: Michael Keyes Date: Sat, 31 Jul 2021 12:36:36 +0100 Subject: [PATCH 1/6] A bit of refactoring (with a view to adding VCPI support) --- src2/Dos64stb2.asm | 72 +++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/src2/Dos64stb2.asm b/src2/Dos64stb2.asm index 863ac68..2c92496 100644 --- a/src2/Dos64stb2.asm +++ b/src2/Dos64stb2.asm @@ -25,7 +25,7 @@ DGROUP group _TEXT ;makes a tiny model ?MPIC equ 78h ; master PIC base, remapped to 78h ?SPIC equ 70h ; slave PIC, isn't changed -?RESETLME equ 0;1=(re)set EFER.LME for temp switch to real-mode +?RESETLME equ 1;1=(re)set EFER.LME for temp switch to real-mode ?RESETPAE equ 1;1=(re)set CR4.PAE for temp switch to real-mode ?SETCR3 equ 1;1=set CR3 after temp switch to real-mode ?IDTADR equ 100000h ;address of IDT @@ -93,11 +93,12 @@ GDT dq 0 ; null descriptor dw -1,0,9200h,0h ; 16-bit, 64k data descriptor dw -1,0,9A00h,0h ; 16-bit, 64k code descriptor dw -1,0,9200h,0CFh ; 32-bit flat data descriptor, used for unreal mode only +sizeGDT equ $-GDT ; PluM modification 31 July 2021 (make it more generic) .data GDTR label fword ; Global Descriptors Table Register - dw 5*8-1 ; limit of GDT (size minus one) + dw sizeGDT-1 ; limit of GDT (size minus one) dd offset GDT ; linear address of GDT IDTR label fword ; IDTR in long mode dw 256*16-1 ; limit of IDT (size minus one) @@ -678,25 +679,26 @@ readsection endp backtoreal proc - mov eax,cr0 - and eax,7ffffffeh ; disable protected-mode & paging - mov cr0,eax - jmp far16 ptr @F -@@: +;--- PluM refactoring 31 July 2021 + call switch2rm + @@exit2:: mov ax, cs mov ss, ax ; SS=DGROUP mov ds, ax ; DS=DGROUP - @lidt [nullidt] ; IDTR=real-mode compatible values +if ?RESETLME eq 0 mov ecx,0C0000080h ; EFER MSR rdmsr and ah,0feh ; disable long mode (EFER.LME=0) wrmsr +endif +if ?RESETPAE eq 0 mov eax,cr4 and al,0DFh ; reset bit 5, disable PAE paging mov cr4,eax +endif mov dx,7008h call setpic @@ -730,12 +732,10 @@ backtoreal endp ;--- switch to real-mode switch2rm proc -;--- disable paging & protected-mode +;--- disable paging first (PluM modification) mov eax,cr0 - and eax,7ffffffeh + and eax,7fffffffh mov cr0, eax - jmp far16 ptr @F -@@: ;--- disable long mode if ?RESETLME mov ecx,0C0000080h ; EFER MSR @@ -748,6 +748,13 @@ if ?RESETPAE and al,0DFh ; reset bit 5, disable PAE paging mov cr4,eax endif +;--- PluM modification: now disable protection +;--- TODO: (or switch to VM86 mode) + mov eax, cr0 + and al, 0feh + mov cr0, eax + jmp far16 ptr @F +@@: @lidt cs:[nullidt] ; IDTR=real-mode compatible values ret switch2rm endp @@ -770,12 +777,8 @@ if ?RESETPAE mov cr4,eax endif if ?SETCR3 -; mov eax,cr3 ; useless to check if CR will change because -; cmp eax,cs:pPML4 ; turning paging off has reset the TLB -; jz @F mov eax,cs:pPML4 mov cr3,eax -;@@: endif ;--- enable protected-mode + paging mov eax,cr0 @@ -1026,6 +1029,10 @@ long_start proc ;--- ensure ss is valid! mov ax,SEL_DATA16 mov ss,eax +;--- PluM modification 31 July 2021: +;--- and fs/gs so we don't triple-fault trying to save/restore them in IRQs! + mov fs,eax + mov gs,eax ;--- linear address of image start (=PE header) should be in edx::ebx ;--- move it to rbx using registers only. @@ -1216,10 +1223,22 @@ endif @call_rm_irq macro procname, interrupt procname proc push eax -if ?RESETLME push ecx push edx -endif +;--- PluM modification 31 July 2021: +;--- Save FS and GS (selectors + bases) since "usermode" may use them + mov ecx, 0c0000100h ; fs base + rdmsr + push edx + push eax + push fs + + mov ecx, 0c0000101h ; gs base + rdmsr + push edx + push eax + push gs + call switch2rm ;modifies eax [, ecx, edx] ;--- SS still holds a selector - hence a possible temporary ;--- stack switch inside irq handler would cause a crash. @@ -1227,10 +1246,23 @@ endif int interrupt cli call switch2pm ;modifies eax [, ecx, edx] -if ?RESETLME + +;--- PluM modification 31 July 2021: +;--- Restore FS and GS since "usermode" may use them + pop gs + mov ecx, 0c0000101h ; gs base + pop eax + pop edx + wrmsr + + pop fs + mov ecx, 0c0000100h ; fs base + pop eax + pop edx + wrmsr + pop edx pop ecx -endif pop eax retd procname endp From bc8f455826a55a6d6eeef8d113acc7a81dd7c303 Mon Sep 17 00:00:00 2001 From: Michael Keyes Date: Sun, 1 Aug 2021 23:00:50 +0100 Subject: [PATCH 2/6] Fixed race condition, added TSS for double-fault handling etc. --- src2/Dos64stb2.asm | 78 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/src2/Dos64stb2.asm b/src2/Dos64stb2.asm index 2c92496..a27f080 100644 --- a/src2/Dos64stb2.asm +++ b/src2/Dos64stb2.asm @@ -29,6 +29,17 @@ DGROUP group _TEXT ;makes a tiny model ?RESETPAE equ 1;1=(re)set CR4.PAE for temp switch to real-mode ?SETCR3 equ 1;1=set CR3 after temp switch to real-mode ?IDTADR equ 100000h ;address of IDT +?DFSTKADR equ (1 shl 47) - 8 ;address of double-fault stack for TSS +?KSTKADR equ ?DFSTKADR - 100h ;address of "kernel" stack for TSS + +KSTKBTM equ ?KSTKADR and not 0fffh +DFSTKBTM equ ?DFSTKADR and not 0fffh + +if KSTKBTM ne DFSTKBTM +EXTRASTKPGS equ 2 +else +EXTRASTKPGS equ 1 +endif EMM struct ;XMS block move help struct _size dd ? @@ -79,20 +90,41 @@ endm ;--- 16bit start/exit code -SEL_CODE64 equ 1*8 -SEL_DATA16 equ 2*8 -SEL_CODE16 equ 3*8 -SEL_FLAT equ 4*8 - .code assume ds:DGROUP +;--- PluM modification 1 August 2021: add TSS +TSS dd 0 ;reserved +RSP_r0 dq ?KSTKADR +RSP_r1 dq 0 +RSP_r2 dq 0 +pPML4 label dword +TSS_CR3 dq 0 ;technically reserved, but might come in handy... +IST1 dq ?DFSTKADR +IST2 dq 0 +IST3 dq 0 +IST4 dq 0 +IST5 dq 0 +IST6 dq 0 +IST7 dq 0 + dq 0 ;reserved + dw 0 ;reserved +IOPB dw 0DFFFh;max possible to make sure there is NO IOBP! +sizeTSS equ $-TSS + GDT dq 0 ; null descriptor +SEL_CODE64 equ $-GDT dw -1,0,9A00h,0AFh ; 64-bit code descriptor +SEL_DATA16 equ $-GDT dw -1,0,9200h,0h ; 16-bit, 64k data descriptor +SEL_CODE16 equ $-GDT dw -1,0,9A00h,0h ; 16-bit, 64k code descriptor +SEL_FLAT equ $-GDT dw -1,0,9200h,0CFh ; 32-bit flat data descriptor, used for unreal mode only +SEL_TSS equ $-GDT + dw sizeTSS-1,offset TSS,8900h,40h + dq 0 ; TSS descriptor 16 bytes in long mode?? sizeGDT equ $-GDT ; PluM modification 31 July 2021 (make it more generic) .data @@ -110,7 +142,7 @@ nullidt label fword ; IDTR for real-mode xmsaddr dd 0 dwCSIP label dword adjust dd 0 -pPML4 dd 0 +;pPML4 dd 0 retad label fword dd 0 dw SEL_CODE64 @@ -189,9 +221,14 @@ start16 proc add dword ptr [GDTR+2], eax ; convert offset to linear address mov word ptr [GDT + SEL_DATA16 + 2], ax mov word ptr [GDT + SEL_CODE16 + 2], ax + add word ptr [GDT + SEL_TSS + 2], ax + pushf + shr eax,16 mov byte ptr [GDT + SEL_DATA16 + 4], al mov byte ptr [GDT + SEL_CODE16 + 4], al + popf + adc byte ptr [GDT + SEL_TSS + 4], al smsw ax test al,1 @@ -308,8 +345,10 @@ start16 proc ;--- 3 for remainder of PDPT,PD,PT ;--- 1 for PML4 ;--- 3 (PT,PD,PDPT) for mapping DOS conventional memory +;--- PluM (1 August): 1/2 for alt stacks (particularly for double fault) +;--- 3 (PT,PD,PDPT) to point at the alt stacks ;--- 1 extra page that may be needed to align to page boundary - add edx,3+1+3+1 + add edx,3+1+3+EXTRASTKPGS+3+1 test edx,0C0000000h mov bp,CStr("too much extended memory needed") @@ -395,6 +434,14 @@ start16 proc mov dword ptr [IDTR+2], eax invoke MapPages, 1, ?IDTADR, ecx +;--- PluM modification 1 August: create alt stack(s) + add PhysCurr,1000h + invoke MapPages, 1, KSTKBTM, PhysCurr +if EXTRASTKPGS eq 2 + add PhysCurr,1000h + invoke MapPages, 1, DFSTKBTM, PhysCurr +endif + mov eax,PhysCurr mov ecx,ImgSize shl ecx,12 @@ -762,6 +809,7 @@ switch2rm endp ;--- switch to protected-mode switch2pm proc + and byte ptr cs:[GDT+SEL_TSS+5], 0FDh ; clear busy bit @lgdt cs:[GDTR] @lidt cs:[IDTR] ;--- (re)enable long mode @@ -784,6 +832,8 @@ endif mov eax,cr0 or eax,80000001h mov cr0,eax + mov ax, SEL_TSS + ltr ax ret switch2pm endp @@ -853,6 +903,10 @@ make_exc_gates: mov ax,SEL_CODE64 stosw mov ax,8E00h + cmp ecx, 20 ; 32-0Ch - i.e. this is the double-fault gate + jne @F + mov al,1 ; PluM modification 1 Aug: IST 1 +@@: stosd xor eax, eax stosd @@ -870,7 +924,7 @@ make_exc_gates: lea di,[di+?MPIC*16] mov cx,8 mov edx,offset Irq0007 - mov si, 8E00h + ;mov si, 8E00h ; PluM 1 August 2021: this would turn on interrupts in IRQ handlers - that can't be right (causes races) call make_int_gates pop di lea di,[di+?SPIC*16] @@ -1047,9 +1101,12 @@ long_start proc mov ecx,[rbx].IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage add rcx,[rbx].IMAGE_NT_HEADERS.OptionalHeader.SizeOfStackReserve lea rsp,[rcx+rbx] - sti ; stack pointer ok, interrupts can be used -; call baserelocs ; handle base relocations +;--- PluM modification 1 August 2021: setup TSS for alt stacks etc. + mov ax,SEL_TSS + ltr ax + + sti ; stack pointer(s) ok, interrupts can be used mov esi,[rbx].IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint add rsi,rbx @@ -1158,7 +1215,6 @@ WriteNb: jmp WriteChr ;--- exception handler -;--- might not work for exception 0Ch, since stack isn't switched. exception: excno = 0 From 8b1af040b264b4f5ba0bc70bde8f956e0bde0095 Mon Sep 17 00:00:00 2001 From: Michael Keyes Date: Sun, 8 Aug 2021 17:20:03 +0100 Subject: [PATCH 3/6] Initial VCPI support (double-faults gracefully!) Also reverted IDT change based on misreading of osdev wiki. --- src2/Dos64stb2.asm | 676 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 636 insertions(+), 40 deletions(-) diff --git a/src2/Dos64stb2.asm b/src2/Dos64stb2.asm index a27f080..fe23ac8 100644 --- a/src2/Dos64stb2.asm +++ b/src2/Dos64stb2.asm @@ -99,7 +99,7 @@ TSS dd 0 ;reserved RSP_r0 dq ?KSTKADR RSP_r1 dq 0 RSP_r2 dq 0 -pPML4 label dword +pRealPML4 label dword TSS_CR3 dq 0 ;technically reserved, but might come in handy... IST1 dq ?DFSTKADR IST2 dq 0 @@ -126,6 +126,24 @@ SEL_TSS equ $-GDT dw sizeTSS-1,offset TSS,8900h,40h dq 0 ; TSS descriptor 16 bytes in long mode?? sizeGDT equ $-GDT ; PluM modification 31 July 2021 (make it more generic) +SEL_VCPICODE equ $-GDT + dq 3 dup (0) ; VCPI allocates three 8-byte descriptors +sizeGDT_VCPI equ $-GDT + +;--- PluM modification 2 August 2012: VCPI control structure +vcpiCR3 dd 0 ; not the long-mode CR3, a 32-bit one! +vcpiGDT dd offset GDTR +vcpiIDT dd offset IDTR +vcpiLDT dw 0 +vcpiTSS dw SEL_TSS +vcpiEIP dd offset vcpi_switchOK +vcpiCS dw SEL_CODE16 + +;--- *physical* EMS pages used for setting up the 32-bit page tables +EMSPG_PD equ 0 ; always keep the PD in page 0 +EMSPG_PT equ 1 ; keep the current PT in page 1 +EMSPG_DATA equ 2 ; use page 2 to copy data and lookup physical addxs + .data @@ -142,11 +160,16 @@ nullidt label fword ; IDTR for real-mode xmsaddr dd 0 dwCSIP label dword adjust dd 0 -;pPML4 dd 0 +pPML4 dd 0 +LinBase dd 100000h ; first linear addx that "we own" (1 MiB by default) retad label fword dd 0 dw SEL_CODE64 xmshdl dw -1 +vcpiint label fword +vcpiadr dd -1 + dw SEL_VCPICODE +emshdl dw -1 fhandle dw -1 .data? @@ -181,6 +204,7 @@ endif .code MapPages proto stdcall pages:dword, linaddr:qword, physaddr:dword +MapEMS4kPage proto stdcall pagenum:dword, physpage:byte start16 proc @@ -219,6 +243,8 @@ start16 proc movzx eax,ax shl eax,4 add dword ptr [GDTR+2], eax ; convert offset to linear address + add [vcpiGDT], eax ; convert offset to linear address + add [vcpiIDT], eax ; convert offset to linear address mov word ptr [GDT + SEL_DATA16 + 2], ax mov word ptr [GDT + SEL_CODE16 + 2], ax add word ptr [GDT + SEL_TSS + 2], ax @@ -230,16 +256,47 @@ start16 proc popf adc byte ptr [GDT + SEL_TSS + 4], al - smsw ax - test al,1 - mov bp,CStr("Mode is V86. Need REAL mode to switch to LONG mode!") - jnz @@error +;--- PluM 2 August 2021: do this first, so EMS v XMS code can be grouped xor edx,edx mov eax,80000001h ; test if long-mode is supported cpuid bt edx,29 mov bp,CStr("No 64bit cpu detected.") jnc @@error + + smsw ax + test al,1 + jz @@checkxms +;--- in vm86 mode - check if there's EMS / VCPI + mov bp,CStr("Mode is V86, no VCPI. Need REAL mode to switch to LONG mode!") + mov dx,CStr("EMMXXXX0") + mov ax,3D00h ; open read-only + int 21h + jc @@error + mov bx,ax + mov ax,4400h ; get device information + int 21h + jc @@error + test dx,80h ; is it a device? + jz @@error + mov ax,4407h ; get device output status + int 21h + push ax + mov ah,3Eh ; close + int 21h + pop ax + cmp al,0FFh ; device ready? + jne @@error +;--- so we have EMS, but does it support VCPI? + mov ax,0DE00h ; vcpi check + int 67h + test ah,ah + jnz @@error +;--- we have VCPI, so we need three more descriptors in our GDT! + mov word ptr [GDTR], sizeGDT_VCPI-1 + jmp @@havexms_ems + +@@checkxms: mov ax,4300h int 2fh ;XMS host available? test al,80h @@ -253,6 +310,7 @@ start16 proc mov ah,5 ;local enable A20 call xmsaddr +@@havexms_ems: push ds lds dx,fname mov ax,3D00h @@ -346,17 +404,22 @@ start16 proc ;--- 1 for PML4 ;--- 3 (PT,PD,PDPT) for mapping DOS conventional memory ;--- PluM (1 August): 1/2 for alt stacks (particularly for double fault) -;--- 3 (PT,PD,PDPT) to point at the alt stacks +;--- 3/6 (PT,PD,PDPT)*1/2 to point at the alt stacks ;--- 1 extra page that may be needed to align to page boundary - add edx,3+1+3+EXTRASTKPGS+3+1 + add edx,3+1+3+(EXTRASTKPGS*4)+1 test edx,0C0000000h mov bp,CStr("too much extended memory needed") jnz @@error - push edx - shl edx,2 +;--- are we using EMS or XMS? + cmp word ptr [GDTR], sizeGDT_VCPI-1 + je @@ems_alloc + +@@xms_alloc: ;--- allocate the extended memory block needed for image + systabs + push edx + shl edx,2 ; convert pages to KiB mov ah,89h call xmsaddr cmp ax,1 @@ -393,6 +456,7 @@ start16 proc add eax, ebx mov PhysBase, eax mov pPML4, eax ; allocate the first page for PML4 + mov pRealPML4, eax ; in XMS mode, physical and "unreal" addxs are the same add eax,1000h mov PhysCurr, eax ; start of free physical pages @@ -403,9 +467,6 @@ start16 proc mov word ptr emm2.srcofs+0, sp mov word ptr emm2.srcofs+2, ss -;--- map conventional memory - invoke MapPages, 256, 0, 0 - ;--- setup ebx/rbx with linear address of _TEXT64 mov ebx,seg long_start @@ -433,6 +494,198 @@ start16 proc mov eax, ?IDTADR mov dword ptr [IDTR+2], eax invoke MapPages, 1, ?IDTADR, ecx + jmp @@allocdone + +@@ems_alloc: +;--- need additional pages in EMS mode: +;--- N/1024 + 1 to map them all in a linear 32-bit space +;--- 2 for VCPI page table and directory pointing to all of the above +;--- 3 to round up to nearest 16-kiB EMS page! + push edx ; save number of pages we'll need to map in 32-bit mode + mov eax,edx + shr eax,10 ; convert pages to page-tables + add edx,eax + add edx,1+2+3 ; PT for remainder + VCPI page table + directory + round-up + shr edx,2 ; convert to EMS pages + test edx,0FFFF0000h + mov bp,CStr("too much expanded memory needed") + jnz @@error + + mov ebx,edx + mov ah,43h ; allocate pages + int 67h + test ah,ah + mov bp,CStr("EMS memory allocation failed.") + jnz @@error + mov emshdl, dx + +;--- use FS for the frame ("frame segment"!) + mov ah,41h ; get page frame address + int 67h + test ah,ah + mov bp,CStr("EMS page frame inaccessible.") + jnz @@error + mov fs,bx ; frame segment - don't mess with it until done with MapEMS4kPage + + pop ebp ; number of pages to map; or, first page of 32-bit mapping set +;--- start out by mapping pages for the following into the EMS frame: +;--- * 32-bit PD (on the ebp-th 4K page) +;--- * First 32-bit PT, to be filled out by VCPI (on the ebp+1-th page) +;--- * The first four 4K pages (i.e. first EMS page), for the IDT and PML4 + invoke MapEMS4kPage, ebp, EMSPG_PD + jc @@emserr + push es + pop gs ; use GS for the PD + mov vcpiCR3, eax ; physical addx of 32-bit PD +;--- clear the PD + xor di,di + mov cx,400h + xor eax,eax + rep stosd + + lea edx, [ebp+1] + invoke MapEMS4kPage, edx, EMSPG_PT + jc @@emserr +;--- clear the PT + xor di,di + mov cx,400h + xor eax,eax + rep stosd + push es ; we'll use this again in a minute + + invoke MapEMS4kPage, 0, EMSPG_DATA + jc @@emserr + mov pRealPML4, eax ; we'll use the first page for our PML4 in Long Mode + mov ebx, es + shl ebx, 4 + mov pPML4, ebx ; in the 32-bit addx space, the PML4 will be fixed here +;--- clear the PML4 + xor di,di + mov cx,400h + xor eax,eax + rep stosd + +;--- and we'll put the IDT on the next page + add ebx, 1000h + mov dword ptr [IDTR+2], ebx +;--- setup ebx/rbx with linear address of _TEXT64 + mov ebx,seg long_start + shl ebx,4 + add [llgofs], ebx + call createIDT + + mov ax,0DE01h ; get protected mode interface + pop es + xor edi,edi ; ES:(E)DI points to first PT + mov si,offset GDT+SEL_VCPICODE ; DS:SI points to descriptors + int 67h + mov vcpiadr, ebx + mov ecx,edi + shr ecx,2 ; convert to page count +;--- clear bits 9-11 of all the PT entries, as per the VCPI standard +@@: + and byte ptr es:[ecx*4-3],0F1h ; byte index n*4 - 3, where n > 0 + loop @B + shl edi,10 ; convert from dword count to linear addx + mov LinBase, edi +;--- now the ebp+1-th 4K page contains a 32-bit page table mapping the first 1~4 +;--- MiB exactly as they are now - i.e. with the 32-bit PD @ GS*16, the first +;--- 32-bit PT @ ES*16, and the 64-bit PML4 @ pPML4. + + mov ebx,es + shr ebx,6 ; convert segment address to PT offset (left 4, right 12, left 2) + mov eax,es:[ebx] ; get the PT entry corresponding to the PT itself + mov gs:[0],eax ; and fill it into the first entry of the PD + mov ebx,gs + shr ebx,6 + mov eax,es:[ebx] ; get the PT entry corresponding to the PD + mov gs:[0FFCh],eax ; and fill it into the last entry to get a recursive map + +;--- initialize the loop ready to pull in the next page table (DI>=1000h), +;--- and start mapping from the 2nd (ESI=2) zero-relative 4K page in the EMS map + mov di,1000h + mov esi,2 + + .while esi < ebp +;------- save far pointer to the next position in the current page table + push es + push di + +;------- map in the next 4K page to the EMS page frame + invoke MapEMS4kPage, esi, EMSPG_DATA + jc @@emserr +;------- now ES:DI is a far pointer to the 4K page, and EAX is its physical addx + push eax ; save physical addx + xor eax,eax + xor di,di + mov cx,400h + rep stosd ; clear the page + + pop eax +;------- restore far pointer to the next position in the current page table + pop di + pop es + + .if di >= 1000h ; past the end of the page table? + push eax ; save physical addx again + push esi ; save page number + + shr esi,10 ; convert to page table count +;----------- The ebp-th 4K page is the PD, and the ebp+1-th is the first PT, +;----------- which was filled by VCPI. So, our own PTs start from the ebp+2-th. + push esi + lea esi,[esi+ebp+2] + invoke MapEMS4kPage, esi, EMSPG_PT + jc @@emserr + + pop esi ; get back to page table count + lea esi,[esi*4+4] ; convert to page directory offset (skipping 0) + or eax,11b ; stamp as R/W and present + mov gs:[esi],eax ; save physical address of PT into PD + +;----------- clear the PT + xor di,di + mov cx,400h + xor eax,eax + rep stosd + + pop esi ; restore index of current 4K page + pop eax ; and its physical addx + + mov edi,esi + and edi,3FFh; get its index in the current PT + shl di,2 ; and convert to offset + .endif + + or eax,11b ; stamp as R/W and present + stosd ; save physical address of page into PT + + inc esi ; next page + .endw + + push ds + pop es ; restore tiny model + +;--- all going well, our 32-bit memory map now looks like this: +;--- 00000000-00100000: first MiB exactly as it was when we called int 67h DE01h +;--- -----------------: (including our 64-bit PML4 and IDT) +;--- 00100000-00400000: *may* also have been mapped by int 67h DE01h +;--- 00400000-00402000: unmapped (!) +;--- 00402000-XXXXX000: blank EMS memory, ready to fill with data +;--- XXXXX000-FFC00000: unmapped (where XXXXX = EBP + 400h) +;--- FFC00000-00000000: the 32-bit page tables + + mov PhysBase, 400000h ; this addx isn't actually "physical" in EMS mode, + mov PhysCurr, 402000h ; but using these should accomplish what we need + +;--- point at stack buffer (which was *not* used for the IDT in this mode!) + mov di,sp + +@@allocdone: +;--- map conventional memory + mov ebx,[LinBase] + shr ebx,12 ; convert to page count + invoke MapPages, ebx, 0, 0 ;--- PluM modification 1 August: create alt stack(s) add PhysCurr,1000h @@ -526,9 +779,6 @@ endif cli - mov eax, pPML4 - mov cr3, eax ; load page-map level-4 base - if ?MPIC ne 8 in al,21h mov bPICM,al @@ -539,8 +789,23 @@ if ?SPIC ne 70h endif mov dx,?SPIC shl 8 or ?MPIC call setpic + + cmp word ptr [GDTR], sizeGDT_VCPI-1 + je @F @lgdt [GDTR] @lidt [IDTR] + jmp @@setCR3_4 + +@@: + call vcpi_switch2pm +;--- turn off paging temporarily to reconfigure it for 64-bit mode... + mov eax,cr0 + and eax,7fffffffh + mov cr0,eax + +@@setCR3_4: + mov eax, pRealPML4 + mov cr3, eax ; load page-map level-4 base mov eax,cr4 or ax,220h ; enable PAE (bit 5) and OSFXSR (bit 9) @@ -564,6 +829,8 @@ endif db 66h,0eah ; jmp far32 llgofs dd offset long_start dw SEL_CODE64 +@@emserr:: + mov bp,CStr("Failed to map EMS page") @@error:: mov si,bp nextchar: @@ -578,7 +845,7 @@ newline db 13,10,'$' done: mov dx,offset newline mov ah,9 - int 21 + int 21h jmp @@exit myint23: iret @@ -616,15 +883,17 @@ MapPages proc stdcall uses es pages:dword, linaddr:qword, physaddr:dword .if (edx == 0) ;does PDPTE/PDE/PTE exist? mov edx,PhysCurr add PhysCurr,1000h - or dl,11b + call AddrToPageMap mov es:[ebx+eax],edx ; mov es:[ebx+eax+4],x ;if phys ram > 4 GB is used .endif pop eax and eax,0ff8h mov ebx,edx -; and bx,0FC00h - and bx,0F000h + call PageMapToAddr + cmp ebx,-1 + stc + je exit loop @B test byte ptr es:[ebx+eax],1 ;something already mapped there? @@ -632,7 +901,7 @@ MapPages proc stdcall uses es pages:dword, linaddr:qword, physaddr:dword jnz exit mov edx,physaddr add physaddr,1000h - or dl,11b + call AddrToPageMap mov es:[ebx+eax],edx ; mov dword ptr es:[ebx+eax+4],x ;if phys ram > 4 GB is used add dword ptr linaddr+0,1000h @@ -641,12 +910,157 @@ MapPages proc stdcall uses es pages:dword, linaddr:qword, physaddr:dword .endw clc exit: + call DisableUnreal ret MapPages endp +;--- obtain a first-megabyte-memory mapping of the pagenum-th *4K page* in EMS, +;--- within the physpage-th "physical" EMS page, point ES at that 4K page, and +;--- give its physical address in EAX +;--- * EXPECTS EMS PAGE FRAME in FS * + +MapEMS4kPage proc stdcall uses ebx ecx edx pagenum:dword, physpage:byte + + mov ah,44h ; map handle page + mov al,physpage + mov ebx,pagenum + shr ebx,2 ; convert 4K page number to EMS page + mov dx,cs:emshdl + int 67h + test ah,ah + jnz @F + + mov ebx,fs + movzx eax,physpage + shl eax,10 ; convert 16K page size to segment delta + add ebx,eax; now EBX is a segment pointing at the base of the EMS page + + mov eax,pagenum + and eax,3 ; get the index of the requested 4K page, within this EMS page + shl eax,8 ; convert 4K page size to segment delta + add ebx,eax + mov es,ebx + +;--- now get its physical addx + mov ecx,ebx + shr ecx,8 ; convert back to a 4K page idx + mov ax,0DE06h ; get physical addx of page in first MiB + int 67h + test ah,ah + jnz @F + + mov eax,edx + and eax,NOT 0FFFh + clc + ret + +@@: + xor eax,eax + stc + ret + +MapEMS4kPage endp + +;--- Instead of "unreal mode", when using VCPI, we go into actual protected mode +;--- and map all EMS memory into contiguous space compatible with the non-VCPI +;--- program logic. This function converts the addresses in this space to actual +;--- physical addresses. + +AddrToPageMap proc + + cmp word ptr [GDTR], sizeGDT_VCPI-1 + je @F + or dl,11b ; XMS mode - addx is already physical, just stamp as Present + RW + ret + +@@: + shr edx,10 ; convert to page table offset + sub edx,1 SHL 22 ; all page tables mapped into upper 4 MiB of addx space + push edx + sar edx,10 ; get the corresponding PD entry (in upper 4 kiB of space) + and edx,NOT 3 + test byte ptr es:[edx],1 + jz @F ; no PD entry - defer #PF until we get to long mode! + pop edx + and edx,NOT 3 + mov edx,es:[edx] ; get the addx + control bits from the page table + ret + +@@: + add sp,4 + xor edx,edx + ret + +AddrToPageMap endp + +;--- Inverse of the above. In XMS mode, blanks lower 12 bits of EBX. In EMS/VCPI +;--- mode, walks the 32-bit page tables to find what's mapped to the physical +;--- addx in EBX, and returns the linear addx in EBX. + +PageMapToAddr proc + +; and bx,0FC00h + and bx,0F000h + cmp word ptr [GDTR], sizeGDT_VCPI-1 + je @F + ret + +@@: + push eax + push edi + push cx + xor eax,eax + mov edi,-1000h ; PD mapped into upper 4 kiB of addx space + mov cx,400h +@@nextPT: + repz scasd + push esi + push eax + push cx + mov esi,edi + sub esi,4 ; Back to the one we just scanned over + shl esi,10 ; Go to corresponding PT in upper 4 MiB + mov cx,400h +@@: + lods dword ptr es:[esi] + and ax,NOT 0FFFh + cmp eax,ebx + loopne @B + je @F + pop cx + pop eax + pop esi + jcxz @@notfound + jmp @@nextPT + +@@: +;--- found the right addx + sub esi,4 ; Back to the one we just scanned over + mov ebx,esi + shl ebx,10 + add esp,6 + pop esi + pop cx + pop edi + pop eax + ret + +@@notfound: + xor ebx,ebx + dec ebx + pop cx + pop edi + pop eax + ret + +PageMapToAddr endp + EnableUnreal proc cli + cmp word ptr [GDTR], sizeGDT_VCPI-1 + je @@unreal_vcpi + @lgdt [GDTR] mov eax,cr0 or al,1 @@ -663,18 +1077,90 @@ EnableUnreal proc xor ax,ax mov es,ax ret + +@@unreal_vcpi: +;--- don't actually enable unreal mode, just put us in temporary protected mode +;--- with a flat selector in ES, and *no interrupts*! + call vcpi_switch2pm + push SEL_FLAT + pop es + ret EnableUnreal endp +DisableUnreal proc + pushf ; preserve carry state + cmp word ptr [GDTR], sizeGDT_VCPI-1 + je @F + popf + ret ; XMS mode - unreal is harmless + +@@: +;--- back to VM86 and enable interrupts + call vcpi_switch2vm86 + popf + sti + ret +DisableUnreal endp + ;--- copy cx bytes to extended memory ;--- ds:si -> emm struct copy2ext proc mov [si].EMM._size,ecx push ecx - push bx + push ebx + cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 + je @F + mov ah,0bh call xmsaddr - pop bx + jmp @@movedone + +@@: +;--- EMS mode - assumes intent is srchdl = 0! + mov ah,41h ; get page frame address + int 67h + test ah,ah + stc + jnz @F + mov fs,bx ; frame segment - don't mess with it until done with MapEMS4kPage + + push es + push edi + mov edi,[si].EMM.dstofs + push ds + push si + lds si,[si].EMM.srcofs + mov ebx,edi + shr ebx,12 ; get index of 4K page + and edi,0FFFh ; and offset in that page + shr ecx,1 ; convert to word count + +@@mapnextpage: + invoke MapEMS4kPage, ebx, EMSPG_DATA +@@: + jc @F + movsw + cmp di,1000h + clc + loopne @B + jcxz @F + + inc ebx + xor di,di + jmp @@mapnextpage +@@: + pop si + pop ds + pop edi + pop es + + setc al + xor ah,ah + btc ax,0 ; CY => AX=0; NC => AX=1 + +@@movedone: + pop ebx pop ecx cmp ax,1 mov bp,CStr("error copying to extended memory.") @@ -757,6 +1243,12 @@ endif jz @F mov ah,3Eh int 21h +@@: + mov dx,emshdl + cmp dx,-1 + jz @F + mov ah,45h ;deallocate pages + int 67h @@: mov dx,xmshdl cmp dx,-1 @@ -782,7 +1274,7 @@ switch2rm proc ;--- disable paging first (PluM modification) mov eax,cr0 and eax,7fffffffh - mov cr0, eax + mov cr0,eax ;--- disable long mode if ?RESETLME mov ecx,0C0000080h ; EFER MSR @@ -795,8 +1287,17 @@ if ?RESETPAE and al,0DFh ; reset bit 5, disable PAE paging mov cr4,eax endif -;--- PluM modification: now disable protection -;--- TODO: (or switch to VM86 mode) +;--- PluM modification: now disable protection, or switch to VM86 mode + cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 + jne @F + mov eax, cs:[vcpiCR3] + mov cr3, eax ; reinstate VCPI page table + mov eax,cr0 + or eax,80000000h + mov cr0,eax ; and reenable paging + jmp vcpi_switch2vm86 + +@@: mov eax, cr0 and al, 0feh mov cr0, eax @@ -806,12 +1307,86 @@ endif ret switch2rm endp +vcpi_switch2vm86 proc + cli +;--- VCPI requires a flat selector in DS for this... + push SEL_FLAT + pop ds + + push eax + push ebx + mov ebx,esp + +;--- setup segments - make a tiny model... + movzx eax,cs:[wStkBot+2] + push eax ; GS + push eax ; FS + push eax ; DS + push eax ; ES + push eax ; SS + push ebx ; ESP + sub esp,4 ; EFLAGS + push eax ; CS + pushd offset @@vcpi_returnOK ; EIP + + mov ax, 0DE0Ch ; switch to VM86 + call cs:vcpiint + +@@vcpi_returnOK: + pop ebx + pop eax + ret +vcpi_switch2vm86 endp + ;--- switch to protected-mode +vcpi_switch2pm: + push esi + push cs:[wStkBot] + mov cs:[wStkBot], sp + cli + mov esi,cs + shl esi,4 + add esi,offset vcpiCR3 + mov ax, 0DE0Ch ;switch to PM + int 67h + +vcpi_switchOK: + mov ax, SEL_DATA16 + mov ds, ax + mov es, ax + mov ss, ax + mov sp, [wStkBot] ; DS is OK now + + pop [wStkBot] + pop esi +;--- now we're in 32-bit PM but the GDT and IDT are full of 64-bit code segments +;--- so leave interrupts off! + ret + switch2pm proc + cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 + jne @F + call vcpi_switch2pm +;--- turn off paging temporarily to reconfigure it for 64-bit mode... + mov eax,cr0 + and eax,7fffffffh + mov cr0,eax + jmp @@inpm + +@@: and byte ptr cs:[GDT+SEL_TSS+5], 0FDh ; clear busy bit @lgdt cs:[GDTR] @lidt cs:[IDTR] +;--- enable protected mode but not paging (yet) + mov eax,cr0 + or al,1 + mov cr0,eax + jmp @F +@@: + mov ax, SEL_TSS + ltr ax +@@inpm: ;--- (re)enable long mode if ?RESETLME mov ecx,0C0000080h ; EFER MSR @@ -825,15 +1400,13 @@ if ?RESETPAE mov cr4,eax endif if ?SETCR3 - mov eax,cs:pPML4 + mov eax,cs:pRealPML4 mov cr3,eax endif -;--- enable protected-mode + paging +;--- enable paging mov eax,cr0 - or eax,80000001h + or eax,80000000h mov cr0,eax - mov ax, SEL_TSS - ltr ax ret switch2pm endp @@ -888,7 +1461,7 @@ make_int_gates proc make_int_gates endp ;--- create IDT for long mode -;--- DI->4 KB buffer +;--- ES:DI->4 KB buffer ;--- EBX->linear address of _TEXT64 segment createIDT proc @@ -921,13 +1494,13 @@ make_exc_gates: push di push di - lea di,[di+?MPIC*16] + lea di,es:[di+?MPIC*16] mov cx,8 mov edx,offset Irq0007 - ;mov si, 8E00h ; PluM 1 August 2021: this would turn on interrupts in IRQ handlers - that can't be right (causes races) + mov si, 8E00h call make_int_gates pop di - lea di,[di+?SPIC*16] + lea di,es:[di+?SPIC*16] mov cx,8 mov edx,offset Irq080F call make_int_gates @@ -946,9 +1519,9 @@ nextitem: shl dx,4 push di add di,dx - mov [di],ax + mov es:[di],ax shr eax,16 - mov [di+6],ax + mov es:[di+6],ax pop di loop nextitem ret @@ -1103,8 +1676,11 @@ long_start proc lea rsp,[rcx+rbx] ;--- PluM modification 1 August 2021: setup TSS for alt stacks etc. + cmp word ptr [GDTR],sizeGDT_VCPI-1 + je @F ; VCPI already did this, so it's busy mov ax,SEL_TSS ltr ax +@@: sti ; stack pointer(s) ok, interrupts can be used @@ -1299,7 +1875,12 @@ procname proc ;--- SS still holds a selector - hence a possible temporary ;--- stack switch inside irq handler would cause a crash. mov ss,cs:[wStkBot+2] - int interrupt + push es + push 0 + pop es + pushf + call far16 ptr es:[interrupt*4] + pop es cli call switch2pm ;modifies eax [, ecx, edx] @@ -1335,10 +1916,25 @@ p&prefix&_rm label fword dw SEL_CODE16 .code _TEXT64 prefix: +;--- RM IRQ handler can't be trusted to preserve upper dwords of GP regs + push rax + push rbx + push rcx + push rdx + push rbp + push rsi + push rdi mov [qwRSP],rsp - mov sp,[wStkBot] + movzx esp,[wStkBot] call p&prefix&_rm mov rsp,[qwRSP] + pop rdi + pop rsi + pop rbp + pop rdx + pop rcx + pop rbx + pop rax iretq endm @@ -1430,7 +2026,7 @@ pback_to_real label ptr far16 .code _TEXT64 int21_4c: cli - mov sp,[wStkBot] + movzx esp,[wStkBot] jmp [pback_to_real] int21 endp From 0f03f46dc84fbe306650e1d956d505053006a1ff Mon Sep 17 00:00:00 2001 From: Michael Keyes Date: Sun, 8 Aug 2021 18:23:28 +0100 Subject: [PATCH 4/6] I meant "stack-faults gracefully"! --- src2/Dos64stb2.asm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src2/Dos64stb2.asm b/src2/Dos64stb2.asm index fe23ac8..fd5f5d5 100644 --- a/src2/Dos64stb2.asm +++ b/src2/Dos64stb2.asm @@ -1476,10 +1476,13 @@ make_exc_gates: mov ax,SEL_CODE64 stosw mov ax,8E00h - cmp ecx, 20 ; 32-0Ch - i.e. this is the double-fault gate - jne @F - mov al,1 ; PluM modification 1 Aug: IST 1 + cmp ecx, 24 ; 32-8 - i.e. this is the double-fault gate + je @F + cmp ecx, 20 ; 32-0Ch - i.e. this is the stack-fault gate + jne @@ist_set @@: + mov al,1 ; IST 1 - TODO: Different ISTs for #SS and #DF? +@@ist_set: stosd xor eax, eax stosd From d26281f2c6b1db2433162c131f79ad11739c8079 Mon Sep 17 00:00:00 2001 From: Michael Keyes Date: Sat, 14 Aug 2021 12:58:38 +0100 Subject: [PATCH 5/6] VCPI support now fully working --- src2/Dos64stb2.asm | 95 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 12 deletions(-) diff --git a/src2/Dos64stb2.asm b/src2/Dos64stb2.asm index fd5f5d5..de0035d 100644 --- a/src2/Dos64stb2.asm +++ b/src2/Dos64stb2.asm @@ -171,6 +171,9 @@ vcpiadr dd -1 dw SEL_VCPICODE emshdl dw -1 fhandle dw -1 +vPIC label word +vPICM db 8 ;saved master PIC vector +vPICS db 70h ;saved slave PIC vector .data? @@ -412,6 +415,13 @@ start16 proc mov bp,CStr("too much extended memory needed") jnz @@error +;--- prepare EMB moves + mov emm.srchdl, 0 + mov emm2.srchdl, 0 + mov word ptr emm.srcofs+2, ds + mov word ptr emm2.srcofs+0, sp + mov word ptr emm2.srcofs+2, ss + ;--- are we using EMS or XMS? cmp word ptr [GDTR], sizeGDT_VCPI-1 je @@ems_alloc @@ -460,13 +470,6 @@ start16 proc add eax,1000h mov PhysCurr, eax ; start of free physical pages -;--- prepare EMB moves - mov emm.srchdl, 0 - mov emm2.srchdl, 0 - mov word ptr emm.srcofs+2, ds - mov word ptr emm2.srcofs+0, sp - mov word ptr emm2.srcofs+2, ss - ;--- setup ebx/rbx with linear address of _TEXT64 mov ebx,seg long_start @@ -572,6 +575,22 @@ start16 proc mov ebx,seg long_start shl ebx,4 add [llgofs], ebx + +;--- check if anyone has reprogrammed the PIC, and setup our IDT accordingly + mov ax,0DE0Ah + push bx + int 67h + mov vPICM,bl + mov vPICS,cl + cmp vPIC,7008h + je @F ; nope, nobody reprogrammed it + + mov [tab1],bx ; clock vector (IRQ0) + inc bx + mov [tab1+4],bx ; kbd vector (IRQ1) + +@@: + pop bx call createIDT mov ax,0DE01h ; get protected mode interface @@ -775,6 +794,9 @@ endif mov ax,2523h int 21h + cmp vPIC,7008h + jne @F + call setints cli @@ -790,6 +812,8 @@ endif mov dx,?SPIC shl 8 or ?MPIC call setpic +@@: + cli cmp word ptr [GDTR], sizeGDT_VCPI-1 je @F @lgdt [GDTR] @@ -1233,7 +1257,9 @@ if ?RESETPAE eq 0 mov cr4,eax endif - mov dx,7008h + mov dx,vPIC + cmp dx,7008h + jne @@exit call setpic call restoreints @@exit:: @@ -1640,6 +1666,19 @@ if ?SPIC ne 70h mov al,bPICS out 0A1h,al endif + + cmp word ptr [GDTR], sizeGDT_VCPI-1 + jne @F + push bx + push cx + movzx bx,dl + movzx cx,dh + mov ax,0DE0Bh + int 67h + pop cx + pop bx + +@@: ret setpic endp @@ -2057,6 +2096,22 @@ int31_300: push rdi mov rsi,rdi +;--- Save FS and GS (selectors + bases) since "usermode" may use them + + mov ecx, 0c0000100h ; fs base + rdmsr + shl rdx,32 + or rax,rdx + push rax + push fs + + mov ecx, 0c0000101h ; gs base + rdmsr + shl rdx,32 + or rax,rdx + push rax + push gs + ;--- the contents of the RMCS has to be copied ;--- to conventional memory. We use the DGROUP stack @@ -2093,6 +2148,22 @@ int31_300: ; mov ss,eax ;but interrupts need a valid SS mov rsp,[qwRSP] +;--- Restore FS and GS since "usermode" may use them + + pop gs + mov ecx, 0c0000101h ; gs base + pop rax + mov rdx,rax + shr rdx,32 + wrmsr + + pop fs + mov ecx, 0c0000100h ; fs base + pop rax + mov rdx,rax + shr rdx,32 + wrmsr + mov rdi,[rsp] cld movsq ;copy 2Ah bytes back, don't copy CS:IP & SS:SP fields @@ -2116,7 +2187,7 @@ int31_203: jae ret_with_carry push rax push rdi - mov edi,?IDTADR + mov edi,dword ptr [IDTR+2] movzx eax,bl shl eax,4 add edi,eax @@ -2126,9 +2197,9 @@ int31_203: mov ax,cx stosw mov ax,8E00h - stosd ;+store highword edx! - shr rax,32 - stosd + stosq ;+store highword edx! + ;shr rax,32 + ;stosd pop rdi pop rax iretq From d5aa3ef407452ea8cedd5b91e04657819cd6ab2a Mon Sep 17 00:00:00 2001 From: Michael Keyes Date: Wed, 18 Aug 2021 21:25:38 +0100 Subject: [PATCH 6/6] Resetting PAE, CR3 and LME is not optional in VCPI mode. But resetting FS/GS is always optional. --- src2/Dos64stb2.asm | 77 +++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/src2/Dos64stb2.asm b/src2/Dos64stb2.asm index de0035d..f955718 100644 --- a/src2/Dos64stb2.asm +++ b/src2/Dos64stb2.asm @@ -25,9 +25,10 @@ DGROUP group _TEXT ;makes a tiny model ?MPIC equ 78h ; master PIC base, remapped to 78h ?SPIC equ 70h ; slave PIC, isn't changed -?RESETLME equ 1;1=(re)set EFER.LME for temp switch to real-mode +?RESETLME equ 0;1=(re)set EFER.LME for temp switch to real-mode ?RESETPAE equ 1;1=(re)set CR4.PAE for temp switch to real-mode ?SETCR3 equ 1;1=set CR3 after temp switch to real-mode +?SETFSGS equ 1;1=save/restore FS/GS selectors and bases for temp switch ?IDTADR equ 100000h ;address of IDT ?DFSTKADR equ (1 shl 47) - 8 ;address of double-fault stack for TSS ?KSTKADR equ ?DFSTKADR - 100h ;address of "kernel" stack for TSS @@ -94,7 +95,8 @@ endm assume ds:DGROUP -;--- PluM modification 1 August 2021: add TSS +;--- TSS to specify ISTs for stack fault and double fault + TSS dd 0 ;reserved RSP_r0 dq ?KSTKADR RSP_r1 dq 0 @@ -125,12 +127,12 @@ SEL_FLAT equ $-GDT SEL_TSS equ $-GDT dw sizeTSS-1,offset TSS,8900h,40h dq 0 ; TSS descriptor 16 bytes in long mode?? -sizeGDT equ $-GDT ; PluM modification 31 July 2021 (make it more generic) +sizeGDT equ $-GDT SEL_VCPICODE equ $-GDT dq 3 dup (0) ; VCPI allocates three 8-byte descriptors sizeGDT_VCPI equ $-GDT -;--- PluM modification 2 August 2012: VCPI control structure +;--- VCPI control structure vcpiCR3 dd 0 ; not the long-mode CR3, a 32-bit one! vcpiGDT dd offset GDTR vcpiIDT dd offset IDTR @@ -259,7 +261,6 @@ start16 proc popf adc byte ptr [GDT + SEL_TSS + 4], al -;--- PluM 2 August 2021: do this first, so EMS v XMS code can be grouped xor edx,edx mov eax,80000001h ; test if long-mode is supported cpuid @@ -406,7 +407,7 @@ start16 proc ;--- 3 for remainder of PDPT,PD,PT ;--- 1 for PML4 ;--- 3 (PT,PD,PDPT) for mapping DOS conventional memory -;--- PluM (1 August): 1/2 for alt stacks (particularly for double fault) +;--- 1/2 for alt stacks (particularly for double fault) ;--- 3/6 (PT,PD,PDPT)*1/2 to point at the alt stacks ;--- 1 extra page that may be needed to align to page boundary add edx,3+1+3+(EXTRASTKPGS*4)+1 @@ -706,7 +707,7 @@ start16 proc shr ebx,12 ; convert to page count invoke MapPages, ebx, 0, 0 -;--- PluM modification 1 August: create alt stack(s) +;--- create alt stack(s) add PhysCurr,1000h invoke MapPages, 1, KSTKBTM, PhysCurr if EXTRASTKPGS eq 2 @@ -1236,7 +1237,6 @@ readsection endp backtoreal proc -;--- PluM refactoring 31 July 2021 call switch2rm @@exit2:: @@ -1244,6 +1244,10 @@ backtoreal proc mov ss, ax ; SS=DGROUP mov ds, ax ; DS=DGROUP +;--- in VCPI mode, switch2rm has already reset LME and PAE, so don't do it again + cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 + je @F + if ?RESETLME eq 0 mov ecx,0C0000080h ; EFER MSR rdmsr @@ -1257,6 +1261,7 @@ if ?RESETPAE eq 0 mov cr4,eax endif +@@: mov dx,vPIC cmp dx,7008h jne @@exit @@ -1297,23 +1302,32 @@ backtoreal endp ;--- switch to real-mode switch2rm proc -;--- disable paging first (PluM modification) +;--- disable paging first mov eax,cr0 and eax,7fffffffh mov cr0,eax + ;--- disable long mode -if ?RESETLME +if ?RESETLME eq 0 + cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 + jne @F +endif mov ecx,0C0000080h ; EFER MSR rdmsr and ah,0feh wrmsr + +@@: +if ?RESETPAE eq 0 + cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 + jne @F endif -if ?RESETPAE mov eax,cr4 and al,0DFh ; reset bit 5, disable PAE paging mov cr4,eax -endif -;--- PluM modification: now disable protection, or switch to VM86 mode + +@@: +;--- now disable protection, or switch to VM86 mode cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 jne @F mov eax, cs:[vcpiCR3] @@ -1414,21 +1428,30 @@ switch2pm proc ltr ax @@inpm: ;--- (re)enable long mode -if ?RESETLME +if ?RESETLME eq 0 + cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 + jne @F +endif mov ecx,0C0000080h ; EFER MSR rdmsr or ah,1 wrmsr +@@: +if ?RESETPAE eq 0 + cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 + jne @F endif -if ?RESETPAE mov eax,cr4 or ax,220h ; enable PAE (bit 5) and OSFXSR (bit 9) mov cr4,eax +@@: +if ?SETCR3 eq 0 + cmp word ptr cs:[GDTR], sizeGDT_VCPI-1 + jne @F endif -if ?SETCR3 mov eax,cs:pRealPML4 mov cr3,eax -endif +@@: ;--- enable paging mov eax,cr0 or eax,80000000h @@ -1698,10 +1721,12 @@ long_start proc ;--- ensure ss is valid! mov ax,SEL_DATA16 mov ss,eax -;--- PluM modification 31 July 2021: + +if ?SETFSGS ;--- and fs/gs so we don't triple-fault trying to save/restore them in IRQs! mov fs,eax mov gs,eax +endif ;--- linear address of image start (=PE header) should be in edx::ebx ;--- move it to rbx using registers only. @@ -1717,7 +1742,7 @@ long_start proc add rcx,[rbx].IMAGE_NT_HEADERS.OptionalHeader.SizeOfStackReserve lea rsp,[rcx+rbx] -;--- PluM modification 1 August 2021: setup TSS for alt stacks etc. +;--- setup TSS for alt stacks etc. cmp word ptr [GDTR],sizeGDT_VCPI-1 je @F ; VCPI already did this, so it's busy mov ax,SEL_TSS @@ -1899,7 +1924,7 @@ procname proc push eax push ecx push edx -;--- PluM modification 31 July 2021: +if ?SETFSGS ;--- Save FS and GS (selectors + bases) since "usermode" may use them mov ecx, 0c0000100h ; fs base rdmsr @@ -1912,6 +1937,7 @@ procname proc push edx push eax push gs +endif call switch2rm ;modifies eax [, ecx, edx] ;--- SS still holds a selector - hence a possible temporary @@ -1926,7 +1952,7 @@ procname proc cli call switch2pm ;modifies eax [, ecx, edx] -;--- PluM modification 31 July 2021: +if ?SETFSGS ;--- Restore FS and GS since "usermode" may use them pop gs mov ecx, 0c0000101h ; gs base @@ -1939,6 +1965,7 @@ procname proc pop eax pop edx wrmsr +endif pop edx pop ecx @@ -2096,8 +2123,8 @@ int31_300: push rdi mov rsi,rdi +if ?SETFSGS ;--- Save FS and GS (selectors + bases) since "usermode" may use them - mov ecx, 0c0000100h ; fs base rdmsr shl rdx,32 @@ -2111,6 +2138,7 @@ int31_300: or rax,rdx push rax push gs +endif ;--- the contents of the RMCS has to be copied ;--- to conventional memory. We use the DGROUP stack @@ -2148,8 +2176,8 @@ int31_300: ; mov ss,eax ;but interrupts need a valid SS mov rsp,[qwRSP] +if ?SETFSGS ;--- Restore FS and GS since "usermode" may use them - pop gs mov ecx, 0c0000101h ; gs base pop rax @@ -2163,6 +2191,7 @@ int31_300: mov rdx,rax shr rdx,32 wrmsr +endif mov rdi,[rsp] cld @@ -2198,8 +2227,6 @@ int31_203: stosw mov ax,8E00h stosq ;+store highword edx! - ;shr rax,32 - ;stosd pop rdi pop rax iretq