home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / PJ8_3.ZIP / BIOS.ASM < prev    next >
Assembly Source File  |  1989-12-04  |  14KB  |  674 lines

  1. ;            LAST UPDATE NOVEMBER 1989
  2. ;
  3. ;        ASSEMBLER:    TASM 1.0
  4. ;        LINKER:        TLINK 2.0
  5. ;    ASSEMBBLE WITH:
  6. ;        TASM BIOS
  7. ;        TLINK BIOS /T
  8. ;
  9. ;conditionals**************
  10.  
  11. TRUE    equ 0FFH
  12. FALSE    equ 000H
  13.  
  14. _80386    equ TRUE
  15.  
  16. ;group info*****************
  17.  
  18. TSRGROUP    GROUP CODESEG,DATASEG,INITSEG
  19.  
  20. TSR    equ TSRGROUP    ;for group overrides
  21.  
  22. ;includes****************
  23.  
  24.  
  25. ;equates*******************
  26.  
  27. ROM_SEG    equ 0F000H
  28.  
  29. ON    equ 0FFH
  30. OFF    equ 0
  31.  
  32.  
  33. ;------------------
  34. ;interrupt control port of 8259 PIC
  35. ;------------------
  36. INT_CONTROL    equ 20h
  37. EOI        equ 20h        ;End Of Interrupt code
  38.  
  39. ;--------------
  40. ;8042 KEYBOARD CONTROLLER equates
  41. ;--------------
  42.  
  43. STATUS_PORT    equ 64H
  44. PORT_A        equ 60H
  45.  
  46. ENABLE_A20    equ 0DFH
  47. DISABLE_A20    equ 0DDH
  48. WRITE2_8042    equ 0D1H
  49. READ_FROM_8042    equ 0D0H
  50.  
  51. SUCCESS        equ 0    ;RETURN CODES
  52. FAILURE        equ 2    ;8042 could not perform the command
  53.  
  54. OUTPUT_BUFFER_FULL    equ 1
  55. INPUT_BUFFER_FULL    equ 2
  56.  
  57. CMOS_PORT        equ 70H
  58.  
  59. ;--------------------
  60. ;DATA_SEG_TYPES
  61. ;--------------------
  62. DATA_SEGMENT        equ 8 SHL 1
  63. WRITABLE        equ 1 SHL 1    ;BIT 0 = ACCESSED BIT
  64. EXPAND_DOWN        equ 2 SHL 1    ;FOR STACK SEGMENTS
  65.  
  66. ;--------------------
  67. ;CODE_SEG_TYPES
  68. ;--------------------
  69. CODE_SEGMENT        equ 12 SHL 1
  70. READABLE        equ 1 SHL 1    ;BIT 0 = ACCESSED BIT
  71. CONFORMING        equ 2 SHL 1    ;USED BY PROTECTION MECHANISM
  72.                     ;SEE MORSE,ISAACSON,ALBERT PAGE 215
  73. ;--------------------
  74. ;SYSTEM AND GATE DESCRIPTOR TYPES
  75. ;--------------------
  76. AVAIL_286_TSS        equ 1 SHL 1    ;BIT 0 = ACCESSED BIT
  77. LOCAL_DESCRIPTOR_TABLE    equ 2 SHL 1
  78. CALL_GATE        equ 4 SHL 1
  79. TASK_GATE        equ 5 SHL 1
  80. _286_INT_GATE        equ 6 SHL 1
  81. _286_TRAP_GATE        equ 7 SHL 1
  82. AVAIL_386_TSS        equ 9 SHL 1
  83. _386_CALL_GATE        equ 0CH SHL 1
  84. _386_INT_GATE        equ 0EH SHL 1
  85. _386_TRAP_GATE        equ 0FH SHL 1
  86.  
  87. ;-------------------
  88. ;PRIVILIDGE LEVELS
  89. ;-------------------
  90. KERNAL            equ 0 SHL 5
  91. SYSTEM            equ 1 SHL 5
  92. EXTENSIONS        equ 2 SHL 5
  93. APPLICATION        equ 3 SHL 5
  94.  
  95. PRESENT            equ 1 SHL 7
  96.  
  97.  
  98. ;macros********************
  99.  
  100. JMPF    macro
  101.     db 0EAH        ;jump far immediate
  102.     endm
  103.  
  104. JMPS    macro TARGET
  105.     jmp short TARGET
  106.     endm
  107.  
  108. SEG_DESCRIPTOR    macro BASE,LIMIT,GRANULARITY,ACCESS_RIGHTS
  109. ;--------------------
  110. ;BASE IS A 32 BIT PHYSICAL ADDRESS
  111. ;LIMIT IS A 20 BIT QUANTITY
  112. ;    IF GRANULARITY = 0 LIMIT IS IN BYTES
  113. ;    IF GRANULARITY = 1 LIMIT IS IN PAGES = 4096 = 2^12 BYTES, SO 32 BIT BYTE LIMIT
  114. ;--------------------
  115.     dw 0FFFFH AND LIMIT            ;LO 16 BITS OF SEG LIMIT
  116.     dw 0FFFFH AND BASE            ;LO 16 BITS OF BASE ADDRESS
  117.     dw ( (BASE SHR 16) AND 0FFH ) + ( (ACCESS_RIGHTS) SHL 8)
  118. ;N.B. TASM BUG! NEED ( ) AROUND ACCESS_RIGHTS OR MACRO DOES NOT EXPAND CORRECTLY
  119.                         ;BITS 16 - 23 OF BASE
  120.                         ;ACCESS_RIGHTS
  121.     dw ( (LIMIT SHR 16) AND 0FH) + (GRANULARITY SHL 7) + ( (BASE SHR 16) AND 0FF00H)
  122.                         ;HI NIBBLE OF LIMIT
  123.                         ;GRANULARITY IN BIT 7
  124.                         ;HI BYTE OF BASE
  125.     endm
  126.  
  127.  
  128. ;structures****************
  129.  
  130. XMBMOVE_GDT    struc
  131.     UNUSABLE    dq ?
  132.     XMBMOVE_GDT_PTR    dq ?    ;points to GDT, gives segment limit, etc.
  133.     SOURCE_DESC    dq ?    ;descriptor for source
  134.     TARGET_DESC    dq ?    ;ditto target
  135.     BIOS_CS        dq ?    ;CS descriptor filled in by BIOS
  136.     BIOS_SS        dq ?    ;ditto for SS
  137. XMBMOVE_GDT    ends
  138.  
  139.  
  140. DESCRIPTOR    struc
  141. ;-----------------------------------------------------------------------------;
  142. ;  simplified Segment Descriptor (entry in a Global/Local Descriptor Table)   ;
  143. ;-----------------------------------------------------------------------------;
  144. SEGMENT_LIMIT    dw ?
  145. SEGMENT_BASE    dw ?    ;24 BIT physical address
  146.         dw ?
  147.         dw ?
  148. DESCRIPTOR    ends
  149.  
  150.  
  151. ;dummy segments************
  152.  
  153. ROM    segment at 0F000H
  154.  
  155. ROM    ends
  156.  
  157. ;
  158.  
  159. INT_VECTORS_SEG    segment at 0000H
  160.     ORG 15*4
  161. INT_15H_VECTOR    dd ?
  162. INT_VECTORS_SEG    ends
  163.  
  164.  
  165. ;publics*******************
  166.  
  167.  
  168.  
  169. ;--------------
  170. ;SPECIFY THE LOAD ORDER FOR THE LINKER
  171. ;--------------
  172. ;
  173. CODESEG    SEGMENT BYTE PUBLIC 'PROG'
  174. CODESEG    ENDS
  175. ;
  176. DATASEG    SEGMENT BYTE PUBLIC 'DATA'
  177. DATASEG    ENDS
  178. ;
  179. INITSEG    SEGMENT BYTE PUBLIC 'INIT'
  180. INITSEG    ENDS
  181. ;
  182. ;--------------
  183. ;START OF ACTUAL PROGRAM SEGMENTS
  184. ;--------------
  185. ;
  186. ;--------------
  187. DATASEG    SEGMENT BYTE PUBLIC 'DATA'
  188.         ASSUME DS:TSRGROUP
  189. ;--------------
  190. ;Resident data area
  191. ;--------------
  192. ;
  193.  
  194.  
  195. ;
  196. LAST_BYTE    label byte        ;mark the end of resident data and code
  197. ;
  198. DATASEG    ENDS
  199.  
  200. ;
  201.  
  202. CODESEG    SEGMENT BYTE PUBLIC 'PROG'
  203.         ASSUME CS:TSRGROUP,DS:TSRGROUP ;ES:TSRGROUP,SS:TSRGROUP
  204.         ORG 100H
  205. ;--------------
  206. ;RESIDENT CODE
  207. ;TSR OVERRIDE AUF ALLE DATAVARIABLEN IM DATASEGMENT NICHT VERGESSEN!!!
  208. ;--------------
  209. BEGIN:        jmp SETUP
  210.  
  211.             ;---------------------------;
  212.             ;EXTENDED MEMORY BLOCK MOVE ;
  213.             ;---------------------------;
  214.  
  215. INT_15H_HANDLER    proc far
  216. ;---------------
  217. ;Trap calls to the extended memory block move function, and replace with our
  218. ;own routine.
  219. ;    ENTRY:    GATE_A20 IS OPEN
  220. ;        SEGMENT LIMIT ON DS AND ES RELAXED TO 4 GIGABYTE
  221. ;        AH = FUNCTION CODE
  222. ;----------------
  223.     cmp ah,87h        ;EXTENDED MEMORY BLOCK MOVE?
  224.     je XMBMOVE        ;YES
  225.  
  226.     jmpf            ;NO, PASS ON THE INTERRUPT
  227. INT_15H    label dword
  228. INT_15H_OFF    dw ?
  229. INT_15H_SEG    dw ?
  230.  
  231. XMBMOVE:
  232. ;----------------
  233. ;    ENTRY:    AL = EXTENDED MEMORY BLOCK MOVE CODE
  234. ;        CX = # WORDS TO MOVE
  235. ;        ES:[SI] ---> GDT TO USE
  236. ;    EXIT:    AX = 0 ===> NO ERROR
  237. ;        ZR & NC ===> DITTO
  238. ;----------------
  239. .386
  240.     push ecx
  241.     push esi
  242.     push edi
  243. .8086
  244.     push DS
  245.     push ES
  246.     pushf
  247.     STI
  248. .386
  249.     mov edi,dword ptr ES:[si].TARGET_DESC.SEGMENT_BASE
  250.     and edi,0FFFFFFH        ;mask off hi byte
  251.     mov esi,dword ptr ES:[si].SOURCE_DESC.SEGMENT_BASE
  252.     and esi,0FFFFFFH        ;ditto
  253. .8086
  254.     xor ax,ax
  255.     mov DS,ax
  256.     mov ES,ax
  257. ;-----------------------
  258. ;    DS:[ESI] ---> SOURCE
  259. ;    ES:[EDI] ---> TARGET    
  260. ;-----------------------
  261.     CLD
  262. .386
  263.     movzx ecx,cx            ;zero hi word
  264.     shr ecx,1            ;convert word count to dword count
  265. ;------------------------
  266. ;Since the next instruction uses an address size of 32 bits the register ECX
  267. ;is used for the count. LOGO, BUT BE WARNED!
  268. ;------------------------
  269.     rep movs dword ptr [edi],dword ptr [esi]
  270. ;------------------------
  271. ;move the odd word if need be: do not empty prefetch queue with a branch
  272. ;------------------------
  273.     rcl ecx,1                ;recover remainder mod 2 of word count
  274.     rep movs word ptr [edi],word ptr [esi]    ;move last word in odd case
  275. .8086
  276.     popf
  277. XMBMOVE_X:
  278.     pop ES
  279.     pop DS
  280. .386
  281.     pop edi
  282.     pop esi
  283.     pop ecx
  284. .8086
  285.     xor ax,ax        ;set no error condition
  286.                 ;pretty cockey what?
  287.     RETF 2
  288.  
  289. INT_15H_HANDLER    endp
  290.  
  291.  
  292. CODESEG    ENDS
  293.  
  294. ;
  295.  
  296. INITSEG    SEGMENT BYTE PUBLIC 'INIT'
  297.         ASSUME CS:TSRGROUP,DS:TSRGROUP
  298. ;--------------
  299. ;Throwaway code and data for the initilization of the resident portion
  300. ;--------------
  301. ;--------------
  302. ;INITDATA
  303. ;--------------
  304.  
  305. ;-------------------
  306. ;GLOBAL DESCRIPTOR TABLE FOR FOURGIG_SEG GIG!
  307. ;-------------------
  308.  
  309. GDT_PTR    label pword    ;6 bytes of data for lgdt
  310. GDT_LIMIT    dw ?
  311. GDT_ADDRESS    dd ?
  312.  
  313. GDT    label word
  314. ;-----------------
  315. ;THIS GLOBAL DESCRIPTOR TABLE IS SUITABLE TO RUN A COM FILE IN PROTECTED MODE.
  316. ;SEG_DESCRIPTOR IS A MACRO IN STD_MACS.
  317. ;-----------------
  318.         dw 4 dup (0)        ;FIRST DESCRIPTOR UNUSABLE
  319. CS_DESCRIPTOR    equ $ - GDT
  320.     SEG_DESCRIPTOR 00000000H, 000FFFFH, 0, PRESENT+CODE_SEGMENT+READABLE
  321. DS_DESCRIPTOR    equ $ - GDT
  322.     SEG_DESCRIPTOR 00000000H, 000FFFFH, 0, PRESENT+DATA_SEGMENT+WRITABLE
  323. FOURGIG_DESCRIPTOR    equ $ - GDT
  324.     SEG_DESCRIPTOR 00000000H, 07FFFFFH, 1, PRESENT+DATA_SEGMENT+WRITABLE
  325.  
  326. GDT_END    label byte
  327.  
  328. BAD_CPU_MSG    db 'XTRABIOS needs an 80386 or 80486 to run. Aborting!',07,'$'
  329.  
  330.  
  331. ;-----------------
  332. ;INIT CODE
  333. ;-----------------
  334.  
  335. SETUP:    call CHK4386
  336.     jnz INIT_1
  337.  
  338.     mov dx,offset TSR:[BAD_CPU_MSG]
  339.     mov ah,09
  340.     int 21H
  341.     int 20H
  342.  
  343. INIT_1:    call GATE_A20
  344. ;--------------------
  345. ;one could error check here
  346. ;--------------------
  347. INIT_2:
  348.     call FOURGIG_SEGS
  349. ;------------------------
  350. ;and here
  351. ;------------------------
  352. INSTALL:
  353. ;-------------------
  354. ;get the addresses of the interrupts we trap and place them in our code.
  355. ;-------------------
  356.     xor ax,ax
  357.     mov ES,ax
  358.         ASSUME ES:INT_VECTORS_SEG
  359. .386
  360.     mov eax,ES:[INT_15H_VECTOR]
  361.     mov [INT_15H],eax
  362. .8086
  363.  
  364. COPY2ROM:
  365. ;----------------
  366. ;copy our BIOS to ROM
  367. ;----------------
  368.     call OPEN_SHADOW_ROM
  369.  
  370.     mov ax,SEG ROM
  371.     mov ES,ax
  372.         ASSUME ES:ROM
  373.     xor si,si
  374.     xor di,di
  375.     mov cx,offset TSR:LAST_BYTE
  376.     CLD
  377.     rep movsb
  378.  
  379.     call CLOSE_SHADOW_ROM
  380.  
  381. ;------------------
  382. ;point interrupt vectors at our xtrabios handlers
  383. ;------------------
  384.     xor ax,ax
  385.     mov DS,ax
  386.         ASSUME DS:INT_VECTORS_SEG
  387.     CLI
  388. .386
  389.     mov [INT_15H_VECTOR],ROM_SEG SHL 16 + offset TSR:INT_15H_HANDLER
  390. .8086
  391.     STI
  392.     int 20H
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.         ASSUME DS:TSRGROUP
  400.  
  401.  
  402.  
  403.  
  404. OPEN_SHADOW_ROM    proc near
  405. ;---------------------------
  406. ;Flip bits in 8042 status register
  407. ;---------------------------
  408.     CLI            ;Disable interrupts
  409.     call GET_PORT_A        ;get 8042 status in AL
  410.     or al,10h        ;flip bit 4 on
  411.     and al,0F7h        ;bit 3 off
  412.     call WRITE2_PORT_A    ;send it to 8042
  413.     STI            ;Enable interrupts
  414.     RET
  415. OPEN_SHADOW_ROM    endp
  416.  
  417.  
  418. CLOSE_SHADOW_ROM    proc near
  419. ;---------------------------
  420. ;Flip bits 3 and 4 of keyboard data port on.
  421. ;    EXIT:    AL = CURRENT STATUS
  422. ;---------------------------
  423.     CLI            ;Disable interrupts
  424.     call GET_PORT_A        ;get keyboard controller status in AL
  425.     or al,18h        ;flip bits 3 and 4 on
  426.     call WRITE2_PORT_A    ;send it
  427.     STI            ;Enable interrupts
  428.     RET
  429. CLOSE_SHADOW_ROM    endp
  430.  
  431.  
  432.  
  433. WRITE2_PORT_A    proc near
  434. ;------------------------
  435. ;    ENTRY:    AL = CODE TO SEND TO 8042
  436. ;-------------------------
  437.     mov ah,al        ;save command
  438.     CLI
  439.     call EMPTY_8042        ;be sure 8042 input buffer is empty
  440.  
  441.     mov al,WRITE2_8042    ;enable the 8042 for a command
  442.     out STATUS_PORT,al
  443.     call EMPTY_8042
  444.  
  445.     mov al,ah        ;get the command
  446.     out PORT_A,al        ;send it to the 8042
  447.     call EMPTY_8042
  448. WRITE2_PORT_A_X:
  449.     RET
  450. WRITE2_PORT_A    endp
  451.  
  452.  
  453. GET_PORT_A    proc near
  454. ;-------------------
  455. ;    EXIT:    AL = 8042 KEYBOARD CONTROLLER STATUS
  456. ;-------------------
  457.     call EMPTY_8042        ;wait for keyboard buffer to empty
  458.     mov al,READ_FROM_8042    ;al = 0D0h, read 8042 out port
  459.     out STATUS_PORT,al    ;port 64h, kybd cntrlr functn
  460. GPA_LOOP:
  461.     in al,STATUS_PORT    ;port 64h, keyboard status
  462.     test al,OUTPUT_BUFFER_FULL
  463.     jz GPA_LOOP        ;keep waiting until data appears
  464.  
  465.     in al,PORT_A        ;get data for sw1 in AL
  466.     RET            ;return it
  467. GET_PORT_A    endp
  468.  
  469.  
  470. EMPTY_8042    proc near
  471. ;---------------
  472. ;This routine waits for the 8042 input buffer to empty
  473. ;    ENTRY:    NONE
  474. ;    EXIT:    8042 STATUS PORT EMPTY
  475. ;N.B. THIS COULD LEAD TO AN INFINITE LOOP ON A DEFECTIVE 8042
  476. ;---------------
  477. EMPTY_LOOP:
  478.     in al,STATUS_PORT
  479.     test al,INPUT_BUFFER_FULL
  480.     jnz EMPTY_LOOP
  481.  
  482.     RET
  483. EMPTY_8042    endp
  484.  
  485. GATE_A20    proc near
  486. ;------------------------
  487. ;    ENTRY:    NONE
  488. ;    EXIT:    AL = STATUS CODE
  489. ;-------------------------
  490.     CLI
  491.     call EMPTY_8042        ;be sure 8042 input buffer is empty
  492.  
  493.     mov al,WRITE2_8042    ;enable the 8042 for a command
  494.     out STATUS_PORT,al
  495.     call EMPTY_8042
  496.  
  497.     mov al,ENABLE_A20    ;get the command
  498.     out PORT_A,al        ;send it to the 8042
  499.     call EMPTY_8042
  500. GATE_A20_X:
  501.     RET
  502. GATE_A20    endp
  503.  
  504.  
  505. CHK4386    proc near
  506. ;-----------------
  507. ;make sure we are running on an 80386
  508. ;    RETURN:    NZ ===> 80386
  509. ;        Z ===> ERROR
  510. ;-----------------
  511.     push sp        ;8086 pushs the NEW stack pointer
  512.     pop ax
  513.     sub ax,2
  514.     cmp sp,ax    ;was new stack pointer pushed?
  515.     je CHK4386_X    ;YES
  516.  
  517. ;----------------
  518. ;If we get here it is an 80286 or an 80386.
  519. ;Try to set the hi bits in the flags.
  520. ;----------------
  521.     mov ax,0f000H
  522.     push ax
  523.     popf
  524.     pushf
  525.     pop ax
  526.     and ax,0f000h
  527. ;-----------------------
  528. ;If Z then it is not  386
  529. ;-----------------------
  530. CHK4386_X:
  531.     RET
  532. CHK4386    endp
  533.  
  534.  
  535. FOURGIG_SEGS    proc near
  536. ;------------
  537. ;    ENTRY:    NONE
  538. ;    EXIT:    DS,ES,FS,GS SEG LIMITS RELAXED TO 4 GIGABYTE
  539. ;        ALL REGISTERS PRESERVED
  540. ;------------
  541. .386
  542.     pushad
  543.     push GS
  544.     push FS
  545. .8086
  546.     push ES
  547.     push DS
  548.     pushf            ;store flags for return from protected mode
  549.  
  550.  
  551.     mov ax,CS        ;get our segment address
  552. ;----------------
  553. ;WARNING!!!!!!    SELF MODIFYING CODE.
  554. ;----------------
  555.     mov [THIS_CODESEG],ax    ;store it as part of far jump instruction!!
  556. .386
  557.     movzx eax,ax
  558.     shl eax,4        ;make it a linear address: N.B. ONLY 20 BITS THOUGH
  559. ;-----------------
  560. ;INITIALIZE CS, DS DESCRIPTOR BASE ADDRESSES
  561. ;-----------------
  562.     or dword ptr [GDT + CS_DESCRIPTOR  + 2],eax
  563.     or dword ptr [GDT + DS_DESCRIPTOR  + 2],eax
  564. ;-----------------
  565. ;INITIALIZE PTR FOR LGDT
  566. ;-----------------
  567.     add eax, offset TSR:[GDT]    ;linear address of GDT
  568.     mov [GDT_ADDRESS],eax        ;store
  569. .8086
  570.     mov [GDT_LIMIT],offset TSR:[GDT_END] - TSR:[GDT] - 1    
  571.  
  572.  
  573. ;-----------
  574. ;Turn off ALL interrupts: even NMI. IDT will be invalid in protected mode.
  575. ;-----------
  576.     CLI            ;easy part
  577. ;-----------
  578. ;now hard part: NMI (see AT ROM BIOS LISTING 5-52)
  579. ;-----------
  580.     in al,CMOS_PORT
  581.     mov ch,al        ;save current setting
  582.     and ch,80H        ;isolate the current NMI bit
  583.     or al,80H        ;set bit 15 to turn OFF NMIs
  584.     out CMOS_PORT,al    ;do it
  585.  
  586.     mov bx,CS        ;save current code segment
  587.  
  588. ;-------------
  589. ;switch to protected mode
  590. ;-------------
  591. .386P
  592.     lgdt CS:[GDT_PTR]    ;load GDTR
  593.     mov eax,CR0        ;get control word
  594.     or al,01B        ;set protected mode bit
  595.     mov CR0,eax        ;switch modes
  596. ;--------------
  597. ;now executing in protected mode
  598. ;--------------
  599.     jmpf            ;clear prefetch queue
  600.     dw offset TSR:[PROTECTED_MODE]
  601.     dw CS_DESCRIPTOR    ;in this protected mode segment
  602. .8086
  603. PROTECTED_MODE:
  604. ;-------------
  605. ;LOAD UP SOME REGISTERS
  606. ;-------------
  607.     mov ax,DS_DESCRIPTOR
  608.     mov SS,ax        ;point SS at a valid stack segment
  609. ;-------------
  610. ;set segment limit for DS,ES,FS,GS to 4 gigabytes
  611. ;-------------
  612.     mov ax,FOURGIG_DESCRIPTOR
  613.     mov DS,ax
  614.     mov ES,ax
  615. .386
  616.     mov FS,ax
  617.     mov GS,ax
  618. .8086
  619. ;-------------
  620. ;return to REAL mode
  621. ;-------------
  622. .386P
  623.     mov eax,CR0
  624.     and al,NOT 01B        ;turn off protected mode bit
  625.     mov CR0,eax
  626. .8086
  627. ;--------------
  628. ;clear prefetch queue: relies on self modification!!!!!!!
  629. ;--------------
  630.     jmpf            ;clear the prefetch queue!!!!!
  631. THIS_LABEL    label word
  632.     dw offset TSR:[RETURN2REALITY]
  633. THIS_CODESEG    label word
  634.      dw ?
  635. .8086
  636.  
  637. RETURN2REALITY:
  638. ;--------------
  639. ;restore segment registers
  640. ;--------------
  641.     mov SS,bx        ;bx = CS from real mode
  642.     mov DS,bx
  643.     mov ES,bx
  644.     xor ax,ax
  645. .386
  646.     mov FS,ax
  647.     mov GS,ax
  648. .8086
  649. ;--------------
  650. ;restore NMI setting
  651. ;--------------
  652.     in al,CMOS_PORT
  653.     and al,7FH        ;turn off NMI bit
  654.     or al,ch        ;restore old value
  655.     out CMOS_PORT,al    ;of NMI bit
  656.  
  657.     popf            ;and flags
  658.     pop DS
  659.     pop ES
  660. .386
  661.     pop FS
  662.     pop GS
  663.     popad
  664. .386
  665.     RET
  666.  
  667. FOURGIG_SEGS    endp
  668.  
  669.  
  670.  
  671.  
  672. INITSEG    ENDS
  673.     END BEGIN
  674.