diff options
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm')
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm | 656 |
1 files changed, 656 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm b/board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm new file mode 100644 index 0000000000..42b5cf3692 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm @@ -0,0 +1,656 @@ +;**************************************************************************** +;* +;* SciTech OS Portability Manager Library +;* +;* ======================================================================== +;* +;* The contents of this file are subject to the SciTech MGL Public +;* License Version 1.0 (the "License"); you may not use this file +;* except in compliance with the License. You may obtain a copy of +;* the License at http://www.scitechsoft.com/mgl-license.txt +;* +;* Software distributed under the License is distributed on an +;* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +;* implied. See the License for the specific language governing +;* rights and limitations under the License. +;* +;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc. +;* +;* The Initial Developer of the Original Code is SciTech Software, Inc. +;* All Rights Reserved. +;* +;* ======================================================================== +;* +;* Language: 80386 Assembler, TASM 4.0 or NASM +;* Environment: IBM PC Real mode and 16/32 bit protected mode +;* +;* Description: Low level assembly support for the PM library specific to +;* MSDOS. +;* +;**************************************************************************** + + IDEAL + +include "scitech.mac" ; Memory model macros + +header _pmdos ; Set up memory model + +begdataseg _pmdos + +ifndef flatmodel + +struc rmregs_s +ax dw ? +ax_high dw ? +bx dw ? +bx_high dw ? +cx dw ? +cx_high dw ? +dx dw ? +dx_high dw ? +si dw ? +si_high dw ? +di dw ? +di_high dw ? +cflag dw ? +cflag_high dw ? +ends rmregs_s +RMREGS = (rmregs_s PTR es:bx) + +struc rmsregs_s +es dw ? +cs dw ? +ss dw ? +ds dw ? +ends rmsregs_s +RMSREGS = (rmsregs_s PTR es:bx) + +endif ; !flatmodel + +ifdef flatmodel + cextern _PM_savedDS,USHORT + cextern _PM_VXD_off,UINT + cextern _PM_VXD_sel,UINT +ifdef DOS4GW + cextern _PM_haveCauseWay,UINT +endif +endif +intel_id db "GenuineIntel" ; Intel vendor ID + +PMHELP_GETPDB EQU 0026h +PMHELP_FLUSHTLB EQU 0027h + +enddataseg _pmdos + +P586 + +begcodeseg _pmdos ; Start of code segment + +ifndef flatmodel + +;---------------------------------------------------------------------------- +; void PM_callRealMode(unsigned s,unsigned o, RMREGS *regs, +; RMSREGS *sregs) +;---------------------------------------------------------------------------- +; Calls a real mode procedure, loading the appropriate registers values +; from the passed in structures. Only the DS and ES register are loaded +; from the SREGS structure. +;---------------------------------------------------------------------------- +cprocstart PM_callRealMode + + ARG s:WORD, o:WORD, regs:DWORD, sregs:DWORD + + LOCAL addr:DWORD, bxVal:WORD, esVal:WORD, flags:WORD = LocalSize + + enter_c + push ds + push es + + mov ax,[o] ; Build the address to call in 'addr' + mov [WORD addr],ax + mov ax,[s] + mov [WORD addr+2],ax + + les bx,[sregs] + mov ax,[RMSREGS.ds] + mov ds,ax ; DS := passed in value + mov ax,[RMSREGS.es] + mov [esVal],ax + les bx,[regs] + mov ax,[RMREGS.bx] + mov [bxVal],ax + mov ax,[RMREGS.ax] ; AX := passed in value + mov cx,[RMREGS.cx] ; CX := passed in value + mov dx,[RMREGS.dx] ; DX := passed in value + mov si,[RMREGS.si] ; SI := passed in value + mov di,[RMREGS.di] ; DI := passed in value + push bp + push [esVal] + pop es ; ES := passed in value + mov bx,[bxVal] ; BX := passed in value + + call [addr] ; Call the specified routine + + pushf ; Save flags for later + pop [flags] + + pop bp + push es + pop [esVal] + push bx + pop [bxVal] + les bx,[sregs] + push ds + pop [RMSREGS.ds] ; Save value of DS + push [esVal] + pop [RMSREGS.es] ; Save value of ES + les bx,[regs] + mov [RMREGS.ax],ax ; Save value of AX + mov [RMREGS.cx],cx ; Save value of CX + mov [RMREGS.dx],dx ; Save value of DX + mov [RMREGS.si],si ; Save value of SI + mov [RMREGS.di],di ; Save value of DI + mov ax,[flags] ; Return flags + and ax,1h ; Isolate carry flag + mov [RMREGS.cflag],ax ; Save carry flag status + mov ax,[bxVal] + mov [RMREGS.bx],ax ; Save value of BX + + pop es + pop ds + leave_c + ret + +cprocend + +endif + +;---------------------------------------------------------------------------- +; void PM_segread(PMSREGS *sregs) +;---------------------------------------------------------------------------- +; Read the current value of all segment registers +;---------------------------------------------------------------------------- +cprocstartdll16 PM_segread + + ARG sregs:DPTR + + enter_c + + mov ax,es + _les _si,[sregs] + mov [_ES _si],ax + mov [_ES _si+2],cs + mov [_ES _si+4],ss + mov [_ES _si+6],ds + mov [_ES _si+8],fs + mov [_ES _si+10],gs + + leave_c + ret + +cprocend + +; Create a table of the 256 different interrupt calls that we can jump +; into + +ifdef USE_NASM + +%assign intno 0 + +intTable: +%rep 256 + db 0CDh + db intno +%assign intno intno + 1 + ret + nop +%endrep + +else + +intno = 0 + +intTable: + REPT 256 + db 0CDh + db intno +intno = intno + 1 + ret + nop + ENDM + +endif + +;---------------------------------------------------------------------------- +; _PM_genInt - Generate the appropriate interrupt +;---------------------------------------------------------------------------- +cprocnear _PM_genInt + + push _ax ; Save _ax + push _bx ; Save _bx +ifdef flatmodel + mov ebx,[UINT esp+12] ; EBX := interrupt number +else + mov bx,sp ; Make sure ESP is zeroed + mov bx,[UINT ss:bx+6] ; BX := interrupt number +endif + mov _ax,offset intTable ; Point to interrupt generation table + shl _bx,2 ; _BX := index into table + add _ax,_bx ; _AX := pointer to interrupt code +ifdef flatmodel + xchg eax,[esp+4] ; Restore eax, and set for int +else + mov bx,sp + xchg ax,[ss:bx+2] ; Restore ax, and set for int +endif + pop _bx ; restore _bx + ret + +cprocend + +;---------------------------------------------------------------------------- +; int PM_int386x(int intno, PMREGS *in, PMREGS *out,PMSREGS *sregs) +;---------------------------------------------------------------------------- +; Issues a software interrupt in protected mode. This routine has been +; written to allow user programs to load CS and DS with different values +; other than the default. +;---------------------------------------------------------------------------- +cprocstartdll16 PM_int386x + + ARG intno:UINT, inptr:DPTR, outptr:DPTR, sregs:DPTR + + LOCAL flags:UINT, sv_ds:UINT, sv_esi:ULONG = LocalSize + + enter_c + push ds + push es ; Save segment registers + push fs + push gs + + _lds _si,[sregs] ; DS:_SI -> Load segment registers + mov es,[_si] + mov bx,[_si+6] + mov [sv_ds],_bx ; Save value of user DS on stack + mov fs,[_si+8] + mov gs,[_si+10] + + _lds _si,[inptr] ; Load CPU registers + mov eax,[_si] + mov ebx,[_si+4] + mov ecx,[_si+8] + mov edx,[_si+12] + mov edi,[_si+20] + mov esi,[_si+16] + + push ds ; Save value of DS + push _bp ; Some interrupts trash this! + clc ; Generate the interrupt + push [UINT intno] + mov ds,[WORD sv_ds] ; Set value of user's DS selector + call _PM_genInt + pop _bp ; Pop intno from stack (flags unchanged) + pop _bp ; Restore value of stack frame pointer + pop ds ; Restore value of DS + + pushf ; Save flags for later + pop [UINT flags] + push esi ; Save ESI for later + pop [DWORD sv_esi] + push ds ; Save DS for later + pop [UINT sv_ds] + + _lds _si,[outptr] ; Save CPU registers + mov [_si],eax + mov [_si+4],ebx + mov [_si+8],ecx + mov [_si+12],edx + push [DWORD sv_esi] + pop [DWORD _si+16] + mov [_si+20],edi + + mov _bx,[flags] ; Return flags + and ebx,1h ; Isolate carry flag + mov [_si+24],ebx ; Save carry flag status + + _lds _si,[sregs] ; Save segment registers + mov [_si],es + mov _bx,[sv_ds] + mov [_si+6],bx ; Get returned DS from stack + mov [_si+8],fs + mov [_si+10],gs + + pop gs ; Restore segment registers + pop fs + pop es + pop ds + leave_c + ret + +cprocend + +ifndef flatmodel +_PM_savedDS dw _DATA ; Saved value of DS +endif + +;---------------------------------------------------------------------------- +; void PM_saveDS(void) +;---------------------------------------------------------------------------- +; Save the value of DS into a section of the code segment, so that we can +; quickly load this value at a later date in the PM_loadDS() routine from +; inside interrupt handlers etc. The method to do this is different +; depending on the DOS extender being used. +;---------------------------------------------------------------------------- +cprocstartdll16 PM_saveDS + +ifdef flatmodel + mov [_PM_savedDS],ds ; Store away in data segment +endif + ret + +cprocend + +;---------------------------------------------------------------------------- +; void PM_loadDS(void) +;---------------------------------------------------------------------------- +; Routine to load the DS register with the default value for the current +; DOS extender. Only the DS register is loaded, not the ES register, so +; if you wish to call C code, you will need to also load the ES register +; in 32 bit protected mode. +;---------------------------------------------------------------------------- +cprocstartdll16 PM_loadDS + + mov ds,[cs:_PM_savedDS] ; We can access the proper DS through CS + ret + +cprocend + +ifdef flatmodel + +;---------------------------------------------------------------------------- +; ibool DPMI_allocateCallback(void (*pmcode)(), void *rmregs, long *RMCB) +;---------------------------------------------------------------------------- +cprocstart _DPMI_allocateCallback + + ARG pmcode:CPTR, rmregs:DPTR, RMCB:DPTR + + enter_c + push ds + push es + + push cs + pop ds + mov esi,[pmcode] ; DS:ESI -> protected mode code to call + mov edi,[rmregs] ; ES:EDI -> real mode register buffer + mov ax,303h ; AX := allocate realmode callback function + int 31h + mov eax,0 ; Return failure! + jc @@Fail + + mov eax,[RMCB] + shl ecx,16 + mov cx,dx + mov [es:eax],ecx ; Return real mode address + mov eax,1 ; Return success! + +@@Fail: pop es + pop ds + leave_c + ret + +cprocend + +;---------------------------------------------------------------------------- +; void DPMI_freeCallback(long RMCB) +;---------------------------------------------------------------------------- +cprocstart _DPMI_freeCallback + + ARG RMCB:ULONG + + enter_c + + mov cx,[WORD RMCB+2] + mov dx,[WORD RMCB] ; CX:DX := real mode callback + mov ax,304h + int 31h + + leave_c + ret + +cprocend + +endif + +; Macro to delay briefly to ensure that enough time has elapsed between +; successive I/O accesses so that the device being accessed can respond +; to both accesses even on a very fast PC. + +ifdef USE_NASM +%macro DELAY 0 + jmp short $+2 + jmp short $+2 + jmp short $+2 +%endmacro +%macro IODELAYN 1 +%rep %1 + DELAY +%endrep +%endmacro +else +macro DELAY + jmp short $+2 + jmp short $+2 + jmp short $+2 +endm +macro IODELAYN N + rept N + DELAY + endm +endm +endif + +;---------------------------------------------------------------------------- +; uchar _PM_readCMOS(int index) +;---------------------------------------------------------------------------- +; Read the value of a specific CMOS register. We do this with both +; normal interrupts and NMI disabled. +;---------------------------------------------------------------------------- +cprocstart _PM_readCMOS + + ARG index:UINT + + push _bp + mov _bp,_sp + pushfd + mov al,[BYTE index] + or al,80h ; Add disable NMI flag + cli + out 70h,al + IODELAYN 5 + in al,71h + mov ah,al + xor al,al + IODELAYN 5 + out 70h,al ; Re-enable NMI + sti + mov al,ah ; Return value in AL + popfd + pop _bp + ret + +cprocend + +;---------------------------------------------------------------------------- +; void _PM_writeCMOS(int index,uchar value) +;---------------------------------------------------------------------------- +; Read the value of a specific CMOS register. We do this with both +; normal interrupts and NMI disabled. +;---------------------------------------------------------------------------- +cprocstart _PM_writeCMOS + + ARG index:UINT, value:UCHAR + + push _bp + mov _bp,_sp + pushfd + mov al,[BYTE index] + or al,80h ; Add disable NMI flag + cli + out 70h,al + IODELAYN 5 + mov al,[value] + out 71h,al + xor al,al + IODELAYN 5 + out 70h,al ; Re-enable NMI + sti + popfd + pop _bp + ret + +cprocend + +ifdef flatmodel + +;---------------------------------------------------------------------------- +; int _PM_pagingEnabled(void) +;---------------------------------------------------------------------------- +; Returns 1 if paging is enabled, 0 if not or -1 if not at ring 0 +;---------------------------------------------------------------------------- +cprocstart _PM_pagingEnabled + + mov eax,-1 +ifdef DOS4GW + mov cx,cs + and ecx,3 + jz @@Ring0 + cmp [UINT _PM_haveCauseWay],0 + jnz @@Ring0 + jmp @@Exit + +@@Ring0: + mov eax,cr0 ; Load CR0 + shr eax,31 ; Isolate paging enabled bit +endif +@@Exit: ret + +cprocend + +;---------------------------------------------------------------------------- +; _PM_getPDB - Return the Page Table Directory Base address +;---------------------------------------------------------------------------- +cprocstart _PM_getPDB + +ifdef DOS4GW + mov ax,cs + and eax,3 + jz @@Ring0 + cmp [UINT _PM_haveCauseWay],0 + jnz @@Ring0 +endif + +; Call VxD if running at ring 3 in a DOS box + + cmp [WORD _PM_VXD_sel],0 + jz @@Fail + mov eax,PMHELP_GETPDB +ifdef USE_NASM + call far dword [_PM_VXD_off] +else + call [FCPTR _PM_VXD_off] +endif + ret + +@@Ring0: +ifdef DOS4GW + mov eax,cr3 + and eax,0FFFFF000h + ret +endif +@@Fail: xor eax,eax + ret + +cprocend + +;---------------------------------------------------------------------------- +; PM_flushTLB - Flush the Translation Lookaside buffer +;---------------------------------------------------------------------------- +cprocstart PM_flushTLB + + mov ax,cs + and eax,3 + jz @@Ring0 +ifdef DOS4GW + cmp [UINT _PM_haveCauseWay],0 + jnz @@Ring0 +endif + +; Call VxD if running at ring 3 in a DOS box + + cmp [WORD _PM_VXD_sel],0 + jz @@Fail + mov eax,PMHELP_FLUSHTLB +ifdef USE_NASM + call far dword [_PM_VXD_off] +else + call [FCPTR _PM_VXD_off] +endif + ret + +@@Ring0: +ifdef DOS4GW + wbinvd ; Flush the CPU cache + mov eax,cr3 + mov cr3,eax ; Flush the TLB +endif +@@Fail: ret + +cprocend + +endif + +;---------------------------------------------------------------------------- +; void _PM_VxDCall(VXD_regs far *r,uint off,uint sel); +;---------------------------------------------------------------------------- +cprocstart _PM_VxDCall + + ARG r:DPTR, off:UINT, sel:UINT + + enter_c + +; Load all registers from the registers structure + + mov ebx,[r] + mov eax,[ebx+0] + mov ecx,[ebx+8] + mov edx,[ebx+12] + mov esi,[ebx+16] + mov edi,[ebx+20] + mov ebx,[ebx+4] ; Trashes BX structure pointer! + +; Call the VxD entry point (on stack) + +ifdef USE_NASM + call far dword [off] +else + call [FCPTR off] +endif + +; Save all registers back in the structure + + push ebx ; Push EBX onto stack for later + mov ebx,[r] + mov [ebx+0],eax + mov [ebx+8],ecx + mov [ebx+12],edx + mov [ebx+16],esi + mov [ebx+20],edi + pop [DWORD ebx+4] ; Save value of EBX from stack + + leave_c + ret + +cprocend + +endcodeseg _pmdos + + END ; End of module |