diff options
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm/smx')
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/_event.asm | 175 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/_lztimer.asm | 58 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/_pm.asm | 448 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/_pmsmx.asm | 933 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/_vflat.asm | 652 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/cpuinfo.c | 72 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/event.c | 368 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/oshdr.h | 29 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/pm.c | 1187 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/pmsmx.c | 471 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/vflat.c | 49 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/smx/ztimer.c | 115 |
12 files changed, 4557 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_event.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_event.asm new file mode 100644 index 0000000..da62b1f --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_event.asm @@ -0,0 +1,175 @@ +;**************************************************************************** +;* +;* SciTech Multi-platform Graphics 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 +;* Environment: IBM PC (MS DOS) +;* +;* Description: Assembly language support routines for the event module. +;* +;**************************************************************************** + + ideal + +include "scitech.mac" ; Memory model macros + +ifdef flatmodel + +header _event ; Set up memory model + +begdataseg _event + + cextern _EVT_biosPtr,DPTR + + cpublic _EVT_dataStart + +ifdef USE_NASM +%define KB_HEAD WORD esi+01Ah ; Keyboard buffer head in BIOS data area +%define KB_TAIL WORD esi+01Ch ; Keyboard buffer tail in BIOS data area +%define KB_START WORD esi+080h ; Start of keyboard buffer in BIOS data area +%define KB_END WORD esi+082h ; End of keyboard buffer in BIOS data area +else +KB_HEAD EQU WORD esi+01Ah ; Keyboard buffer head in BIOS data area +KB_TAIL EQU WORD esi+01Ch ; Keyboard buffer tail in BIOS data area +KB_START EQU WORD esi+080h ; Start of keyboard buffer in BIOS data area +KB_END EQU WORD esi+082h ; End of keyboard buffer in BIOS data area +endif + + cpublic _EVT_dataEnd + +enddataseg _event + +begcodeseg _event ; Start of code segment + + cpublic _EVT_codeStart + +;---------------------------------------------------------------------------- +; int _EVT_getKeyCode(void) +;---------------------------------------------------------------------------- +; Returns the key code for the next available key by extracting it from +; the BIOS keyboard buffer. +;---------------------------------------------------------------------------- +cprocstart _EVT_getKeyCode + + enter_c + + mov esi,[_EVT_biosPtr] + xor ebx,ebx + xor eax,eax + mov bx,[KB_HEAD] + cmp bx,[KB_TAIL] + jz @@Done + xor eax,eax + mov ax,[esi+ebx] ; EAX := character from keyboard buffer + inc _bx + inc _bx + cmp bx,[KB_END] ; Hit the end of the keyboard buffer? + jl @@1 + mov bx,[KB_START] +@@1: mov [KB_HEAD],bx ; Update keyboard buffer head pointer + +@@Done: leave_c + ret + +cprocend + +;---------------------------------------------------------------------------- +; int _EVT_disableInt(void); +;---------------------------------------------------------------------------- +; Return processor interrupt status and disable interrupts. +;---------------------------------------------------------------------------- +cprocstart _EVT_disableInt + + pushf ; Put flag word on stack + cli ; Disable interrupts! + pop eax ; deposit flag word in return register + ret + +cprocend + +;---------------------------------------------------------------------------- +; void _EVT_restoreInt(int ps); +;---------------------------------------------------------------------------- +; Restore processor interrupt status. +;---------------------------------------------------------------------------- +cprocstart _EVT_restoreInt + + ARG ps:UINT + + push ebp + mov ebp,esp ; Set up stack frame + push [DWORD ps] + popf ; Restore processor status (and interrupts) + pop ebp + ret + +cprocend + +;---------------------------------------------------------------------------- +; int EVT_rdinx(int port,int index) +;---------------------------------------------------------------------------- +; Reads an indexed register value from an I/O port. +;---------------------------------------------------------------------------- +cprocstart EVT_rdinx + + ARG port:UINT, index:UINT + + push ebp + mov ebp,esp + mov edx,[port] + mov al,[BYTE index] + out dx,al + inc dx + in al,dx + movzx eax,al + pop ebp + ret + +cprocend + +;---------------------------------------------------------------------------- +; void EVT_wrinx(int port,int index,int value) +;---------------------------------------------------------------------------- +; Writes an indexed register value to an I/O port. +;---------------------------------------------------------------------------- +cprocstart EVT_wrinx + + ARG port:UINT, index:UINT, value:UINT + + push ebp + mov ebp,esp + mov edx,[port] + mov al,[BYTE index] + mov ah,[BYTE value] + out dx,ax + pop ebp + ret + +cprocend + + cpublic _EVT_codeEnd + +endcodeseg _event + +endif + + END ; End of module diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_lztimer.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_lztimer.asm new file mode 100644 index 0000000..068eea6 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_lztimer.asm @@ -0,0 +1,58 @@ +;**************************************************************************** +;* +;* 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: NASM or TASM Assembler +;* Environment: smx 32 bit intel CPU +;* +;* Description: SMX does not support 486's, so this module is not necessary. +;* +;* All registers and all flags are preserved by all routines, except +;* interrupts which are always turned on +;* +;**************************************************************************** + + IDEAL + +include "scitech.mac" + +header _lztimer + +begdataseg _lztimer + +enddataseg _lztimer + +begcodeseg _lztimer ; Start of code segment + +cprocstart LZ_disable + cli + ret +cprocend + +cprocstart LZ_enable + sti + ret +cprocend + +endcodeseg _lztimer + + END diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_pm.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_pm.asm new file mode 100644 index 0000000..1c7cb21 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_pm.asm @@ -0,0 +1,448 @@ +;**************************************************************************** +;* +;* 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: 32-bit SMX embedded systems development +;* +;* Description: Low level assembly support for the PM library specific to +;* SMX. +;* +;**************************************************************************** + + IDEAL + +include "scitech.mac" ; Memory model macros + +header _pm ; Set up memory model + +begdataseg _pm + + cextern _PM_savedDS,USHORT + +intel_id db "GenuineIntel" ; Intel vendor ID + +enddataseg _pm + +begcodeseg _pm ; Start of code segment + +;---------------------------------------------------------------------------- +; 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 + mov ebx,[UINT esp+12] ; EBX := interrupt number + mov _ax,offset intTable ; Point to interrupt generation table + shl _bx,2 ; _BX := index into table + add _ax,_bx ; _AX := pointer to interrupt code + xchg eax,[esp+4] ; Restore eax, and set for int + 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 + +;---------------------------------------------------------------------------- +; 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 + + mov [_PM_savedDS],ds ; Store away in data segment + 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 + +;---------------------------------------------------------------------------- +; void PM_setBankA(int bank) +;---------------------------------------------------------------------------- +cprocstart PM_setBankA + + ARG bank:UINT + + push ebp + mov ebp,esp + push ebx + mov _bx,0 + mov _ax,4F05h + mov _dx,[bank] + int 10h + pop ebx + pop ebp + ret + +cprocend + +;---------------------------------------------------------------------------- +; void PM_setBankAB(int bank) +;---------------------------------------------------------------------------- +cprocstart PM_setBankAB + + ARG bank:UINT + + push ebp + mov ebp,esp + push ebx + mov _bx,0 + mov _ax,4F05h + mov _dx,[bank] + int 10h + mov _bx,1 + mov _ax,4F05h + mov _dx,[bank] + int 10h + pop ebx + pop ebp + ret + +cprocend + +;---------------------------------------------------------------------------- +; void PM_setCRTStart(int x,int y,int waitVRT) +;---------------------------------------------------------------------------- +cprocstart PM_setCRTStart + + ARG x:UINT, y:UINT, waitVRT:UINT + + push ebp + mov ebp,esp + push ebx + mov _bx,[waitVRT] + mov _cx,[x] + mov _dx,[y] + mov _ax,4F07h + int 10h + pop ebx + pop ebp + ret + +cprocend + +;---------------------------------------------------------------------------- +; int _PM_inp(int port) +;---------------------------------------------------------------------------- +; Reads a byte from the specified port +;---------------------------------------------------------------------------- +cprocstart _PM_inp + + ARG port:UINT + + push _bp + mov _bp,_sp + xor _ax,_ax + mov _dx,[port] + in al,dx + pop _bp + ret + +cprocend + +;---------------------------------------------------------------------------- +; void _PM_outp(int port,int value) +;---------------------------------------------------------------------------- +; Write a byte to the specified port. +;---------------------------------------------------------------------------- +cprocstart _PM_outp + + ARG port:UINT, value:UINT + + push _bp + mov _bp,_sp + mov _dx,[port] + mov _ax,[value] + out dx,al + pop _bp + ret + +cprocend + +; 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 + +;---------------------------------------------------------------------------- +; _PM_getPDB - Return the Page Table Directory Base address +;---------------------------------------------------------------------------- +cprocstart _PM_getPDB + + mov eax,cr3 + and eax,0FFFFF000h + ret + +cprocend + +;---------------------------------------------------------------------------- +; _PM_flushTLB - Flush the Translation Lookaside buffer +;---------------------------------------------------------------------------- +cprocstart PM_flushTLB + + wbinvd ; Flush the CPU cache + mov eax,cr3 + mov cr3,eax ; Flush the TLB + ret + +cprocend + +endcodeseg _pm + + END ; End of module diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_pmsmx.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_pmsmx.asm new file mode 100644 index 0000000..8352ce3 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_pmsmx.asm @@ -0,0 +1,933 @@ +;**************************************************************************** +;* +;* 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: 32-bit SMX embedded systems development +;* +;* Description: Low level assembly support for the PM library specific to +;* SMX interrupt handling. +;* +;**************************************************************************** + + IDEAL + +include "scitech.mac" ; Memory model macros + +header _pmsmx ; Set up memory model + +; Define the size of our local stacks. For real mode code they cant be +; that big, but for 32 bit protected mode code we can make them nice and +; large so that complex C functions can be used. + +MOUSE_STACK EQU 4096 +TIMER_STACK EQU 4096 +KEY_STACK EQU 1024 +INT10_STACK EQU 1024 + +ifdef USE_NASM + +; Macro to load DS and ES registers with correct value. + +%imacro LOAD_DS 0 + mov ds,[cs:_PM_savedDS] + mov es,[cs:_PM_savedDS] +%endmacro + +; Note that interrupts we disable interrupts during the following stack +; %imacro for correct operation, but we do not enable them again. Normally +; these %imacros are used within interrupt handlers so interrupts should +; already be off. We turn them back on explicitly later if the user code +; needs them to be back on. + +; Macro to switch to a new local stack. + +%imacro NEWSTK 1 + cli + mov [seg_%1],ss + mov [ptr_%1],_sp + mov [TempSeg],ds + mov ss,[TempSeg] + mov _sp,offset %1 +%endmacro + +; %imacro to switch back to the old stack. + +%imacro RESTSTK 1 + cli + mov ss,[seg_%1] + mov _sp,[ptr_%1] +%endmacro + +; %imacro to swap the current stack with the one saved away. + +%imacro SWAPSTK 1 + cli + mov ax,ss + xchg ax,[seg_%1] + mov ss,ax + xchg _sp,[ptr_%1] +%endmacro + +else + +; Macro to load DS and ES registers with correct value. + +MACRO LOAD_DS + mov ds,[cs:_PM_savedDS] + mov es,[cs:_PM_savedDS] +ENDM + +; Note that interrupts we disable interrupts during the following stack +; macro for correct operation, but we do not enable them again. Normally +; these macros are used within interrupt handlers so interrupts should +; already be off. We turn them back on explicitly later if the user code +; needs them to be back on. + +; Macro to switch to a new local stack. + +MACRO NEWSTK stkname + cli + mov [seg_&stkname&],ss + mov [ptr_&stkname&],_sp + mov [TempSeg],ds + mov ss,[TempSeg] + mov _sp,offset stkname +ENDM + +; Macro to switch back to the old stack. + +MACRO RESTSTK stkname + cli + mov ss,[seg_&stkname&] + mov _sp,[ptr_&stkname&] +ENDM + +; Macro to swap the current stack with the one saved away. + +MACRO SWAPSTK stkname + cli + mov ax,ss + xchg ax,[seg_&stkname&] + mov ss,ax + xchg _sp,[ptr_&stkname&] +ENDM + +endif + +begdataseg _pmsmx + + cextern _PM_savedDS,USHORT + cextern _PM_critHandler,CPTR + cextern _PM_breakHandler,CPTR + cextern _PM_timerHandler,CPTR + cextern _PM_rtcHandler,CPTR + cextern _PM_keyHandler,CPTR + cextern _PM_key15Handler,CPTR + cextern _PM_mouseHandler,CPTR + cextern _PM_int10Handler,CPTR + + cextern _PM_ctrlCPtr,DPTR + cextern _PM_ctrlBPtr,DPTR + cextern _PM_critPtr,DPTR + + cextern _PM_prevTimer,FCPTR + cextern _PM_prevRTC,FCPTR + cextern _PM_prevKey,FCPTR + cextern _PM_prevKey15,FCPTR + cextern _PM_prevBreak,FCPTR + cextern _PM_prevCtrlC,FCPTR + cextern _PM_prevCritical,FCPTR + cextern _PM_prevRealTimer,ULONG + cextern _PM_prevRealRTC,ULONG + cextern _PM_prevRealKey,ULONG + cextern _PM_prevRealKey15,ULONG + cextern _PM_prevRealInt10,ULONG + +cpublic _PM_pmsmxDataStart + +; Allocate space for all of the local stacks that we need. These stacks +; are not very large, but should be large enough for most purposes +; (generally you want to handle these interrupts quickly, simply storing +; the information for later and then returning). If you need bigger +; stacks then change the appropriate value in here. + + ALIGN 4 + dclb MOUSE_STACK ; Space for local stack (small) +MsStack: ; Stack starts at end! +ptr_MsStack DUINT 0 ; Place to store old stack offset +seg_MsStack dw 0 ; Place to store old stack segment + + ALIGN 4 + dclb INT10_STACK ; Space for local stack (small) +Int10Stack: ; Stack starts at end! +ptr_Int10Stack DUINT 0 ; Place to store old stack offset +seg_Int10Stack dw 0 ; Place to store old stack segment + + ALIGN 4 + dclb TIMER_STACK ; Space for local stack (small) +TmStack: ; Stack starts at end! +ptr_TmStack DUINT 0 ; Place to store old stack offset +seg_TmStack dw 0 ; Place to store old stack segment + + ALIGN 4 + dclb TIMER_STACK ; Space for local stack (small) +RtcStack: ; Stack starts at end! +ptr_RtcStack DUINT 0 ; Place to store old stack offset +seg_RtcStack dw 0 ; Place to store old stack segment +RtcInside dw 0 ; Are we still handling current interrupt + + ALIGN 4 + dclb KEY_STACK ; Space for local stack (small) +KyStack: ; Stack starts at end! +ptr_KyStack DUINT 0 ; Place to store old stack offset +seg_KyStack dw 0 ; Place to store old stack segment +KyInside dw 0 ; Are we still handling current interrupt + + ALIGN 4 + dclb KEY_STACK ; Space for local stack (small) +Ky15Stack: ; Stack starts at end! +ptr_Ky15Stack DUINT 0 ; Place to store old stack offset +seg_Ky15Stack dw 0 ; Place to store old stack segment + +TempSeg dw 0 ; Place to store stack segment + +cpublic _PM_pmsmxDataEnd + +enddataseg _pmsmx + +begcodeseg _pmsmx ; Start of code segment + +cpublic _PM_pmsmxCodeStart + +;---------------------------------------------------------------------------- +; PM_mouseISR - Mouse interrupt subroutine dispatcher +;---------------------------------------------------------------------------- +; Interrupt subroutine called by the mouse driver upon interrupts, to +; dispatch control to high level C based subroutines. Interrupts are on +; when we call the user code. +; +; It is _extremely_ important to save the state of the extended registers +; as these may well be trashed by the routines called from here and not +; restored correctly by the mouse interface module. +; +; NOTE: This routine switches to a local stack before calling any C code, +; and hence is _not_ re-entrant. For mouse handlers this is not a +; problem, as the mouse driver arbitrates calls to the user mouse +; handler for us. +; +; Entry: AX - Condition mask giving reason for call +; BX - Mouse button state +; CX - Horizontal cursor coordinate +; DX - Vertical cursor coordinate +; SI - Horizontal mickey value +; DI - Vertical mickey value +; +;---------------------------------------------------------------------------- +cprocfar _PM_mouseISR + + push ds ; Save value of DS + push es + pushad ; Save _all_ extended registers + cld ; Clear direction flag + + LOAD_DS ; Load DS register + NEWSTK MsStack ; Switch to local stack + +; Call the installed high level C code routine + + clrhi dx ; Clear out high order values + clrhi cx + clrhi bx + clrhi ax + sgnhi si + sgnhi di + + push _di + push _si + push _dx + push _cx + push _bx + push _ax + sti ; Enable interrupts + call [CPTR _PM_mouseHandler] + _add sp,12,24 + + RESTSTK MsStack ; Restore previous stack + + popad ; Restore all extended registers + pop es + pop ds + ret ; We are done!! + +cprocend + +;---------------------------------------------------------------------------- +; PM_timerISR - Timer interrupt subroutine dispatcher +;---------------------------------------------------------------------------- +; Hardware interrupt handler for the timer interrupt, to dispatch control +; to high level C based subroutines. We save the state of all registers +; in this routine, and switch to a local stack. Interrupts are *off* +; when we call the user code. +; +; NOTE: This routine switches to a local stack before calling any C code, +; and hence is _not_ re-entrant. Make sure your C code executes as +; quickly as possible, since a timer overrun will simply hang the +; system. +;---------------------------------------------------------------------------- +cprocfar _PM_timerISR + + push ds ; Save value of DS + push es + pushad ; Save _all_ extended registers + cld ; Clear direction flag + + LOAD_DS ; Load DS register + + NEWSTK TmStack ; Switch to local stack + call [CPTR _PM_timerHandler] + RESTSTK TmStack ; Restore previous stack + + popad ; Restore all extended registers + pop es + pop ds + iret ; Return from interrupt + +cprocend + +;---------------------------------------------------------------------------- +; PM_chainPrevTimer - Chain to previous timer interrupt and return +;---------------------------------------------------------------------------- +; Chains to the previous timer interrupt routine and returns control +; back to the high level interrupt handler. +;---------------------------------------------------------------------------- +cprocstart PM_chainPrevTimer + +ifdef TNT + push eax + push ebx + push ecx + pushfd ; Push flags on stack to simulate interrupt + mov ax,250Eh ; Call real mode procedure function + mov ebx,[_PM_prevRealTimer] + mov ecx,1 ; Copy real mode flags to real mode stack + int 21h ; Call the real mode code + popfd + pop ecx + pop ebx + pop eax + ret +else + SWAPSTK TmStack ; Swap back to previous stack + pushf ; Save state of interrupt flag + pushf ; Push flags on stack to simulate interrupt +ifdef USE_NASM + call far dword [_PM_prevTimer] +else + call [_PM_prevTimer] +endif + popf ; Restore state of interrupt flag + SWAPSTK TmStack ; Swap back to C stack again + ret +endif + +cprocend + +; 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 + +;---------------------------------------------------------------------------- +; PM_rtcISR - Real time clock interrupt subroutine dispatcher +;---------------------------------------------------------------------------- +; Hardware interrupt handler for the timer interrupt, to dispatch control +; to high level C based subroutines. We save the state of all registers +; in this routine, and switch to a local stack. Interrupts are *off* +; when we call the user code. +; +; NOTE: This routine switches to a local stack before calling any C code, +; and hence is _not_ re-entrant. Make sure your C code executes as +; quickly as possible, since a timer overrun will simply hang the +; system. +;---------------------------------------------------------------------------- +cprocfar _PM_rtcISR + + push ds ; Save value of DS + push es + pushad ; Save _all_ extended registers + cld ; Clear direction flag + +; Clear priority interrupt controller and re-enable interrupts so we +; dont lock things up for long. + + mov al,20h + out 0A0h,al + out 020h,al + +; Clear real-time clock timeout + + in al,70h ; Read CMOS index register + push _ax ; and save for later + IODELAYN 3 + mov al,0Ch + out 70h,al + IODELAYN 5 + in al,71h + +; Call the C interrupt handler function + + LOAD_DS ; Load DS register + cmp [BYTE RtcInside],1 ; Check for mutual exclusion + je @@Exit + mov [BYTE RtcInside],1 + sti ; Re-enable interrupts + NEWSTK RtcStack ; Switch to local stack + call [CPTR _PM_rtcHandler] + RESTSTK RtcStack ; Restore previous stack + mov [BYTE RtcInside],0 + +@@Exit: pop _ax + out 70h,al ; Restore CMOS index register + popad ; Restore all extended registers + pop es + pop ds + iret ; Return from interrupt + +cprocend + +;---------------------------------------------------------------------------- +; PM_keyISR - keyboard interrupt subroutine dispatcher +;---------------------------------------------------------------------------- +; Hardware interrupt handler for the keyboard interrupt, to dispatch control +; to high level C based subroutines. We save the state of all registers +; in this routine, and switch to a local stack. Interrupts are *off* +; when we call the user code. +; +; NOTE: This routine switches to a local stack before calling any C code, +; and hence is _not_ re-entrant. However we ensure within this routine +; mutual exclusion to the keyboard handling routine. +;---------------------------------------------------------------------------- +cprocfar _PM_keyISR + + push ds ; Save value of DS + push es + pushad ; Save _all_ extended registers + cld ; Clear direction flag + + LOAD_DS ; Load DS register + + cmp [BYTE KyInside],1 ; Check for mutual exclusion + je @@Reissued + + mov [BYTE KyInside],1 + NEWSTK KyStack ; Switch to local stack + call [CPTR _PM_keyHandler] ; Call C code + RESTSTK KyStack ; Restore previous stack + mov [BYTE KyInside],0 + +@@Exit: popad ; Restore all extended registers + pop es + pop ds + iret ; Return from interrupt + +; When the BIOS keyboard handler needs to change the SHIFT status lights +; on the keyboard, in the process of doing this the keyboard controller +; re-issues another interrupt, while the current handler is still executing. +; If we recieve another interrupt while still handling the current one, +; then simply chain directly to the previous handler. +; +; Note that for most DOS extenders, the real mode interrupt handler that we +; install takes care of this for us. + +@@Reissued: +ifdef TNT + push eax + push ebx + push ecx + pushfd ; Push flags on stack to simulate interrupt + mov ax,250Eh ; Call real mode procedure function + mov ebx,[_PM_prevRealKey] + mov ecx,1 ; Copy real mode flags to real mode stack + int 21h ; Call the real mode code + popfd + pop ecx + pop ebx + pop eax +else + pushf +ifdef USE_NASM + call far dword [_PM_prevKey] +else + call [_PM_prevKey] +endif +endif + jmp @@Exit + +cprocend + +;---------------------------------------------------------------------------- +; PM_chainPrevkey - Chain to previous key interrupt and return +;---------------------------------------------------------------------------- +; Chains to the previous key interrupt routine and returns control +; back to the high level interrupt handler. +;---------------------------------------------------------------------------- +cprocstart PM_chainPrevKey + +ifdef TNT + push eax + push ebx + push ecx + pushfd ; Push flags on stack to simulate interrupt + mov ax,250Eh ; Call real mode procedure function + mov ebx,[_PM_prevRealKey] + mov ecx,1 ; Copy real mode flags to real mode stack + int 21h ; Call the real mode code + popfd + pop ecx + pop ebx + pop eax + ret +else + +; YIKES! For some strange reason, when execution returns from the +; previous keyboard handler, interrupts are re-enabled!! Since we expect +; interrupts to remain off during the duration of our handler, this can +; cause havoc. However our stack macros always turn off interrupts, so they +; will be off when we exit this routine. Obviously there is a tiny weeny +; window when interrupts will be enabled, but there is nothing we can +; do about this. + + SWAPSTK KyStack ; Swap back to previous stack + pushf ; Push flags on stack to simulate interrupt +ifdef USE_NASM + call far dword [_PM_prevKey] +else + call [_PM_prevKey] +endif + SWAPSTK KyStack ; Swap back to C stack again + ret +endif + +cprocend + +;---------------------------------------------------------------------------- +; PM_key15ISR - Int 15h keyboard interrupt subroutine dispatcher +;---------------------------------------------------------------------------- +; This routine gets called if we have been called to handle the Int 15h +; keyboard interrupt callout from real mode. +; +; Entry: AX - Hardware scan code to process +; Exit: AX - Hardware scan code to process (0 to ignore) +;---------------------------------------------------------------------------- +cprocfar _PM_key15ISR + + push ds + push es + LOAD_DS + cmp ah,4Fh + jnz @@NotOurs ; Quit if not keyboard callout + + pushad + cld ; Clear direction flag + xor ah,ah ; AX := scan code + NEWSTK Ky15Stack ; Switch to local stack + push _ax + call [CPTR _PM_key15Handler] ; Call C code + _add sp,2,4 + RESTSTK Ky15Stack ; Restore previous stack + test ax,ax + jz @@1 + stc ; Set carry to process as normal + jmp @@2 +@@1: clc ; Clear carry to ignore scan code +@@2: popad + jmp @@Exit ; We are done + +@@NotOurs: +ifdef TNT + push eax + push ebx + push ecx + pushfd ; Push flags on stack to simulate interrupt + mov ax,250Eh ; Call real mode procedure function + mov ebx,[_PM_prevRealKey15] + mov ecx,1 ; Copy real mode flags to real mode stack + int 21h ; Call the real mode code + popfd + pop ecx + pop ebx + pop eax +else + pushf +ifdef USE_NASM + call far dword [_PM_prevKey15] +else + call [_PM_prevKey15] +endif +endif +@@Exit: pop es + pop ds + retf 4 + +cprocend + +;---------------------------------------------------------------------------- +; PM_breakISR - Control Break interrupt subroutine dispatcher +;---------------------------------------------------------------------------- +; Hardware interrupt handler for the Ctrl-Break interrupt. We simply set +; the Ctrl-Break flag to a 1 and leave (note that this is accessed through +; a far pointer, as it may well be located in conventional memory). +;---------------------------------------------------------------------------- +cprocfar _PM_breakISR + + sti + push ds ; Save value of DS + push es + push _bx + + LOAD_DS ; Load DS register + mov ebx,[_PM_ctrlBPtr] + mov [UINT _ES _bx],1 + +; Run alternate break handler code if installed + + cmp [CPTR _PM_breakHandler],0 + je @@Exit + + pushad + mov _ax,1 + push _ax + call [CPTR _PM_breakHandler] ; Call C code + pop _ax + popad + +@@Exit: pop _bx + pop es + pop ds + iret ; Return from interrupt + +cprocend + +;---------------------------------------------------------------------------- +; int PM_ctrlBreakHit(int clearFlag) +;---------------------------------------------------------------------------- +; Returns the current state of the Ctrl-Break flag and possibly clears it. +;---------------------------------------------------------------------------- +cprocstart PM_ctrlBreakHit + + ARG clearFlag:UINT + + enter_c + pushf ; Save interrupt status + push es + mov ebx,[_PM_ctrlBPtr] + cli ; No interrupts thanks! + mov _ax,[_ES _bx] + test [BYTE clearFlag],1 + jz @@Done + mov [UINT _ES _bx],0 + +@@Done: pop es + popf ; Restore interrupt status + leave_c + ret + +cprocend + +;---------------------------------------------------------------------------- +; PM_ctrlCISR - Control Break interrupt subroutine dispatcher +;---------------------------------------------------------------------------- +; Hardware interrupt handler for the Ctrl-C interrupt. We simply set +; the Ctrl-C flag to a 1 and leave (note that this is accessed through +; a far pointer, as it may well be located in conventional memory). +;---------------------------------------------------------------------------- +cprocfar _PM_ctrlCISR + + sti + push ds ; Save value of DS + push es + push _bx + + LOAD_DS ; Load DS register + mov ebx,[_PM_ctrlCPtr] + mov [UINT _ES _bx],1 + +; Run alternate break handler code if installed + + cmp [CPTR _PM_breakHandler],0 + je @@Exit + + pushad + mov _ax,0 + push _ax + call [CPTR _PM_breakHandler] ; Call C code + pop _ax + popad + +@@Exit: pop _bx + pop es + pop ds + iret ; Return from interrupt + iretd + +cprocend + +;---------------------------------------------------------------------------- +; int PM_ctrlCHit(int clearFlag) +;---------------------------------------------------------------------------- +; Returns the current state of the Ctrl-C flag and possibly clears it. +;---------------------------------------------------------------------------- +cprocstart PM_ctrlCHit + + ARG clearFlag:UINT + + enter_c + pushf ; Save interrupt status + push es + mov ebx,[_PM_ctrlCPtr] + cli ; No interrupts thanks! + mov _ax,[_ES _bx] + test [BYTE clearFlag],1 + jz @@Done + mov [UINT _ES _bx],0 + +@@Done: + pop es + popf ; Restore interrupt status + leave_c + ret + +cprocend + +;---------------------------------------------------------------------------- +; PM_criticalISR - Control Error handler interrupt subroutine dispatcher +;---------------------------------------------------------------------------- +; Interrupt handler for the MSDOS Critical Error interrupt, to dispatch +; control to high level C based subroutines. We save the state of all +; registers in this routine, and switch to a local stack. We also pass +; the values of the AX and DI registers to the as pointers, so that the +; values can be modified before returning to MSDOS. +;---------------------------------------------------------------------------- +cprocfar _PM_criticalISR + + sti + push ds ; Save value of DS + push es + push _bx ; Save register values changed + cld ; Clear direction flag + + LOAD_DS ; Load DS register + mov ebx,[_PM_critPtr] + mov [_ES _bx],ax + mov [_ES _bx+2],di + +; Run alternate critical handler code if installed + + cmp [CPTR _PM_critHandler],0 + je @@NoAltHandler + + pushad + push _di + push _ax + call [CPTR _PM_critHandler] ; Call C code + _add sp,4,8 + popad + + pop _bx + pop es + pop ds + iret ; Return from interrupt + +@@NoAltHandler: + mov ax,3 ; Tell MSDOS to fail the operation + pop _bx + pop es + pop ds + iret ; Return from interrupt + +cprocend + +;---------------------------------------------------------------------------- +; int PM_criticalError(int *axVal,int *diVal,int clearFlag) +;---------------------------------------------------------------------------- +; Returns the current state of the critical error flags, and the values that +; MSDOS passed in the AX and DI registers to our handler. +;---------------------------------------------------------------------------- +cprocstart PM_criticalError + + ARG axVal:DPTR, diVal:DPTR, clearFlag:UINT + + enter_c + pushf ; Save interrupt status + push es + mov ebx,[_PM_critPtr] + cli ; No interrupts thanks! + xor _ax,_ax + xor _di,_di + mov ax,[_ES _bx] + mov di,[_ES _bx+2] + test [BYTE clearFlag],1 + jz @@NoClear + mov [ULONG _ES _bx],0 +@@NoClear: + _les _bx,[axVal] + mov [_ES _bx],_ax + _les _bx,[diVal] + mov [_ES _bx],_di + pop es + popf ; Restore interrupt status + leave_c + ret + +cprocend + +;---------------------------------------------------------------------------- +; void PM_setMouseHandler(int mask, PM_mouseHandler mh) +;---------------------------------------------------------------------------- +cprocstart _PM_setMouseHandler + + ARG mouseMask:UINT + + enter_c + push es + + mov ax,0Ch ; AX := Function 12 - install interrupt sub + mov _cx,[mouseMask] ; CX := mouse mask + mov _dx,offset _PM_mouseISR + push cs + pop es ; ES:_DX -> mouse handler + int 33h ; Call mouse driver + + pop es + leave_c + ret + +cprocend + +;---------------------------------------------------------------------------- +; void PM_mousePMCB(void) +;---------------------------------------------------------------------------- +; Mouse realmode callback routine. Upon entry to this routine, we recieve +; the following from the DPMI server: +; +; Entry: DS:_SI -> Real mode stack at time of call +; ES:_DI -> Real mode register data structure +; SS:_SP -> Locked protected mode stack to use +;---------------------------------------------------------------------------- +cprocfar _PM_mousePMCB + + pushad + mov eax,[es:_di+1Ch] ; Load register values from real mode + mov ebx,[es:_di+10h] + mov ecx,[es:_di+18h] + mov edx,[es:_di+14h] + mov esi,[es:_di+04h] + mov edi,[es:_di] + call _PM_mouseISR ; Call the mouse handler + popad + + mov ax,[ds:_si] + mov [es:_di+2Ah],ax ; Plug in return IP address + mov ax,[ds:_si+2] + mov [es:_di+2Ch],ax ; Plug in return CS value + add [WORD es:_di+2Eh],4 ; Remove return address from stack + iret ; Go back to real mode! + +cprocend + +;---------------------------------------------------------------------------- +; void PM_int10PMCB(void) +;---------------------------------------------------------------------------- +; int10 realmode callback routine. Upon entry to this routine, we recieve +; the following from the DPMI server: +; +; Entry: DS:ESI -> Real mode stack at time of call +; ES:EDI -> Real mode register data structure +; SS:ESP -> Locked protected mode stack to use +;---------------------------------------------------------------------------- +cprocfar _PM_int10PMCB + + pushad + push ds + push es + push fs + + pushfd + pop eax + mov [es:edi+20h],ax ; Save return flag status + mov ax,[ds:esi] + mov [es:edi+2Ah],ax ; Plug in return IP address + mov ax,[ds:esi+2] + mov [es:edi+2Ch],ax ; Plug in return CS value + add [WORD es:edi+2Eh],4 ; Remove return address from stack + +; Call the install int10 handler in protected mode. This function gets called +; with DS set to the current data selector, and ES:EDI pointing the the +; real mode DPMI register structure at the time of the interrupt. The +; handle must be written in assembler to be able to extract the real mode +; register values from the structure + + push es + pop fs ; FS:EDI -> real mode registers + LOAD_DS + NEWSTK Int10Stack ; Switch to local stack + + call [_PM_int10Handler] + + RESTSTK Int10Stack ; Restore previous stack + pop fs + pop es + pop ds + popad + iret ; Go back to real mode! + +cprocend + +cpublic _PM_pmsmxCodeEnd + +endcodeseg _pmsmx + + END ; End of module diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_vflat.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_vflat.asm new file mode 100644 index 0000000..34985a9 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_vflat.asm @@ -0,0 +1,652 @@ +;**************************************************************************** +;* +;* 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. +;* +;* ======================================================================== +;* +;* Based on original code Copyright 1994 Otto Chrons +;* +;* Language: 80386 Assembler, TASM 4.0 or later +;* Environment: IBM PC 32 bit protected mode +;* +;* Description: Low level page fault handler for virtual linear framebuffers. +;* +;**************************************************************************** + + IDEAL + JUMPS + +include "scitech.mac" ; Memory model macros + +header _vflat ; Set up memory model + +VFLAT_START EQU 0F0000000h +VFLAT_END EQU 0F03FFFFFh +PAGE_PRESENT EQU 1 +PAGE_NOTPRESENT EQU 0 +PAGE_READ EQU 0 +PAGE_WRITE EQU 2 + +ifdef DOS4GW + +;---------------------------------------------------------------------------- +; DOS4G/W flat linear framebuffer emulation. +;---------------------------------------------------------------------------- + +begdataseg _vflat + +; Near pointers to the page directory base and our page tables. All of +; this memory is always located in the first Mb of DOS memory. + +PDBR dd 0 ; Page directory base register (CR3) +accessPageAddr dd 0 +accessPageTable dd 0 + +; CauseWay page directory & 1st page table linear addresses. + +CauseWayDIRLinear dd 0 +CauseWay1stLinear dd 0 + +; Place to store a copy of the original Page Table Directory before we +; intialised our virtual buffer code. + +pageDirectory: resd 1024 ; Saved page table directory + +ValidCS dw 0 ; Valid CS for page faults +Ring0CS dw 0 ; Our ring 0 code selector +LastPage dd 0 ; Last page we mapped in +BankFuncBuf: resb 101 ; Place to store bank switch code +BankFuncPtr dd offset BankFuncBuf + +INT14Gate: +INT14Offset dd 0 ; eip of original vector +INT14Selector dw 0 ; cs of original vector + + cextern _PM_savedDS,USHORT + cextern VF_haveCauseWay,BOOL + +enddataseg _vflat + +begcodeseg _vflat ; Start of code segment + + cextern VF_malloc,FPTR + +;---------------------------------------------------------------------------- +; PF_handler64k - Page fault handler for 64k banks +;---------------------------------------------------------------------------- +; The handler below is a 32 bit ring 0 page fault handler. It receives +; control immediately after any page fault or after an IRQ6 (hardware +; interrupt). This provides the fastest possible handling of page faults +; since it jump directly here. If this is a page fault, the number +; immediately on the stack will be an error code, at offset 4 will be +; the eip of the faulting instruction, at offset 8 will be the cs of the +; faulting instruction. If it is a hardware interrupt, it will not have +; the error code and the eflags will be at offset 8. +;---------------------------------------------------------------------------- +cprocfar PF_handler64k + +; Check if this is a processor exeception or a page fault + + push eax + mov ax,[cs:ValidCS] ; Use CS override to access data + cmp [ss:esp+12],ax ; Is this a page fault? + jne @@ToOldHandler ; Nope, jump to the previous handler + +; Get address of page fault and check if within our handlers range + + mov eax,cr2 ; EBX has page fault linear address + cmp eax,VFLAT_START ; Is the fault less than ours? + jb @@ToOldHandler ; Yep, go to previous handler + cmp eax,VFLAT_END ; Is the fault more than ours? + jae @@ToOldHandler ; Yep, go to previous handler + +; This is our page fault, so we need to handle it + + pushad + push ds + push es + mov ebx,eax ; EBX := page fault address + and ebx,invert 0FFFFh ; Mask to 64k bank boundary + mov ds,[cs:_PM_savedDS]; Load segment registers + mov es,[cs:_PM_savedDS] + +; Map in the page table for our virtual framebuffer area for modification + + mov edi,[PDBR] ; EDI points to page directory + mov edx,ebx ; EDX = linear address + shr edx,22 ; EDX = offset to page directory + mov edx,[edx*4+edi] ; EDX = physical page table address + mov eax,edx + mov edx,[accessPageTable] + or eax,7 + mov [edx],eax + mov eax,cr3 + mov cr3,eax ; Update page table cache + +; Mark all pages valid for the new page fault area + + mov esi,ebx ; ESI := linear address for page + shr esi,10 + and esi,0FFFh ; Offset into page table + add esi,[accessPageAddr] +ifdef USE_NASM +%assign off 0 +%rep 16 + or [DWORD esi+off],0000000001h ; Enable pages +%assign off off+4 +%endrep +else +off = 0 +REPT 16 + or [DWORD esi+off],0000000001h ; Enable pages +off = off+4 +ENDM +endif + +; Mark all pages invalid for the previously mapped area + + xchg esi,[LastPage] ; Save last page for next page fault + test esi,esi + jz @@DoneMapping ; Dont update if first time round +ifdef USE_NASM +%assign off 0 +%rep 16 + or [DWORD esi+off],0FFFFFFFEh ; Disable pages +%assign off off+4 +%endrep +else +off = 0 +REPT 16 + and [DWORD esi+off],0FFFFFFFEh ; Disable pages +off = off+4 +ENDM +endif + +@@DoneMapping: + mov eax,cr3 + mov cr3,eax ; Flush the TLB + +; Now program the new SuperVGA starting bank address + + mov eax,ebx ; EAX := page fault address + shr eax,16 + and eax,0FFh ; Mask to 0-255 + call [BankFuncPtr] ; Call the bank switch function + + pop es + pop ds + popad + pop eax + add esp,4 ; Pop the error code from stack + iretd ; Return to faulting instruction + +@@ToOldHandler: + pop eax +ifdef USE_NASM + jmp far dword [cs:INT14Gate]; Chain to previous handler +else + jmp [FWORD cs:INT14Gate]; Chain to previous handler +endif + +cprocend + +;---------------------------------------------------------------------------- +; PF_handler4k - Page fault handler for 4k banks +;---------------------------------------------------------------------------- +; The handler below is a 32 bit ring 0 page fault handler. It receives +; control immediately after any page fault or after an IRQ6 (hardware +; interrupt). This provides the fastest possible handling of page faults +; since it jump directly here. If this is a page fault, the number +; immediately on the stack will be an error code, at offset 4 will be +; the eip of the faulting instruction, at offset 8 will be the cs of the +; faulting instruction. If it is a hardware interrupt, it will not have +; the error code and the eflags will be at offset 8. +;---------------------------------------------------------------------------- +cprocfar PF_handler4k + +; Fill in when we have tested all the 64Kb code + +ifdef USE_NASM + jmp far dword [cs:INT14Gate]; Chain to previous handler +else + jmp [FWORD cs:INT14Gate]; Chain to previous handler +endif + +cprocend + +;---------------------------------------------------------------------------- +; void InstallFaultHandler(void *baseAddr,int bankSize) +;---------------------------------------------------------------------------- +; Installes the page fault handler directly int the interrupt descriptor +; table for maximum performance. This of course requires ring 0 access, +; but none of this stuff will run without ring 0! +;---------------------------------------------------------------------------- +cprocstart InstallFaultHandler + + ARG baseAddr:ULONG, bankSize:UINT + + enter_c + + mov [DWORD LastPage],0 ; No pages have been mapped + mov ax,cs + mov [ValidCS],ax ; Save CS value for page faults + +; Put address of our page fault handler into the IDT directly + + sub esp,6 ; Allocate space on stack +ifdef USE_NASM + sidt [ss:esp] ; Store pointer to IDT +else + sidt [FWORD ss:esp] ; Store pointer to IDT +endif + pop ax ; add esp,2 + pop eax ; Absolute address of IDT + add eax,14*8 ; Point to Int #14 + +; Note that Interrupt gates do not have the high and low word of the +; offset in adjacent words in memory, there are 4 bytes separating them. + + mov ecx,[eax] ; Get cs and low 16 bits of offset + mov edx,[eax+6] ; Get high 16 bits of offset in dx + shl edx,16 + mov dx,cx ; edx has offset + mov [INT14Offset],edx ; Save offset + shr ecx,16 + mov [INT14Selector],cx ; Save original cs + mov [eax+2],cs ; Install new cs + mov edx,offset PF_handler64k + cmp [UINT bankSize],4 + jne @@1 + mov edx,offset PF_handler4k +@@1: mov [eax],dx ; Install low word of offset + shr edx,16 + mov [eax+6],dx ; Install high word of offset + + leave_c + ret + +cprocend + +;---------------------------------------------------------------------------- +; void RemoveFaultHandler(void) +;---------------------------------------------------------------------------- +; Closes down the virtual framebuffer services and restores the previous +; page fault handler. +;---------------------------------------------------------------------------- +cprocstart RemoveFaultHandler + + enter_c + +; Remove page fault handler from IDT + + sub esp,6 ; Allocate space on stack +ifdef USE_NASM + sidt [ss:esp] ; Store pointer to IDT +else + sidt [FWORD ss:esp] ; Store pointer to IDT +endif + + pop ax ; add esp,2 + pop eax ; Absolute address of IDT + add eax,14*8 ; Point to Int #14 + mov cx,[INT14Selector] + mov [eax+2],cx ; Restore original CS + mov edx,[INT14Offset] + mov [eax],dx ; Install low word of offset + shr edx,16 + mov [eax+6],dx ; Install high word of offset + + leave_c + ret + +cprocend + +;---------------------------------------------------------------------------- +; void InstallBankFunc(int codeLen,void *bankFunc) +;---------------------------------------------------------------------------- +; Installs the bank switch function by relocating it into our data segment +; and making it into a callable function. We do it this way to make the +; code identical to the way that the VflatD devices work under Windows. +;---------------------------------------------------------------------------- +cprocstart InstallBankFunc + + ARG codeLen:UINT, bankFunc:DPTR + + enter_c + + mov esi,[bankFunc] ; Copy the code into buffer + mov edi,offset BankFuncBuf + mov ecx,[codeLen] + rep movsb + mov [BYTE edi],0C3h ; Terminate the function with a near ret + + leave_c + ret + +cprocend + +;---------------------------------------------------------------------------- +; int InitPaging(void) +;---------------------------------------------------------------------------- +; Initializes paging system. If paging is not enabled, builds a page table +; directory and page tables for physical memory +; +; Exit: 0 - Successful +; -1 - Couldn't initialize paging mechanism +;---------------------------------------------------------------------------- +cprocstart InitPaging + + push ebx + push ecx + push edx + push esi + push edi + +; Are we running under CauseWay? + + mov ax,0FFF9h + int 31h + jc @@NotCauseway + cmp ecx,"CAUS" + jnz @@NotCauseway + cmp edx,"EWAY" + jnz @@NotCauseway + + mov [BOOL VF_haveCauseWay],1 + mov [CauseWayDIRLinear],esi + mov [CauseWay1stLinear],edi + +; Check for DPMI + + mov ax,0ff00h + push es + int 31h + pop es + shr edi,2 + and edi,3 + cmp edi,2 + jz @@ErrExit ; Not supported under DPMI + + mov eax,[CauseWayDIRLinear] + jmp @@CopyCR3 + +@@NotCauseway: + mov ax,cs + test ax,3 ; Which ring are we running + jnz @@ErrExit ; Needs zero ring to access + ; page tables (CR3) + mov eax,cr0 ; Load CR0 + test eax,80000000h ; Is paging enabled? + jz @@ErrExit ; No, we must have paging! + + mov eax,cr3 ; Load directory address + and eax,0FFFFF000h + +@@CopyCR3: + mov [PDBR],eax ; Save it + mov esi,eax + mov edi,offset pageDirectory + mov ecx,1024 + cld + rep movsd ; Copy the original page table directory + cmp [DWORD accessPageAddr],0; Check if we have allocated page + jne @@HaveRealMem ; table already (we cant free it) + + mov eax,0100h ; DPMI DOS allocate + mov ebx,8192/16 + int 31h ; Allocate 8192 bytes + and eax,0FFFFh + shl eax,4 ; EAX points to newly allocated memory + add eax,4095 + and eax,0FFFFF000h ; Page align + mov [accessPageAddr],eax + +@@HaveRealMem: + mov eax,[accessPageAddr] ; EAX -> page table in 1st Mb + shr eax,12 + and eax,3FFh ; Page table offset + shl eax,2 + cmp [BOOL VF_haveCauseWay],0 + jz @@NotCW0 + mov ebx,[CauseWay1stLinear] + jmp @@Put1st + +@@NotCW0: + mov ebx,[PDBR] + mov ebx,[ebx] + and ebx,0FFFFF000h ; Page table for 1st megabyte + +@@Put1st: + add eax,ebx + mov [accessPageTable],eax + sub eax,eax ; No error + jmp @@Exit + +@@ErrExit: + mov eax,-1 + +@@Exit: pop edi + pop esi + pop edx + pop ecx + pop ebx + ret + +cprocend + +;---------------------------------------------------------------------------- +; void ClosePaging(void) +;---------------------------------------------------------------------------- +; Closes the paging system +;---------------------------------------------------------------------------- +cprocstart ClosePaging + + push eax + push ecx + push edx + push esi + push edi + + mov eax,[accessPageAddr] + call AccessPage ; Restore AccessPage mapping + mov edi,[PDBR] + mov esi,offset pageDirectory + mov ecx,1024 + cld + rep movsd ; Restore the original page table directory + +@@Exit: pop edi + pop esi + pop edx + pop ecx + pop eax + ret + +cprocend + +;---------------------------------------------------------------------------- +; long AccessPage(long phys) +;---------------------------------------------------------------------------- +; Maps a known page to given physical memory +; Entry: EAX - Physical memory +; Exit: EAX - Linear memory address of mapped phys mem +;---------------------------------------------------------------------------- +cprocstatic AccessPage + + push edx + mov edx,[accessPageTable] + or eax,7 + mov [edx],eax + mov eax,cr3 + mov cr3,eax ; Update page table cache + mov eax,[accessPageAddr] + pop edx + ret + +cprocend + +;---------------------------------------------------------------------------- +; long GetPhysicalAddress(long linear) +;---------------------------------------------------------------------------- +; Returns the physical address of linear address +; Entry: EAX - Linear address to convert +; Exit: EAX - Physical address +;---------------------------------------------------------------------------- +cprocstatic GetPhysicalAddress + + push ebx + push edx + mov edx,eax + shr edx,22 ; EDX is the directory offset + mov ebx,[PDBR] + mov edx,[edx*4+ebx] ; Load page table address + push eax + mov eax,edx + call AccessPage ; Access the page table + mov edx,eax + pop eax + shr eax,12 + and eax,03FFh ; EAX offset into page table + mov eax,[edx+eax*4] ; Load physical address + and eax,0FFFFF000h + pop edx + pop ebx + ret + +cprocend + +;---------------------------------------------------------------------------- +; void CreatePageTable(long pageDEntry) +;---------------------------------------------------------------------------- +; Creates a page table for specific address (4MB) +; Entry: EAX - Page directory entry (top 10-bits of address) +;---------------------------------------------------------------------------- +cprocstatic CreatePageTable + + push ebx + push ecx + push edx + push edi + mov ebx,eax ; Save address + mov eax,8192 + push eax + call VF_malloc ; Allocate page table directory + add esp,4 + add eax,0FFFh + and eax,0FFFFF000h ; Page align (4KB) + mov edi,eax ; Save page table linear address + sub eax,eax ; Fill with zero + mov ecx,1024 + cld + rep stosd ; Clear page table + sub edi,4096 + mov eax,edi + call GetPhysicalAddress + mov edx,[PDBR] + or eax,7 ; Present/write/user bit + mov [edx+ebx*4],eax ; Save physical address into page directory + mov eax,cr3 + mov cr3,eax ; Update page table cache + pop edi + pop edx + pop ecx + pop ebx + ret + +cprocend + +;---------------------------------------------------------------------------- +; void MapPhysical2Linear(ulong pAddr, ulong lAddr, int pages, int flags); +;---------------------------------------------------------------------------- +; Maps physical memory into linear memory +; Entry: pAddr - Physical address +; lAddr - Linear address +; pages - Number of 4K pages to map +; flags - Page flags +; bit 0 = present +; bit 1 = Read(0)/Write(1) +;---------------------------------------------------------------------------- +cprocstart MapPhysical2Linear + + ARG pAddr:ULONG, lAddr:ULONG, pages:UINT, pflags:UINT + + enter_c + + and [ULONG pAddr],0FFFFF000h; Page boundary + and [ULONG lAddr],0FFFFF000h; Page boundary + mov ecx,[pflags] + and ecx,11b ; Just two bits + or ecx,100b ; Supervisor bit + mov [pflags],ecx + + mov edx,[lAddr] + shr edx,22 ; EDX = Directory + mov esi,[PDBR] + mov edi,[pages] ; EDI page count + mov ebx,[lAddr] + +@@CreateLoop: + mov ecx,[esi+edx*4] ; Load page table address + test ecx,1 ; Is it present? + jnz @@TableOK + mov eax,edx + call CreatePageTable ; Create a page table +@@TableOK: + mov eax,ebx + shr eax,12 + and eax,3FFh + sub eax,1024 + neg eax ; EAX = page count in this table + inc edx ; Next table + mov ebx,0 ; Next time we'll map 1K pages + sub edi,eax ; Subtract mapped pages from page count + jns @@CreateLoop ; Create more tables if necessary + + mov ecx,[pages] ; ECX = Page count + mov esi,[lAddr] + shr esi,12 ; Offset part isn't needed + mov edi,[pAddr] +@@MappingLoop: + mov eax,esi + shr eax,10 ; EAX = offset to page directory + mov ebx,[PDBR] + mov eax,[eax*4+ebx] ; EAX = page table address + call AccessPage + mov ebx,esi + and ebx,3FFh ; EBX = offset to page table + mov edx,edi + add edi,4096 ; Next physical address + inc esi ; Next linear page + or edx,[pflags] ; Update flags... + mov [eax+ebx*4],edx ; Store page table entry + loop @@MappingLoop + mov eax,cr3 + mov cr3,eax ; Update page table cache + + leave_c + ret + +cprocend + +endcodeseg _vflat + +endif + + END ; End of module diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/smx/cpuinfo.c new file mode 100644 index 0000000..5447e57 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/cpuinfo.c @@ -0,0 +1,72 @@ +/**************************************************************************** +* +* Ultra Long Period Timer +* +* ======================================================================== +* +* 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: ANSI C +* Environment: 32-bit SMX embedded systems development. +* +* Description: SMX specific code for the CPU detection module. +* +****************************************************************************/ + +/*----------------------------- Implementation ----------------------------*/ + +/* External timing function */ + +void __ZTimerInit(void); + +/**************************************************************************** +REMARKS: +Do nothing for DOS because we don't have thread priorities. +****************************************************************************/ +#define SetMaxThreadPriority() 0 + +/**************************************************************************** +REMARKS: +Do nothing for DOS because we don't have thread priorities. +****************************************************************************/ +#define RestoreThreadPriority(i) (void)(i) + +/**************************************************************************** +REMARKS: +Initialise the counter and return the frequency of the counter. +****************************************************************************/ +static void GetCounterFrequency( + CPU_largeInteger *freq) +{ + ulong resolution; + + __ZTimerInit(); + ULZTimerResolution(&resolution); + freq->low = (ulong)(10000000000.0 / resolution); + freq->high = 0; +} + +/**************************************************************************** +REMARKS: +Read the counter and return the counter value. +****************************************************************************/ +#define GetCounter(t) \ +{ \ + (t)->low = ULZReadTime() * 10000L; \ + (t)->high = 0; \ +} diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/event.c b/board/MAI/bios_emulator/scitech/src/pm/smx/event.c new file mode 100644 index 0000000..fc13bbb --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/event.c @@ -0,0 +1,368 @@ +/**************************************************************************** +* +* 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: ANSI C +* Environment: 32-bit SMX embedded systems development +* +* Description: 32-bit SMX implementation for the SciTech cross platform +* event library. +* +****************************************************************************/ + +#include "smx/ps2mouse.h" + +/*--------------------------- Global variables ----------------------------*/ + +ibool _VARAPI _EVT_useEvents = true; /* True to use event handling */ +ibool _VARAPI _EVT_installed = 0; /* Event handers installed? */ +uchar _VARAPI *_EVT_biosPtr = NULL; /* Pointer to the BIOS data area */ +static ibool haveMouse = false; /* True if we have a mouse */ + +/*---------------------------- Implementation -----------------------------*/ + +/* External assembler functions */ + +void EVTAPI _EVT_pollJoystick(void); +uint EVTAPI _EVT_disableInt(void); +uint EVTAPI _EVT_restoreInt(uint flags); +void EVTAPI _EVT_codeStart(void); +void EVTAPI _EVT_codeEnd(void); +void EVTAPI _EVT_cCodeStart(void); +void EVTAPI _EVT_cCodeEnd(void); +int EVTAPI _EVT_getKeyCode(void); +int EVTAPI EVT_rdinx(int port,int index); +void EVTAPI EVT_wrinx(int port,int index,int value); + +/**************************************************************************** +REMARKS: +Do nothing for DOS, because we are fully interrupt driven. +****************************************************************************/ +#define _EVT_pumpMessages() + +/**************************************************************************** +REMARKS: +This function is used to return the number of ticks since system +startup in milliseconds. This should be the same value that is placed into +the time stamp fields of events, and is used to implement auto mouse down +events. +****************************************************************************/ +ulong _EVT_getTicks(void) +{ + return (ulong)PM_getLong(_EVT_biosPtr+0x6C) * 55UL; +} + +/**************************************************************************** +REMARKS: +Include generic raw scancode keyboard module. +****************************************************************************/ +#include "common/keyboard.c" + +/**************************************************************************** +REMARKS: +Determines if we have a mouse attached and functioning. +****************************************************************************/ +static ibool detectMouse(void) +{ + return(ps2Query()); +} + +/**************************************************************************** +PARAMETERS: +what - Event code +message - Event message +x,y - Mouse position at time of event +but_stat - Mouse button status at time of event + +REMARKS: +Adds a new mouse event to the event queue. This routine is called from within +the mouse interrupt subroutine, so it must be efficient. + +NOTE: Interrupts MUST be OFF while this routine is called to ensure we have + mutually exclusive access to our internal data structures for + interrupt driven systems (like under DOS). +****************************************************************************/ +static void addMouseEvent( + uint what, + uint message, + int x, + int y, + int mickeyX, + int mickeyY, + uint but_stat) +{ + event_t evt; + + if (EVT.count < EVENTQSIZE) { + /* Save information in event record. */ + evt.when = _EVT_getTicks(); + evt.what = what; + evt.message = message; + evt.modifiers = but_stat; + evt.where_x = x; /* Save mouse event position */ + evt.where_y = y; + evt.relative_x = mickeyX; + evt.relative_y = mickeyY; + evt.modifiers |= EVT.keyModifiers; + addEvent(&evt); /* Add to tail of event queue */ + } +} + +/**************************************************************************** +PARAMETERS: +mask - Event mask +butstate - Button state +x - Mouse x coordinate +y - Mouse y coordinate + +REMARKS: +Mouse event handling routine. This gets called when a mouse event occurs, +and we call the addMouseEvent() routine to add the appropriate mouse event +to the event queue. + +Note: Interrupts are ON when this routine is called by the mouse driver code. +//AM: NOTE: This function has not actually been ported from DOS yet and should not +//AM: be installed until it is. +****************************************************************************/ +static void EVTAPI mouseISR( + uint mask, + uint butstate, + int x, + int y, + int mickeyX, + int mickeyY) +{ + RMREGS regs; + uint ps; + + if (mask & 1) { + /* Save the current mouse coordinates */ + EVT.mx = x; EVT.my = y; + + /* If the last event was a movement event, then modify the last + * event rather than post a new one, so that the queue will not + * become saturated. Before we modify the data structures, we + * MUST ensure that interrupts are off. + */ + ps = _EVT_disableInt(); + if (EVT.oldMove != -1) { + EVT.evtq[EVT.oldMove].where_x = x; /* Modify existing one */ + EVT.evtq[EVT.oldMove].where_y = y; + EVT.evtq[EVT.oldMove].relative_x += mickeyX; + EVT.evtq[EVT.oldMove].relative_y += mickeyY; + } + else { + EVT.oldMove = EVT.freeHead; /* Save id of this move event */ + addMouseEvent(EVT_MOUSEMOVE,0,x,y,mickeyX,mickeyY,butstate); + } + _EVT_restoreInt(ps); + } + if (mask & 0x2A) { + ps = _EVT_disableInt(); + addMouseEvent(EVT_MOUSEDOWN,mask >> 1,x,y,0,0,butstate); + EVT.oldMove = -1; + _EVT_restoreInt(ps); + } + if (mask & 0x54) { + ps = _EVT_disableInt(); + addMouseEvent(EVT_MOUSEUP,mask >> 2,x,y,0,0,butstate); + EVT.oldMove = -1; + _EVT_restoreInt(ps); + } + EVT.oldKey = -1; +} + +/**************************************************************************** +REMARKS: +Keyboard interrupt handler function. + +NOTE: Interrupts are OFF when this routine is called by the keyboard ISR, + and we leave them OFF the entire time. This has been modified to work + in conjunction with smx keyboard handler. +****************************************************************************/ +static void EVTAPI keyboardISR(void) +{ + PM_chainPrevKey(); + processRawScanCode(PM_inpb(0x60)); + PM_outpb(0x20,0x20); +} + +/**************************************************************************** +REMARKS: +Safely abort the event module upon catching a fatal error. +****************************************************************************/ +void _EVT_abort() +{ + EVT_exit(); + PM_fatalError("Unhandled exception!"); +} + +/**************************************************************************** +PARAMETERS: +mouseMove - Callback function to call wheneve the mouse needs to be moved + +REMARKS: +Initiliase the event handling module. Here we install our mouse handling ISR +to be called whenever any button's are pressed or released. We also build +the free list of events in the event queue. + +We use handler number 2 of the mouse libraries interrupt handlers for our +event handling routines. +****************************************************************************/ +void EVTAPI EVT_init( + _EVT_mouseMoveHandler mouseMove) +{ + int i; + + EVT.mouseMove = mouseMove; + _EVT_biosPtr = PM_getBIOSPointer(); + EVT_resume(); +} + +/**************************************************************************** +REMARKS: +Initiailises the internal event handling modules. The EVT_suspend function +can be called to suspend event handling (such as when shelling out to DOS), +and this function can be used to resume it again later. +****************************************************************************/ +void EVTAPI EVT_resume(void) +{ + static int locked = 0; + int stat; + uchar mods; + PM_lockHandle lh; + + if (_EVT_useEvents) { + /* Initialise the event queue and enable our interrupt handlers */ + initEventQueue(); + PM_setKeyHandler(keyboardISR); + if ((haveMouse = detectMouse()) != 0) + PM_setMouseHandler(0xFFFF,mouseISR); + + /* Read the keyboard modifier flags from the BIOS to get the + * correct initialisation state. The only state we care about is + * the correct toggle state flags such as SCROLLLOCK, NUMLOCK and + * CAPSLOCK. + */ + EVT.keyModifiers = 0; + mods = PM_getByte(_EVT_biosPtr+0x17); + if (mods & 0x10) + EVT.keyModifiers |= EVT_SCROLLLOCK; + if (mods & 0x20) + EVT.keyModifiers |= EVT_NUMLOCK; + if (mods & 0x40) + EVT.keyModifiers |= EVT_CAPSLOCK; + + /* Lock all of the code and data used by our protected mode interrupt + * handling routines, so that it will continue to work correctly + * under real mode. + */ + if (!locked) { + /* It is difficult to ensure that we lock our global data, so we + * do this by taking the address of a variable locking all data + * 2Kb on either side. This should properly cover the global data + * used by the module (the other alternative is to declare the + * variables in assembler, in which case we know it will be + * correct). + */ + stat = !PM_lockDataPages(&EVT,sizeof(EVT),&lh); + stat |= !PM_lockDataPages(&_EVT_biosPtr,sizeof(_EVT_biosPtr),&lh); + stat |= !PM_lockCodePages((__codePtr)_EVT_cCodeStart,(int)_EVT_cCodeEnd-(int)_EVT_cCodeStart,&lh); + stat |= !PM_lockCodePages((__codePtr)_EVT_codeStart,(int)_EVT_codeEnd-(int)_EVT_codeStart,&lh); + if (stat) { + PM_fatalError("Page locking services failed - interrupt handling not safe!"); + exit(1); + } + locked = 1; + } + + _EVT_installed = true; + } +} + +/**************************************************************************** +REMARKS +Changes the range of coordinates returned by the mouse functions to the +specified range of values. This is used when changing between graphics +modes set the range of mouse coordinates for the new display mode. +****************************************************************************/ +void EVTAPI EVT_setMouseRange( + int xRes, + int yRes) +{ + if (haveMouse) { + ps2MouseStop(); + ps2MouseStart( 0, xRes, 0, yRes, -1, -1, -1); + } +} + +/**************************************************************************** +REMARKS +Modifes the mouse coordinates as necessary if scaling to OS coordinates, +and sets the OS mouse cursor position. +****************************************************************************/ +void _EVT_setMousePos( + int *x, + int *y) +{ + if (haveMouse) + ps2MouseMove(*x, *y); +} + +/**************************************************************************** +REMARKS +Suspends all of our event handling operations. This is also used to +de-install the event handling code. +****************************************************************************/ +void EVTAPI EVT_suspend(void) +{ + uchar mods; + + if (_EVT_installed) { + PM_restoreKeyHandler(); + if (haveMouse) + PM_restoreMouseHandler(); + + /* Set the keyboard modifier flags in the BIOS to our values */ + EVT_allowLEDS(true); + mods = PM_getByte(_EVT_biosPtr+0x17) & ~0x70; + if (EVT.keyModifiers & EVT_SCROLLLOCK) + mods |= 0x10; + if (EVT.keyModifiers & EVT_NUMLOCK) + mods |= 0x20; + if (EVT.keyModifiers & EVT_CAPSLOCK) + mods |= 0x40; + PM_setByte(_EVT_biosPtr+0x17,mods); + + /* Flag that we are no longer installed */ + _EVT_installed = false; + } +} + +/**************************************************************************** +REMARKS +Exits the event module for program terminatation. +****************************************************************************/ +void EVTAPI EVT_exit(void) +{ + EVT_suspend(); +} diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/smx/oshdr.h new file mode 100644 index 0000000..3ff8daa --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/oshdr.h @@ -0,0 +1,29 @@ +/**************************************************************************** +* +* 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: ANSI C +* Environment: 32-bit SMX embedded systems development. +* +* Description: Include file to include all OS specific header files. +* +****************************************************************************/ diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/pm.c b/board/MAI/bios_emulator/scitech/src/pm/smx/pm.c new file mode 100644 index 0000000..d6c95d6 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/pm.c @@ -0,0 +1,1187 @@ +/**************************************************************************** +* +* 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: ANSI C +* Environment: 32 bit SMX embedded systems development. +* +* Description: Implementation for the OS Portability Manager Library, which +* contains functions to implement OS specific services in a +* generic, cross platform API. Porting the OS Portability +* Manager library is the first step to porting any SciTech +* products to a new platform. +* +****************************************************************************/ + +#include "pmapi.h" +#include "drvlib/os/os.h" +#include "ztimerc.h" +#include "event.h" +#include "mtrr.h" +#include "pm_help.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dos.h> +#include <conio.h> +#ifdef __GNUC__ +#include <unistd.h> +#include <sys/nearptr.h> +#include <sys/stat.h> +#else +#include <direct.h> +#endif +#ifdef __BORLANDC__ +#pragma warn -par +#endif + +/*--------------------------- Global variables ----------------------------*/ + +typedef struct { + int oldMode; + int old50Lines; + } DOS_stateBuf; + +#define MAX_RM_BLOCKS 10 + +static struct { + void *p; + uint tag; + } rmBlocks[MAX_RM_BLOCKS]; + +static uint VESABuf_len = 1024; /* Length of the VESABuf buffer */ +static void *VESABuf_ptr = NULL; /* Near pointer to VESABuf */ +static uint VESABuf_rseg; /* Real mode segment of VESABuf */ +static uint VESABuf_roff; /* Real mode offset of VESABuf */ +static void (PMAPIP fatalErrorCleanup)(void) = NULL; +ushort _VARAPI _PM_savedDS = 0; +static ulong PDB = 0,*pPDB = NULL; +static uint VXD_version = -1; + +/*----------------------------- Implementation ----------------------------*/ + +ulong _ASMAPI _PM_getPDB(void); +void _ASMAPI _PM_VxDCall(VXD_regs *regs,uint off,uint sel); + +/**************************************************************************** +REMARKS: +External function to call the PMHELP helper VxD. +****************************************************************************/ +void PMAPI PM_VxDCall( + VXD_regs *regs) +{ +} + +/**************************************************************************** +RETURNS: +BCD coded version number of the VxD, or 0 if not loaded (ie: 0x202 - 2.2) + +REMARKS: +This function gets the version number for the VxD that we have connected to. +****************************************************************************/ +uint PMAPI PMHELP_getVersion(void) +{ + return VXD_version = 0; +} + +void PMAPI PM_init(void) +{ +#ifndef REALMODE + MTRR_init(); +#endif +} + +/**************************************************************************** +PARAMETERS: +base - The starting physical base address of the region +size - The size in bytes of the region +type - Type to place into the MTRR register + +RETURNS: +Error code describing the result. + +REMARKS: +Function to enable write combining for the specified region of memory. +****************************************************************************/ +int PMAPI PM_enableWriteCombine( + ulong base, + ulong size, + uint type) +{ +#ifndef REALMODE + return MTRR_enableWriteCombine(base,size,type); +#else + return PM_MTRR_NOT_SUPPORTED; +#endif +} + +ibool PMAPI PM_haveBIOSAccess(void) +{ return false; } + +long PMAPI PM_getOSType(void) +{ return _OS_SMX; } + +int PMAPI PM_getModeType(void) +{ return PM_386; } + +void PMAPI PM_backslash(char *s) +{ + uint pos = strlen(s); + if (s[pos-1] != '\\') { + s[pos] = '\\'; + s[pos+1] = '\0'; + } +} + +void PMAPI PM_setFatalErrorCleanup( + void (PMAPIP cleanup)(void)) +{ + fatalErrorCleanup = cleanup; +} + +void MGLOutput(char *); + +void PMAPI PM_fatalError(const char *msg) +{ + if (fatalErrorCleanup) + fatalErrorCleanup(); + MGLOutput(msg); +// No support for fprintf() under smx currently! +// fprintf(stderr,"%s\n", msg); + exit(1); +} + +static void ExitVBEBuf(void) +{ + if (VESABuf_ptr) + PM_freeRealSeg(VESABuf_ptr); + VESABuf_ptr = 0; +} + +void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff) +{ + if (!VESABuf_ptr) { + /* Allocate a global buffer for communicating with the VESA VBE */ + if ((VESABuf_ptr = PM_allocRealSeg(VESABuf_len, &VESABuf_rseg, &VESABuf_roff)) == NULL) + return NULL; + atexit(ExitVBEBuf); + } + *len = VESABuf_len; + *rseg = VESABuf_rseg; + *roff = VESABuf_roff; + return VESABuf_ptr; +} + +int PMAPI PM_int386(int intno, PMREGS *in, PMREGS *out) +{ + PMSREGS sregs; + PM_segread(&sregs); + return PM_int386x(intno,in,out,&sregs); +} + +/* Routines to set and get the real mode interrupt vectors, by making + * direct real mode calls to DOS and bypassing the DOS extenders API. + * This is the safest way to handle this, as some servers try to be + * smart about changing real mode vectors. + */ + +void PMAPI _PM_getRMvect(int intno, long *realisr) +{ + RMREGS regs; + RMSREGS sregs; + + PM_saveDS(); + regs.h.ah = 0x35; + regs.h.al = intno; + PM_int86x(0x21, ®s, ®s, &sregs); + *realisr = ((long)sregs.es << 16) | regs.x.bx; +} + +void PMAPI _PM_setRMvect(int intno, long realisr) +{ + RMREGS regs; + RMSREGS sregs; + + PM_saveDS(); + regs.h.ah = 0x25; + regs.h.al = intno; + sregs.ds = (int)(realisr >> 16); + regs.x.dx = (int)(realisr & 0xFFFF); + PM_int86x(0x21, ®s, ®s, &sregs); +} + +void PMAPI _PM_addRealModeBlock(void *mem,uint tag) +{ + int i; + + for (i = 0; i < MAX_RM_BLOCKS; i++) { + if (rmBlocks[i].p == NULL) { + rmBlocks[i].p = mem; + rmBlocks[i].tag = tag; + return; + } + } + PM_fatalError("To many real mode memory block allocations!"); +} + +uint PMAPI _PM_findRealModeBlock(void *mem) +{ + int i; + + for (i = 0; i < MAX_RM_BLOCKS; i++) { + if (rmBlocks[i].p == mem) + return rmBlocks[i].tag; + } + PM_fatalError("Could not find prior real mode memory block allocation!"); + return 0; +} + +char * PMAPI PM_getCurrentPath( + char *path, + int maxLen) +{ + return getcwd(path,maxLen); +} + +char PMAPI PM_getBootDrive(void) +{ return 'C'; } + +const char * PMAPI PM_getVBEAFPath(void) +{ return "c:\\"; } + +const char * PMAPI PM_getNucleusPath(void) +{ + static char path[256]; + char *env; + + if ((env = getenv("NUCLEUS_PATH")) != NULL) + return env; + return "c:\\nucleus"; +} + +const char * PMAPI PM_getNucleusConfigPath(void) +{ + static char path[256]; + strcpy(path,PM_getNucleusPath()); + PM_backslash(path); + strcat(path,"config"); + return path; +} + +const char * PMAPI PM_getUniqueID(void) +{ return "SMX"; } + +const char * PMAPI PM_getMachineName(void) +{ return "SMX"; } + +int PMAPI PM_kbhit(void) +{ + int hit; + event_t evt; + + hit = EVT_peekNext(&evt,EVT_KEYDOWN | EVT_KEYREPEAT); + EVT_flush(~(EVT_KEYDOWN | EVT_KEYREPEAT)); + return hit; +} + +int PMAPI PM_getch(void) +{ + event_t evt; + + EVT_halt(&evt,EVT_KEYDOWN); + return EVT_asciiCode(evt.message); +} + +PM_HWND PMAPI PM_openConsole(PM_HWND hwndUser,int device,int xRes,int yRes,int bpp,ibool fullScreen) +{ + /* Not used for SMX */ + (void)hwndUser; + (void)device; + (void)xRes; + (void)yRes; + (void)bpp; + (void)fullScreen; + return 0; +} + +int PMAPI PM_getConsoleStateSize(void) +{ + return sizeof(DOS_stateBuf); +} + +void PMAPI PM_saveConsoleState(void *stateBuf,PM_HWND hwndConsole) +{ + RMREGS regs; + DOS_stateBuf *sb = stateBuf; + + /* Save the old video mode state */ + regs.h.ah = 0x0F; + PM_int86(0x10,®s,®s); + sb->oldMode = regs.h.al & 0x7F; + sb->old50Lines = false; + if (sb->oldMode == 0x3) { + regs.x.ax = 0x1130; + regs.x.bx = 0; + regs.x.dx = 0; + PM_int86(0x10,®s,®s); + sb->old50Lines = (regs.h.dl == 42 || regs.h.dl == 49); + } + (void)hwndConsole; +} + +void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags)) +{ + /* Not used for SMX */ + (void)saveState; +} + +void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND hwndConsole) +{ + RMREGS regs; + const DOS_stateBuf *sb = stateBuf; + + /* Retore 50 line mode if set */ + if (sb->old50Lines) { + regs.x.ax = 0x1112; + regs.x.bx = 0; + PM_int86(0x10,®s,®s); + } + (void)hwndConsole; +} + +void PMAPI PM_closeConsole(PM_HWND hwndConsole) +{ + /* Not used for SMX */ + (void)hwndConsole; +} + +void PMAPI PM_setOSCursorLocation(int x,int y) +{ + uchar *_biosPtr = PM_getBIOSPointer(); + PM_setByte(_biosPtr+0x50,x); + PM_setByte(_biosPtr+0x51,y); +} + +void PMAPI PM_setOSScreenWidth(int width,int height) +{ + uchar *_biosPtr = PM_getBIOSPointer(); + PM_setWord(_biosPtr+0x4A,width); + PM_setWord(_biosPtr+0x4C,width*2); + PM_setByte(_biosPtr+0x84,height-1); + if (height > 25) { + PM_setWord(_biosPtr+0x60,0x0607); + PM_setByte(_biosPtr+0x85,0x08); + } + else { + PM_setWord(_biosPtr+0x60,0x0D0E); + PM_setByte(_biosPtr+0x85,0x016); + } +} + +void * PMAPI PM_mallocShared(long size) +{ + return PM_malloc(size); +} + +void PMAPI PM_freeShared(void *ptr) +{ + PM_free(ptr); +} + +#define GetRMVect(intno,isr) *(isr) = ((ulong*)rmZeroPtr)[intno] +#define SetRMVect(intno,isr) ((ulong*)rmZeroPtr)[intno] = (isr) + +ibool PMAPI PM_doBIOSPOST( + ushort axVal, + ulong BIOSPhysAddr, + void *mappedBIOS, + ulong BIOSLen) +{ + static int firstTime = true; + static uchar *rmZeroPtr; + long Current10,Current6D,Current42; + RMREGS regs; + RMSREGS sregs; + + /* Create a zero memory mapping for us to use */ + if (firstTime) { + rmZeroPtr = PM_mapPhysicalAddr(0,0x7FFF,true); + firstTime = false; + } + + /* Remap the secondary BIOS to 0xC0000 physical */ + if (BIOSPhysAddr != 0xC0000L || BIOSLen > 32768) { + /* SMX cannot virtually remap the BIOS, so we can only work if all + * the secondary controllers are identical, and we then use the + * BIOS on the first controller for all the remaining controllers. + * + * For OS'es that do virtual memory, and remapping of 0xC0000 + * physical (perhaps a copy on write mapping) should be all that + * is needed. + */ + return false; + } + + /* Save current handlers of int 10h and 6Dh */ + GetRMVect(0x10,&Current10); + GetRMVect(0x6D,&Current6D); + + /* POST the secondary BIOS */ + GetRMVect(0x42,&Current42); + SetRMVect(0x10,Current42); /* Restore int 10h to STD-BIOS */ + regs.x.ax = axVal; + PM_callRealMode(0xC000,0x0003,®s,&sregs); + + /* Restore current handlers */ + SetRMVect(0x10,Current10); + SetRMVect(0x6D,Current6D); + + /* Second the primary BIOS mappin 1:1 for 0xC0000 physical */ + if (BIOSPhysAddr != 0xC0000L) { + /* SMX does not support this */ + (void)mappedBIOS; + } + return true; +} + +void PMAPI PM_sleep(ulong milliseconds) +{ + ulong microseconds = milliseconds * 1000L; + LZTimerObject tm; + + LZTimerOnExt(&tm); + while (LZTimerLapExt(&tm) < microseconds) + ; + LZTimerOffExt(&tm); +} + +int PMAPI PM_getCOMPort(int port) +{ + switch (port) { + case 0: return 0x3F8; + case 1: return 0x2F8; + } + return 0; +} + +int PMAPI PM_getLPTPort(int port) +{ + switch (port) { + case 0: return 0x3BC; + case 1: return 0x378; + case 2: return 0x278; + } + return 0; +} + +PM_MODULE PMAPI PM_loadLibrary( + const char *szDLLName) +{ + (void)szDLLName; + return NULL; +} + +void * PMAPI PM_getProcAddress( + PM_MODULE hModule, + const char *szProcName) +{ + (void)hModule; + (void)szProcName; + return NULL; +} + +void PMAPI PM_freeLibrary( + PM_MODULE hModule) +{ + (void)hModule; +} + +int PMAPI PM_setIOPL( + int level) +{ + return level; +} + +/**************************************************************************** +REMARKS: +Internal function to convert the find data to the generic interface. +****************************************************************************/ +static void convertFindData( + PM_findData *findData, + struct find_t *blk) +{ + ulong dwSize = findData->dwSize; + + memset(findData,0,findData->dwSize); + findData->dwSize = dwSize; + if (blk->attrib & _A_RDONLY) + findData->attrib |= PM_FILE_READONLY; + if (blk->attrib & _A_SUBDIR) + findData->attrib |= PM_FILE_DIRECTORY; + if (blk->attrib & _A_ARCH) + findData->attrib |= PM_FILE_ARCHIVE; + if (blk->attrib & _A_HIDDEN) + findData->attrib |= PM_FILE_HIDDEN; + if (blk->attrib & _A_SYSTEM) + findData->attrib |= PM_FILE_SYSTEM; + findData->sizeLo = blk->size; + strncpy(findData->name,blk->name,PM_MAX_PATH); + findData->name[PM_MAX_PATH-1] = 0; +} + +#define FIND_MASK (_A_RDONLY | _A_ARCH | _A_SUBDIR | _A_HIDDEN | _A_SYSTEM) + +/**************************************************************************** +REMARKS: +Function to find the first file matching a search criteria in a directory. +****************************************************************************/ +void * PMAPI PM_findFirstFile( + const char *filename, + PM_findData *findData) +{ + struct find_t *blk; + + if ((blk = PM_malloc(sizeof(*blk))) == NULL) + return PM_FILE_INVALID; + if (_dos_findfirst((char*)filename,FIND_MASK,blk) == 0) { + convertFindData(findData,blk); + return blk; + } + return PM_FILE_INVALID; +} + +/**************************************************************************** +REMARKS: +Function to find the next file matching a search criteria in a directory. +****************************************************************************/ +ibool PMAPI PM_findNextFile( + void *handle, + PM_findData *findData) +{ + struct find_t *blk = handle; + + if (_dos_findnext(blk) == 0) { + convertFindData(findData,blk); + return true; + } + return false; +} + +/**************************************************************************** +REMARKS: +Function to close the find process +****************************************************************************/ +void PMAPI PM_findClose( + void *handle) +{ + PM_free(handle); +} + +/**************************************************************************** +REMARKS: +Function to determine if a drive is a valid drive or not. Under Unix this +function will return false for anything except a value of 3 (considered +the root drive, and equivalent to C: for non-Unix systems). The drive +numbering is: + + 1 - Drive A: + 2 - Drive B: + 3 - Drive C: + etc + +****************************************************************************/ +ibool PMAPI PM_driveValid( + char drive) +{ + RMREGS regs; + regs.h.dl = (uchar)(drive - 'A' + 1); + regs.h.ah = 0x36; // Get disk information service + PM_int86(0x21,®s,®s); + return regs.x.ax != 0xFFFF; // AX = 0xFFFF if disk is invalid +} + +/**************************************************************************** +REMARKS: +Function to get the current working directory for the specififed drive. +Under Unix this will always return the current working directory regardless +of what the value of 'drive' is. +****************************************************************************/ +void PMAPI PM_getdcwd( + int drive, + char *dir, + int len) +{ + uint oldDrive,maxDrives; + _dos_getdrive(&oldDrive); + _dos_setdrive(drive,&maxDrives); + getcwd(dir,len); + _dos_setdrive(oldDrive,&maxDrives); +} + +/**************************************************************************** +REMARKS: +Function to change the file attributes for a specific file. +****************************************************************************/ +void PMAPI PM_setFileAttr( + const char *filename, + uint attrib) +{ +#if defined(TNT) && defined(_MSC_VER) + DWORD attr = 0; + + if (attrib & PM_FILE_READONLY) + attr |= FILE_ATTRIBUTE_READONLY; + if (attrib & PM_FILE_ARCHIVE) + attr |= FILE_ATTRIBUTE_ARCHIVE; + if (attrib & PM_FILE_HIDDEN) + attr |= FILE_ATTRIBUTE_HIDDEN; + if (attrib & PM_FILE_SYSTEM) + attr |= FILE_ATTRIBUTE_SYSTEM; + SetFileAttributes((LPSTR)filename, attr); +#else + uint attr = 0; + + if (attrib & PM_FILE_READONLY) + attr |= _A_RDONLY; + if (attrib & PM_FILE_ARCHIVE) + attr |= _A_ARCH; + if (attrib & PM_FILE_HIDDEN) + attr |= _A_HIDDEN; + if (attrib & PM_FILE_SYSTEM) + attr |= _A_SYSTEM; + _dos_setfileattr(filename,attr); +#endif +} + +/**************************************************************************** +REMARKS: +Function to create a directory. +****************************************************************************/ +ibool PMAPI PM_mkdir( + const char *filename) +{ +#ifdef __GNUC__ + return mkdir(filename,S_IRUSR) == 0; +#else +//AM: return mkdir(filename) == 0; + return(false); +#endif +} + +/**************************************************************************** +REMARKS: +Function to remove a directory. +****************************************************************************/ +ibool PMAPI PM_rmdir( + const char *filename) +{ +//AM: return rmdir(filename) == 0; + return(false); +} + +/**************************************************************************** +REMARKS: +Allocates a block of locked, physically contiguous memory. The memory +may be required to be below the 16Meg boundary. +****************************************************************************/ +void * PMAPI PM_allocLockedMem( + uint size, + ulong *physAddr, + ibool contiguous, + ibool below16M) +{ + void *p; + uint r_seg,r_off; + PM_lockHandle lh; + + /* Under DOS the only way to know the physical memory address is to + * allocate the memory below the 1Meg boundary as real mode memory. + * We also allocate 4095 bytes more memory than we need, so we can + * properly page align the start of the memory block for DMA operations. + */ + if (size > 4096) + return NULL; + if ((p = PM_allocRealSeg((size + 0xFFF) & ~0xFFF,&r_seg,&r_off)) == NULL) + return NULL; + *physAddr = ((r_seg << 4) + r_off + 0xFFF) & ~0xFFF; + PM_lockDataPages(p,size*2,&lh); + return p; +} + +void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous) +{ + (void)size; + PM_freeRealSeg(p); +} + +/*-------------------------------------------------------------------------*/ +/* Generic DPMI routines common to 16/32 bit code */ +/*-------------------------------------------------------------------------*/ + +ulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit) +{ + PMREGS r; + ulong physOfs; + + if (physAddr < 0x100000L) { + /* We can't map memory below 1Mb, but the linear address are already + * mapped 1:1 for this memory anyway so we just return the base address. + */ + return physAddr; + } + + /* Round the physical address to a 4Kb boundary and the limit to a + * 4Kb-1 boundary before passing the values to DPMI as some extenders + * will fail the calls unless this is the case. If we round the + * physical address, then we also add an extra offset into the address + * that we return. + */ + physOfs = physAddr & 4095; + physAddr = physAddr & ~4095; + limit = ((limit+physOfs+1+4095) & ~4095)-1; + + r.x.ax = 0x800; /* DPMI map physical to linear */ + r.x.bx = physAddr >> 16; + r.x.cx = physAddr & 0xFFFF; + r.x.si = limit >> 16; + r.x.di = limit & 0xFFFF; + PM_int386(0x31, &r, &r); + if (r.x.cflag) + return 0xFFFFFFFFUL; + return ((ulong)r.x.bx << 16) + r.x.cx + physOfs; +} + +int PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr) +{ + PMREGS r; + + r.x.ax = 7; /* DPMI set selector base address */ + r.x.bx = sel; + r.x.cx = linAddr >> 16; + r.x.dx = linAddr & 0xFFFF; + PM_int386(0x31, &r, &r); + if (r.x.cflag) + return 0; + return 1; +} + +ulong PMAPI DPMI_getSelectorBase(ushort sel) +{ + PMREGS r; + + r.x.ax = 6; /* DPMI get selector base address */ + r.x.bx = sel; + PM_int386(0x31, &r, &r); + return ((ulong)r.x.cx << 16) + r.x.dx; +} + +int PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit) +{ + PMREGS r; + + r.x.ax = 8; /* DPMI set selector limit */ + r.x.bx = sel; + r.x.cx = limit >> 16; + r.x.dx = limit & 0xFFFF; + PM_int386(0x31, &r, &r); + if (r.x.cflag) + return 0; + return 1; +} + +uint PMAPI DPMI_createSelector(ulong base,ulong limit) +{ + uint sel; + PMREGS r; + + /* Allocate 1 descriptor */ + r.x.ax = 0; + r.x.cx = 1; + PM_int386(0x31, &r, &r); + if (r.x.cflag) return 0; + sel = r.x.ax; + + /* Set the descriptor access rights (for a 32 bit page granular + * segment, ring 0). + */ + r.x.ax = 9; + r.x.bx = sel; + r.x.cx = 0x4093; + PM_int386(0x31, &r, &r); + + /* Map physical memory and create selector */ + if ((base = DPMI_mapPhysicalToLinear(base,limit)) == 0xFFFFFFFFUL) + return 0; + if (!DPMI_setSelectorBase(sel,base)) + return 0; + if (!DPMI_setSelectorLimit(sel,limit)) + return 0; + return sel; +} + +void PMAPI DPMI_freeSelector(uint sel) +{ + PMREGS r; + + r.x.ax = 1; + r.x.bx = sel; + PM_int386(0x31, &r, &r); +} + +int PMAPI DPMI_lockLinearPages(ulong linear,ulong len) +{ + PMREGS r; + + r.x.ax = 0x600; /* DPMI Lock Linear Region */ + r.x.bx = (linear >> 16); /* Linear address in BX:CX */ + r.x.cx = (linear & 0xFFFF); + r.x.si = (len >> 16); /* Length in SI:DI */ + r.x.di = (len & 0xFFFF); + PM_int386(0x31, &r, &r); + return (!r.x.cflag); +} + +int PMAPI DPMI_unlockLinearPages(ulong linear,ulong len) +{ + PMREGS r; + + r.x.ax = 0x601; /* DPMI Unlock Linear Region */ + r.x.bx = (linear >> 16); /* Linear address in BX:CX */ + r.x.cx = (linear & 0xFFFF); + r.x.si = (len >> 16); /* Length in SI:DI */ + r.x.di = (len & 0xFFFF); + PM_int386(0x31, &r, &r); + return (!r.x.cflag); +} + +void * PMAPI DPMI_mapPhysicalAddr(ulong base,ulong limit,ibool isCached) +{ + PMSREGS sregs; + ulong linAddr; + ulong DSBaseAddr; + + /* Get the base address for the default DS selector */ + PM_segread(&sregs); + DSBaseAddr = DPMI_getSelectorBase(sregs.ds); + if ((base < 0x100000) && (DSBaseAddr == 0)) { + /* DS is zero based, so we can directly access the first 1Mb of + * system memory (like under DOS4GW). + */ + return (void*)base; + } + + /* Map the memory to a linear address using DPMI function 0x800 */ + if ((linAddr = DPMI_mapPhysicalToLinear(base,limit)) == 0) { + if (base >= 0x100000) + return NULL; + /* If the linear address mapping fails but we are trying to + * map an area in the first 1Mb of system memory, then we must + * be running under a Windows or OS/2 DOS box. Under these + * environments we can use the segment wrap around as a fallback + * measure, as this does work properly. + */ + linAddr = base; + } + + /* Now expand the default DS selector to 4Gb so we can access it */ + if (!DPMI_setSelectorLimit(sregs.ds,0xFFFFFFFFUL)) + return NULL; + + /* Finally enable caching for the page tables that we just mapped in, + * since DOS4GW and PMODE/W create the page table entries without + * caching enabled which hurts the performance of the linear framebuffer + * as it disables write combining on Pentium Pro and above processors. + * + * For those processors cache disabling is better handled through the + * MTRR registers anyway (we can write combine a region but disable + * caching) so that MMIO register regions do not screw up. + */ + if (isCached) { + if ((PDB = _PM_getPDB()) != 0 && DSBaseAddr == 0) { + int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage; + ulong pageTable,*pPageTable; + if (!pPDB) { + if (PDB >= 0x100000) + pPDB = (ulong*)DPMI_mapPhysicalToLinear(PDB,0xFFF); + else + pPDB = (ulong*)PDB; + } + if (pPDB) { + startPDB = (linAddr >> 22) & 0x3FF; + startPage = (linAddr >> 12) & 0x3FF; + endPDB = ((linAddr+limit) >> 22) & 0x3FF; + endPage = ((linAddr+limit) >> 12) & 0x3FF; + for (iPDB = startPDB; iPDB <= endPDB; iPDB++) { + pageTable = pPDB[iPDB] & ~0xFFF; + if (pageTable >= 0x100000) + pPageTable = (ulong*)DPMI_mapPhysicalToLinear(pageTable,0xFFF); + else + pPageTable = (ulong*)pageTable; + start = (iPDB == startPDB) ? startPage : 0; + end = (iPDB == endPDB) ? endPage : 0x3FF; + for (iPage = start; iPage <= end; iPage++) + pPageTable[iPage] &= ~0x18; + } + } + } + } + + /* Now return the base address of the memory into the default DS */ + return (void*)(linAddr - DSBaseAddr); +} + +/* Some DOS extender implementations do not directly support calling a + * real mode procedure from protected mode. However we can simulate what + * we need temporarily hooking the INT 6Ah vector with a small real mode + * stub that will call our real mode code for us. + */ + +static uchar int6AHandler[] = { + 0x00,0x00,0x00,0x00, /* __PMODE_callReal variable */ + 0xFB, /* sti */ + 0x2E,0xFF,0x1E,0x00,0x00, /* call [cs:__PMODE_callReal] */ + 0xCF, /* iretf */ + }; +static uchar *crPtr = NULL; /* Pointer to of int 6A handler */ +static uint crRSeg,crROff; /* Real mode seg:offset of handler */ + +void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in, + RMSREGS *sregs) +{ + uchar *p; + uint oldSeg,oldOff; + + if (!crPtr) { + /* Allocate and copy the memory block only once */ + crPtr = PM_allocRealSeg(sizeof(int6AHandler), &crRSeg, &crROff); + memcpy(crPtr,int6AHandler,sizeof(int6AHandler)); + } + PM_setWord(crPtr,off); /* Plug in address to call */ + PM_setWord(crPtr+2,seg); + p = PM_mapRealPointer(0,0x6A * 4); + oldOff = PM_getWord(p); /* Save old handler address */ + oldSeg = PM_getWord(p+2); + PM_setWord(p,crROff+4); /* Hook 6A handler */ + PM_setWord(p+2,crRSeg); + PM_int86x(0x6A, in, in, sregs); /* Call real mode code */ + PM_setWord(p,oldOff); /* Restore old handler */ + PM_setWord(p+2,oldSeg); +} + +void * PMAPI PM_getBIOSPointer(void) +{ return PM_mapPhysicalAddr(0x400,0xFFFF,true); } + +void * PMAPI PM_getA0000Pointer(void) +{ return PM_mapPhysicalAddr(0xA0000,0xFFFF,true); } + +void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached) +{ return DPMI_mapPhysicalAddr(base,limit,isCached); } + +void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit) +{ + /* Mapping cannot be free */ +} + +ulong PMAPI PM_getPhysicalAddr(void *p) +{ + // TODO: This function should find the physical address of a linear + // address. + (void)p; + return 0xFFFFFFFFUL; +} + +void * PMAPI PM_mapToProcess(void *base,ulong limit) +{ + (void)limit; + return (void*)base; +} + +void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off) +{ + static uchar *zeroPtr = NULL; + + if (!zeroPtr) + zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true); + return (void*)(zeroPtr + MK_PHYS(r_seg,r_off)); +} + +void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off) +{ + PMREGS r; + void *p; + + r.x.ax = 0x100; /* DPMI allocate DOS memory */ + r.x.bx = (size + 0xF) >> 4; /* number of paragraphs */ + PM_int386(0x31, &r, &r); + if (r.x.cflag) + return NULL; /* DPMI call failed */ + *r_seg = r.x.ax; /* Real mode segment */ + *r_off = 0; + p = PM_mapRealPointer(*r_seg,*r_off); + _PM_addRealModeBlock(p,r.x.dx); + return p; +} + +void PMAPI PM_freeRealSeg(void *mem) +{ + PMREGS r; + + r.x.ax = 0x101; /* DPMI free DOS memory */ + r.x.dx = _PM_findRealModeBlock(mem);/* DX := selector from 0x100 */ + PM_int386(0x31, &r, &r); +} + +static DPMI_handler_t DPMI_int10 = NULL; + +void PMAPI DPMI_setInt10Handler(DPMI_handler_t handler) +{ + DPMI_int10 = handler; +} + +void PMAPI DPMI_int86(int intno, DPMI_regs *regs) +{ + PMREGS r; + PMSREGS sr; + + if (intno == 0x10 && DPMI_int10) { + if (DPMI_int10(regs)) + return; + } + PM_segread(&sr); + r.x.ax = 0x300; /* DPMI issue real interrupt */ + r.h.bl = intno; + r.h.bh = 0; + r.x.cx = 0; + sr.es = sr.ds; + r.e.edi = (uint)regs; + PM_int386x(0x31, &r, &r, &sr); /* Issue the interrupt */ +} + +#define IN(reg) rmregs.reg = in->e.reg +#define OUT(reg) out->e.reg = rmregs.reg + +int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out) +{ + DPMI_regs rmregs; + + memset(&rmregs, 0, sizeof(rmregs)); + IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi); + +// These real mode ints may cause crashes. +//AM: DPMI_int86(intno,&rmregs); /* DPMI issue real interrupt */ + + OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi); + out->x.cflag = rmregs.flags & 0x1; + return out->x.ax; +} + +int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, + RMSREGS *sregs) +{ + DPMI_regs rmregs; + + memset(&rmregs, 0, sizeof(rmregs)); + IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi); + rmregs.es = sregs->es; + rmregs.ds = sregs->ds; + +//AM: DPMI_int86(intno,&rmregs); /* DPMI issue real interrupt */ + + OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi); + sregs->es = rmregs.es; + sregs->cs = rmregs.cs; + sregs->ss = rmregs.ss; + sregs->ds = rmregs.ds; + out->x.cflag = rmregs.flags & 0x1; + return out->x.ax; +} + +#pragma pack(1) + +typedef struct { + uint LargestBlockAvail; + uint MaxUnlockedPage; + uint LargestLockablePage; + uint LinAddrSpace; + uint NumFreePagesAvail; + uint NumPhysicalPagesFree; + uint TotalPhysicalPages; + uint FreeLinAddrSpace; + uint SizeOfPageFile; + uint res[3]; + } MemInfo; + +#pragma pack() + +void PMAPI PM_availableMemory(ulong *physical,ulong *total) +{ + PMREGS r; + PMSREGS sr; + MemInfo memInfo; + + PM_segread(&sr); + r.x.ax = 0x500; /* DPMI get free memory info */ + sr.es = sr.ds; + r.e.edi = (uint)&memInfo; + PM_int386x(0x31, &r, &r, &sr); /* Issue the interrupt */ + *physical = memInfo.NumPhysicalPagesFree * 4096; + *total = memInfo.LargestBlockAvail; + if (*total < *physical) + *physical = *total; +} + +/**************************************************************************** +REMARKS: +Function to get the file attributes for a specific file. +****************************************************************************/ +uint PMAPI PM_getFileAttr( + const char *filename) +{ + // TODO: Implement this! + return 0; +} + +/**************************************************************************** +REMARKS: +Function to get the file time and date for a specific file. +****************************************************************************/ +ibool PMAPI PM_getFileTime( + const char *filename, + ibool gmTime, + PM_time *time) +{ + // TODO: Implement this! + return false; +} + +/**************************************************************************** +REMARKS: +Function to set the file time and date for a specific file. +****************************************************************************/ +ibool PMAPI PM_setFileTime( + const char *filename, + ibool gmTime, + PM_time *time) +{ + // TODO: Implement this! + return false; +} diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/pmsmx.c b/board/MAI/bios_emulator/scitech/src/pm/smx/pmsmx.c new file mode 100644 index 0000000..2596c76 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/pmsmx.c @@ -0,0 +1,471 @@ +/**************************************************************************** +* +* 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: ANSI C +* Environment: 32-bit SMX embedded systems development +* +* Description: Implementation for the OS Portability Manager Library, which +* contains functions to implement OS specific services in a +* generic, cross platform API. Porting the OS Portability +* Manager library is the first step to porting any SciTech +* products to a new platform. +* +****************************************************************************/ + +#include "pmapi.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dos.h> +#include "smx/ps2mouse.h" + +/*--------------------------- Global variables ----------------------------*/ + +static int globalDataStart; + +PM_criticalHandler _VARAPI _PM_critHandler = NULL; +PM_breakHandler _VARAPI _PM_breakHandler = NULL; +PM_intHandler _VARAPI _PM_timerHandler = NULL; +PM_intHandler _VARAPI _PM_rtcHandler = NULL; +PM_intHandler _VARAPI _PM_keyHandler = NULL; +PM_key15Handler _VARAPI _PM_key15Handler = NULL; +PM_mouseHandler _VARAPI _PM_mouseHandler = NULL; +PM_intHandler _VARAPI _PM_int10Handler = NULL; +int _VARAPI _PM_mouseMask; + +uchar * _VARAPI _PM_ctrlCPtr; /* Location of Ctrl-C flag */ +uchar * _VARAPI _PM_ctrlBPtr; /* Location of Ctrl-Break flag */ +uchar * _VARAPI _PM_critPtr; /* Location of Critical error Bf*/ +PMFARPTR _VARAPI _PM_prevTimer = PMNULL; /* Previous timer handler */ +PMFARPTR _VARAPI _PM_prevRTC = PMNULL; /* Previous RTC handler */ +PMFARPTR _VARAPI _PM_prevKey = PMNULL; /* Previous key handler */ +PMFARPTR _VARAPI _PM_prevKey15 = PMNULL; /* Previous key15 handler */ +PMFARPTR _VARAPI _PM_prevBreak = PMNULL; /* Previous break handler */ +PMFARPTR _VARAPI _PM_prevCtrlC = PMNULL; /* Previous CtrlC handler */ +PMFARPTR _VARAPI _PM_prevCritical = PMNULL; /* Previous critical handler */ +long _VARAPI _PM_prevRealTimer; /* Previous real mode timer */ +long _VARAPI _PM_prevRealRTC; /* Previous real mode RTC */ +long _VARAPI _PM_prevRealKey; /* Previous real mode key */ +long _VARAPI _PM_prevRealKey15; /* Previous real mode key15 */ +long _VARAPI _PM_prevRealInt10; /* Previous real mode int 10h */ +static uchar _PM_oldCMOSRegA; /* CMOS register A contents */ +static uchar _PM_oldCMOSRegB; /* CMOS register B contents */ +static uchar _PM_oldRTCPIC2; /* Mask value for RTC IRQ8 */ + +/*----------------------------- Implementation ----------------------------*/ + +/* Globals for locking interrupt handlers in _pmsmx.asm */ + +extern int _ASMAPI _PM_pmsmxDataStart; +extern int _ASMAPI _PM_pmsmxDataEnd; +void _ASMAPI _PM_pmsmxCodeStart(void); +void _ASMAPI _PM_pmsmxCodeEnd(void); + +/* Protected mode interrupt handlers, also called by PM callbacks below */ + +void _ASMAPI _PM_timerISR(void); +void _ASMAPI _PM_rtcISR(void); +void _ASMAPI _PM_keyISR(void); +void _ASMAPI _PM_key15ISR(void); +void _ASMAPI _PM_breakISR(void); +void _ASMAPI _PM_ctrlCISR(void); +void _ASMAPI _PM_criticalISR(void); +void _ASMAPI _PM_mouseISR(void); +void _ASMAPI _PM_int10PMCB(void); + +/* Protected mode DPMI callback handlers */ + +void _ASMAPI _PM_mousePMCB(void); + +/* Routine to install a mouse handler function */ + +void _ASMAPI _PM_setMouseHandler(int mask); + +/* Routine to allocate DPMI real mode callback routines */ + +void _ASMAPI _DPMI_allocateCallback(void (_ASMAPI *pmcode)(),void *rmregs,long *RMCB); +void _ASMAPI _DPMI_freeCallback(long RMCB); + +/* DPMI helper functions in PMLITE.C */ + +ulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit); +int PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr); +ulong PMAPI DPMI_getSelectorBase(ushort sel); +int PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit); +uint PMAPI DPMI_createSelector(ulong base,ulong limit); +void PMAPI DPMI_freeSelector(uint sel); +int PMAPI DPMI_lockLinearPages(ulong linear,ulong len); +int PMAPI DPMI_unlockLinearPages(ulong linear,ulong len); + +/* Functions to read and write CMOS registers */ + +uchar PMAPI _PM_readCMOS(int index); +void PMAPI _PM_writeCMOS(int index,uchar value); + +/*-------------------------------------------------------------------------*/ +/* Generic routines common to all environments */ +/*-------------------------------------------------------------------------*/ + +void PMAPI PM_resetMouseDriver(int hardReset) +{ + ps2MouseReset(); +} + +void PMAPI PM_setRealTimeClockFrequency(int frequency) +{ + static short convert[] = { + 8192, + 4096, + 2048, + 1024, + 512, + 256, + 128, + 64, + 32, + 16, + 8, + 4, + 2, + -1, + }; + int i; + + /* First clear any pending RTC timeout if not cleared */ + _PM_readCMOS(0x0C); + if (frequency == 0) { + /* Disable RTC timout */ + _PM_writeCMOS(0x0A,_PM_oldCMOSRegA); + _PM_writeCMOS(0x0B,_PM_oldCMOSRegB & 0x0F); + } + else { + /* Convert frequency value to RTC clock indexes */ + for (i = 0; convert[i] != -1; i++) { + if (convert[i] == frequency) + break; + } + + /* Set RTC timout value and enable timeout */ + _PM_writeCMOS(0x0A,(_PM_oldCMOSRegA & 0xF0) | (i+3)); + _PM_writeCMOS(0x0B,(_PM_oldCMOSRegB & 0x0F) | 0x40); + } +} + +static void PMAPI lockPMHandlers(void) +{ + static int locked = 0; + int stat = 0; + PM_lockHandle lh; + + /* Lock all of the code and data used by our protected mode interrupt + * handling routines, so that it will continue to work correctly + * under real mode. + */ + if (!locked) { + PM_saveDS(); + stat = !PM_lockDataPages(&globalDataStart-2048,4096,&lh); + stat |= !PM_lockDataPages(&_PM_pmsmxDataStart,(int)&_PM_pmsmxDataEnd - (int)&_PM_pmsmxDataStart,&lh); + stat |= !PM_lockCodePages((__codePtr)_PM_pmsmxCodeStart,(int)_PM_pmsmxCodeEnd-(int)_PM_pmsmxCodeStart,&lh); + if (stat) { + printf("Page locking services failed - interrupt handling not safe!\n"); + exit(1); + } + locked = 1; + } +} + +void PMAPI PM_getPMvect(int intno, PMFARPTR *isr) +{ + PMREGS regs; + + regs.x.ax = 0x204; + regs.h.bl = intno; + PM_int386(0x31,®s,®s); + isr->sel = regs.x.cx; + isr->off = regs.e.edx; +} + +void PMAPI PM_setPMvect(int intno, PM_intHandler isr) +{ + PMSREGS sregs; + PMREGS regs; + + PM_saveDS(); + regs.x.ax = 0x205; /* Set protected mode vector */ + regs.h.bl = intno; + PM_segread(&sregs); + regs.x.cx = sregs.cs; + regs.e.edx = (uint)isr; + PM_int386(0x31,®s,®s); +} + +void PMAPI PM_restorePMvect(int intno, PMFARPTR isr) +{ + PMREGS regs; + + regs.x.ax = 0x205; + regs.h.bl = intno; + regs.x.cx = isr.sel; + regs.e.edx = isr.off; + PM_int386(0x31,®s,®s); +} + +static long prevRealBreak; /* Previous real mode break handler */ +static long prevRealCtrlC; /* Previous real mode CtrlC handler */ +static long prevRealCritical; /* Prev real mode critical handler */ + +int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh) +{ + lockPMHandlers(); /* Ensure our handlers are locked */ + + _PM_mouseHandler = mh; + return 0; +} + +void PMAPI PM_restoreMouseHandler(void) +{ + if (_PM_mouseHandler) + _PM_mouseHandler = NULL; +} + +static void getISR(int intno, PMFARPTR *pmisr, long *realisr) +{ + PM_getPMvect(intno,pmisr); +} + +static void restoreISR(int intno, PMFARPTR pmisr, long realisr) +{ + PM_restorePMvect(intno,pmisr); +} + +static void setISR(int intno, void (* PMAPI pmisr)()) +{ + lockPMHandlers(); /* Ensure our handlers are locked */ + PM_setPMvect(intno,pmisr); +} + +void PMAPI PM_setTimerHandler(PM_intHandler th) +{ + getISR(PM_IRQ0, &_PM_prevTimer, &_PM_prevRealTimer); + _PM_timerHandler = th; + setISR(PM_IRQ0, _PM_timerISR); +} + +void PMAPI PM_restoreTimerHandler(void) +{ + if (_PM_timerHandler) { + restoreISR(PM_IRQ0, _PM_prevTimer, _PM_prevRealTimer); + _PM_timerHandler = NULL; + } +} + +ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency) +{ + /* Save the old CMOS real time clock values */ + _PM_oldCMOSRegA = _PM_readCMOS(0x0A); + _PM_oldCMOSRegB = _PM_readCMOS(0x0B); + + /* Set the real time clock interrupt handler */ + getISR(0x70, &_PM_prevRTC, &_PM_prevRealRTC); + _PM_rtcHandler = th; + setISR(0x70, _PM_rtcISR); + + /* Program the real time clock default frequency */ + PM_setRealTimeClockFrequency(frequency); + + /* Unmask IRQ8 in the PIC2 */ + _PM_oldRTCPIC2 = PM_inpb(0xA1); + PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE); + return true; +} + +void PMAPI PM_restoreRealTimeClockHandler(void) +{ + if (_PM_rtcHandler) { + /* Restore CMOS registers and mask RTC clock */ + _PM_writeCMOS(0x0A,_PM_oldCMOSRegA); + _PM_writeCMOS(0x0B,_PM_oldCMOSRegB); + PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE)); + + /* Restore the interrupt vector */ + restoreISR(0x70, _PM_prevRTC, _PM_prevRealRTC); + _PM_rtcHandler = NULL; + } +} + +void PMAPI PM_setKeyHandler(PM_intHandler kh) +{ + getISR(PM_IRQ1, &_PM_prevKey, &_PM_prevRealKey); + _PM_keyHandler = kh; + setISR(PM_IRQ1, _PM_keyISR); +} + +void PMAPI PM_restoreKeyHandler(void) +{ + if (_PM_keyHandler) { + restoreISR(PM_IRQ1, _PM_prevKey, _PM_prevRealKey); + _PM_keyHandler = NULL; + } +} + +void PMAPI PM_setKey15Handler(PM_key15Handler kh) +{ + getISR(0x15, &_PM_prevKey15, &_PM_prevRealKey15); + _PM_key15Handler = kh; + setISR(0x15, _PM_key15ISR); +} + +void PMAPI PM_restoreKey15Handler(void) +{ + if (_PM_key15Handler) { + restoreISR(0x15, _PM_prevKey15, _PM_prevRealKey15); + _PM_key15Handler = NULL; + } +} + +/* Real mode Ctrl-C and Ctrl-Break handler. This handler simply sets a + * flag in the real mode code segment and exit. We save the location + * of this flag in real mode memory so that both the real mode and + * protected mode code will be modifying the same flags. + */ + +static uchar ctrlHandler[] = { + 0x00,0x00,0x00,0x00, /* ctrlBFlag */ + 0x66,0x2E,0xC7,0x06,0x00,0x00, + 0x01,0x00,0x00,0x00, /* mov [cs:ctrlBFlag],1 */ + 0xCF, /* iretf */ + }; + +void PMAPI PM_installAltBreakHandler(PM_breakHandler bh) +{ + uint rseg,roff; + + getISR(0x1B, &_PM_prevBreak, &prevRealBreak); + getISR(0x23, &_PM_prevCtrlC, &prevRealCtrlC); + _PM_breakHandler = bh; + setISR(0x1B, _PM_breakISR); + setISR(0x23, _PM_ctrlCISR); + + /* Hook the real mode vectors for these handlers, as these are not + * normally reflected by the DPMI server up to protected mode + */ + _PM_ctrlBPtr = PM_allocRealSeg(sizeof(ctrlHandler)*2, &rseg, &roff); + memcpy(_PM_ctrlBPtr,ctrlHandler,sizeof(ctrlHandler)); + memcpy(_PM_ctrlBPtr+sizeof(ctrlHandler),ctrlHandler,sizeof(ctrlHandler)); + _PM_ctrlCPtr = _PM_ctrlBPtr + sizeof(ctrlHandler); + _PM_setRMvect(0x1B,((long)rseg << 16) | (roff+4)); + _PM_setRMvect(0x23,((long)rseg << 16) | (roff+sizeof(ctrlHandler)+4)); +} + +void PMAPI PM_installBreakHandler(void) +{ + PM_installAltBreakHandler(NULL); +} + +void PMAPI PM_restoreBreakHandler(void) +{ + if (_PM_prevBreak.sel) { + restoreISR(0x1B, _PM_prevBreak, prevRealBreak); + restoreISR(0x23, _PM_prevCtrlC, prevRealCtrlC); + _PM_prevBreak.sel = 0; + _PM_breakHandler = NULL; + PM_freeRealSeg(_PM_ctrlBPtr); + } +} + +/* Real mode Critical Error handler. This handler simply saves the AX and + * DI values in the real mode code segment and exits. We save the location + * of this flag in real mode memory so that both the real mode and + * protected mode code will be modifying the same flags. + */ + +static uchar criticalHandler[] = { + 0x00,0x00, /* axCode */ + 0x00,0x00, /* diCode */ + 0x2E,0xA3,0x00,0x00, /* mov [cs:axCode],ax */ + 0x2E,0x89,0x3E,0x02,0x00, /* mov [cs:diCode],di */ + 0xB8,0x03,0x00, /* mov ax,3 */ + 0xCF, /* iretf */ + }; + +void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch) +{ + uint rseg,roff; + + getISR(0x24, &_PM_prevCritical, &prevRealCritical); + _PM_critHandler = ch; + setISR(0x24, _PM_criticalISR); + + /* Hook the real mode vector, as this is not normally reflected by the + * DPMI server up to protected mode. + */ + _PM_critPtr = PM_allocRealSeg(sizeof(criticalHandler)*2, &rseg, &roff); + memcpy(_PM_critPtr,criticalHandler,sizeof(criticalHandler)); + _PM_setRMvect(0x24,((long)rseg << 16) | (roff+4)); +} + +void PMAPI PM_installCriticalHandler(void) +{ + PM_installAltCriticalHandler(NULL); +} + +void PMAPI PM_restoreCriticalHandler(void) +{ + if (_PM_prevCritical.sel) { + restoreISR(0x24, _PM_prevCritical, prevRealCritical); + PM_freeRealSeg(_PM_critPtr); + _PM_prevCritical.sel = 0; + _PM_critHandler = NULL; + } +} + +int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh) +{ + PMSREGS sregs; + PM_segread(&sregs); + return DPMI_lockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len); +} + +int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh) +{ + PMSREGS sregs; + PM_segread(&sregs); + return DPMI_unlockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len); +} + +int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh) +{ + PMSREGS sregs; + PM_segread(&sregs); +//AM: causes minor glitch with +//AM: older versions pmEasy which don't allow DPMI 06 on +//AM: Code selector 0x0C -- assume base is 0 which it should be. + return DPMI_lockLinearPages((uint)p,len); +} + +int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh) +{ + PMSREGS sregs; + PM_segread(&sregs); + return DPMI_unlockLinearPages((uint)p,len); +} diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/smx/vflat.c new file mode 100644 index 0000000..579ef2c --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/vflat.c @@ -0,0 +1,49 @@ +/**************************************************************************** +* +* 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: ANSI C +* Environment: Any +* +* Description: Dummy module; no virtual framebuffer for this OS +* +****************************************************************************/ + +#include "pmapi.h" + +ibool PMAPI VF_available(void) +{ + return false; +} + +void * PMAPI VF_init(ulong baseAddr,int bankSize,int codeLen,void *bankFunc) +{ + baseAddr = baseAddr; + bankSize = bankSize; + codeLen = codeLen; + bankFunc = bankFunc; + return NULL; +} + +void PMAPI VF_exit(void) +{ +} diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/smx/ztimer.c new file mode 100644 index 0000000..01e180b --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/smx/ztimer.c @@ -0,0 +1,115 @@ +/**************************************************************************** +* +* Ultra Long Period Timer +* +* ======================================================================== +* +* 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: ANSI C +* Environment: 32-bit SMX embedded systems development +* +* Description: OS specific implementation for the Zen Timer functions. +* LZTimer not supported for smx (as needed for i486 processors), only +* ULZTimer is supported at this time. +* +****************************************************************************/ + +/*---------------------------- Global smx variables -----------------------*/ + +extern ulong _cdecl etime; /* elapsed time */ +extern ulong _cdecl xticks_per_second(void); + +/*----------------------------- Implementation ----------------------------*/ + +/* External assembler functions */ + +void _ASMAPI LZ_disable(void); +void _ASMAPI LZ_enable(void); + + +/**************************************************************************** +REMARKS: +Initialise the Zen Timer module internals. +****************************************************************************/ +void __ZTimerInit(void) +{ +} + +ulong reterr(void) +{ + PM_fatalError("Zen Timer not supported for smx."); + return(0); +} + +/**************************************************************************** +REMARKS: +Call the assembler Zen Timer functions to do the timing. +****************************************************************************/ +#define __LZTimerOn(tm) PM_fatalError("Zen Timer not supported for smx.") + +/**************************************************************************** +REMARKS: +Call the assembler Zen Timer functions to do the timing. +****************************************************************************/ +#define __LZTimerLap(tm) reterr() + +/**************************************************************************** +REMARKS: +Call the assembler Zen Timer functions to do the timing. +****************************************************************************/ +#define __LZTimerOff(tm) PM_fatalError("Zen Timer not supported for smx.") + +/**************************************************************************** +REMARKS: +Call the assembler Zen Timer functions to do the timing. +****************************************************************************/ +#define __LZTimerCount(tm) reterr() + +/**************************************************************************** +REMARKS: +Define the resolution of the long period timer as seconds per timer tick. +****************************************************************************/ +#define ULZTIMER_RESOLUTION (ulong)(1000000/xticks_per_second()) + +/**************************************************************************** +REMARKS: +Read the Long Period timer value from the smx timer tick. +****************************************************************************/ +static ulong __ULZReadTime(void) +{ + ulong ticks; + LZ_disable(); /* Turn of interrupts */ + ticks = etime; + LZ_enable(); /* Turn on interrupts again */ + return ticks; +} + +/**************************************************************************** +REMARKS: +Compute the elapsed time from the BIOS timer tick. Note that we check to see +whether a midnight boundary has passed, and if so adjust the finish time to +account for this. We cannot detect if more that one midnight boundary has +passed, so if this happens we will be generating erronous results. +****************************************************************************/ +ulong __ULZElapsedTime(ulong start,ulong finish) +{ + if (finish < start) + finish += xticks_per_second() * 3600 *24; /* Number of ticks in 24 hours */ + return finish - start; +} |