VCPI implementation;
fix for Lemmings Chronicles+soundblaster Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@2229
This commit is contained in:
parent
0e0f294202
commit
7e56e57694
1 changed files with 486 additions and 6 deletions
492
src/ints/ems.cpp
492
src/ints/ems.cpp
|
@ -16,7 +16,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* $Id: ems.cpp,v 1.39 2005-03-25 11:59:24 qbix79 Exp $ */
|
||||
/* $Id: ems.cpp,v 1.40 2005-07-05 20:22:02 c2woody Exp $ */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -30,6 +30,8 @@
|
|||
#include "inout.h"
|
||||
#include "dos_inc.h"
|
||||
#include "setup.h"
|
||||
#include "support.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define EMM_PAGEFRAME 0xE000
|
||||
#define EMM_PAGEFRAME4K ((EMM_PAGEFRAME*16)/4096)
|
||||
|
@ -43,6 +45,10 @@
|
|||
#define NULL_HANDLE 0xffff
|
||||
#define NULL_PAGE 0xffff
|
||||
|
||||
#define ENABLE_VCPI 1
|
||||
#define ENABLE_V86_STARTUP 0
|
||||
|
||||
|
||||
/* EMM errors */
|
||||
#define EMM_NO_ERROR 0x00
|
||||
#define EMM_SOFT_MAL 0x80
|
||||
|
@ -94,6 +100,13 @@ struct EMM_Handle {
|
|||
static EMM_Handle emm_handles[EMM_MAX_HANDLES];
|
||||
static EMM_Mapping emm_mappings[EMM_MAX_PHYS];
|
||||
|
||||
static struct {
|
||||
bool enabled;
|
||||
Bit16u ems_handle;
|
||||
Bitu pm_interface;
|
||||
MemHandle private_area;
|
||||
Bit8u pic1_remapping,pic2_remapping;
|
||||
} vcpi ;
|
||||
|
||||
struct MoveRegion {
|
||||
Bit32u bytes;
|
||||
|
@ -198,7 +211,9 @@ static Bit8u EMM_ReleaseMemory(Bit16u handle) {
|
|||
|
||||
static Bit8u EMM_SavePageMap(Bit16u handle) {
|
||||
/* Check for valid handle */
|
||||
if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) return EMM_INVALID_HANDLE;
|
||||
if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) {
|
||||
if (handle!=0) return EMM_INVALID_HANDLE;
|
||||
}
|
||||
/* Check for previous save */
|
||||
if (emm_handles[handle].saved_page_map) return EMM_PAGE_MAP_SAVED;
|
||||
/* Copy the mappings over */
|
||||
|
@ -220,7 +235,9 @@ static Bit8u EMM_RestoreMappingTable(void) {
|
|||
}
|
||||
static Bit8u EMM_RestorePageMap(Bit16u handle) {
|
||||
/* Check for valid handle */
|
||||
if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) return EMM_INVALID_HANDLE;
|
||||
if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) {
|
||||
if (handle!=0) return EMM_INVALID_HANDLE;
|
||||
}
|
||||
/* Check for previous save */
|
||||
if (!emm_handles[handle].saved_page_map) return EMM_INVALID_HANDLE;
|
||||
/* Restore the mappings */
|
||||
|
@ -585,8 +602,153 @@ static Bitu INT67_Handler(void) {
|
|||
};
|
||||
break;
|
||||
case 0xDE: /* VCPI Functions */
|
||||
LOG(LOG_MISC,LOG_ERROR)("EMS:VCPI Call %2X not supported",reg_al);
|
||||
reg_ah=EMM_FUNC_NOSUP;
|
||||
if (!vcpi.enabled) {
|
||||
LOG(LOG_MISC,LOG_ERROR)("EMS:VCPI Call %2X not supported",reg_al);
|
||||
reg_ah=EMM_FUNC_NOSUP;
|
||||
} else {
|
||||
switch (reg_al) {
|
||||
case 0x00: /* VCPI Installation Check */
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
reg_bx=0x100;
|
||||
break;
|
||||
case 0x01: /* VCPI Get Protected Mode Interface */
|
||||
/* Set up page table buffer */
|
||||
for (Bitu ct=0; ct<0xff; ct++) {
|
||||
real_writeb(SegValue(es),reg_di+ct*4+0x00,0x67); // access bits
|
||||
real_writew(SegValue(es),reg_di+ct*4+0x01,ct*0x10); // mapping
|
||||
real_writeb(SegValue(es),reg_di+ct*4+0x03,0x00);
|
||||
}
|
||||
for (Bitu ct=0xff; ct<0x100; ct++) {
|
||||
real_writeb(SegValue(es),reg_di+ct*4+0x00,0x67); // access bits
|
||||
real_writew(SegValue(es),reg_di+ct*4+0x01,(ct-0xff)*0x10+0x1100); // mapping
|
||||
real_writeb(SegValue(es),reg_di+ct*4+0x03,0x00);
|
||||
}
|
||||
reg_di+=0x800; // advance pointer by 0x200*4
|
||||
|
||||
/* Set up three descriptor table entries */
|
||||
real_writed(SegValue(ds),reg_si+0x00,0x8000ffff); // descriptor 1 (code segment)
|
||||
real_writed(SegValue(ds),reg_si+0x04,0x00009a0c); // descriptor 1
|
||||
real_writed(SegValue(ds),reg_si+0x08,0x0000ffff); // descriptor 2 (data segment)
|
||||
real_writed(SegValue(ds),reg_si+0x0c,0x00009200); // descriptor 2
|
||||
real_writed(SegValue(ds),reg_si+0x10,0x0000ffff); // descriptor 3
|
||||
real_writed(SegValue(ds),reg_si+0x14,0x00009200); // descriptor 3
|
||||
|
||||
reg_ebx=(vcpi.pm_interface&0xffff);
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
break;
|
||||
case 0x02: /* VCPI Maximum Physical Address */
|
||||
reg_edx=((MEM_TotalPages()*MEM_PAGESIZE)-1)&0xfffff000;
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
break;
|
||||
case 0x03: /* VCPI Get Number of Free Pages */
|
||||
reg_edx=MEM_FreeTotal();
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
break;
|
||||
case 0x04: { /* VCPI Allocate one Page */
|
||||
MemHandle mem = MEM_AllocatePages(1,false);
|
||||
if (mem) {
|
||||
reg_edx=mem<<12;
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
} else {
|
||||
reg_ah=EMM_OUT_OF_LOG;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x05: /* VCPI Free Page */
|
||||
MEM_ReleasePages(reg_edx>>12);
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
break;
|
||||
case 0x06: { /* VCPI Get Physical Address of Page in 1st MB */
|
||||
if (((reg_cx<<8)>=EMM_PAGEFRAME) && ((reg_cx<<8)<EMM_PAGEFRAME+0x1000)) {
|
||||
/* Page is in Pageframe, so check what EMS-page it is
|
||||
and return the physical address */
|
||||
Bit8u phys_page;
|
||||
Bit16u mem_seg=reg_cx<<8;
|
||||
if (mem_seg<EMM_PAGEFRAME+0x400) phys_page=0;
|
||||
else if (mem_seg<EMM_PAGEFRAME+0x800) phys_page=1;
|
||||
else if (mem_seg<EMM_PAGEFRAME+0xc00) phys_page=2;
|
||||
else phys_page=3;
|
||||
Bit16u handle=emm_mappings[phys_page].handle;
|
||||
if (handle==0xffff) {
|
||||
reg_ah=EMM_ILL_PHYS;
|
||||
break;
|
||||
} else {
|
||||
MemHandle memh=MEM_NextHandleAt(
|
||||
emm_handles[handle].mem,
|
||||
emm_mappings[phys_page].page*4);
|
||||
reg_edx=(memh+(reg_cx&3))<<12;
|
||||
}
|
||||
} else {
|
||||
/* Page not in Pageframe, so just translate into physical address */
|
||||
reg_edx=reg_cx<<12;
|
||||
}
|
||||
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
}
|
||||
break;
|
||||
case 0x0a: /* VCPI Get PIC Vector Mappings */
|
||||
reg_bx=vcpi.pic1_remapping; // master PIC
|
||||
reg_cx=vcpi.pic2_remapping; // slave PIC
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
break;
|
||||
case 0x0b: /* VCPI Set PIC Vector Mappings */
|
||||
reg_flags&=(~FLAG_IF);
|
||||
vcpi.pic1_remapping=reg_bx&0xff;
|
||||
vcpi.pic2_remapping=reg_cx&0xff;
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
break;
|
||||
case 0x0c: { /* VCPI Switch from V86 to Protected Mode */
|
||||
reg_flags&=(~FLAG_IF);
|
||||
cpu.cpl=0;
|
||||
|
||||
/* Read data from ESI (linear address) */
|
||||
Bit32u new_cr3=mem_readd(reg_esi);
|
||||
Bit32u new_gdt_addr=mem_readd(reg_esi+4);
|
||||
Bit32u new_idt_addr=mem_readd(reg_esi+8);
|
||||
Bit16u new_ldt=mem_readw(reg_esi+0x0c);
|
||||
Bit16u new_tr=mem_readw(reg_esi+0x0e);
|
||||
Bit32u new_eip=mem_readd(reg_esi+0x10);
|
||||
Bit16u new_cs=mem_readw(reg_esi+0x14);
|
||||
|
||||
/* Get GDT and IDT entries */
|
||||
Bit16u new_gdt_limit=mem_readw(new_gdt_addr);
|
||||
Bit32u new_gdt_base=mem_readd(new_gdt_addr+2);
|
||||
Bit16u new_idt_limit=mem_readw(new_idt_addr);
|
||||
Bit32u new_idt_base=mem_readd(new_idt_addr+2);
|
||||
|
||||
/* Switch to protected mode, paging enabled if necessary */
|
||||
Bit32u new_cr0=CPU_GET_CRX(0)|1;
|
||||
if (new_cr3!=0) new_cr0|=0x80000000;
|
||||
CPU_SET_CRX(0, new_cr0);
|
||||
CPU_SET_CRX(3, new_cr3);
|
||||
|
||||
PhysPt tbaddr=new_gdt_base+(new_tr&0xfff8)+5;
|
||||
Bit8u tb=mem_readb(tbaddr);
|
||||
mem_writeb(tbaddr, tb&0xfd);
|
||||
|
||||
/* Load tables and initialize segment registers */
|
||||
CPU_LGDT(new_gdt_limit, new_gdt_base);
|
||||
CPU_LIDT(new_idt_limit, new_idt_base);
|
||||
CPU_LLDT(new_ldt);
|
||||
CPU_LTR(new_tr);
|
||||
|
||||
CPU_SetSegGeneral(ds,0);
|
||||
CPU_SetSegGeneral(es,0);
|
||||
CPU_SetSegGeneral(fs,0);
|
||||
CPU_SetSegGeneral(gs,0);
|
||||
|
||||
/* Switch to protected mode */
|
||||
reg_flags&=(~(FLAG_VM|FLAG_NT));
|
||||
reg_flags|=0x3000;
|
||||
CPU_JMP(true, new_cs, new_eip, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(LOG_MISC,LOG_ERROR)("EMS:VCPI Call %x not supported",reg_ax);
|
||||
reg_ah=EMM_FUNC_NOSUP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(LOG_MISC,LOG_ERROR)("EMS:Call %2X not supported",reg_ah);
|
||||
|
@ -596,6 +758,263 @@ static Bitu INT67_Handler(void) {
|
|||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
static Bitu VCPI_PM_Handler() {
|
||||
// LOG_MSG("VCPI PMODE handler, function %x",reg_ax);
|
||||
switch (reg_ax) {
|
||||
case 0xDE03: /* VCPI Get Number of Free Pages */
|
||||
reg_edx=MEM_FreeTotal();
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
break;
|
||||
case 0xDE04: { /* VCPI Allocate one Page */
|
||||
MemHandle mem = MEM_AllocatePages(1,false);
|
||||
if (mem) {
|
||||
reg_edx=mem<<12;
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
} else {
|
||||
reg_ah=EMM_OUT_OF_LOG;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xDE05: /* VCPI Free Page */
|
||||
MEM_ReleasePages(reg_edx>>12);
|
||||
reg_ah=EMM_NO_ERROR;
|
||||
break;
|
||||
case 0xDE0C: { /* VCPI Switch from Protected Mode to V86 */
|
||||
reg_flags&=(~FLAG_IF);
|
||||
|
||||
/* Flags need to be filled in, VM=true, IOPL=3 */
|
||||
mem_writed(SegPhys(ss) + (reg_esp & cpu.stack.mask)+0x10, 0x23002);
|
||||
|
||||
/* Disable Paging */
|
||||
CPU_SET_CRX(0, CPU_GET_CRX(0)&0x7ffffff7);
|
||||
CPU_SET_CRX(3, 0);
|
||||
|
||||
PhysPt tbaddr=vcpi.private_area+0x0000+(0x10&0xfff8)+5;
|
||||
Bit8u tb=mem_readb(tbaddr);
|
||||
mem_writeb(tbaddr, tb&0xfd);
|
||||
|
||||
/* Load descriptor table registers */
|
||||
CPU_LGDT(0xff, vcpi.private_area+0x0000);
|
||||
CPU_LIDT(0x7ff, vcpi.private_area+0x2000);
|
||||
CPU_LLDT(0x08);
|
||||
CPU_LTR(0x10);
|
||||
|
||||
reg_flags&=(~FLAG_NT);
|
||||
reg_esp+=8; // skip interrupt return information
|
||||
|
||||
/* Switch to v86-task */
|
||||
CPU_IRET(true,0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(LOG_MISC,LOG_WARN)("Unhandled VCPI-function %x in protected mode",reg_al);
|
||||
break;
|
||||
}
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
static Bitu V86_Monitor() {
|
||||
/* Calculate which interrupt did occur */
|
||||
Bitu int_num=(mem_readw(SegPhys(ss)+(reg_esp & cpu.stack.mask))-0x2803);
|
||||
|
||||
/* See if Exception 0x0d and not Interrupt 0x0d */
|
||||
if ((int_num==(0x0d*4)) && ((reg_sp&0xffff)!=0x1fda)) {
|
||||
/* Protection violation during V86-execution,
|
||||
needs intervention by monitor (depends on faulting opcode) */
|
||||
|
||||
reg_esp+=6; // skip ip of CALL and error code of EXCEPTION 0x0d
|
||||
|
||||
/* Get adress of faulting instruction */
|
||||
Bit16u v86_cs=mem_readw(SegPhys(ss)+((reg_esp+4) & cpu.stack.mask));
|
||||
Bit16u v86_ip=mem_readw(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask));
|
||||
Bit8u v86_opcode=mem_readb((v86_cs<<4)+v86_ip);
|
||||
// LOG_MSG("v86 monitor caught protection violation at %x:%x, opcode=%x",v86_cs,v86_ip,v86_opcode);
|
||||
switch (v86_opcode) {
|
||||
case 0x0f: // double byte opcode
|
||||
v86_opcode=mem_readb((v86_cs<<4)+v86_ip+1);
|
||||
switch (v86_opcode) {
|
||||
case 0x20: { // mov reg,CRx
|
||||
Bitu rm_val=mem_readb((v86_cs<<4)+v86_ip+2);
|
||||
Bitu which=(rm_val >> 3) & 7;
|
||||
if ((rm_val<0xc0) || (rm_val>=0xe8))
|
||||
E_Exit("Invalid opcode 0x0f 0x20 %x caused a protection fault!",rm_val);
|
||||
Bit32u crx=CPU_GET_CRX(which);
|
||||
switch (rm_val&3) {
|
||||
case 0: reg_eax=crx; break;
|
||||
case 1: reg_ecx=crx; break;
|
||||
case 2: reg_edx=crx; break;
|
||||
case 3: reg_ebx=crx; break;
|
||||
case 4: reg_esp=crx; break;
|
||||
case 5: reg_ebp=crx; break;
|
||||
case 6: reg_esi=crx; break;
|
||||
case 7: reg_edi=crx; break;
|
||||
}
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+3);
|
||||
}
|
||||
break;
|
||||
case 0x22: { // mov CRx,reg
|
||||
Bitu rm_val=mem_readb((v86_cs<<4)+v86_ip+2);
|
||||
Bitu which=(rm_val >> 3) & 7;
|
||||
if ((rm_val<0xc0) || (rm_val>=0xe8))
|
||||
E_Exit("Invalid opcode 0x0f 0x22 %x caused a protection fault!",rm_val);
|
||||
Bit32u crx;
|
||||
switch (rm_val&3) {
|
||||
case 0: crx=reg_eax; break;
|
||||
case 1: crx=reg_ecx; break;
|
||||
case 2: crx=reg_edx; break;
|
||||
case 3: crx=reg_ebx; break;
|
||||
case 4: crx=reg_esp; break;
|
||||
case 5: crx=reg_ebp; break;
|
||||
case 6: crx=reg_esi; break;
|
||||
case 7: crx=reg_edi; break;
|
||||
}
|
||||
if (which==0) crx|=1; // protection bit always on
|
||||
CPU_SET_CRX(which,crx);
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
E_Exit("Unhandled opcode 0x0f %x caused a protection fault!",v86_opcode);
|
||||
}
|
||||
break;
|
||||
case 0xe4: // IN AL,Ib
|
||||
reg_al=IO_ReadB(mem_readb((v86_cs<<4)+v86_ip+1));
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+2);
|
||||
break;
|
||||
case 0xe5: // IN AX,Ib
|
||||
reg_ax=IO_ReadW(mem_readb((v86_cs<<4)+v86_ip+1));
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+2);
|
||||
break;
|
||||
case 0xe6: // OUT Ib,AL
|
||||
IO_WriteB(mem_readb((v86_cs<<4)+v86_ip+1),reg_al);
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+2);
|
||||
break;
|
||||
case 0xe7: // OUT Ib,AX
|
||||
IO_WriteW(mem_readb((v86_cs<<4)+v86_ip+1),reg_ax);
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+2);
|
||||
break;
|
||||
case 0xec: // IN AL,DX
|
||||
reg_al=IO_ReadB(reg_dx);
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1);
|
||||
break;
|
||||
case 0xed: // IN AX,DX
|
||||
reg_ax=IO_ReadW(reg_dx);
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1);
|
||||
break;
|
||||
case 0xee: // OUT DX,AL
|
||||
IO_WriteB(reg_dx,reg_al);
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1);
|
||||
break;
|
||||
case 0xef: // OUT DX,AX
|
||||
IO_WriteW(reg_dx,reg_ax);
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1);
|
||||
break;
|
||||
case 0xf0: // LOCK prefix
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1);
|
||||
break;
|
||||
case 0xf4: // HLT
|
||||
reg_flags|=FLAG_IF;
|
||||
CPU_HLT(reg_eip);
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1);
|
||||
break;
|
||||
default:
|
||||
E_Exit("Unhandled opcode %x caused a protection fault!",v86_opcode);
|
||||
}
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
/* Get address to interrupt handler */
|
||||
Bit16u vint_vector_seg=mem_readw(SegValue(ds)+int_num+2);
|
||||
Bit16u vint_vector_ofs=mem_readw(int_num);
|
||||
if (reg_sp!=0x1fda) reg_esp+=(2+3*4); // Interrupt from within protected mode
|
||||
else reg_esp+=2;
|
||||
|
||||
/* Read entries that were pushed onto the stack by the interrupt */
|
||||
Bit16u return_ip=mem_readw(SegPhys(ss)+(reg_esp & cpu.stack.mask));
|
||||
Bit16u return_cs=mem_readw(SegPhys(ss)+((reg_esp+4) & cpu.stack.mask));
|
||||
Bit32u return_eflags=mem_readd(SegPhys(ss)+((reg_esp+8) & cpu.stack.mask));
|
||||
|
||||
/* Modify stack to call v86-interrupt handler */
|
||||
mem_writed(SegPhys(ss)+(reg_esp & cpu.stack.mask),vint_vector_ofs);
|
||||
mem_writed(SegPhys(ss)+((reg_esp+4) & cpu.stack.mask),vint_vector_seg);
|
||||
mem_writed(SegPhys(ss)+((reg_esp+8) & cpu.stack.mask),return_eflags&(~(FLAG_IF|FLAG_TF)));
|
||||
|
||||
/* Adjust SP of v86-stack */
|
||||
Bit16u v86_ss=mem_readw(SegPhys(ss)+((reg_esp+0x10) & cpu.stack.mask));
|
||||
Bit16u v86_sp=mem_readw(SegPhys(ss)+((reg_esp+0x0c) & cpu.stack.mask))-6;
|
||||
mem_writew(SegPhys(ss)+((reg_esp+0x0c) & cpu.stack.mask),v86_sp);
|
||||
|
||||
/* Return to original code after v86-interrupt handler */
|
||||
mem_writew((v86_ss<<4)+v86_sp+0,return_ip);
|
||||
mem_writew((v86_ss<<4)+v86_sp+2,return_cs);
|
||||
mem_writew((v86_ss<<4)+v86_sp+4,(Bit16u)(return_eflags&0xffff));
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
static void SetupVCPI() {
|
||||
vcpi.enabled=true;
|
||||
|
||||
vcpi.pic1_remapping=0x08; // master PIC base
|
||||
vcpi.pic2_remapping=0x70; // slave PIC base
|
||||
|
||||
/* Allocate one EMS-page for private VCPI-data in memory beyond 1MB */
|
||||
EMM_AllocateMemory(1,vcpi.ems_handle);
|
||||
vcpi.private_area=emm_handles[vcpi.ems_handle].mem<<12;
|
||||
|
||||
/* GDT */
|
||||
mem_writed(vcpi.private_area+0x0000,0x00000000); // descriptor 0
|
||||
mem_writed(vcpi.private_area+0x0004,0x00000000); // descriptor 0
|
||||
|
||||
Bit32u ldt_address=(vcpi.private_area+0x1000);
|
||||
Bit16u ldt_limit=0xff;
|
||||
Bit32u ldt_desc_part=((ldt_address&0xffff)<<16)|ldt_limit;
|
||||
mem_writed(vcpi.private_area+0x0008,ldt_desc_part); // descriptor 1 (LDT)
|
||||
ldt_desc_part=((ldt_address&0xff0000)>>16)|(ldt_address&0xff000000)|0x8200;
|
||||
mem_writed(vcpi.private_area+0x000c,ldt_desc_part); // descriptor 1
|
||||
|
||||
Bit32u tss_address=(vcpi.private_area+0x3000);
|
||||
Bit32u tss_desc_part=((tss_address&0xffff)<<16)|(0x0068+0x200);
|
||||
mem_writed(vcpi.private_area+0x0010,tss_desc_part); // descriptor 2 (TSS)
|
||||
tss_desc_part=((tss_address&0xff0000)>>16)|(tss_address&0xff000000)|0x8900;
|
||||
mem_writed(vcpi.private_area+0x0014,tss_desc_part); // descriptor 2
|
||||
|
||||
/* LDT */
|
||||
mem_writed(vcpi.private_area+0x1000,0x00000000); // descriptor 0
|
||||
mem_writed(vcpi.private_area+0x1004,0x00000000); // descriptor 0
|
||||
Bit32u cs_desc_part=((vcpi.private_area&0xffff)<<16)|0xffff;
|
||||
mem_writed(vcpi.private_area+0x1008,cs_desc_part); // descriptor 1 (code)
|
||||
cs_desc_part=((vcpi.private_area&0xff0000)>>16)|(vcpi.private_area&0xff000000)|0x9a00;
|
||||
mem_writed(vcpi.private_area+0x100c,cs_desc_part); // descriptor 1
|
||||
Bit32u ds_desc_part=((vcpi.private_area&0xffff)<<16)|0xffff;
|
||||
mem_writed(vcpi.private_area+0x1010,ds_desc_part); // descriptor 2 (data)
|
||||
ds_desc_part=((vcpi.private_area&0xff0000)>>16)|(vcpi.private_area&0xff000000)|0x9200;
|
||||
mem_writed(vcpi.private_area+0x1014,ds_desc_part); // descriptor 2
|
||||
|
||||
/* IDT setup */
|
||||
for (Bitu int_ct=0; int_ct<0x100; int_ct++) {
|
||||
/* build a CALL NEAR V86MON, the value of IP pushed by the
|
||||
CALL is used to identify the interrupt number */
|
||||
mem_writeb(vcpi.private_area+0x2800+int_ct*4+0,0xe8); // call
|
||||
mem_writew(vcpi.private_area+0x2800+int_ct*4+1,0x05fd-(int_ct*4));
|
||||
mem_writeb(vcpi.private_area+0x2800+int_ct*4+3,0xcf); // iret (dummy)
|
||||
|
||||
/* put a Gate-Descriptor into the IDT */
|
||||
mem_writed(vcpi.private_area+0x2000+int_ct*8+0,0x000c0000|(0x2800+int_ct*4));
|
||||
mem_writed(vcpi.private_area+0x2000+int_ct*8+4,0x0000ee00);
|
||||
}
|
||||
|
||||
/* TSS */
|
||||
for (Bitu tse_ct=0; tse_ct<0x68+0x200; tse_ct++) {
|
||||
/* clear the TSS as most entries are not used here */
|
||||
mem_writeb(vcpi.private_area+0x3000,0);
|
||||
}
|
||||
/* Set up the ring0-stack */
|
||||
mem_writed(vcpi.private_area+0x3004,0x00002000); // esp
|
||||
mem_writed(vcpi.private_area+0x3008,0x00000014); // ss
|
||||
|
||||
mem_writed(vcpi.private_area+0x3066,0x0068); // io-map base (map follows, all zero)
|
||||
}
|
||||
|
||||
static Bitu INT4B_Handler() {
|
||||
switch (reg_ah) {
|
||||
case 0x81:
|
||||
|
@ -616,7 +1035,7 @@ private:
|
|||
* stored 32 bytes.*/
|
||||
static Bit16u emsnameseg;
|
||||
RealPt old4b_pointer,old67_pointer;
|
||||
CALLBACK_HandlerObject call_vdma,int67;
|
||||
CALLBACK_HandlerObject call_vdma,int67,call_vcpi,call_v86mon;
|
||||
|
||||
public:
|
||||
EMS(Section* configuration):Module_base(configuration){
|
||||
|
@ -624,6 +1043,8 @@ public:
|
|||
/* Virtual DMA interrupt callback */
|
||||
call_vdma.Install(&INT4B_Handler,CB_IRET,"Int 4b vdma");
|
||||
call_vdma.Set_RealVec(0x4b);
|
||||
|
||||
vcpi.enabled=false;
|
||||
|
||||
Section_prop * section=static_cast<Section_prop *>(configuration);
|
||||
if (!section->Get_bool("ems")) return;
|
||||
|
@ -656,6 +1077,51 @@ public:
|
|||
emm_mappings[i].page=NULL_PAGE;
|
||||
emm_mappings[i].handle=NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (!ENABLE_VCPI) return;
|
||||
|
||||
/* Install a callback that handles VCPI-requests in protected mode requests */
|
||||
call_vcpi.Install(&VCPI_PM_Handler,CB_RETF,"VCPI PM");
|
||||
vcpi.pm_interface=(call_vcpi.Get_callback())<<4;
|
||||
|
||||
/* Use IRETD instead of IRET for this protected mode callback */
|
||||
mem_writeb(CB_BASE+vcpi.pm_interface+4,(Bit8u)0x66);
|
||||
mem_writeb(CB_BASE+vcpi.pm_interface+5,(Bit8u)0xCB); //A IRETD Instruction
|
||||
|
||||
/* Initialize private data area and set up descriptor tables */
|
||||
SetupVCPI();
|
||||
|
||||
/* Install v86-callback that handles interrupts occuring
|
||||
in v86 mode, including protection fault exceptions */
|
||||
call_v86mon.Install(&V86_Monitor,CB_IRET,"V86 Monitor");
|
||||
|
||||
mem_writeb(vcpi.private_area+0x2e00,(Bit8u)0xFE); //GRP 4
|
||||
mem_writeb(vcpi.private_area+0x2e01,(Bit8u)0x38); //Extra Callback instruction
|
||||
mem_writew(vcpi.private_area+0x2e02,call_v86mon.Get_callback()); //The immediate word
|
||||
mem_writeb(vcpi.private_area+0x2e04,(Bit8u)0x66);
|
||||
mem_writeb(vcpi.private_area+0x2e05,(Bit8u)0xCF); //A IRETD Instruction
|
||||
|
||||
/* Testcode only, starts up dosbox in v86-mode */
|
||||
if (ENABLE_V86_STARTUP) {
|
||||
/* Prepare V86-task */
|
||||
CPU_SET_CRX(0, 1);
|
||||
CPU_LGDT(0xff, vcpi.private_area+0x0000);
|
||||
CPU_LIDT(0x7ff, vcpi.private_area+0x2000);
|
||||
CPU_LLDT(0x08);
|
||||
CPU_LTR(0x10);
|
||||
|
||||
CPU_Push32(SegValue(gs));
|
||||
CPU_Push32(SegValue(fs));
|
||||
CPU_Push32(SegValue(ds));
|
||||
CPU_Push32(SegValue(es));
|
||||
CPU_Push32(SegValue(ss));
|
||||
CPU_Push32(0x23002);
|
||||
CPU_Push32(SegValue(cs));
|
||||
CPU_Push32(reg_eip&0xffff);
|
||||
/* Switch to V86-mode */
|
||||
cpu.cpl=0;
|
||||
CPU_IRET(true,0);
|
||||
}
|
||||
}
|
||||
|
||||
~EMS() {
|
||||
|
@ -674,6 +1140,20 @@ public:
|
|||
RealSetVec(0x67,old67_pointer);
|
||||
/* Clear handle and page tables */
|
||||
//TODO
|
||||
|
||||
if (!ENABLE_VCPI) return;
|
||||
|
||||
/* Free private data area in expanded memory */
|
||||
EMM_ReleaseMemory(vcpi.ems_handle);
|
||||
|
||||
if (cpu.pmode && GETFLAG(VM)) {
|
||||
/* Switch back to real mode if in v86-mode */
|
||||
CPU_SET_CRX(0, 0);
|
||||
CPU_SET_CRX(3, 0);
|
||||
reg_flags&=(~(FLAG_IOPL|FLAG_VM));
|
||||
CPU_LIDT(0x3ff, 0);
|
||||
cpu.cpl=0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue