home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0010 - 0019 / ibm0010-0019 / ibm0010.tar / ibm0010 / CDOSDSK5.ZIP / CDOSDSK5.TD0 / XIOS / V386.A86 < prev    next >
Encoding:
Text File  |  1989-01-26  |  53.8 KB  |  2,187 lines

  1. ; V386.A86
  2. title '386 Initialization'
  3. pagesize 60+11
  4. ;********************************************************
  5. ;*                            *
  6. ;*        XIOS INITIALIZATION ROUTINE        *
  7. ;*        CDOS 386 XIOS                *
  8. ;*        DRI OS ENGR, GMS, JW            *
  9. ;*                            *
  10. ;********************************************************
  11. ;*                            *
  12. ;*        RASM86 V386 $pz sz nc 286        *
  13. ;*                            *
  14. ;********************************************************
  15.  
  16. ; Modifications :-
  17. ;
  18. ; 3.0
  19. ; 12 JAN 89 -- Page fault detects reset IDLE if screen I/O    GMS
  20. ; 12 Jan 89 -- increase memory free list for systems =512 conv  IJ
  21. ; 10 Nov 88 -- check if ROM BIOS access to port 61h on SR    GMS
  22. ;  9 Nov 88 -- support IN/OUT AX                IJ
  23. ;  3 NOV 88 -- make Gate A20 code MCA compatible - no bleep    JW
  24. ; 14 Oct 88 -- Reuse 386 initialization code            JW
  25. ; 10 Oct 88 -- Align check now handles full 64k            IJ
  26. ;  7 OCT 88 -- do stack switch on EXCEP_HANDLER            GMS
  27. ; 21 SEP 88 -- Include PTERM.EQU                GMS
  28. ; 21 SEP 88 -- Include PCTERM exception handler code        GMS
  29. ; 20 SEP 88 -- Exception handler re-written            GMS
  30. ;  8 AUG 88 -- changed DMA error message            GMS
  31. ;  8 AUG 88 -- keyboard interrupts always go to XIOS handler    GMS
  32. ;  3 AUG 88 -- support dma address translation channels 1-3    GMS
  33. ; 29 JUL 88 -- TMP Banked window allocated in alloc_tmp@    GMS
  34. ; 20 JUL 88 -- change CONV_DMA to check every 4 K        JW/GMS
  35. ; 26 MAY 88 -- SunRiver support added                GMS
  36. ; 24 MAR 88 -- support for DMA address translation on DMA CH1    GMS
  37. ; 18 MAR 88 -- Added setup check for extending above A000h    GMS    
  38. ;  2 DEC 87 -- replaced ega$ with redefined video$        GMS
  39. ; 6.0/2.0
  40. ; 17 NOV 87 -- autoscan lim emulation pages and disable if failed GMS
  41. ; 13 NOV 87 -- force MEM to setup 22 LIM save areas        GMS+JW
  42. ; 12 NOV 87 -- Add memory checksum test if autoscanning        GMS
  43. ; 10 NOV 87 -- Always enable high memory on COMPAQ's between    GMS
  44. ;        E000h - EFFFh, we use EGA ROM at C000h.
  45. ;  7 NOV 87 -- disable hi memory scan at E000-FFFF on Model 80     JW
  46. ;  6 NOV 87 -- add extra ROM check to autoscan            GMS
  47. ;  1 Nov 87 -- tell MEM it's O.K. to move SYSDAT         JW
  48. ; 27 OCT 87 -- map out lim area from hi memory test        GMS
  49. ; 16 OCT 87 -- add hi memory support from setup info        GMS
  50. ;  5-Aug-87 -- add TPA at C000 or C400 for PCTmps's         JW
  51. ; 28/JUL/87 -- Support for PS/2 model 80 hard disk DMA        GMS
  52. ; 20/JUL/87 -- I/O bit map increased to support ports upto FFFFh JW
  53. ;  2/JUL/87 -- Conv_dma changed to check for linear mem on     GMS
  54. ;        transfers over 16k boundary.
  55. ; 22/MAY/87 -- increase memory free list for systems <640k conv GMS
  56. ; 15/MAY/87 -- LIM default settings read from setup area    GMS
  57. ; 28/APR/87 -- direct DMA - check if next block contiguous    GMS
  58. ;  3/APR/87 -- increase I/O bit map to 1000h            GMS
  59. ; 18/FEB/87 -- increase memory free list for hercules/cga    GMS
  60.  
  61. eject
  62.  
  63. nolist
  64. include CDOS.EQU
  65. include XIOS.EQU
  66. include PCHW.EQU
  67. include ASCII.EQU
  68. include ROSDATA.EQU
  69. include PTERM.EQU
  70. list
  71. ; These have been included:
  72. ; include CDOS.EQU
  73. ; include XIOS.EQU
  74. ; include PCHW.EQU
  75. ; include ASCII.EQU
  76. ; include ROSDATA.EQU
  77. ; include PTERM.EQU
  78. eject
  79.  
  80. ;     Global Descriptor Table Selectors
  81.  
  82. DESC_LEN    equ    08h        ; length of GDT descriptor
  83. GDT_GDT_SEL    equ    1*DESC_LEN    ; GDT itself
  84. GDT_SYSDAT_SEL    equ    4*DESC_LEN    ; SYSDAT descriptor
  85. GDT_SS_SEL    equ    7*DESC_LEN    ; SS descriptor
  86. GDT_INT_SEL    equ    8*DESC_LEN    ; 8086 interrupt vectors
  87. GDT_PTBL_SEL    equ    9*DESC_LEN    ; PTBL descriptor
  88. GDT_XIOSC_SEL    equ    3*DESC_LEN    ; XIOS code seg descriptor
  89.  
  90.  
  91. ;    Page size used for allocation
  92.  
  93. MBLK_SIZE    equ    16*1024        ;16 Kbytes
  94. MBLK_PARA    equ    MBLK_SIZE/16    ;page size in paragraphs
  95. MBLK_MASK    equ    MBLK_PARA-1    ;mask all but page select bits
  96. MBLK_SHIFT    equ    10        ;log2(MBLK_PARA)
  97.  
  98. ; Descriptor table sizes
  99. PAGE_SHIFT    equ    12        ; 386 uses 2**12 bits per page (4 Kb)
  100. IDT_SIZE    equ    128*8        ; we only use vectors 00h-77h
  101. TSS_SIZE    equ    (68h+(2000h)+1)
  102. PAGE_SIZE    equ    (1 shl PAGE_SHIFT)
  103.  
  104. ; I/O permission bit map equates
  105. DMA_INIT_BIT    equ    0000010000000000b    ; dma initialise
  106. DMA_80_INIT    equ    0000000100000000b    ; dma initialise
  107.  
  108. DMA        equ    0
  109. DMA_INIT    equ    DMA+10            ; dma init port address
  110.  
  111. ; Descriptor table definitions
  112. DATA_ACCESS    equ    092h        ; data type descriptor
  113. INT_GATE    equ    08eh        ; 386 interrupt gate 
  114.  
  115. MAX_HI_PAGES    equ    14        ; max number of 16k blocks to check
  116.  
  117. ;    Hardware interrupt stack frame
  118.  
  119. EX_BP        equ    word ptr 0[bp]
  120. EX_INT        equ    word ptr 4[bp]    ; interrupt vector * 4
  121. EX_IP        equ    word ptr 6[bp]
  122. EX_CS        equ    word ptr 10[bp]
  123. EX_EFLAGS    equ    word ptr 14[bp]
  124. EX_SP        equ    word ptr 18[bp]
  125. EX_SS        equ    word ptr 22[bp]
  126. EX_ES        equ    word ptr 26[bp]
  127. EX_DS        equ    word ptr 30[bp]
  128. EX_FS        equ    word ptr 34[bp]
  129. EX_GS        equ    word ptr 38[bp]
  130.  
  131.  
  132. ;     Exception interrupt handler stack frame
  133.  
  134. EXCEP_AL    equ    byte ptr 4[bp]
  135. EXCEP_AH    equ    byte ptr 5[bp]
  136. EXCEP_AX    equ    word ptr 4[bp]
  137. EXCEP_IP    equ    word ptr 6[bp]
  138. EXCEP_CS    equ    word ptr 8[bp]
  139. EXCEP_FLAGS    equ    word ptr 10[bp]
  140.  
  141. ;    Codemacro for 80386 instruction:
  142.  
  143.  
  144. CodeMacro    OP_32
  145.         DB    66h
  146. EndM
  147.  
  148. eject
  149.  
  150.  
  151. CGROUP        group    V386_CODE
  152. DGROUP        group    V386_DATA
  153.  
  154.  
  155.  
  156. V386_CODE    cseg
  157.  
  158. extrn    sysdat$:word                ; in HEADER.A86
  159.  
  160. extrn    mem_alloc_i@ :near            ; in INIT.A86
  161. extrn    io_mem_alloc@:near
  162. extrn    init_reuse@:near
  163. extrn    io_conout@ :near
  164. extrn    fatal_int@ :near            ; in ISRS.A86
  165. extrn    proc_abort@:near            ; in WINDOWS1.A86
  166. extrn    i_keyboard@:near            ; in KEYBOARD.A86
  167. extrn    point_vs@:near, point_cursor@:near    ; in WINDOWS2.A86
  168.  
  169. public    init_386@                ; for INIT.A86
  170. public    vxm_dma@                ; for FLOPPY.A86
  171. public    alloc_tmp@                ; for INIT.A86
  172.  
  173. if not SR
  174. extrn    point_vc@:near                ; in PCTERM.A86
  175. extrn    pc_point_curs@:near
  176. endif
  177.  
  178.         dseg    
  179. public    vm_flag$                ; we're in virtual mode
  180.  
  181. public    hi_xmem_addr$, hi_xmem_size$        ; shadowed RAM from A000-E000
  182. public    num_pages$
  183.  
  184. extrn     dma_low16$:word                ; in FLOPPY.A86
  185. extrn    dma_high4$:byte                ;
  186. extrn    pc_at$:byte
  187. extrn    fatal_prot$:byte            ; in ISRS.A86
  188. extrn    active_vc$:byte                ; in PCTERM.A86
  189. extrn    fatal_page$:byte
  190.  
  191. extrn    hi_on$:word, hi_off$:word        ; in INIT.A86
  192. extrn    kbd_imhere$: byte            ; in KEYBOARD.A86
  193. extrn    video$:byte                ; in WINDOWS1.A86
  194. extrn    su_check$:word, su_lim_flag$:byte    ; in HEADER.A86
  195. extrn    su_lim_base$:word, su_lim_maxsize$:word
  196. extrn    su_hi_enable$:word, su_hi_auto$:word
  197. extrn    su_flag_bits$:word
  198. extrn    num_mmkb$:word                ; in PUBDATA.A86
  199. extrn    ccb_list$:word
  200. if SR
  201. extrn    io_basead$:word                ; in SRTERM.A86
  202. extrn    switch_seg$:word
  203. endif
  204.  
  205. V386_CODE    cseg
  206.  
  207. INITCODE_START    equ    offset $    ; start of reusable code
  208.  
  209. ;---------
  210. init_386@:    ; test for the 80386
  211. ;---------
  212.  
  213. ;; 386 Machine - setup
  214. ;; -------------------
  215.     mov    vm_flag$,0ffh        ; internal XIOS flag
  216.     mov    bx,v386_ptr$        ; load BX -> to V386 specific table
  217.                     ; see if SETUP been run
  218.     cmp    su_check$,0DDB2h    ; check for secret code
  219.     jnz    no_setup        ; no, do not change defaults
  220.     mov    ax,su_lim_base$        ; get setup values
  221.     mov    lim_pfba$,ax        ; and save in v386 table
  222.     mov    al,su_lim_flag$        
  223.     mov    lim_flag$,al        
  224.     mov    ax,su_lim_maxsize$
  225.     mov    lim_maxpag$,ax
  226. no_setup:
  227.     test    lim_flag$,0ffh        ; lim emulation enabled ?
  228.      jz    no_check
  229.     mov    dx,lim_pfba$        ; get lim base address
  230.     mov    cx,4            ; number of 16 kb pages to test
  231. check_lim:
  232.     call    auto_extra        ; scan LIM area for use as ROM or RAM
  233.     or    al,al
  234.      jnz    dis_limemu        ; if page unavailable disable emulation
  235.     call    auto_scan
  236.     or    al,al
  237.      jnz    dis_limemu
  238.     add    dx,MBLK_PARA    
  239.     loop    check_lim
  240.     jmps    no_check        ; All 4 pages o.k
  241. dis_limemu:
  242.     mov    lim_flag$,00h        ; disable lim emulation
  243.  
  244. no_check:
  245.     call    mem_init        ; initialise for paged memory
  246.     call    build_idt        ; build the interrupt descriptor table
  247.     call    build_tss        ; build task state segment descriptor
  248.  
  249.     cli                ;; lock out interrupts for a while
  250.     mov    bx,5070h
  251.     call    reprog_pic        ;; reprogram PIC for protected mode
  252.     mov    di,50h*4        ;; start vector
  253.     mov    si,offset dummy_int_50    ;; start offset of isr
  254.     mov    cx,8            ;; count
  255.     call    do_int_vecs        ;; setup some dummy int vectors at 50h
  256.     call    gate_a20_on        ;; enable A20 for 1meg wrap
  257.  
  258.     mov    bx,v386_ptr$        ;; get pointer to vxm table in SYSDAT
  259.     mov    ax,offset excep_handler
  260.     mov    excep_off,ax        ; put our exception handler address
  261.     mov    excep_seg,cs        ; into SYSDAT.
  262.     mov    keyboard_isr + 2,cs    ; also store for keyboard isr address
  263.     mov    ax,offset pfault_handler
  264.     mov    pfault_off,ax        ; put page fault handler into SYSDAT
  265.     mov    pfault_seg,cs
  266.  
  267.     mov    nvcons$,NUM_VIR_CONS+2*NUM_AUX_PORTS
  268.                     ; force memory manager to allocate
  269.                     ; LIM save areas for the maximum
  270.                     ; # of virtual consoles that we support
  271.                     ; (two VC's per serial port)
  272.                     ; actual values set in ALLOC_SER_RSPS
  273.                     ;   in INIT.A86
  274.  
  275.     or    v386_flag,80h        ; O.K. to move SYSDAT (if possible)
  276.                     ; this can only be turned on if
  277.                     ;   there are no MFL/MWD entries
  278.                     ;   below SYSDAT, memory at the low
  279.                     ;   end of the TPA is contiguous,
  280.                     ;   no segment allocations have been
  281.                     ;   made yet and no pointers to SYSDAT
  282.                     ;   are stored anywhere in the
  283.                     ;   operating system yet (except
  284.                     ;   XIOS CS:6, SUP CS:6 and NDOS CS:6)
  285.     mov    si,INITCODE_START
  286.     mov    di,INITCODE_END
  287.     call    init_reuse@        ; reuse initialization code
  288.  
  289.     ret        
  290.  
  291. eject
  292. mem_init:        ; initialise for paged memory
  293. ;--------        ; BX -> V386 table
  294.     mov    ah,88h
  295.     int    15h            ; get extended memory size above 1024k
  296.     mov    emem,ax            ; addressing range AX=size in 1k blocks
  297.     push    ax
  298.     or     ax,ax            ; is there any extended memory
  299.     jnz    grow_mem
  300.     jmp    dont_grow        ; no - silly system
  301. grow_mem:
  302.     mov    ax,num_mmkb$        ; AX = conventional memory size in K
  303.     cmp    ax,512            ; is it already full window?
  304.      jne    is_640            ; yes..
  305.     mov    cx,128/16        ; else grow mfl from 512k to 640k
  306.     mov    ax,8000h
  307.     call    increase_mfl
  308. is_640:
  309.     test    video$,EGA+VGA        ; test if EGA/VGA installed
  310.      jnz    is_ega            ; EGA attached - EXIT
  311.     test    su_flag_bits$,A000_VIDEO ; is non ega video ram at A000h
  312.      jnz    is_ega            ; yes, don't extend TPA
  313.     mov    ax,0A000h        ; increase no. memory partitions by 4
  314.     mov    cx,4
  315.     call    increase_mfl
  316. is_ega:
  317.  
  318. ; Lets grow the free high memory
  319. ; if SETUP options enabled
  320.     push    bx            ; save v386_ptr
  321.  
  322.     test    lim_flag,0ffh        ; lets find if LIM enabled
  323.      jz    no_lim            ; and mask out LIM region from hi mem
  324.     mov    dx,lim_pfba        ; get lim base address
  325.     mov    cx,MAX_HI_PAGES
  326.     mov    ax,0001h        ; mask regs
  327.     xor    bx,bx
  328.     sub    dx,(0C000h-MBLK_PARA)
  329. lim_loop:
  330.     sub    dx,MBLK_PARA        ; 16k block    
  331.      jz    found_lim
  332.     shl    ax,1
  333.     loop    lim_loop
  334. found_lim:
  335.     or    bx,ax            ; mask out
  336.     mov    dx,1000h        ; 64k in paragraphs
  337. lim_loop2:
  338.     sub    dx,MBLK_PARA
  339.      jz    found_lim2
  340.     shl    ax,1            ; shift mask
  341.     or    bx,ax            ; and set
  342.     loop    lim_loop2        ; keep going for length of LIM
  343. found_lim2:
  344.     not    bx
  345.     and    su_hi_enable$,bx    ; mask enable setup bits
  346.     and    su_hi_auto$,bx        ;  and autoscan bits
  347.  
  348. no_lim:
  349.     test    word ptr su_hi_auto$, 0ffffh ; any auto-scanning enabled
  350.      jz    no_auto
  351.     call    autoscan_all        ; find free memory and set enable flags
  352. no_auto:
  353.     mov    ax,hi_off$
  354.     and    su_hi_enable$,ax    ; on COMPAQ: and 0FFFh: nothing >= F000
  355.     mov    ax,hi_on$
  356.     or    su_hi_enable$,ax    ; on COMPAQ: or 0F00h: use E000-EFFF
  357.  
  358.     mov    bx,su_hi_enable$
  359.     test    bx, bx            ; any high mem pages enabled?
  360.      jz    no_hi_mem
  361.                     ; build high MFL
  362.     mov    cx,MAX_HI_PAGES        ; max pages to enable
  363.     mov    di,offset hi_mfl    ; high memory free list
  364.     mov    si,di
  365.     mov    dx,0C000h        ; start search address
  366. search_loop:
  367.     shr    bx,1            ; get setup bits
  368.      jnc    next_scan
  369.     test    hi_on$,1        ; known-good memory?
  370.      jnz    enable1            ; skip the test (COMPAQ/Sprite)
  371.     call    auto_scan        ; check for ROM/RAM
  372.     or    al,al
  373.      jz    enable1            ; enable bit
  374. disable_loop:
  375.     dec    al            ; count of bad 16k blocks
  376.      jz    next_scan
  377.     shr    hi_on$,1        ; skip next bit in "forced-on" mask
  378.     shr    bx,1            ; skip next bit in mask
  379.     add    dx,MBLK_PARA        ; next 16k block
  380.     jmps    disable_loop
  381.  
  382. enable1:
  383.     mov    MD_START[di],dx        ; else build memory descriptor
  384.     mov    MD_LENGTH[di],MBLK_PARA    ;  16k block
  385.     mov    si,di            ; current MD
  386.     add    di,MD_SIZE        ; next descriptor
  387.     mov    MD_LINK[si],di        ; link to next
  388. next_scan:
  389.     shr    hi_on$,1        ; shift enforced on bits
  390.     add    dx,MBLK_PARA        ; next 16k block
  391.     loop    search_loop
  392.  
  393.     mov    MD_LINK[si],0000h    ; terminate link
  394.     cmp    MD_START[si],0000h
  395.      jz    no_hi_mem        ; none allocated
  396.  
  397.     mov    si,offset hi_mfl
  398.     mov    bx,v386_ptr
  399.     mov    hi_mfl_root,si        ; start of hi_mfl into 386 table
  400. no_hi_mem:
  401.  
  402. ; Group together all contiguous memory allocations from auto scan
  403.     mov    bx,v386_ptr
  404.     mov    di,hi_mfl_root        ; start of hi_mfl from 386 table
  405.     test    di,di            ; did scan find any memory
  406.      jz    end_trim        ; no hi mem allocs
  407. not_contig:
  408.     mov    bx,di            ; move to next item
  409. trim_next:
  410.     mov    di,MD_LINK[bx]        ; link to next
  411.     or    di,di
  412.      jz    end_trim        ; end of linked list
  413.     mov    ax,MD_START[bx]        ; start seg
  414.     add    ax,MD_LENGTH[bx]    ;  + length of partition
  415.     cmp    ax,MD_START[di]
  416.      jne    not_contig        ; not contiguous
  417.     mov    ax,MD_LENGTH[di]    ; else fold two partitions together
  418.     add    MD_LENGTH[bx],ax
  419.     mov    ax,mdul
  420.     xchg    ax,MD_LINK[di]        ; release entry into MDUL
  421.     mov    mdul,di
  422.     mov    MD_LINK[bx],ax        ; skip now unused entry
  423.     jmps    trim_next
  424.  
  425. end_trim:
  426.     pop    bx            ; restore v386_ptr
  427.  
  428. dont_grow:
  429.     pop    ax            ; get conventional memory size in K
  430.     add    ax,1024            ; add in 1st megabyte
  431.     shr    ax,4            ; AX = # of 16 K pages
  432.     cmp    hi_xmem_size$,0        ; is there RAM above extended memory?
  433.      je    no_hi_xmem        ; skip if regular extended memory only
  434.     mov    ax,hi_xmem_addr$    ; AX = A16..A31 of extra high memory
  435.     shl    ax,2            ; convert to 16 K block #
  436.     add    ax,hi_xmem_size$    ; add in the size in 16 K blocks
  437.     and    ax,(0-8)        ; make sure it's paragraph alignable
  438. no_hi_xmem:
  439.     mov    npages$,ax        ; # of words in free space map
  440.     shr    ax,3            ; 8 words per paragraph
  441.     xchg    ax,dx            ; DX = # of paragraphs
  442.     call    mem_alloc_i@        ; allocate free space map segment
  443.     mov    mp_table$,ax        ; AX = map segment - insert in SYSDAT
  444.     mov    es,ax            ; ES -> map segment
  445.  
  446.     mov    cx,npages$        ; CX = word count
  447.     mov    ax,0FFFFh        ; AX <> 0: not available for allocation
  448.     sub    di,di
  449.     rep    stosw            ; mark all pages as used
  450.  
  451.     mov    ax,num_mmkb$        ; get normal memory
  452.     shr    ax,4            ; available in 16k blocks
  453.     mov    cx,ax            ; mark as available - either 512/640
  454.     sub    ax,ax            ; 0000 means available
  455.     sub    di,di
  456.     rep    stosw            ; mark conventional RAM as usable
  457.  
  458.     mov    di,(1024/16)*WORD    ; base of extended memory in mp_table$
  459.     mov    cx,emem            ; get extended memory size in Kb
  460.     shr    cx,4            ; convert to 16 Kb blocks
  461.     rep    stosw            ; mark extended memory as available
  462.  
  463.     mov    di,hi_xmem_addr$    ; base of extra high memory
  464.     shl    di,3            ; convert to offset in mp_table$
  465.     mov    cx,hi_xmem_size$    ; get # of good pages up there
  466.     rep    stosw            ; mark hi extended as available
  467.  
  468.     ; Now print a short summary:
  469.  
  470.     sub    dx,dx
  471.     mov    cx,npages$        ; count all available pages
  472.     sub    si,si
  473.     mov    es,mp_table$
  474. count_pages:
  475.     lods    es:ax
  476.     test    ax,ax
  477.      jnz    count_pag1
  478.     add    dx,MBLK_SIZE/1024
  479. count_pag1:
  480.     loop    count_pages
  481.     xchg    ax,dx            ; AX = # of kilobytes
  482.     mov    num_pages$,ax
  483.     ret
  484.  
  485. ; Scan hi memory regions from C000h-F7FFh
  486. ; for ROM or RAM if "su_hi_auto$" bit set
  487. ; and set corresponding bits in "su_hi_enable$"
  488. autoscan_all:
  489.     mov    bx,su_hi_auto$        ; get autoscan enable bits
  490.     mov    cx,MAX_HI_PAGES        ; max pages to enable
  491.     mov    dx,0C000h        ; start search address
  492.     mov    si,0001h        ; setup enable bit mask
  493. autoscan_loop:
  494.     shr    bx,1            ; autoscan enabled
  495.      jnc    next_autoscan        ; no..
  496.     call    auto_extra        ; extra scan for autoscanning
  497.     or    al,al
  498.      jnz    dis_loop        ; found something so disable
  499.                     ;  else do more tests
  500.     push    si
  501.     call    auto_scan        ; test region
  502.     or    al,al
  503.     pop    si
  504.      jz    ena            ; enable bit
  505. dis_loop:
  506.     dec    al            ; count of bad 16k blocks
  507.      jz    next_autoscan
  508.     shr    bx,1            ; update autoscan bits
  509.     shl    si,1            ; update mask
  510.     add    dx,MBLK_PARA        ; next 16k block
  511.     jmps    dis_loop
  512. ena:
  513.     or    su_hi_enable$,si    ; set setup enable bit
  514. next_autoscan:    
  515.     shl    si,1            ; update mask
  516.     add    dx,MBLK_PARA        ; next 16k block
  517.     loop    autoscan_loop        ; scan all
  518.  
  519.     ret
  520.  
  521. ; Extra scan routine for Autoscanning modes
  522. ; Entry : DX = scan segment
  523. ; Exit:
  524. ;    AL = 0 no valid info
  525. ;         else AL = count of unavailable pages
  526. auto_extra:
  527.     push bx ! push cx ! push dx ! push si ! push di
  528.     push    ds    
  529.     mov    ds,dx            ; scan segment
  530.     mov    es,dx        
  531.     xor    di,di
  532.     mov    cx,256
  533.     xor    ax,ax
  534.     repe    scasw            ; if all zeroes
  535.     jz    end_test        ; then exit (test invalid)
  536.  
  537.     xor    di,di
  538.     mov    cx,256
  539.     mov    ax,0ffffh
  540.     repe    scasw            ; if all bytes FFh
  541.      jz    end_test        ; then exit (test invalid)
  542.  
  543.     call    chk_test        ; get checksum of area
  544.     mov    dx,bx            ; and store
  545.     mov    cx,10h            ; loop count
  546. do_chk_loop:
  547.     push    cx
  548.     call    chk_test        ; get checksum again
  549.     pop    cx
  550.     cmp    bx,dx            ; compare new checksum with original
  551.     loope    do_chk_loop        ; retry if still the same
  552.     mov    al,1            ; ready for error exit
  553.      je    not_avail        ; if data remains constant then segment
  554.                     ; probably contains ROM or RAM
  555.                     ; so mark as unavailable
  556. end_test:
  557.     xor    al,al            ; test proved inadequate
  558. not_avail:
  559.     pop    ds
  560.     pop di ! pop si ! pop dx ! pop cx ! pop bx
  561.     ret
  562.  
  563. chk_test:
  564.     xor    si,si
  565.     xor    ah,ah
  566.     xor    bx,bx
  567.     mov    cx,512
  568. chk_loop:
  569.     lodsb
  570.     add    bx,ax            ; compute simple checksum
  571.     loop    chk_loop
  572.     ret
  573.  
  574. ; Scan region for presence of ROM or RAM
  575. ; Entry : DX = scan segment address
  576. ; Exit:    
  577. ;      AL = 0 if available
  578. ;        else AL = count of unavailable pages
  579. auto_scan:
  580.     push    di ! push cx
  581.     mov    ax,0ffffh        ; find start of ROM segment
  582.     mov    es,ax            ; reset vector address
  583.     mov    ax,es:.01h        ; get offset
  584.     and     ax,0C000h        ; round down to 
  585.     shr    ax,4
  586.     add    ax,es:.03h        ; + segment of reset code
  587.     cmp    dx,ax
  588.     mov    al,1
  589.      jae    scan_ret        ; exit AL = unavailable count
  590.  
  591.     mov    es,dx
  592.     xor    di,di
  593.     mov    ax,0AA55h        ; IBM ROM ID
  594.     scasw                ; check for ROM ID, DI += 2
  595.      jne    test_ram        ; no ROM so test RAM
  596.     mov    al,es:[di]        ; get # of 512 byte pages in ROM
  597.     add    al,((16384/512)-1)
  598.     mov    cl,5
  599.     shr    al,cl            ; AL = # of 16 Kb pages
  600. ;;    inc    al            ; ##JW## this seems wrong
  601.     jmps    scan_ret        ; exit AL = unavailable count
  602.  
  603. test_ram:
  604.     xor    di,di        ; check for RAM
  605.     mov    cx,10
  606.     mov    al,80h
  607.     out    CMOS_ADDR,al        ; disable NMI
  608.     jmps    $+2
  609.     in    al,CMOS_DATA        ; dummy read
  610. ram_check:
  611.     mov    al,es:[di]        ; read a byte
  612.     push    ax            ; and preserve
  613.     not    al
  614.     mov    es:[di],al        ; write a differnt pattern
  615.     jmps    $+2            ; use the data bus
  616.     cmp    al,es:[di]        ; read back the value
  617.     pop    ax
  618.     mov    es:[di],al        ; write back original byte
  619.     mov    ah,0            ; for good return
  620.      jnz    map_ok            ; no RAM up there so available
  621.     inc    di ! inc di        ; even boundary read/write check
  622.     loop    ram_check
  623.     inc    ah            ; bad return
  624. map_ok:                ; return ZF reset
  625.     mov    al,0
  626.     out    CMOS_ADDR,al        ; re-enable NMI
  627.     jmps    $+2
  628.     in    al,CMOS_DATA        ; dummy read
  629.     mov    al,ah            ; return code
  630. scan_ret:
  631.     pop cx ! pop di
  632.     ret
  633.  
  634.  
  635. print_num:
  636. ;    entry:    AX = number to print
  637.  
  638.     sub    dx,dx
  639.     mov    cx,10
  640.     div    cx            ; AX = result, DX = remainder
  641.     push    dx
  642.     test    ax,ax
  643.      jz    print_num1
  644.     call    print_num        ; print result if non-zero
  645. print_num1:
  646.     pop    cx            ; remainder is last digit in binary
  647.     add    cl,'0'            ; convert to ASCII digit
  648.     sub    dx,dx            ; ouput to master console
  649.     jmp    io_conout@        ; print the last character
  650.  
  651.  
  652. print_msg:
  653.     lodsb                    ; fetch a character
  654. pr_msg_loop:
  655.     push    si
  656.     call    print_char            ; print just one
  657.     pop    si
  658.     lodsb                    ; fetch another
  659.     test    al,al
  660.      jnz    pr_msg_loop            ; when char = 0, done
  661.     ret
  662.  
  663.  
  664. print_char:
  665.     mov    cl,al                ; char to cl
  666.     mov    dl,0
  667.     jmp    io_conout@            ; print it
  668.  
  669.  
  670. ; Build interrupt descriptor table
  671. ; must be at least 256 bytes in size for 80386 ints
  672. ; Enter BX = -> V386 table in SYSDAT
  673. build_idt:
  674.     push    bx
  675.     mov    dx,(IDT_SIZE+15)/16
  676.     call    mem_alloc_i@
  677.     mov    idt_seg$,ax        ; insert in SYSDAT
  678.     mov    idt_limit$,IDT_SIZE-1
  679.     mov    es,ax            ; IDT destination seg
  680.     xor    di,di
  681.     xor    ax,ax            ; clear whole table
  682.     mov    cx,IDT_SIZE/2        ; words
  683.     rep    stosw
  684.  
  685.     mov    bx,GDT_XIOSC_SEL    ; XIOS code segment selector
  686.     mov    dh,INT_GATE        ; interrupt gate type
  687.     xor    dl,dl
  688.                 ; build 8 descriptors in IDT for Master PIC ints
  689.                 ; PIC ints 50h -> 57h
  690.     mov    si,offset idt_m_pic_offs
  691.     mov    di,50h*8        ; offset 50h in IDT
  692.     mov    cx,8
  693.     call    idt_loop        ; insert in IDT
  694.  
  695.                 ; build 8 descriptors in IDT for Slave PIC ints
  696.                 ; PIC ints 70h -> 77h
  697.     mov    si,offset idt_s_pic_offs
  698.     mov    di,70h*8        ; offset 70h in IDT
  699.     mov    cx,8
  700.     call    idt_loop        ; insert in IDT
  701.     pop    bx
  702.     ret
  703.  
  704.  
  705. ; setup IDT params
  706. idt_loop:
  707.     movsw                ; get routine entry offset
  708.     mov    ax,bx            ; IDT code segment selector
  709.     stosw                ; store in IDT
  710.     mov    ax,dx            ; interrupt gate type
  711.     stosw
  712.     mov    ax,0            ; high bits of offset
  713.     stosw
  714.     loop    idt_loop
  715.     ret
  716.  
  717.  
  718. ; build task state segment
  719. ; and I/O permission bit map:
  720. ; Enter BX = -> V386 table in SYSDAT
  721. build_tss:
  722.     mov    dx,(TSS_SIZE+15)/16
  723.     call    mem_alloc_i@
  724.     mov    tss_seg$,ax        ; insert in SYSDAT
  725.     mov    tss_limit$,TSS_SIZE
  726.     mov    es,ax
  727.     sub    di,di
  728.     mov    cx,TSS_SIZE/2        ; size of TSS including I/O map
  729.     sub    ax,ax
  730.     rep    stosw            ; initilaise TSS + I/O map
  731.     mov    di,66h            ; insert offset of BIT_MAP_OFFSET
  732.     lea    ax,2[di]        ; start bit map after offset
  733.     stosw                
  734.     or    es:word ptr[di],DMA_INIT_BIT ; set bit in I/O map - port 0Ah
  735.     test    pc_at$,02h        ; is it model 80
  736.     jz    not_80
  737.     or    es:word ptr 2[di],DMA_80_INIT ; set bit in I/O map - port 18h
  738. not_80:
  739.     ret                ; trap on access to DMA initialise
  740.  
  741.  
  742.  
  743. reprog_pic:
  744. ;----------
  745. ;    entry:    BH = master PIC vector
  746. ;        BL = slave PIC vector
  747.  
  748.     in    al,MAST_PIC1        ; read old interrupt mask
  749.     push    ax
  750.     mov    al,11h            ; get ICW1 (edge triggered, master)
  751.     out    MAST_PIC0,al
  752.     jmps    $+2
  753.     mov    al,bh            ; get master's base address
  754.     out    MAST_PIC1,al        ;     (ICW2 = vector #)
  755.     jmps    $+2
  756.     mov    al,04h            ; ICW3: slave hooked up to #2
  757.     out    MAST_PIC1,al
  758.     jmps    $+2
  759.     mov    al,01h            ; ICW4: master PIC, 8086 mode
  760.     out    MAST_PIC1,al
  761.     jmps    $+2
  762.     pop    ax
  763.     out    MAST_PIC1,al        ; restore interrupt mask
  764.  
  765.     jmps    $+2
  766.  
  767.     in    al,SLAVE_PIC1        ; read old interrupt mask
  768.     push    ax
  769.     mov    al,11h            ; get ICW1 (edge triggered, master)
  770.     out    SLAVE_PIC0,al
  771.     jmps    $+2
  772.     mov    al,bl            ; get slave's base address
  773.     out    SLAVE_PIC1,al        ;     (ICW2 = vector #)
  774.     jmps    $+2
  775.     mov    al,02h            ; ICW3: slave hooked up to #2
  776.     out    SLAVE_PIC1,al
  777.     jmps    $+2
  778.     mov    al,01h            ; ICW4: master PIC, 8086 mode
  779.     out    SLAVE_PIC1,al
  780.     jmps    $+2
  781.     pop    ax
  782.     out    SLAVE_PIC1,al        ; restore interrupt mask
  783.     ret
  784.  
  785. ; Set up some dummy interrupt vectors
  786. ; in case we have an interrupt from the PIC
  787. ; before protected mode is enabled..
  788. ; Entry :    DI = int vector offset
  789. ;        SI = start isr offsets
  790. ;        CX = count
  791. do_int_vecs:
  792.     xor    ax,ax
  793.     mov    es,ax
  794.     mov    ax,cs
  795. do_all_ints:
  796.     mov    es:[di],si        ; store offset
  797.     add    si,3            ; next offset address
  798.     inc di ! inc di
  799.     stosw                ; store segment
  800.     loop    do_all_ints    
  801.     ret
  802.  
  803. eject
  804. ; Routine to enable or disable A20 for 1meg wrap
  805. gate_a20_on:
  806.     test    pc_at$,2        ; MCA based machine?
  807.      jz    pcat_a20_on        ; skip if "classic bus" machine
  808.     in    al,MCA_SYSCTLA
  809.     or    al,SYSCTLA_A20        ; enable the A20 line
  810.     out    MCA_SYSCTLA,al
  811.     ret
  812.  
  813. pcat_a20_on:
  814.     mov    ah,0dfh
  815.     cli
  816.     call    wait_8042        ; ensure the keyboard buffer is empty
  817.     jnz    gate_ret
  818.     mov    al,0d1h            ; command to write output port
  819.     out    AT_KBD_STATUS,al
  820.     call    wait_8042
  821.     jnz    gate_ret
  822.     mov    al,ah
  823.     out    KBD_DATA,al
  824. gate_ret:
  825.     ret
  826.  
  827. wait_8042:            ; wait for the 8042 input buff empty
  828.     sub    cx,cx
  829. wait_loop:
  830.     in    al,AT_KBD_STATUS
  831.     and    al,IN_BUF_FULL    ; test input buffer flag
  832.     loopnz    wait_loop
  833.     ret
  834.  
  835. INITCODE_END    equ    offset $    ; end of reusable initialization code
  836.  
  837. eject
  838.  
  839. dummy_int_50:
  840.     int    08h            ; go to 8086 interrupt service routine
  841.     iret
  842.  
  843. dummy_int_51:
  844.     int    09h
  845.     iret
  846.  
  847. dummy_int_52:
  848.     int    0ah
  849.     iret
  850.  
  851. dummy_int_53:
  852.     int    0bh
  853.     iret
  854.  
  855. dummy_int_54:
  856.     int    0ch
  857.     iret
  858.  
  859. dummy_int_55:
  860.     int    0dh
  861.     iret
  862.  
  863. dummy_int_56:
  864.     int    0eh
  865.     iret
  866.  
  867. dummy_int_57:
  868.     int    0fh
  869.     iret
  870.  
  871. eject
  872.  
  873. ; Allocate 16k banked window for TMP allocation
  874. ; at top of TPA - uses best fit by calling io_mem_alloc 
  875. ; Called from io_protect.
  876. alloc_tmp@:
  877.     mov    cx,(PAGE_SIZE)/16 -1    ; align on 4k boundary    
  878.     mov    dx,1024*16/16        ; allocate 16k window
  879.     call    io_mem_alloc@        ; return AX = start segment address
  880.     mov    cx,16/16        ; enf of mwd for TMP allocation
  881. ;;    call    increase_mwd
  882. ;;    ret            ;;; fall through
  883. increase_mwd:
  884.     lea    si,mwdr$        ; memory window list root
  885.     jmps    find_next
  886.  
  887. ; increase memory free list
  888. ; Entry : CX = number of 16k blocks
  889. ;      AX = start segment address
  890. increase_mfl:
  891.     lea    si,mfl$            ; memory free list root
  892. find_next:
  893.     mov    di,si            ; save previous link
  894.     mov    si,MD_LINK[di]        ; link to next
  895.     test    si,si            ; find end of MFL
  896.      jnz    find_next        ; 0 => end of list
  897.  
  898.     mov    si,mdul$        
  899.     mov    MD_LINK[di],si        ; insert start into end of MFL
  900. add_mem:
  901.     mov    dx,MBLK_PARA        ; starting at A000h length 400h
  902.     mov    di,si            ; save previous
  903.     mov    MD_START[si],ax
  904.     mov    MD_LENGTH[si],dx
  905.     add    ax,dx
  906.     mov    si,MD_LINK[si]        ; link to next partition
  907.     loop    add_mem
  908.     mov    MD_LINK[di],0000    ; end new MFL
  909.     mov    mdul$,si        ; new start of MDUL
  910.     ret
  911.  
  912.     
  913. eject
  914.  
  915. ; Exception handler interrupt service routine
  916. ; arrives here as per normal 8086 interrupt except CS:IP return address
  917. ; on stack actually points to the violating instruction.
  918. ; Before returning update IP on stack to point to next
  919. ; instruction and execute IRET.
  920. ;
  921. ; Note: before executing any I/O instruction
  922. ;    reset relevent BIT in I/O map, else
  923. ;    another exception interrupt will occur
  924. ;    and you will be here for the rest of time.
  925.  
  926. excep_handler:
  927.     cli
  928.     cld
  929.     push    ax
  930.     push    bp
  931.     push    ds
  932.     mov    bp,sp                ; stack frame pointer
  933.     mov    ds,sysdat$
  934.     mov    excep_ss,ss            ; save the registers
  935.     mov    excep_sp,sp
  936.     mov    ss,sysdat$
  937.     mov    sp,offset excep_stack_top
  938.  
  939.     pusha
  940.     push    es
  941.  
  942.     mov    es,excep_ss        ; get original stack seg
  943.  
  944.     mov    cx,ax            ; DX , AX = params for OUT DX,AX
  945.     mov    ds,es:EXCEP_CS
  946.     mov    si,es:EXCEP_IP        ; DS:SI = violating instruction
  947.     lodsb                ; get 8086 opcode
  948.     cmp    al,0EEh            ; check if "OUT DX,AL"
  949.      je    em_out_dx_al
  950.     cmp    al,0E6h            ; check if "OUT port,AL"
  951.      je    em_out_al
  952.     cmp    al,0EFh            ; check if "OUT DX,AX"
  953.      jmpz     em_out_dx_ax
  954.     cmp    al,0E7H            ; check if "OUT port,AX"
  955.      jmpz    em_out_ax
  956.      
  957.     cmp    al,0ECh            ; check if "IN AL,DX"
  958.      je    em_in_dx_al
  959.     cmp    al,0E4h            ; check if "IN AL,port"
  960.      je    em_in_al
  961.     cmp    al,0EDh            ; check if "IN AX,DX"
  962.      jmpz    em_in_dx_ax
  963.     cmp    al,0E5h            ; check if "IN AX,port"
  964.      jmpz    em_in_ax
  965.      
  966. em_illegal:
  967.     mov    ds,sysdat$
  968.     pop    es
  969.     popa
  970.     mov     ss,excep_ss
  971.     mov     sp,excep_sp
  972.     pop    ds
  973.     pop    bp
  974.     pop    ax
  975.     mov    si,offset fatal_prot$    ; 'Protection interrupt'
  976.     jmp    fatal_int@        ; display error message and terminate
  977.  
  978. ; Emulate OUT instruction
  979. em_out_al:
  980.     lodsb                ; get port address byte
  981.     xor    dh,dh
  982.     mov    dl,al            ; port address in DX
  983. em_out_dx_al:
  984.     mov    es:EXCEP_IP,si        ; update IP for 1 or 2-byte opcode
  985.     mov    ds,sysdat$        ; get sysdat seg
  986.     mov    outbyte,cl        ; save output byte
  987.  
  988.     push    cs
  989.     pop    es
  990.     mov    di,offset port_addr
  991.     mov    ax,dx            ; port address
  992.     mov    cx,num_ports
  993.     repne    scasw
  994.     jmpnz    em_illegal        ; not supported
  995.     sub    di,offset port_addr
  996.     sub    di,2
  997.     call    es:out_table[di]    ; execute "OUT" instruction CL=AL on entry
  998.     jmp    ret_excep
  999.  
  1000. ; Emulate "IN" instruction
  1001. em_in_al:
  1002.     lodsb                ; get port address byte
  1003.     xor    dh,dh
  1004.     mov    dl,al            ; port address in DX
  1005. em_in_dx_al:
  1006.     mov    es:EXCEP_IP,si        ; update IP for 1 or 2-byte opcode
  1007.     mov    ds,sysdat$        ; get sysdat seg
  1008.  
  1009.     push    cs
  1010.     pop    es
  1011.     mov    di,offset port_addr
  1012.     mov    ax,dx            ; port address
  1013.     mov    cx,num_ports
  1014.     repne    scasw
  1015.     jmpnz    em_illegal        ; not supported
  1016.     sub    di,offset port_addr
  1017.     sub    di,2
  1018.     call    es:in_table[di]        ; execute "IN" instruction
  1019.                     ; AL on stack for exit
  1020.     jmp    ret_excep
  1021.  
  1022. ; Emulate OUT AX
  1023. em_out_ax:
  1024.     lodsb                ; get port address byte
  1025.     xor    dh,dh
  1026.     mov    dl,al            ; port address in DX
  1027. em_out_dx_ax:
  1028.     mov    es:EXCEP_IP,si        ; update IP for 1 or 2-byte opcode
  1029.     mov    ds,sysdat$        ; get sysdat seg
  1030.  
  1031.     push    cx            ; save the word we are to output
  1032.     push    dx            ; and the port
  1033.     
  1034.     mov    outbyte,cl        ; save output byte
  1035.     push    cs
  1036.     pop    es
  1037.     mov    di,offset port_addr
  1038.     mov    ax,dx            ; port address
  1039.     mov    cx,num_ports
  1040.     repne    scasw
  1041.     jmpnz    em_illegal        ; not supported
  1042.     sub    di,offset port_addr
  1043.     sub    di,2
  1044.     call    es:out_table[di]    ; execute "OUT" CL=AL on entry
  1045.  
  1046.     pop    dx            ; recover output port
  1047.     pop    cx            ; and the word
  1048.     inc    dx            ; point to next port
  1049.     mov    cl,ch            ; and output the hi byte
  1050.     
  1051.     mov    outbyte,cl        ; save output byte
  1052.     push    cs
  1053.     pop    es
  1054.     mov    di,offset port_addr
  1055.     mov    ax,dx            ; port address
  1056.     mov    cx,num_ports
  1057.     repne    scasw
  1058.     jmpnz    em_illegal        ; not supported
  1059.     sub    di,offset port_addr
  1060.     sub    di,2
  1061.     call    es:out_table[di]    ; execute "OUT" CL=AH on entry
  1062.  
  1063.     jmp    ret_excep
  1064.  
  1065. ; emulate in AX
  1066. em_in_ax:
  1067.     lodsb                ; get port address byte
  1068.     xor    dh,dh
  1069.     mov    dl,al            ; port address in DX
  1070. em_in_dx_ax:
  1071.     mov    es:EXCEP_IP,si        ; update IP for 1 or 2-byte opcode
  1072.     mov    ds,sysdat$        ; get sysdat seg
  1073.  
  1074.     push    dx            ; save the port
  1075.     
  1076.     push    cs
  1077.     pop    es
  1078.     mov    di,offset port_addr
  1079.     mov    ax,dx            ; port address
  1080.     mov    cx,num_ports
  1081.     repne    scasw
  1082.     jmpnz    em_illegal        ; not supported
  1083.     sub    di,offset port_addr
  1084.     sub    di,2
  1085.     call    es:in_table[di]        ; execute "IN" instruction
  1086.                     ; AL on stack for exit
  1087.     pop    dx            ; recover the port number
  1088.     inc    dx            ; and point to the next port
  1089.     mov    es,excep_ss        ; get original stack seg
  1090.     mov    al,es:EXCEP_AL
  1091.     push    ax            ; save lo byte of IN
  1092.  
  1093.     push    cs
  1094.     pop    es
  1095.     mov    di,offset port_addr
  1096.     mov    ax,dx            ; port address
  1097.     mov    cx,num_ports
  1098.     repne    scasw
  1099.     jmpnz    em_illegal        ; not supported
  1100.     sub    di,offset port_addr
  1101.     sub    di,2
  1102.     call    es:in_table[di]        ; execute "IN" instruction
  1103.                     ; AL on stack for exit
  1104.     pop    ax            ; recover lo byte of IN
  1105.     mov    es,excep_ss        ; get original stack seg
  1106.     mov    ah,es:EXCEP_AL        ; get hi byte of IN
  1107.     mov    es:EXCEP_AX,ax        ; and save the word away
  1108.  
  1109. ;    jmp    ret_excep
  1110.  
  1111. ret_excep:
  1112.     pop    es
  1113.     popa
  1114.     mov     ss,excep_ss
  1115.     mov     sp,excep_sp
  1116.     pop    ds
  1117.     pop    bp
  1118.     pop    ax
  1119.     iret
  1120.  
  1121. port_addr    dw    DMA_BMSK_REG    ; dma command port
  1122.         dw    DMA_FUNC_REG    ; model 80 hard disk dma
  1123.         dw    TIMER_2_REG    ; counter timer port (beeper)
  1124.         dw    TIMER_CMND_REG    ; counter timer (beeper)
  1125.         dw    PORT_B
  1126.         dw    CRT_INDEX    ; b&w CRT index registers
  1127.         dw    CRT_DATA
  1128.         dw    CRT_CTRL
  1129.         dw    CRT_STATUS
  1130.         dw    CRT_CONF
  1131.         dw    COL_CRT_INDEX    ; color CRT index registers
  1132.         dw    COL_CRT_DATA
  1133.         dw    COL_CRT_CTRL
  1134.         dw    COL_CRT_STATUS
  1135.         dw    COL_CRT_CONF
  1136.                         
  1137. num_ports    equ    (offset $ - offset port_addr)/2
  1138.  
  1139. out_table    dw    offset out_dma
  1140.         dw    offset out_dma_80
  1141.         dw    offset out_timer2
  1142.         dw    offset out_timer
  1143.         dw    offset out_port_b
  1144.         dw    offset out_crt_index
  1145.         dw    offset out_crt_data
  1146.         dw    offset out_crt_ctrl
  1147.         dw    offset out_crt_status
  1148.         dw    offset out_crt_conf
  1149.         dw    offset out_col_index
  1150.         dw    offset out_col_data
  1151.         dw    offset out_col_ctrl
  1152.         dw    offset out_col_status
  1153.         dw    offset out_col_conf
  1154.         
  1155. in_table    dw    offset in_dma
  1156.         dw    offset in_dma_80
  1157.         dw    offset in_timer2
  1158.         dw    offset in_timer
  1159.         dw    offset in_port_b
  1160.         dw    offset in_crt_index
  1161.         dw    offset in_crt_data
  1162.         dw    offset in_crt_ctrl
  1163.         dw    offset in_crt_status
  1164.         dw    offset in_crt_conf
  1165.         dw    offset in_col_index
  1166.         dw    offset in_col_data
  1167.         dw    offset in_col_ctrl
  1168.         dw    offset in_col_status
  1169.         dw    offset in_col_conf
  1170.  
  1171. ; Set bit in I/O permission bit map
  1172. ; Enter DX = port address
  1173. set_trap:
  1174.     call    get_mask
  1175.     or    es:[bx],al        ; set I/O bit
  1176.     ret
  1177.  
  1178. ; Reset bit in I/O permission bit map
  1179. ; Enter DX = port address
  1180. reset_trap:
  1181.     call    get_mask
  1182.     not    al
  1183.     and    es:[bx],al        ; reset I/O bit
  1184.     ret
  1185.  
  1186. get_mask:
  1187.     mov    bx,v386_ptr
  1188.     mov    es,tss_seg        ; point ES to TSS SEGMENT
  1189.     push    dx
  1190.     mov    ax,dx
  1191.     mov    bx,8
  1192.     xor    dx,dx
  1193.     div    bx            
  1194.     mov    bx,ax            ; BX = byte to set
  1195.     add    bx,68h            ; offset of I/O bit map
  1196.     mov    al,1
  1197.     mov    cl,dl
  1198.     shl    al,cl            ; AL = bit position
  1199.     pop    dx
  1200.     ret
  1201.  
  1202.  
  1203. ; output byte to port
  1204. ; Enter:    DX=port
  1205. ;        outbyte=byte to output
  1206. do_out:
  1207.     call    reset_trap        ; reset I/O bit
  1208.     mov    al,outbyte        ; output byte
  1209.     out    dx,al
  1210.     call    set_trap        ; set I/O bit
  1211.     ret
  1212.  
  1213. ; input byte from port
  1214. ; Enter:    DX=port
  1215. ;        byte on stack for exit
  1216. do_in:
  1217.     call    reset_trap        ; reset I/O bit
  1218.     in    al,dx
  1219.     mov    es,excep_ss        ; get original stack seg
  1220.     mov    es:EXCEP_AL,al
  1221.     call    set_trap        ; set I/O bit
  1222.     ret
  1223.  
  1224. eject
  1225.  
  1226. ; DMA transfer    
  1227. in_dma:
  1228. ;------
  1229.     jmp    do_in            ; just get input byte
  1230. out_dma:
  1231. ;-------
  1232.     mov    es,excep_ss        ; get original stack seg
  1233.     mov    bx,es:EXCEP_CS
  1234.     mov    ax,cs
  1235.     cmp    bx,ax            ; does it come from XIOS
  1236.     jne    out_dma1    
  1237.     jmp    do_out            ; yes it must be our floppy driver
  1238.                     ; so just do OUT instructon
  1239. out_dma1:
  1240.     call    reset_trap        ; reset bit in I/O map 
  1241.     push    dx
  1242.     call    emu_dma            ; emulate DMA
  1243.     pop    dx
  1244.     call    set_trap
  1245.     ret
  1246.  
  1247. ; Model 80 hard disk DMA    
  1248. in_dma_80:
  1249. ;---------
  1250.     jmp    do_in            ; just do input byte
  1251.  
  1252. out_dma_80:
  1253. ;----------
  1254.     call    reset_trap        ; reset bit in I/O map to 
  1255.     push    dx
  1256.     call    do_emu_80        ; emulate OUT DX,AL
  1257.     pop    dx
  1258.     call    set_trap
  1259.     ret
  1260.  
  1261. ; Used by Sunriver stations and PCTERMS
  1262. out_timer2:
  1263. out_timer:
  1264. out_port_b:
  1265. ;----------
  1266. if SR
  1267.     cmp    kbd_imhere$,0        ; in keyboard ISR ?
  1268.     jne    out_sr1            ; yes - do not emulate on SunRiver
  1269.     mov    es,excep_ss        ; get original stack seg
  1270.     mov    bx,es:EXCEP_CS
  1271.     cmp    bx,0e000h        ; from ROS
  1272.     jb    out_sr            ; no emulate
  1273. out_sr1:
  1274.     jmp    do_out            ; else must be for main console
  1275. out_sr:
  1276.     mov    es,io_basead$
  1277.     mov    bx,dx
  1278.     mov    cl,outbyte
  1279.     mov    es:[bx],cl        ; do memory mapped i/o for station
  1280.     ret                    
  1281. else
  1282.  
  1283.     mov    es,excep_ss        ; get original stack seg
  1284.     mov    bx,es:EXCEP_CS        ; handle beeper on PCTERMS
  1285.     mov    ax,cs
  1286.     cmp    bx,ax            ; does it come from XIOS
  1287.     je    port_b1            ; yes..
  1288.     cmp    kbd_imhere$,0        ; in keyboard ISR ?
  1289.     jne    port_b1            ; yes..
  1290.     cmp    bx,0e000h        ; or from ROS
  1291.     jb    emu_beep
  1292. port_b1:        
  1293.     jmp    do_out            ; then do OUT DX,AL
  1294. emu_beep:
  1295.     test    byte ptr outbyte,02h    ; beeper bit on??
  1296.     jz    no_beep            ; no trash it
  1297.     mov    dl,active_vc$        ; get active virtual console
  1298.     call    point_vc@        ; point to VC_ structure
  1299.     or    VC_MODE,BEL_BIT        ; get flush to output bell code
  1300. no_beep:
  1301.     ret            
  1302.  
  1303. endif
  1304.  
  1305. ; Used by Sunriver stations
  1306. in_timer2:
  1307. in_timer:
  1308. ;--------
  1309.     jmp    do_in            ; just do IN instruction
  1310.  
  1311. ; Used by Sunriver stations and PCTERMS
  1312. in_port_b:
  1313. ;---------
  1314. if SR
  1315.     cmp    kbd_imhere$,0        ; in keyboard ISR ?
  1316.     jne    do_in            ; yes - must be for main console
  1317.     mov    es,excep_ss        ; get original stack seg
  1318.     mov    bx,es:EXCEP_CS
  1319.     cmp    bx,0e000h        ; from ROS
  1320.     jae    do_in
  1321.     mov    es,io_basead$
  1322.     mov    bx,dx
  1323.     mov    al,es:[bx]        ; do memory mapped i/o for station
  1324.     mov    es,excep_ss        ; get original stack seg
  1325.     mov    es:EXCEP_AL,al        ; put on stack for exit
  1326.     ret                    
  1327. endif
  1328.     jmp    do_in            ; PCTERM
  1329.  
  1330. ; B&W and Color CRT index registers
  1331. out_crt_index:
  1332. out_col_index:
  1333. ;-------------
  1334.     mov    dl,active_vc$        ; get active virtual console
  1335. if not SR
  1336.     cmp    dl,NUM_VIR_CONS
  1337.     jb    video1
  1338.     call    point_vc@
  1339.     mov    al,outbyte
  1340.     mov    VC_CRT_IDX,al        ; set virtual CRT index register
  1341.     ret                ; in VC_ structure
  1342. endif
  1343. video1:
  1344.     call    point_vs@
  1345.     mov    al,outbyte
  1346.     mov    VS_CRT_IDX,al        ; set virtual CRT index register
  1347.     ret                ; in VC_ structure
  1348.  
  1349. out_crt_data:
  1350. out_col_data:
  1351. ;------------
  1352.     mov    dl,active_vc$        ; get active virtual console
  1353. if not SR
  1354.     cmp    dl,NUM_VIR_CONS
  1355.     jb    video2
  1356.     call    point_vc@
  1357.     mov    dl,VC_CRT_IDX        ; get data register index
  1358.     cmp    dl,13h            ; range check it
  1359.      ja    out_crt1
  1360.     mov    dh,0            ; make it a word
  1361.     lea    di,VC_CRT_DATA        ; get VC_ data area
  1362.     add    di,dx            ; add index
  1363.     mov    al,outbyte
  1364.     mov    [di],al            ; save value written in VC_CRT_DATA
  1365.     cmp    dl,10
  1366.     je    cur_hide
  1367.     cmp    dl,11
  1368.     je    cur_hide        ; cursor start/end regs
  1369.     cmp    dl,15            ; was it cursor address?
  1370.     jne    out_crt1        ; skip if not
  1371.     dec    di
  1372.     mov    ax,[di]            ; get our cursor address
  1373.     xchg    al,ah            ; swap high/low for 6845
  1374.     and    ah,3fh            ; cursor location register is 14 bit
  1375.     mov    dl,CRT_COLS
  1376.     div    dl            ; AL = row, AH = col
  1377.     mov    dh,al            ; DH = row
  1378.     mov    dl,ah            ; DL = column
  1379.     cmp    dh,VC_ROWSB        ; check if in legal range
  1380.      jae    out_crt1        ; no, skip cursor update
  1381.     call    pc_point_curs@
  1382.     mov    VC_OFFSET,ax
  1383.     mov    VC_CURSOR,dx        ; set cursor position
  1384. out_crt1:
  1385.     ret
  1386.  
  1387. cur_hide:
  1388.     lea    di,VC_CRT_DATA        ; get VC_ data area
  1389.     mov    cx,10[di]        ; get cursor start/end
  1390.     xchg    cl,ch
  1391.     test    ch,60h            ; setting bits 5 or 6 turns cursor off
  1392.     jnz    c_off
  1393.     and    ch,0fh            ; mask start cursor line
  1394.     and    cl,0fh            ; and end
  1395.     cmp    ch,cl            ; if start > end
  1396.     ja    c_off            ; then turn cursor off
  1397.     or    VC_MODE,CURSOR_BIT
  1398.     jmps    c_ret            ; turn on 
  1399. c_off:
  1400.     and    VC_MODE,not CURSOR_BIT
  1401. c_ret:
  1402.     or    VC_MODE,UPDATE_BIT    ; flag flush to turn on/off
  1403.     ret
  1404. endif
  1405. video2:
  1406.     call    point_vs@
  1407.     mov    dl,VS_CRT_IDX        ; get data register index
  1408.     cmp    dl,18h            ; range check it
  1409.      ja    out_crt2
  1410.     mov    dh,0            ; make it a word
  1411.     lea    di,VS_CRT_DATA        ; get VC_ data area
  1412.     add    di,dx            ; add index
  1413.     mov    al,outbyte
  1414.     mov    [di],al            ; save value written in VC_CRT_DATA
  1415.     cmp    dl,10
  1416.     je    cur_hide1
  1417.     cmp    dl,11
  1418.     je    cur_hide1        ; cursor start/end regs
  1419.     cmp    dl,15            ; was it cursor address?
  1420.     jne    out_crt2        ; skip if not
  1421.     dec    di
  1422.     mov    ax,[di]            ; get our cursor address
  1423.     xchg    al,ah            ; swap high/low for 6845
  1424.     and    ah,3fh            ; cursor location register is 14 bit
  1425.     mov    dl,CRT_COLS
  1426.     div    dl            ; AL = row, AH = col
  1427.     mov    dh,al            ; DH = row
  1428.     mov    dl,ah            ; DL = column
  1429.     cmp    dh,VS_ROWSB        ; check if in legal range
  1430.      jae    out_crt2        ; no, skip cursor update
  1431.     call    point_cursor@
  1432.     mov    VS_OFFSET,ax
  1433.     mov    VS_CURSOR,dx        ; set cursor position
  1434. out_crt2:
  1435.     ret
  1436.  
  1437. cur_hide1:
  1438.     lea    di,VS_CRT_DATA        ; get VC_ data area
  1439.     mov    cx,10[di]        ; get cursor start/end
  1440.     xchg    cl,ch
  1441.     test    ch,60h            ; setting bits 5 or 6 turns cursor off
  1442.     jnz    c_off1
  1443.     and    ch,0fh            ; mask start cursor line
  1444.     and    cl,0fh            ; and end
  1445.     cmp    ch,cl            ; if start > end
  1446.     ja    c_off1            ; then turn cursor off
  1447.     or    VS_MODE,CURSOR_BIT
  1448.     jmps    c_ret1            ; turn on 
  1449. c_off1:
  1450.     and    VS_MODE,not CURSOR_BIT
  1451. c_ret1:
  1452.     or    VS_MODE,UPDATE_BIT    ; flag flush to turn on/off
  1453.     ret
  1454.  
  1455.  
  1456. out_crt_ctrl:
  1457. out_col_ctrl:
  1458. ;------------
  1459.     mov    dl,active_vc$        ; get active virtual console
  1460. if not SR
  1461.     cmp    dl,NUM_VIR_CONS
  1462.     jb    video3
  1463.     call    point_vc@
  1464.     mov    al,outbyte
  1465.     mov    VC_BLINK,al        ; enable/disable blink attribute
  1466.     ret
  1467. endif
  1468. video3:
  1469.     call    point_vs@
  1470.     mov    al,outbyte
  1471. ;    mov    VS_BLINK,al        ; enable/disable blink attribute
  1472.     ret
  1473.  
  1474. out_crt_status:
  1475. out_col_status:
  1476. ;------------
  1477. out_crt_conf:
  1478. out_col_conf:
  1479. ;------------
  1480.     ret                ; ignore writing to configuration port
  1481.  
  1482.  
  1483. in_crt_index:
  1484. in_col_index:
  1485. ;-----------
  1486.     mov    dl,active_vc$        ; get active virtual console
  1487. if not SR
  1488.     cmp    dl,NUM_VIR_CONS
  1489.     jb    video4
  1490.     call    point_vc@
  1491.     mov    al,VC_CRT_IDX        ; else read back virtual index register
  1492.     mov    es,excep_ss        ; get original stack seg
  1493.     mov    es:EXCEP_AL,al        ; and put on stack for exit
  1494.     ret                    
  1495. endif
  1496. video4:
  1497.     call    point_vs@
  1498.     mov    al,VS_CRT_IDX        ; else read back virtual index register
  1499.     mov    es,excep_ss        ; get original stack seg
  1500.     mov    es:EXCEP_AL,al        ; and put on stack for exit
  1501.     ret                    
  1502.  
  1503. in_crt_data:
  1504. in_col_data:
  1505. ;-----------
  1506.     mov    dl,active_vc$        ; get active virtual console
  1507. if not SR
  1508.     cmp    dl,NUM_VIR_CONS
  1509.     jb    video5
  1510.     call    point_vc@
  1511.     mov    dl,VC_CRT_IDX        ; get data register index
  1512.     mov    dh,0            ; make it a word
  1513.     lea    di,VC_CRT_DATA
  1514.     add    di,dx
  1515.     mov    al,[di]            ; get value written
  1516.     mov    es,excep_ss        ; get original stack seg
  1517.     mov    es:EXCEP_AL,al        ; and put on stack for exit
  1518.     ret                    
  1519. endif
  1520. video5:
  1521.     call    point_vs@
  1522.     mov    dl,VS_CRT_IDX        ; get data register index
  1523.     mov    dh,0            ; make it a word
  1524.     lea    di,VS_CRT_DATA
  1525.     add    di,dx
  1526.     mov    al,[di]            ; get value written
  1527.     mov    es,excep_ss        ; get original stack seg
  1528.     mov    es:EXCEP_AL,al        ; and put on stack for exit
  1529.     ret                    
  1530.  
  1531. in_crt_status:
  1532. in_col_status:
  1533. ;-------------
  1534.     mov    dl,active_vc$        ; get active virtual console
  1535. if not SR
  1536.     cmp    dl,NUM_VIR_CONS
  1537.     jb    video6
  1538.     call    point_vc@
  1539.     inc    VC_CRT_STAT
  1540.     mov    al,VC_CRT_STAT
  1541.     or    al,0F0h            ; these bits always 1 on MDA
  1542.     mov    es,excep_ss        ; get original stack seg
  1543.     mov    es:EXCEP_AL,al        ; and put on stack for exit
  1544.     ret                    
  1545. endif
  1546. video6:
  1547.     call    point_vs@
  1548.     inc    VS_CRT_STAT
  1549.     mov    al,VS_CRT_STAT
  1550.     or    al,0F0h            ; these bits always 1 on MDA
  1551.     mov    es,excep_ss        ; get original stack seg
  1552.     mov    es:EXCEP_AL,al        ; and put on stack for exit
  1553.     ret                    
  1554.  
  1555. in_crt_ctrl:
  1556. in_col_ctrl:
  1557. ;-----------
  1558. in_crt_conf:
  1559. in_col_conf:
  1560. ;-----------
  1561.     jmp    do_in            ; just do "IN"
  1562.  
  1563. eject
  1564.  
  1565. ; Arrives here when all DMA transfer params are setup
  1566. ; either from ROS int 13h or application programming
  1567. ; DMA directly.
  1568. ; If we arrived here from ROS int 13h then the XIOS
  1569. ; has already deblocked over 16K page boundary.
  1570. ; If not from ROS then we can only allow DMA to
  1571. ; continue if the transfer will fit inside the 16K page.
  1572.  
  1573. ; first translate dma address to 32 bit address
  1574. emu_dma:
  1575.  OP_32!    push    bx            ; save EBX - used in conv_dma
  1576.     mov    emu_dma_outport,dx    ; in case we have aligment abort...
  1577.     mov    cl,outbyte        ; get output byte
  1578. ; check if channel 3, 2 (fdc) or channel 1 or DISABLE
  1579.     test    cl,DMA_BMSK_DISABLE    ; is it DISABLE
  1580.     jz    test_dma
  1581.     jmp    init_dma
  1582. test_dma:        
  1583.     and    cl,DMA_BMSK_C3        ; channels 0-3
  1584.     xor    ch,ch
  1585.     mov    di,cx            ; channel number to di
  1586.     dec    di            ; make channels 1-3 zero relative
  1587.     mov    al,0
  1588.     out    DMA_CBPF,al        ; reset flip/flop
  1589.     jmps $+2 ! jmps $+2        ; wait
  1590.     xor    dh,dh
  1591.     mov    dl,dma_page[di]
  1592.     in    al,dx            ; get the high 4 bits of address
  1593.     mov    ch,al
  1594.     mov    dl,dma_address[di]
  1595.     in    al,dx            ; get low address
  1596.     mov    ah,al
  1597.     in    al,dx            ; get high address
  1598.     xchg    al,ah            ; AX 
  1599.  
  1600.     mov    bx,v386_ptr$        ; get v386 table pointer
  1601.     mov    es,ptbl_seg$        ; ES -> page table seg from sysdat
  1602. ;    push    di
  1603.     call    conv_dma        ; convert address in CH, AX
  1604. ;    pop    di            ; to address in BL, DX
  1605.                     ; bytes remaining in page in EAX
  1606.     mov    cx,dx
  1607.  OP_32!    push    ax            ; save count    
  1608.     mov    al,0
  1609.     out    DMA_CBPF,al        ; reset flip/flop
  1610.     jmps $+2 ! jmps $+2        ; wait
  1611.  
  1612.     mov    al,cl            ; get low address
  1613.     xor    dh,dh
  1614.     mov    dl,dma_address[di]
  1615.     out    dx,al
  1616.     jmps $+2 ! jmps $+2        ; wait
  1617.     mov    al,ch            ; and high address
  1618.     out    dx,al
  1619.     jmps $+2 ! jmps $+2        ; wait
  1620.     mov    al,bl            ; get high four bits
  1621.     mov    dl,dma_page[di]
  1622.     out    dx,al            ; to page register
  1623.     jmps $+2 ! jmps $+2        ; wait
  1624.  
  1625.  OP_32!    pop    cx            ; restore remaining byte count
  1626.  
  1627.     mov    ax,EXCEP_CS
  1628.     cmp    ax,0f000h        ; does it come from ROS
  1629.     je    init_dma        ; yes .. no need for further tests
  1630.  
  1631.     mov    bx,v386_ptr$        ; lets look at the global state
  1632.     test    v386_flag,VXF_ALIGN    ; if alignment is on
  1633.      jnz    init_dma        ; then the world is wonderful
  1634.      
  1635. ; get DMA transfer count
  1636.     out    DMA_CBPF,al        ; reset flip/flop
  1637.     jmps $+2 ! jmps $+2        ; wait
  1638.  OP_32!    xor    ax,ax
  1639.     mov    dl,dma_count[di]
  1640.     in    al,dx            ; low byte of dma transfer count
  1641.     mov    ah,al
  1642.     in    al,dx            ; high byte of dma transfer count
  1643.     xchg    ah,al            ; ax = count in bytes
  1644.  OP_32!    cmp    ax,cx            ; enough contiguous memory to fit ?
  1645.  
  1646.     ja    illegal_dma        ; no .. do not allow dma transfer as
  1647.                     ; DMA count will take transfer 
  1648.                     ; over 16k page boundary
  1649. init_dma:
  1650.                     ; else start dma transfer
  1651.     mov    al,outbyte        ; recover value to be output to port
  1652.     out    DMA_BMSK_REG,al        ; initialise disk channel
  1653.  
  1654. init_dma_exit:
  1655.  OP_32! pop    bx            ; restore EBX
  1656.     ret
  1657.  
  1658.  
  1659. illegal_dma:
  1660. ; we have detected a potentially illegal DMA condition. We now give
  1661. ; things one last chance - if the current process has been loaded
  1662. ; into aligned memory then we assume it knows what it is doing.
  1663. ; (We are catering for the case where ALIGN=OFF, but the EXE has been
  1664. ; pifed'd).
  1665. ;
  1666. ; nb. Some programs (eg. Everex Tape Streamer) have been known to program
  1667. ; the DMA from an interrupt context. This can be damaging to your health
  1668. ; as you could attempt to terminate in any (or even no) context.
  1669. ; Roll on banked interrupts!
  1670. ;
  1671.     mov    bx,rlr$            ; get the current process
  1672.     mov    bx,P_MPAR[bx]        ; get the root of the MPAD's
  1673.     test    MPAD_FLAGS[bx],MPADF_ALIGNED
  1674.      jnz    init_dma        ; if aligned then trust it...
  1675.  
  1676.     mov    dx,emu_dma_outport    ; we must reprotect the port
  1677.     call    set_trap        ; before we abort the process
  1678.  
  1679.     mov    ax,offset fatal_dma_msg    ; let's abort the process
  1680.     mov    cx,fatal_dma_msg_len    ; with relevant message
  1681.     jmp    proc_abort@
  1682.  
  1683.  
  1684.  
  1685. ; Model 80 DMA transfers from int 13h function
  1686. ; arrives here when all DMA transfer params are setup.
  1687.  
  1688. ; first translate dma address to 32 bit address
  1689. ; Entry : DX = port address
  1690. ;      outbyte = value to write to port
  1691. do_emu_80:
  1692.     mov    al,outbyte
  1693.     and    al,0f0h            ; mask top nibble - function command
  1694.     cmp    al,0a0h            ; is it initialise command
  1695.     je    do_80
  1696.     call    do_out            ; no execute out instruction
  1697.     ret
  1698.  
  1699. do_80:
  1700.  OP_32!    push    bx            ; save EBX - used in conv_dma
  1701.     mov    al,outbyte
  1702.     and    al,0fh            ; mask channel number
  1703.     or    al,RESET_PTR        ; clear byte pointer command
  1704.     out    DMA_FUNC_REG,al        ; output command
  1705.     jmps $+2 ! jmps $+2        ; wait
  1706.  
  1707.     in    al,DMA_EXEC_REG        ; get low address
  1708.     mov    bl,al
  1709.     in    al,DMA_EXEC_REG        ; get mid address
  1710.     mov    bh,al
  1711.     in    al,DMA_EXEC_REG        ; get page table address
  1712.     mov    ch,al
  1713.     mov    ax,bx
  1714.         
  1715.     mov    bx,v386_ptr$        ; get v386 table pointer
  1716.     mov    es,ptbl_seg$        ; ES -> page table seg from sysdat
  1717.     call    conv_dma        ; convert address in CH, AX
  1718.                     ; to address in BL, DX
  1719.                     ; bytes remaining in page in AX
  1720.     mov    al,outbyte
  1721.     and    al,0fh            ; mask channel number
  1722.     or    al,RESET_PTR        ; clear byte pointer command
  1723.     out    DMA_FUNC_REG,al        ; output command
  1724.     jmps $+2 ! jmps $+2        ; wait
  1725.  
  1726.     mov    al,dl            ; get low address
  1727.     out    DMA_EXEC_REG,al
  1728.     jmps $+2 ! jmps $+2        ; wait
  1729.     mov    al,dh            ; and high address
  1730.     out    DMA_EXEC_REG,al
  1731.     jmps $+2 ! jmps $+2        ; wait
  1732.     mov    al,bl            ; page table address
  1733.     out    DMA_EXEC_REG,al        ; to page register
  1734.     jmps $+2 ! jmps $+2        ; wait
  1735.  
  1736.     mov    al,outbyte
  1737.     out    DMA_FUNC_REG,al        ; initialise disk channel
  1738.  
  1739.  OP_32! pop    bx            ; restore EBX
  1740.     ret
  1741.  
  1742. eject
  1743. ; *****************************************
  1744. ; Page fault handler for IDLE detection
  1745. ; set IDLE bit in CCB if read/write
  1746. ; to/from screen memory A000-C000h
  1747. ; Reset write protect attribute before
  1748. ; returning to process.....
  1749. ;  Entry : 
  1750. ;    stack = 32bit address of page fault
  1751. ;  Exit :
  1752. ;    IRET if screen write
  1753. ;    else display PAGE FAULT
  1754. ; *****************************************
  1755. pfault_handler:
  1756.     cli
  1757.     cld
  1758.  OP_32!    mov    cs:save_eax,ax        ; save EAX
  1759.  OP_32!    pop    ax            ; get linear address into EAX
  1760.  OP_32!    mov    cs:address_eax,ax    ; save linear address
  1761.  
  1762.     push ds ! push es
  1763.     push    bx
  1764.     push    cx
  1765.     push     dx
  1766.  OP_32! push     di
  1767.  OP_32! push    si
  1768.     mov    ds,sysdat$
  1769.     mov    di,rlr$            ; get running proc
  1770.     mov    dl,P_CONS[di]        ; get process's console number
  1771.  
  1772. ;;;    mov    dl,active_vc$        ; get process's console number
  1773.     cmp    dl,NUM_VIR_CONS
  1774.     jb    is_main
  1775.  
  1776. ; must be PC Terminal
  1777.  OP_32!    mov    ax,cs:address_eax    ; get linear address
  1778.  OP_32! and    ax,0ffffh
  1779.      dw    7fffh            ; remove top bit of address
  1780.  OP_32!    xor    di,di
  1781.     mov    di,MONO_SEG
  1782.  OP_32! shl    di,4
  1783.  OP_32! cmp    ax,di
  1784.      jae    test_top
  1785. fatal_error1:
  1786.     jmp    fatal_error
  1787. test_top:
  1788.  OP_32!    add    di,1000h        ; next 4k
  1789.     dw    0000h
  1790.  OP_32! cmp    ax,di
  1791.      jae    fatal_error1
  1792.     mov    di,MONO_SEG        ; restore base
  1793.     jmps    reset_idle
  1794.  
  1795. ; main Video terminal
  1796. is_main:
  1797.     mov    cx,NUM_VIR_CONS
  1798.     mov    dl,0
  1799. test_all_vcs:
  1800.     push    dx
  1801.     push    cx
  1802.     call    point_vs@
  1803.  OP_32!    xor    si,si
  1804.  OP_32!    xor    di,di
  1805.     mov    si,VS_CRT_SEG
  1806.     mov    di,VS_VC_SEG
  1807.  
  1808.  OP_32! shl    di,4
  1809.  OP_32! shl    si,4
  1810.  OP_32!    mov    ax,cs:address_eax    ; get linear address
  1811.  OP_32! and    ax,0ffffh
  1812.      dw    7fffh            ; remove top bit of address
  1813.  
  1814.  OP_32! cmp    ax,di
  1815.      jb    test_si
  1816.  OP_32!    add    di,1000h        ; next 4k
  1817.     dw    0000h
  1818.  OP_32! cmp    ax,di
  1819.      jae    test_si
  1820.     mov    di,VS_VC_SEG        ; restore base
  1821.     jmps    reset_idle1
  1822.     
  1823. test_si:
  1824.  OP_32! cmp    ax,si
  1825.      jb    test_all
  1826.  OP_32!    add    si,1000h        ; next 4k
  1827.     dw    0000h
  1828.  OP_32! cmp    ax,si
  1829.      jae    test_all
  1830.     mov    di,VS_CRT_SEG        ; base to DI
  1831.     jmps    reset_idle1
  1832.         
  1833. test_all:
  1834.     pop    cx
  1835.     pop    dx
  1836.     inc    dl
  1837.     loop    test_all_vcs    
  1838.     jmps    fatal_error
  1839.     
  1840.     
  1841. reset_idle1:
  1842.     pop    cx
  1843.     pop    dx    
  1844. reset_idle:
  1845.     mov    bx,v386_ptr$        ; get pointer to 386 specific table
  1846.     mov    es,ptbl_seg        ;  and page table
  1847.     shr    di,6            ; / 100h *4 = page table entry
  1848.     or    es:byte ptr [di],07h    ; reset write attribute
  1849.     xor    dh,dh
  1850.     mov    di,dx
  1851.     shl    di,1
  1852.     mov    di,ccb_list$[di]    ; get ccb pointer for VC
  1853.     or    C_STATE[di],CSM_IDLE    ; set IDLE bit
  1854.  
  1855.  OP_32!    pop    si
  1856.  OP_32!    pop    di
  1857.     pop    dx
  1858.     pop    cx
  1859.     pop    bx
  1860.     pop es ! pop ds    
  1861.  
  1862.  OP_32! mov    ax,cs:save_eax        ; restore EAX
  1863.     iret
  1864.  
  1865. fatal_error:
  1866.     mov    di,VS_CRT_SEG        ; screen to DI
  1867.     mov    si,VS_VC_SEG
  1868.     mov    bx,v386_ptr$        ; get pointer to 386 specific table
  1869.     mov    es,ptbl_seg        ;  and page table
  1870.     shr    di,6            ; / 100h *4 = page table entry
  1871.     shr    si,6            ; / 100h *4 = page table entry
  1872.     mov    al,67h            ; reset write attribute
  1873.     stosb
  1874.     mov    es:[si],al
  1875.  OP_32! pop    si
  1876.  OP_32! pop    di
  1877.     pop    dx
  1878.     pop    cx
  1879.     pop    bx
  1880.     pop es ! pop ds    
  1881.  
  1882.  OP_32!    mov    ax,cs:address_eax    ; saved EAX
  1883.     mov    si,offset fatal_page$    ; 'Memory protection interrupt'
  1884.     jmp    fatal_int@        ; display error message and terminate
  1885.  
  1886. save_eax    dw    0        ; save EAX area
  1887.         dw    0
  1888. address_eax    dw    0        ; save EAX area
  1889.         dw    0
  1890.  
  1891.  
  1892. ; hardware interrupt handlers (master PIC):
  1893. ; entered in protected mode
  1894.  
  1895. int50:
  1896. ;-----
  1897.     push    08h*4
  1898.     jmps    i_common
  1899. int51:
  1900. ;-----
  1901.     push    09h*4
  1902.     jmps    i_common
  1903. int52:
  1904. ;-----
  1905.     push    0ah*4
  1906.     jmps    i_common
  1907. int53:
  1908. ;-----
  1909.     push    0bh*4
  1910.     jmps    i_common
  1911. int54:
  1912. ;-----
  1913.     push    0ch*4
  1914.     jmps    i_common
  1915. int55:
  1916. ;-----
  1917.     push    0dh*4
  1918.     jmps    i_common
  1919. int56:
  1920. ;-----
  1921.     push    0eh*4
  1922.     jmps    i_common
  1923. int57:
  1924. ;-----
  1925.     push    0fh*4
  1926.     jmps    i_common
  1927.  
  1928. ; hardware interrupt handlers (slave PIC):
  1929.  
  1930. int70:
  1931. ;-----
  1932.     push    70h*4
  1933.     jmps    i_common
  1934. int71:
  1935. ;-----
  1936.     push    71h*4
  1937.     jmps    i_common
  1938. int72:
  1939. ;-----
  1940.     push    72h*4
  1941.     jmps    i_common
  1942. int73:
  1943. ;-----
  1944.     push    73h*4
  1945.     jmps    i_common
  1946. int74:
  1947. ;-----
  1948.     push    74h*4
  1949.     jmps    i_common
  1950. int75:
  1951. ;-----
  1952.     push    75h*4
  1953.     jmps    i_common
  1954. int76:
  1955. ;-----
  1956.     push    76h*4
  1957.     jmps    i_common
  1958. int77:
  1959. ;-----
  1960.     push    77h*4
  1961.     jmps    i_common
  1962.  
  1963. ;--------
  1964. i_common:
  1965. ;--------
  1966.  OP_32!    push    bp            ; push EBP
  1967.  OP_32!    mov    bp,sp            ; point at stack frame
  1968.  OP_32!    push    bx
  1969.  OP_32!    push    si
  1970.     push    ds
  1971.  
  1972.     cld
  1973.     mov    bx,GDT_GDT_SEL
  1974.     mov    ds,bx
  1975.  
  1976.     ; Build user stack alias:
  1977.  
  1978.  OP_32!    sub    bx,bx
  1979.     mov    bx,EX_SS
  1980.  OP_32!    shl    bx,4
  1981.  OP_32!    or    bx,0
  1982.     dw    DATA_ACCESS shl 8
  1983.     mov    si,GDT_SS_SEL
  1984.  OP_32!    mov    2[si],bx
  1985.  
  1986.     ; emulate the 8086 interrupt:
  1987.  
  1988.     mov    ds,si            ; DS -> 8086 stack segment
  1989.     sub    EX_SP,6            ; make space for CS,IP,FLAGS
  1990.     mov    si,EX_SP        ; DS:SI = user stack
  1991.     mov    bx,EX_IP
  1992.     mov    [si],bx            ; push IP on user stack
  1993.     mov    bx,EX_CS
  1994.     mov    2[si],bx        ; push CS on user stack
  1995.     mov    bx,EX_EFLAGS
  1996.     mov    4[si],bx        ; push FLAGS on user stack
  1997.     and    bx,not 0300h        ; clear IF and TF
  1998.     mov    EX_EFLAGS,bx        ; update flags for IRET
  1999.  
  2000.     mov    si,EX_INT        ; get vector # * 4
  2001.     cmp    si,9*4            ; keyboard interrupt
  2002.     jne    i_common1        ; no..
  2003.     mov    bx,GDT_SYSDAT_SEL
  2004.     mov    ds,bx            ; DS -> SYSDAT seg
  2005.                     ; ALWAYS jump to our keyboard handler
  2006. ;;    cmp    active_vc$,NUM_VIR_CONS    ; are we on main console
  2007. ;;    jb    i_common1        ; yes..
  2008.     mov    si,offset keyboard_isr    ; get offset location of keyboard isr address
  2009.     jmps    i_common2
  2010. i_common1:
  2011.     mov    bx,GDT_INT_SEL
  2012.     mov    ds,bx            ; DS -> 8086 int vectors
  2013. i_common2:
  2014.     mov    bx,[si]            ; get offset from interrupt vector
  2015.     mov    EX_IP,bx        ; and store on system stack
  2016.     mov    bx,2[si]        ; get segment from interrupt vector
  2017.     mov    EX_CS,bx        ; and store on system stack
  2018.  
  2019.     pop    ds
  2020.  OP_32!    pop    si
  2021.  OP_32!    pop    bx
  2022.  OP_32!    pop    bp
  2023.     add    sp,2            ; remove int vector from stack
  2024.  OP_32!    iret                ; continue at handler address
  2025.  
  2026.  
  2027. eject
  2028.  
  2029.  
  2030. ; entry from Floppy module for converting
  2031. ; DMA transfer address.
  2032. ; Entry: AX =    bottom 16 bits of address
  2033. ;     CH =    highest 4 bits of address, always less then 16 -
  2034. ;        no megabyte wrap around
  2035. ; Exit:  AX =  number of bytes remaining in page
  2036.  
  2037. vxm_dma@:
  2038.     push    bx ! push dx ! push es    ; save scratch registers
  2039.     mov    bx,v386_ptr$        ; get pointer to V386 table
  2040.     mov    es,ptbl_seg$
  2041.     call    conv_dma
  2042.     mov    dma_low16$,dx        ; store for dma controller
  2043.     mov    dma_high4$,bl        ; store top 4 bits for dma controller
  2044.  
  2045.     pop    es ! pop dx ! pop bx    ; restore scratch registers
  2046.     ret
  2047.  
  2048. ; Translate virtual to physical address for DMA transfers
  2049. ; in virtual address mode and compute # of bytes transferable
  2050. ; in this page until memory becomes noncontiguous.
  2051. ;
  2052. ; Entry: AX = A0-A15 of virtual address
  2053. ;     CH = A16-A19 of virtual address
  2054. ; Exit:  DX = A0-A15 of physical address
  2055. ;     BL = A16-A23 of physical address
  2056. ;     EAX = # of linear bytes in this page
  2057. ;
  2058. ;    SI preserved
  2059.  
  2060. conv_dma:
  2061.  OP_32! sub     bx,bx            ;; clear EBX
  2062.      mov    bl,ch
  2063.     mov    cl,16
  2064.  
  2065.  OP_32! shl    bx,cl
  2066.      mov    bx,ax            ;; EBX = 32 bit address
  2067.  OP_32! shr    bx,PAGE_SHIFT        ;; make byte address into page index
  2068.      shl    bx,2            ; byte offset in page table of 
  2069.                     ; our page
  2070.     mov    dx,es:[bx]        ; lower 16 bits of physical address
  2071.     mov    ch,es:2[bx]        ; get A16-A23
  2072.     and    dx,0 - PAGE_SIZE    ; mask top nibble
  2073.                     ; AX = offset within 64k
  2074.  OP_32!    and    ax,PAGE_SIZE - 1    ; make offset within 4k page
  2075.     dw    0
  2076.     or    dx,ax            ; combine 16 bit offset
  2077.  
  2078.  OP_32!    sub    ax,PAGE_SIZE
  2079.     dw    0
  2080.  OP_32!    neg    ax            ; AX = # of bytes left in page
  2081.  
  2082.     push    si
  2083.     mov    si,bx            ; ES:SI -> page table entry
  2084.  
  2085. conv_dma1:
  2086.     mov    bl,es:1[si]        ; get A12-A16 (4 Kb block)
  2087.     and    bl,not (PAGE_SIZE/256-1); zero A0-A11
  2088.     add    si,4            ; point to next page
  2089. conv_dma2:
  2090.     cmp    ch,es:2[si]        ; next page in same 64 Kb block?
  2091.      jne    conv_dma3        ; skip if not in same 64 K page
  2092.     mov    bh,es:1[si]        ; get next A12-A16
  2093.     and    bh,not (PAGE_SIZE/256-1); zero next A0-A11
  2094.     sub    bh,bl            ; BH = distance between pages
  2095.     cmp    bh,PAGE_SIZE/256    ; are they contiguous?
  2096.      jne    conv_dma3        ; no, stop scanning
  2097.  OP_32!    add    ax,PAGE_SIZE        ; add in size of next page
  2098.      dw    0
  2099.  OP_32!    cmp    ax,0            ; is block getting too large?
  2100.      dw    1            ; ie. >= 64k
  2101.      jb    conv_dma1        ; no, keep on scanning
  2102. conv_dma3:
  2103.     pop    si            ; restore SI
  2104.     mov    bl,ch            ; get A16 - A23
  2105.     ret
  2106.  
  2107.  
  2108.  
  2109. eject
  2110.  
  2111. V386_DATA    dseg    PARA        ; paragraph align for 32-bit stack
  2112.  
  2113.  
  2114. ; Master PIC isr offsets
  2115. idt_m_pic_offs    dw    offset int50
  2116.         dw    offset int51
  2117.         dw    offset int52
  2118.         dw    offset int53
  2119.         dw    offset int54
  2120.         dw    offset int55
  2121.         dw    offset int56
  2122.         dw    offset int57
  2123.  
  2124.  
  2125. ; Slave PIC isr offsets
  2126. idt_s_pic_offs    dw    offset int70
  2127.         dw    offset int71
  2128.         dw    offset int72
  2129.         dw    offset int73
  2130.         dw    offset int74
  2131.         dw    offset int75
  2132.         dw    offset int76
  2133.         dw    offset int77
  2134.  
  2135. ; DMA channel parameters
  2136. dma_page    db    DMA_PAGE_C1    ; a16 to a20 for channel 1
  2137.         db    DMA_PAGE_FDC    ; ditto for channel 2
  2138.         db    DMA_PAGE_C3    ; ditto for channel 3 (hd)
  2139.  
  2140. dma_address    db    DMA_C1_ADDRESS    ; 8237 channel 1 address
  2141.         db    DMA_C2_ADDRESS    ; 8237 channel 2 address
  2142.         db    DMA_C3_ADDRESS    ; 8237 channel 3 address (hd)
  2143.  
  2144. dma_count    db    DMA_C1_COUNT    ; 8237 channel 1 transfer count
  2145.         db    DMA_C2_COUNT    ; 8237 channel 2 transfer count
  2146.         db    DMA_C3_COUNT    ; 8237 channel 3 transfer count
  2147.  
  2148. ; High memory free list (re-uses following tables)
  2149. hi_mfl        rw    160 
  2150.  
  2151. vm_flag$    db    0        ; 0FFh if we're in virtual mode
  2152.         rb    1
  2153.  
  2154. emem        rw    1        ; extended memory size - 1k blocks
  2155.  
  2156. hi_xmem_addr$    dw    0        ; extra RAM base (A16..A31)
  2157. hi_xmem_size$    dw    0        ; extra RAM size (# of 16K blocks)
  2158.  
  2159. error_code    rw    2        ; pop error code into here
  2160.  
  2161. keyboard_isr    dw    offset i_keyboard@    ; pointer to keyboard ISR
  2162.         dw    0000            ; XIOS cseg set up at init
  2163.  
  2164. num_pages$    dw    0000            ; for INIT display
  2165.  
  2166. fatal_dma_msg    db    0dh,0ah
  2167.         db    'DMA transfer error: Use ALIGN option in CCONFIG.SYS.'
  2168. fatal_dma_msg_len    equ offset $ - offset fatal_dma_msg$
  2169. outbyte        rb    1        ; temp storage
  2170. emu_dma_outport    rw    1        ; temp storage
  2171.  
  2172.     dw    0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch
  2173.     dw    0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch
  2174.     dw    0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch
  2175.     dw    0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch
  2176.     dw    0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch
  2177.     dw    0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch,0cccch
  2178.     dw    0cccch,0cccch
  2179.  
  2180. excep_stack_top    rw    1
  2181. excep_ss    rw    1
  2182. excep_sp    rw    1
  2183.  
  2184.  
  2185.      end
  2186.