summaryrefslogtreecommitdiffstats
path: root/board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm
diff options
context:
space:
mode:
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.asm656
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
OpenPOWER on IntegriCloud