📄 _pm.asm
字号:
;****************************************************************************;*;* 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.;*;**************************************************************************** IDEALinclude "scitech.mac" ; Memory model macrosheader _pm ; Set up memory modelbegdataseg _pm cextern _PM_savedDS,USHORTintel_id db "GenuineIntel" ; Intel vendor IDenddataseg _pmbegcodeseg _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 retcprocend; Create a table of the 256 different interrupt calls that we can jump; intoifdef USE_NASM%assign intno 0intTable:%rep 256 db 0CDh db intno%assign intno intno + 1 ret nop%endrepelseintno = 0intTable: REPT 256 db 0CDh db intnointno = intno + 1 ret nop ENDMendif;----------------------------------------------------------------------------; _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 retcprocend;----------------------------------------------------------------------------; 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 retcprocend;----------------------------------------------------------------------------; 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 retcprocend;----------------------------------------------------------------------------; 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 retcprocend;----------------------------------------------------------------------------; 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 retcprocend;----------------------------------------------------------------------------; 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 retcprocend;----------------------------------------------------------------------------; 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 retcprocend;----------------------------------------------------------------------------; 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 retcprocend;----------------------------------------------------------------------------; 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 retcprocend; 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%endmacroelsemacro DELAY jmp short $+2 jmp short $+2 jmp short $+2endmmacro IODELAYN N rept N DELAY endmendmendif;----------------------------------------------------------------------------; 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 retcprocend;----------------------------------------------------------------------------; 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 retcprocend;----------------------------------------------------------------------------; _PM_getPDB - Return the Page Table Directory Base address;----------------------------------------------------------------------------cprocstart _PM_getPDB mov eax,cr3 and eax,0FFFFF000h retcprocend;----------------------------------------------------------------------------; _PM_flushTLB - Flush the Translation Lookaside buffer;----------------------------------------------------------------------------cprocstart PM_flushTLB wbinvd ; Flush the CPU cache mov eax,cr3 mov cr3,eax ; Flush the TLB retcprocendendcodeseg _pm END ; End of module
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -