home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_02_10 / 2n10030a < prev    next >
Text File  |  1991-08-27  |  29KB  |  971 lines

  1.     Page    60,132
  2. ;---------------------------------------------------------------
  3. ;               BEGIN LISTING 1
  4. ;---------------------------------------------------------------
  5. ;
  6. ; 286LOAD.ASM    Copyright (c) 1991 Robert Collins
  7. ;
  8. ;    This program demonstrates various aspects of CPU
  9. ;    behavior that become apparent when using LOADALL.
  10. ;
  11. ;    Test 1:  Checks that LOADALL loads all the general-
  12. ;         purpose registers; loads the segment registers
  13. ;         with values that are inconsistant to their
  14. ;         respective descriptor cache registers.
  15. ;
  16. ;    Test 2:  Access extended memory in real mode.
  17. ;
  18. ;    Test 3:  Tests that the Present bit in a descriptor
  19. ;         table can be loaded using LOADALL without
  20. ;         generating exception 11.  But when the segment
  21. ;         is accessed, exception 13 is generated.
  22. ;         NOTE:    This test should be done in protected
  23. ;         mode, but can be done in real mode.  1) In real
  24. ;         mode, no error code is pushed on the stack
  25. ;         (possibly due to a bug in the CPU).  2) Also
  26. ;         in real mode, when this program is emulated on
  27. ;         a '386, the '386 fails to set the Present bit
  28. ;         when any subsequent segment in loaded.  This
  29. ;         latter condition is clearly a bug in the '386.
  30. ;
  31. ;    This program was written for Microsoft MASM 5.1, and
  32. ;    MS DOS 3.3.  This program contains compiler directives
  33. ;    and branching techniques that might not be available
  34. ;    on previous versions of the Macro Assembler, nor in
  35. ;    competitive products.  If this program is executed on
  36. ;    any version of DOS prior to 3.3, it will most certainaly
  37. ;    cause the system to crash.  No attempt is made in this
  38. ;    program to be compatible with previous versions of DOS,
  39. ;    but compatibility can be done, and is left as an
  40. ;    exercise to the reader.
  41. ;
  42. ;---------------------------------------------------------------
  43.  
  44. ;---------------------------------------------------------------
  45. ; Compiler directives
  46. ;---------------------------------------------------------------
  47.     Title    LOADALL_286
  48.     .radix    16
  49.     .8086
  50.  
  51.  
  52. ;---------------------------------------------------------------
  53. ; Interrupt vector segment
  54. ;---------------------------------------------------------------
  55. ABS0    segment at 0
  56.     org 06h*4            ; INT 06h vector
  57.     INT_6        dd    ?
  58.  
  59.     org      0467h         ; PM Return address
  60.     PM_Ret_off    dw    ?    ;  Offset
  61.     PM_Ret_seg    dw    ?    ;  Segment
  62.  
  63.     org    800h            ; LOADALL table loc'n.
  64.     Loadall_Locn    label    word
  65.  
  66. ABS0    ends
  67.  
  68.  
  69. ;---------------------------------------------------------------
  70. ; Structure definitions
  71. ;---------------------------------------------------------------
  72. Desc_cache    STRUC        ;; Hidden descriptor cache
  73.     A15_A00 dw    ?    ;;  format.
  74.     A23_A16 db    ?
  75.     _Type    db    ?
  76.     _Limit    dw    ?
  77. Desc_cache    ENDS
  78.  
  79.  
  80. Loadall_struc    STRUC        ;; LOADALL memory image format
  81.             dw    3 dup (0)
  82.     _Msw        dw    0
  83.             dw    7 dup (0)
  84.     _Tr        dw    0
  85.     _Flags        dw    2
  86.     _Ip        dw    0
  87.     _Ldt        dw    0
  88.     _Ds        dw    2222h
  89.     _Ss        dw    4444h
  90.     _Cs        dw    1111h
  91.     _Es        dw    3333h
  92.     _Di        dw    6666h
  93.     _Si        dw    7777h
  94.     _Bp        dw    5555h
  95.     _Sp        dw    8888h
  96.     _Bx        dw    2222h
  97.     _Dx        dw    4444h
  98.     _Cx        dw    3333h
  99.     _Ax        dw    1111h
  100.     ES_Desc     db    00,00,03,93h,0ffh,0ffh
  101.     CS_Desc     db    00,00,00,9bh,0ffh,0ffh
  102.     SS_Desc     db    00,00,04,93h,0ffh,0ffh
  103.     DS_Desc     db    00,00,02,93h,0ffh,0ffh
  104.     Gdt_Desc    db    00,00,00,00h,000h,000h
  105.     Ldt_Desc    db    00,00,06,82h,088h,000h
  106.     Idt_Desc    db    00,00,00,00h,0ffh,003h
  107.     TSS_Desc    db    00,00,05,89h,000h,008h
  108. Loadall_Struc    ENDS
  109.  
  110.  
  111. Descriptor  STRUC
  112.     Seg_limit        dw        ?    ; Segment limit
  113.     Base_A15_A00    dw        ?    ; A00..A15 of base address
  114.     Base_A23_A16    db        ?    ; A16..A23 of base address
  115.     Access_rights   db        ?    ; Segment access rights
  116.     Limit_A19_A16   db        ?    ; Granularity, Op-size,
  117.                 ;  Limit A16..A19
  118.     Base_A31_A24    db        ?    ; A24..A31 of base address
  119. Descriptor  ENDS
  120.  
  121.  
  122. INT_Desc    STRUC
  123.     IGate_Offset    dw        ?    ; Offset of handler
  124.     CSEG_Sel        dw        ?    ; Code segment selector
  125.             db        0
  126.             db        86h ; 286 interrupt gate=16bit
  127.                 ;  CS:IP, FLAGS
  128.     Resvd        dw        0    ; Reserved=0
  129. INT_Desc    ENDS
  130.  
  131.  
  132. ;---------------------------------------------------------------
  133. ; Macro definitions
  134. ;---------------------------------------------------------------
  135. FARJMP    MACRO    destination,selector    ; dynamic JMP FAR SEG:OFF
  136.     db    0eah            ;; jmp instruction
  137.     dw    offset destination    ;; offset word
  138.     dw    selector        ;; segment selector word
  139.     endm
  140.  
  141.  
  142. IO_DELAY    MACRO
  143.     out    0edh,ax
  144.     endm
  145.  
  146. LOADALL     MACRO
  147.     mov    cx,ABS0
  148.     mov    es,cx
  149.     mov    cx,(size Loadall_struc) / 2
  150.     mov    si,offset Loadall_tbl
  151.     mov    di,800h
  152.     rep    movsw
  153.     db    0fh,05
  154.     ENDM
  155.  
  156. PRINT_STRING    MACRO    MSG_NAME
  157.     mov    ah,9
  158.     mov    dx,offset MSG_NAME
  159.     int    21h
  160.     ENDM
  161. ;--------------------------------------------------------------
  162.  
  163.  
  164.     _DATA     SEGMENT PARA PUBLIC 'DATA'
  165. ;---------------------------------------------------------------
  166. ; Equates & local variables
  167. ;---------------------------------------------------------------
  168. ; Protected mode access rights
  169. ;---------------------------------------------------------------
  170.     CS_access    equ    10011011b
  171.     DS_access    equ    10010011b
  172.  
  173. ;---------------------------------------------------------------
  174. ; Text equates
  175. ;---------------------------------------------------------------
  176.     CRLF        equ    <0dh,0ah>
  177.     CRLF$        equ    <CRLF,'$'>
  178.     INT6        equ    [bp-4]
  179.  
  180. ;---------------------------------------------------------------
  181. ; Conditional compilation.  Set USE_386=1 if you plan to execute
  182. ; this program on a '386 using EMULOAD.
  183. ;---------------------------------------------------------------
  184.     USE_386     equ    0
  185.  
  186.  
  187. ;---------------------------------------------------------------
  188. ; Loadall table(s)
  189. ;---------------------------------------------------------------
  190.     Loadall_tbl    Loadall_struc <>
  191.     Machine_State    Loadall_struc <>
  192.  
  193. ;---------------------------------------------------------------
  194. ; Global Descriptor Table
  195. ;---------------------------------------------------------------
  196.     GDT_286 Descriptor    <Gdt2_len-1,,,DS_access>
  197.     CSEG2    Descriptor    <0ffffh,,,CS_access>    ; CS
  198.     DSEG2    Descriptor    <0ffffh,,,DS_access>    ; DS
  199.     Gdt2_len      equ    $-Gdt_286
  200.  
  201. ;---------------------------------------------------------------
  202. ; Interrupt Descriptor Table
  203. ;---------------------------------------------------------------
  204. IDT_286 INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT00
  205.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT01
  206.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT02
  207.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT03
  208.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT04
  209.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT05
  210.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT06
  211.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT07
  212.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT08
  213.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT09
  214.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT0a
  215.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT0b
  216.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT0c
  217.     INT_Desc    <Offset INT13,CSEG2-GDT_286>    ; INT0d
  218. IDT2_Len    equ    $-IDT_286
  219.  
  220. ;---------------------------------------------------------------
  221. ; Misc. local variables
  222. ;---------------------------------------------------------------
  223. Mem_buffer    db    400h dup (0)
  224. Results     dw    0
  225. i8259_1     db    ?    ; Status for master device
  226. i8259_2     db    ?    ; Status of slave device
  227.  
  228.  
  229. ;---------------------------------------------------------------
  230. ; String Messages
  231. ;---------------------------------------------------------------
  232. Passed    db    "    PASSED.",CRLF$
  233. Failed    db    "--> FAILED <--",CRLF$
  234. Not_286 db    "Not 80286 class computer.",CRLF$
  235. Rmvd    db    "LOADALL removed from 80286 mask.",CRLF$
  236. RFail    db    "Registers weren't loaded correctly."
  237. LF    db     CRLF$
  238.  
  239. ;---------------------------------------------------------------
  240. ; I'm doing this wierd string definition technique to limit the
  241. ; page width to 64 characters.
  242. ;---------------------------------------------------------------
  243. Test_1    label    word
  244. db    "Test 1:  Testing 286 LOADALL instruction:         ",24
  245.  
  246. Test_2    label    word
  247. db    "Test 2:  Testing extended memory in real mode:    ",24
  248.  
  249. Test_3    label word
  250. db    "Test 3:  Testing Present BIT in descriptor:       ",24
  251.  
  252. _DATA     ends
  253.  
  254.  
  255.     _TEXT    SEGMENT PARA PUBLIC 'CODE'
  256.     ASSUME    CS:_TEXT, DS:_DATA, ES:_DATA, SS:STACK
  257.     .286p
  258. ;---------------------------------------------------------------
  259. ; A little CS-relative data for the stack pointer.  This is
  260. ; to avoid using other kludge techniques, caused by using
  261. ; LOADALL, that make using the data segment undesirable.
  262. ;---------------------------------------------------------------
  263.     Stack_ptr    dw    0
  264.             dw    0
  265.  
  266. ;---------------------------------------------------------------
  267.   LOADALL_286    proc    far
  268. ;---------------------------------------------------------------
  269.     PUSH    DS            ; Setup the stack to
  270.     XOR    AX,AX            ;  return to DOS
  271.     PUSH    AX
  272.  
  273.     MOV    AX,_Data
  274.     MOV    DS,AX
  275.     MOV    ES,AX
  276.  
  277. ;---------------------------------------------------------------
  278. ; Check CPU type, and set up a minimal invalid opcode handler
  279. ; in case LOADALL has been removed from the CPU mask.
  280. ;---------------------------------------------------------------
  281.       IFE    USE_386
  282.     Call    CPU_Type        ; 286, 386?
  283.     cmp    ax,2            ; 286?
  284.     je    short @F        ; yep
  285.     Print_String    LF
  286.     Print_String    Not_286
  287.     retf                ; go split
  288.  
  289. @@:    enter    4,0            ; create stack frame
  290.     mov    word ptr INT6,offset INT6_handler
  291.     mov    INT6[2],cs
  292.     call    set_INT6_vector     ; set our INT6 handler
  293.       ENDIF
  294.  
  295.     cli
  296.     Call    Save_State        ; Save the current CPU
  297.     Print_String    LF        ;  state
  298.     Print_String    Test_1
  299.  
  300.  
  301. ;---------------------------------------------------------------
  302. ;
  303. ; TEST1:  Real mode
  304. ;      Test general purpose registers
  305. ;      Test Segment registers
  306. ;      Test Descriptor cache base address
  307. ;
  308. ;  (1) Setup LOADALL structures, and pointers
  309. ;  (2) Execute LOADALL
  310. ;  (3) Verify results of the test
  311. ;
  312. ;---------------------------------------------------------------
  313.     mov    ax,cs            ; Prepare 24-bit
  314.     mov    es,ax            ;  physical address that
  315.     mov    si,0            ;  is put in the LOADALL
  316.     call    Calc_pm_address     ;  descriptor cache
  317.     mov    Loadall_tbl.CS_Desc.A15_A00,ax    ; entry.
  318.     mov    Loadall_tbl.CS_Desc.A23_A16,dl
  319.     smsw    ax
  320.     mov    Loadall_tbl._Msw,ax
  321.     mov    Loadall_tbl._Ip,offset Verify_State
  322.     mov    word ptr cs:stack_ptr,sp    ; save SS:SP
  323.     mov    word ptr cs:stack_ptr[2],ss
  324.     LOADALL             ; If LOADALL is removed
  325.     nop                ;  from the CPU mask,
  326.     Print_String    failed        ;  then fall through
  327.     Print_String    Rmvd        ;  to here.
  328.  
  329. Loadall_RET:
  330.     call    Restore_state
  331.  
  332.       IFE    USE_386
  333.     call    set_INT6_vector     ; set our INT6 handler
  334.     leave
  335.       ENDIF
  336.  
  337.     retf
  338.  
  339. ;---------------------------------------------------------------
  340.   Verify_State:         ; Verify that LOADALL worked
  341. ;---------------------------------------------------------------
  342. ; This is where we land for the first test of '286 LOADALL.
  343. ; The purpose of this test is to verify that all the general
  344. ; purpose registers get loaded correctly.  Specifically, we are
  345. ; testing to verify that all segment registers contain values
  346. ; that don't correspond to the memory addresses they appear to
  347. ; be pointing to.  In other words, we are checking that the
  348. ; that the segment registers have one value, while their
  349. ; associated hidden descriptor cache registers have different
  350. ; values.
  351. ;---------------------------------------------------------------
  352.     cmp    ax,1111h        ; Test AX
  353.     jne    @F
  354.     cmp    bx,2222h        ; Test BX
  355.     jne    @F
  356.     cmp    cx,3333h        ; Test CX
  357.     jne    @F
  358.     cmp    dx,4444h        ; Test DX
  359.     jne    @F
  360.     cmp    bp,5555h        ; Test BP
  361.     jne    @F
  362.     cmp    di,6666h        ; Test DI
  363.     jne    @F
  364.     cmp    si,7777h        ; Test SI
  365.     jne    @F
  366.     cmp    sp,8888h        ; Test SP
  367.     jne    short @F
  368.     mov    ax,cs            ; Test CS
  369.     cmp    ax,1111h
  370.     jne    short @F
  371.     mov    ax,ds            ; Test DS
  372.     cmp    ax,2222h
  373.     jne    short @F
  374.     mov    ax,es            ; Test ES
  375.     cmp    ax,3333h
  376.     jne    short @F
  377.     mov    ax,ss            ; Test SS
  378.     cmp    ax,4444h
  379.     jne    short @F
  380.     cmp    word ptr ds:[0],0202h    ; Test DS Desc Cache
  381.     jne    short @F
  382.     cmp    word ptr es:[0],0303h    ; Test ES Desc Cache
  383.     jne    short @F
  384.     cmp    word ptr ss:[0],0404h    ; Test SS Desc Cache
  385.     jne    short @F
  386.     mov    ax,_Data
  387.     mov    ds,ax
  388.     mov    es,ax
  389.  
  390.     mov    ax,cs:stack_ptr[2]
  391.     mov    ss,ax
  392.     mov    sp,cs:stack_ptr
  393.     FARJMP    <@Test1_Pass>,<seg _Text>
  394.  
  395. ;---------------------------------------------------------------
  396. ; Loadall failed the REGISTERs test.
  397. ;---------------------------------------------------------------
  398. @@:    mov    ax,_Data
  399.     mov    ds,ax
  400.     mov    es,ax
  401.     mov    ax,cs:stack_ptr[2]
  402.     mov    ss,ax
  403.     mov    sp,cs:stack_ptr
  404.     FARJMP    <@F>,<seg _Text>
  405.  
  406. @@:    Print_String    failed
  407.     Print_String    RFail
  408.     jmp    loadall_ret
  409.  
  410. ;---------------------------------------------------------------
  411. ; LOADALL passed
  412. ;---------------------------------------------------------------
  413. @Test1_Pass:
  414.     Print_String    passed
  415.  
  416. ;---------------------------------------------------------------
  417. ;
  418. ; TEST2:  Access extended memory while in real mode.
  419. ;
  420. ;  (1) Enable A20
  421. ;  (2) Save contents of extended memory
  422. ;  (3) Write data pattern in extended memory
  423. ;  (4) Set IP & ES descriptor cache pointing to extended memory
  424. ;  (5) LOADALL
  425. ;  (6) Verify results
  426. ;  (7) Restore original data in extended memory
  427. ;
  428. ;----------------------------------------------------------------
  429.     Print_String    Test_2
  430.     Call    Enable_Gate20        ; Enable extended memory
  431.     mov    bx,0ffffh        ; Point to extended mem.
  432.     mov    ds,bx            ;  as FFFF:0010
  433.     mov    si,10h
  434.     mov    di,offset Mem_buffer
  435.     mov    cx,400h / 2        ; 1k data block to test
  436.     rep    movsw            ; save extended memory
  437.     mov    ax,5aa5h        ; test pattern
  438.     mov    es,bx            ; point to extended mem.
  439.     mov    cx,400h / 2
  440.     mov    di,10h
  441.     rep    stosw            ; store pattern in mem.
  442.     mov    ax,_data
  443.     mov    ds,ax
  444.     mov    Loadall_tbl._AX,5aa5h
  445.     mov    Loadall_tbl._CX,400h / 2
  446.     mov    Loadall_tbl._DI,0h
  447.     mov    Loadall_tbl._SP,sp    ; save SP
  448.     mov    Loadall_tbl._IP,offset @F
  449.     mov    Loadall_tbl.ES_Desc.A15_A00,00
  450.     mov    Loadall_tbl.ES_Desc.A23_A16,10
  451.     LOADALL
  452.  
  453. @@:    repz    scasw            ; data match?
  454.     lahf                ; get flags
  455.     mov    bx,_Data
  456.     mov    ds,bx
  457.     mov    cx,0ffffh
  458.     mov    es,cx
  459.     mov    cx,400h / 2
  460.     mov    si,offset Mem_buffer
  461.     mov    di,10h
  462.     rep    movsw            ; restore data
  463.     mov    es,bx
  464.     mov    cx,cs:stack_ptr[2]
  465.     mov    ss,cx
  466.     FARJMP    <@F>,<seg _Text>
  467. @@:    sahf                ; restore flags
  468.     jz    @Test2_Pass
  469.     PRINT_STRING    failed
  470.     jmp    Loadall_RET
  471.  
  472. @Test2_Pass:
  473.     PRINT_STRING    passed
  474.  
  475. ;---------------------------------------------------------------
  476. ;
  477. ; TEST3:  Test that the Present bit gets loaded w/out exception,
  478. ;      but when a segment is accessed INT13 get generated.
  479. ;
  480. ;      If LOADALL works even remotely like we think it does,
  481. ;      then this test will work in REAL MODE!  And as this
  482. ;      test was originally programmed, it did!  However, I
  483. ;      was doing my testing by emulating '286 LOADALL with
  484. ;      '386 LOADALL, where I could use an ICE for debug
  485. ;      purposes.  The code worked on a '286, but failed on a
  486. ;      '386!  I found that the '386 fails to clear the
  487. ;      Present bit in the descriptor cache register when a
  488. ;      segment register is loaded in real mode.  This is
  489. ;      obviously a bug in the '386.  Since the CPU is in a
  490. ;      state that can never be duplicated under any program
  491. ;      control, except by using LOADALL (Present=0), the bug
  492. ;      will never be manifested in any production code.  As a
  493. ;      result, I reprogramed this example to use protected
  494. ;      mode so it would work on both the '286 and '386.
  495. ;
  496. ;  (1) Prepare GDT & IDT descriptor cache registers and
  497. ;      descriptor tables, & segment selectors
  498. ;  (2) Set protected mode bit, clear Present bit, set IP
  499. ;  (3) Save the 8259 masks, set the PM return address, and set
  500. ;      CMOS shutdown=5
  501. ;  (4) LOADALL
  502. ;  (5) Generate the exception
  503. ;  (6) Reset ES to a valid segment selector & save results of
  504. ;      test.
  505. ;  (7) Reset the CPU, restore 8259 masks, inhibit A20 from the
  506. ;      CPU bus, restore segment registers to real mode values.
  507. ;  (8) Verify the results
  508. ;
  509. ;---------------------------------------------------------------
  510. ; Test Present bit:  verify that P=0 in a descriptor cache
  511. ; register will, even in REAL MODE, will generate an exception
  512. ; 13 when trying to access memory
  513. ;---------------------------------------------------------------
  514. Test3:    Print_String    Test_3
  515.     mov    ax,_Data
  516.     mov    es,ax
  517.     mov    si,0
  518.     call    Calc_pm_address
  519.     mov    DSEG2.Base_A15_A00,ax
  520.     mov    DSEG2.Base_A23_A16,dl
  521.     add    ax,offset GDT_286
  522.     adc    dl,0
  523.     mov    Loadall_tbl.GDT_Desc.A15_A00,ax
  524.     mov    Loadall_tbl.GDT_Desc.A23_A16,dl
  525.     mov    Loadall_tbl.GDT_Desc._Limit,GDT2_Len-1
  526.     mov    si,offset IDT_286
  527.     call    Calc_pm_address
  528.     mov    Loadall_tbl.IDT_Desc.A15_A00,ax
  529.     mov    Loadall_tbl.IDT_Desc.A23_A16,dl
  530.     mov    Loadall_tbl.IDT_Desc._Limit,IDT2_Len-1
  531.     mov    ax,_TEXT
  532.     mov    es,ax
  533.     mov    si,0
  534.     call    Calc_pm_address
  535.     mov    CSEG2.Base_A15_A00,ax
  536.     mov    CSEG2.Base_A23_A16,dl
  537.     mov    Loadall_tbl._CS,CSEG2-GDT_286
  538.  
  539.     or    Loadall_tbl._MSW,1
  540.     and    Loadall_tbl.ES_Desc._Type,7fh    ; Clear P bit
  541.     mov    Loadall_tbl._IP,offset @PM_286    ; Set IP
  542.  
  543.     Call    Get_INT_Status        ; save PIC masks
  544.     mov    ax,offset @RM_286    ; save real mode return
  545.     Call    SetPM_RET_addr        ;  address
  546.     Call    Set_shutdown_type    ; set shutdown in CMOS
  547.  
  548.     LOADALL
  549.  
  550. @PM_286:mov    al,es:[di][2]
  551.  
  552.     mov    ax,DSEG2-GDT_286
  553.     mov    es,ax
  554.     mov    ES:Results,di
  555.     jmp    RESET_CPU
  556.  
  557. @RM_286:mov    ax,cs:stack_ptr[2]
  558.     mov    ss,ax
  559.     mov    sp,cs:stack_ptr
  560.     mov    ax,_Data
  561.     mov    ds,ax
  562.     mov    es,ax
  563.     call    Set_INT_Status
  564.     call    Shut_A20
  565.  
  566.     mov    di,Results        ; If an exception 13 was
  567.     test    di,1            ;  generated, then the
  568.     jnz    @F            ;  low bit of DI is set
  569.  
  570.  
  571.     Print_String    failed        ; Test failed
  572.     jmp    Loadall_RET
  573.  
  574. @@:    Print_String    passed        ; Test passed
  575.     jmp    Loadall_RET
  576. LOADALL_286    endp
  577.  
  578.  
  579. ;---------------------------------------------------------------
  580. ; Minimal exception 13 handler that points past a 4-byte opcode,
  581. ; and sets the lowest bit in DI before returning.
  582. ;---------------------------------------------------------------
  583.     INT13    label    word
  584.     push    bp
  585.     mov    bp,sp
  586.     add    word ptr [bp][4],4
  587.     or    di,1
  588.     pop    bp
  589.     add    sp,2
  590.     iret
  591.  
  592.  
  593. ;---------------------------------------------------------------
  594. ; Equates & local variables
  595. ;---------------------------------------------------------------
  596. ; I/O Ports
  597. ;---------------------------------------------------------------
  598.     Mstrmsk     equ    021h    ; 8259 master mask addr
  599.     KBC_CTL     equ    060h    ; 8042 control port
  600.     KBC_STAT    equ    064h    ; 8042 status port
  601.     Cmos_index    equ    070h    ; CMOS address port
  602.     Cmos_data    equ    071h    ; CMOS data port
  603.     Slv_msk     equ    0a1h    ; 8259 slave mask addr
  604.  
  605. ;---------------------------------------------------------------
  606. ; CMOS RAM
  607. ;---------------------------------------------------------------
  608.     Shut_down    equ    00fh    ; CMOS index for shutdwn
  609.     Type5        equ    5    ; Shutdown type-5
  610.  
  611. ;---------------------------------------------------------------
  612. ; Keyboard Controller
  613. ;---------------------------------------------------------------
  614.     inpt_buf_full    equ    2    ; Input buffer full
  615.     Shutdown_CMD    equ    0feh    ; Shutdown CMD for KBC
  616.     enable_bit20    equ    0dfh    ; enable A20 command
  617.     disable_bit20    equ    0ddh    ; disable A20 command
  618.  
  619.  
  620. ;---------------------------------------------------------------;
  621.   RESET_CPU:; Resets the CPU by sending a shutdown command to
  622. ;          the keyboard controller.
  623. ;---------------------------------------------------------------
  624. ; Input:   None
  625. ; Output:  None
  626. ; Register(s) modified:  Doesn't matter, the CPU is reset
  627. ;---------------------------------------------------------------
  628.     mov    al,Shutdown_CMD ; get shutdown command
  629.     out    KBC_STAT,al    ; send command to shutdown CPU
  630.     cli            ; disable interrupts so that
  631.                 ;  an INT can't come through
  632.                 ;  before the CPU resets
  633.     hlt            ;
  634.  
  635.  
  636. ;---------------------------------------------------------------;
  637. ; SETPM_RET_ADDR:  Save the real-mode return address @ 40:67
  638. ;           from protected mode.
  639. ;---------------------------------------------------------------
  640. ; Input:   CS:AX = Return address from PM.
  641. ;       DS     = Better darn well have a PM segment selector!
  642. ;           (Or else Kablooie!)
  643. ; Output:  None
  644. ; Register(s) modified:  None
  645. ;---------------------------------------------------------------
  646.   Setpm_ret_addr    proc    near
  647. ;---------------------------------------------------------------
  648.     push    dx        ; save it
  649.     push    ds
  650.     mov    dx,ABS0     ;
  651.     mov    ds,dx
  652. ASSUME    DS:ABS0
  653.     mov    DS:PM_Ret_off,ax
  654.     mov    DS:PM_Ret_seg,cs
  655. ASSUME    DS:_DATA
  656.     pop    ds
  657.     pop    dx
  658.     ret
  659. Setpm_ret_addr    endp
  660.  
  661.  
  662. ;---------------------------------------------------------------
  663. ; Get_INT_status:  Saves the master and slave mask register
  664. ;           contents from the 8259 interrupt controller.
  665. ;---------------------------------------------------------------
  666. ; Input:   DS       = _DATA SEGMENT
  667. ; Output:  i8259_1 = Status of master device
  668. ;       i8259_2 = Status of slave device
  669. ; Register(s) modified:  None
  670. ;---------------------------------------------------------------
  671.   Get_int_status    proc    near
  672. ;---------------------------------------------------------------
  673.     push    ax
  674.     in    al,mstrmsk    ; get master PIC mask
  675.     mov    i8259_1,al
  676.     IO_Delay        ; I/O delay
  677.     in    al,slv_msk    ; get slave PIC mask
  678.     mov    i8259_2,al
  679.     pop    ax
  680.     ret            ; exit
  681. Get_int_status    endp
  682.  
  683.  
  684. ;---------------------------------------------------------------;
  685. ; Set_INT_status:  Restores the interrupt status of the 8259A
  686. ;           programmable interrupt controller (PIC).
  687. ;---------------------------------------------------------------
  688. ; Input:   i8259_1 = Status of master device
  689. ;       i8259_2 = Status of slave device
  690. ;       DS       = _DATA SEGMENT
  691. ; Output:  None
  692. ; Register(s) modified:  None
  693. ;---------------------------------------------------------------
  694.   Set_int_status    proc    near
  695. ;---------------------------------------------------------------
  696.     pushf            ; save interrupt flag
  697.     cli            ; we REALLY don't want an int
  698.                 ;  to come through while we are
  699.     push    ax        ;  reprogramming the PIC masks
  700.     mov    al,i8259_1
  701.     out    mstrmsk,al    ; restore master PIC mask
  702.     IO_Delay        ; I/O delay
  703.     mov    al,i8259_2
  704.     out    slv_msk,al    ; restore slave PIC mask
  705.     pop    ax
  706.     popf            ; restore interrupt flag
  707.     ret            ; exit
  708. Set_int_status    endp
  709.  
  710.  
  711. ;---------------------------------------------------------------
  712. ; SET_SHUTDOWN_TYPE:  Set the processor shutdown type-5 in CMOS.
  713. ;---------------------------------------------------------------
  714. ; Input:   None
  715. ; Output:  None
  716. ; Register(s) modified:  None
  717. ;---------------------------------------------------------------
  718.   Set_shutdown_type    proc    near
  719. ;---------------------------------------------------------------
  720.     pushf            ; save interrupt status
  721.     cli            ; disable ints so somebody else
  722.                 ;  doesn't do this right now
  723.     push    ax
  724.     mov    al,shut_down    ; Set shutdown byte
  725.     out    cmos_index,al    ; to shut down x05.
  726.     IO_Delay        ; I/O delay
  727.     mov    al,Type5    ;
  728.     out    cmos_data,al    ; CMOS data port
  729.     pop    ax
  730.     popf
  731.     ret
  732. set_shutdown_type    endp
  733.  
  734.  
  735. ;---------------------------------------------------------------
  736. ; Enable_gate20:  Turn on A20, and check for errors.
  737. ;---------------------------------------------------------------
  738. ; Input:   None
  739. ; Output:  CY=ERROR
  740. ; Register(s) modified:  None
  741. ;---------------------------------------------------------------
  742.   Enable_gate20 proc    near
  743. ;---------------------------------------------------------------
  744.     push    ax
  745.     mov    ah,enable_bit20     ; gate address bit 20 on
  746.     Call    Gate_A20
  747.     or    al,al            ; command accepted?
  748.     jz    A20_OK            ; go if yes
  749.     stc                ; set error flag
  750. A20_OK: pop    ax
  751.     ret                ; exit
  752. Enable_gate20    endp
  753.  
  754.  
  755. ;---------------------------------------------------------------
  756. ; SHUT_A20:  Disable A20 from CPU address BUS.
  757. ;---------------------------------------------------------------
  758. ; Input:   None
  759. ; Output:  CY=ERROR
  760. ; Register(s) modified:  None
  761. ;---------------------------------------------------------------
  762.   Shut_a20    proc    near
  763. ;---------------------------------------------------------------
  764.     push    ax
  765.     mov    ah,disable_bit20    ; gate address bit 20 on
  766.     Call    Gate_A20
  767.     or    al,al            ; was command accepted?
  768.     jz    A20_Shut        ; go if yes
  769.     stc                ; set error flag
  770.  
  771. A20_Shut:
  772.     pop    ax
  773.     ret                ; exit
  774. Shut_a20    endp
  775.  
  776.  
  777. ;---------------------------------------------------------------
  778. ; GATE_A20:  This routine controls a signal which gates address
  779. ;         line 20 (A20).  The gate A20 signal is an output of
  780. ;         of the 8042 slave processor (keyboard controller).
  781. ;         A20 should be gated on before entering protected
  782. ;         mode, to allow addressing of the entire 16M address
  783. ;         space of the 80286, or 4G address space of the
  784. ;         80386 & 80486.  It should be gated off after
  785. ;         entering real mode -- from protected mode.
  786. ;---------------------------------------------------------------
  787. ; Input:   AH = DD ==> A20 gated off (A20 always 0)
  788. ;       AH = DF ==> A20 gated on  (CPU controls A20)
  789. ; Output:  AL = 0  ==> Operation successful
  790. ;       AL = 2  ==> Operation failed, 8042 can't accept cmd
  791. ; Register(s) modified:  AX
  792. ;---------------------------------------------------------------
  793.   Gate_a20    proc    near
  794. ;---------------------------------------------------------------
  795.     pushf            ; save interrupt status
  796.     cli            ; disable ints while using 8042
  797.     Call    Empty_8042    ; insure 8042 input buffer empty
  798.     jnz    A20_Fail    ; ret: 8042 unable to accept cmd
  799.     IO_Delay        ; I/O Delay
  800.     mov    al,0D1h     ; 8042 cmd to write output port
  801.     out    KBC_STAT,al    ; output cmd to 8042
  802.     Call    Empty_8042    ; wait for 8042 to accept cmd
  803.     jnz    A20_Fail    ; ret: 8042 unable to accept cmd
  804.     mov    al,ah        ; 8042 port data
  805.     out    KBC_CTL,al    ; output port data to 8042
  806.     Call    Empty_8042    ; wait for 8042 to port data
  807.     push    cx        ; save it
  808.     mov    cx,14h        ;
  809. @DLY:    IO_Delay        ; Wait for KBC to execute the
  810.     loop    @DLY        ;  command.  (about 25uS)
  811.     pop    cx        ; restore it
  812.  
  813. A20_Fail:
  814.     popf            ; restore flags
  815.     ret
  816. Gate_a20    endp
  817.  
  818.  
  819. ;---------------------------------------------------------------
  820. ; EMPTY_8042:  This routine waits for the 8042 buffer to empty.
  821. ;---------------------------------------------------------------
  822. ; Input:   None
  823. ; Output:  AL = 0, 8042 input buffer empty:    ZF
  824. ;       AL = 2, Time out; 8042 buffer full:    NZ
  825. ; Register(s) modified:  AX
  826. ;---------------------------------------------------------------
  827.   Empty_8042    proc    near
  828. ;---------------------------------------------------------------
  829.     push    cx        ; save CX
  830.     xor    cx,cx        ; CX=0:  timeout value
  831.  
  832. Try_KBC:
  833.     IO_Delay        ;
  834.     in    al,KBC_STAT    ; read 8042 status port
  835.     and    al,inpt_buf_full; input buffer full flag (D1)
  836.     loopnz    Try_KBC     ; loop until input buffer empty
  837.                 ;   or timeout
  838.     pop    cx        ; restore CX
  839.     ret
  840. Empty_8042    endp
  841.  
  842.  
  843. ;---------------------------------------------------------------
  844. ; CALC_PM_ADDRESS:  Calculate 32-bit protected mode address.
  845. ;            Used for building descriptor tables.
  846. ;---------------------------------------------------------------
  847. ; Input:   ES:SI = Real mode address
  848. ; Output:  DX:AX = 32-bit linear address
  849. ; Register(s) modified:  AX, DX
  850. ;---------------------------------------------------------------
  851.   Calc_pm_address    proc    near
  852. ;---------------------------------------------------------------
  853.     mov    ax,es        ; point to control block
  854.     xor    dh,dh        ; clear upper register
  855.     mov    dl,ah        ; build high byte of 32-bit addr
  856.     shr    dl,4        ; use only high nibble from (AX)
  857.     shl    ax,4        ; strip high nibble from segment
  858.     add    ax,si        ; add GDT offset for low word
  859.     adc    dx,0        ; adj high byte if CY from low
  860.     ret            ; back to calling program
  861. calc_pm_address endp
  862.  
  863.  
  864. ;---------------------------------------------------------------
  865.   Save_state    proc    near    ; Save the machine state before
  866. ;                ; LOADALL
  867. ;---------------------------------------------------------------
  868.     push    ax
  869.     push    ds
  870.     mov    si,0
  871.     mov    di,offset Machine_State.ES_Desc
  872.     mov    ax,3000h        ; ES descriptor
  873.     mov    ds,ax
  874.     mov    bx,0303h
  875.     movsw
  876.     mov    word ptr [si-2],bx
  877.  
  878.     add    ax,1000h        ; SS descriptor
  879.     add    bx,0101h
  880.     mov    si,0
  881.     add    di,0ah
  882.     mov    ds,ax
  883.     movsw
  884.     mov    word ptr [si-2],bx
  885.     sub    ax,2000h        ; DS descriptor
  886.     sub    bx,0202h
  887.     mov    si,0
  888.     add    di,4
  889.     mov    ds,ax
  890.     movsw
  891.     mov    word ptr [si-2],bx
  892.     pop    ds
  893.  
  894.     smsw    ax
  895.     mov    Machine_State._Msw,ax
  896.     pushf
  897.     pop    ax
  898.     mov    Machine_State._Flags,ax
  899.     pop    ax
  900.     mov    Machine_State._DI,di
  901.     mov    Machine_State._SI,si
  902.     mov    Machine_State._BP,bp
  903.     mov    Machine_State._BX,bx
  904.     mov    Machine_State._DX,dx
  905.     mov    Machine_State._CX,cx
  906.     mov    Machine_State._AX,ax
  907.     mov    ax,ds
  908.     mov    Machine_State._DS,ax
  909.     mov    ax,es
  910.     mov    Machine_State._ES,ax
  911.     ret
  912. Save_state    endp
  913.  
  914.  
  915. ;---------------------------------------------------------------
  916.   Restore_state proc    near    ; Restore the machine state
  917. ;                ; after LOADALL
  918. ;---------------------------------------------------------------
  919.     mov    ax,_data
  920.     mov    ds,ax
  921.     mov    ax,3000h        ; ES
  922.     mov    es,ax
  923.     mov    si,offset Machine_State.DS_Desc
  924.     mov    di,0
  925.     movsw
  926.     add    ax,1000h        ; SS
  927.     add    si,0ah
  928.     mov    di,0
  929.     mov    es,ax
  930.     movsw
  931.     sub    ax,2000h        ; DS
  932.     add    si,4
  933.     mov    di,0
  934.     mov    es,ax
  935.     movsw
  936.     mov    ax,Machine_State._ES
  937.     mov    es,ax
  938.     mov    ax,Machine_State._DS
  939.     mov    ds,ax
  940.     mov    ax,Machine_State._Flags
  941.     push    ax
  942.     popf
  943.     mov    ax,Machine_State._Msw
  944.     lmsw    ax
  945.     mov    ax,Machine_State._AX
  946.     mov    cx,Machine_State._CX
  947.     mov    dx,Machine_State._DX
  948.     mov    bx,Machine_State._BX
  949.     mov    bp,Machine_State._BP
  950.     mov    si,Machine_State._SI
  951.     mov    di,Machine_State._DI
  952.     ret
  953. Restore_State    endp
  954.  
  955.  
  956.       IFE    USE_386
  957. ;---------------------------------------------------------------
  958. ; Include the CPU_TYPE procedure & LOADALL test
  959. ;---------------------------------------------------------------
  960.     Include CPU_TYPE.ASM
  961.       ENDIF
  962.  
  963. _text    ends
  964.  
  965.  
  966.     stack    segment para stack 'stack'
  967.     db    400h dup (0)
  968.     stack    ends
  969.  
  970.     end    LOADALL_286
  971.