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

  1. ; INIT.A86
  2. title 'XIOS Initialization'
  3. pagesize 60+11
  4. ;********************************************************
  5. ;*                            *
  6. ;*        XIOS INITIALIZATION ROUTINE        *
  7. ;*        CDOS 6.x/2.x XIOS            *
  8. ;*        DRI OS ENGR, JMB, GMS, JW        *
  9. ;*                            *
  10. ;********************************************************
  11. ; Modifications:
  12. ; V 6.2/3.0
  13. ; 23 Jan 89 -- More XPC checks                    - IJ
  14. ;  1 Dec 88 -- add support for model 30-286            - JW 
  15. ; 28 Nov 88 -- double check XPC settings            - IJ
  16. ; 18 Nov 88 -- allow LOADSYS from drive D:            - GMS
  17. ;  7 NOV 88 -- modified PS/2 check                - JW
  18. ; 27 Oct 88 -- fix_crt now ignores inactive VGA            - IJ
  19. ; 26 SEP 88 -- print digit of 10,000 or more fix        - GMS
  20. ;  1 AUG 88 -- mark unused LCB's as unavailable            - GMS
  21. ; 29 Jul 88 -- build_pin removed                - IJ
  22. ; 29 JUL 88 -- call alloc_tmp to allocate TMP banked window    - GMS
  23. ; 28 JUL 88 -- fix for empty DOS extended partitions        - JW
  24. ; 21 Jul 88 -- intercept int 14                    - IJ
  25. ; 13 Jul 88 -- add XPC protocol support                - IJ
  26. ; 13 Jul 88 -- use PC Terminal Aux port as a printer        - IJ
  27. ;  1 JUL 88 -- removed support for internal MDISK (use VDISK.SYS) GMS
  28. ; 29 JUN 88 -- Big fix in io_mem_alloc with alignment        - GMS
  29. ; 24 JUN 88 -- Align VC buffers on 4k page for SunRiver        - GMS
  30. ; 21 JUN 88 -- move hard disk param tables if below screen    - GMS
  31. ; 17 JUN 88 -- display printer numbers < 9            - GMS
  32. ; 15 JUN 88 -- setup int17 and int14 tables per VC        - GMS
  33. ; 15 JUN 88 -- mark unused ACB's as unavailable            - GMS
  34. ;  6 APR 88 -- added support for Sun River system        - GMS
  35. ; 17 Feb 88 -- Use ROS to read Time and Disk Parameters        - JC/JW
  36. ; 27 JAN 88 -- support loadable Aux device drivers        - JW
  37. ; 27 JAN 88 -- check for 12 bit FAT                - JW
  38. ; 13 JAN 88 -- support Compaq DOS 3.31 big partitions        - GMS
  39. ; 11 JAN 88 -- save_equip$ now setup for XM and saved in VS_    - GMS
  40. ; 10 DEC 87 -- mcga/ega/vga no longer initialise vector table.    - GMS
  41. ; 10 DEC 87 -- video_init replaced with screen_set_only        - GMS
  42. ;  7 DEC 87 -- initialise current monitor only            - GMS
  43. ;  2 DEC 87 -- introduced new flag video$ for monitor types    - GMS
  44. ; 22 NOV 87 -- don't use Sprite ROS as RAM, now like COMPAQ     - JW
  45. ;
  46. ; 6.0/2.0
  47. ; =======
  48. ; 18 NOV 87 -- set flag for AST color card            - GMS
  49. ; 17 NOV 87 -- re-map ega/vga rom, based on rom size value COMPAQ.GMS
  50. ; 16 NOV 87 -- change INT 10h to callf for compaq's sake in fix_ega GMS    
  51. ; 13 NOV 87 -- bug fix for compaq ega test            - GMS
  52. ; 11 NOV 87 -- save ROS keyboard data params for 386        - GMS
  53. ; 10 NOV 87 -- change COMPAQ test to use ega rom at C000h on 386  GMS
  54. ;  9 NOV 87 -- set some ROS keyboard variables for clones      - GMS
  55. ;  7 NOV 87 -- do one video mode init only if VGA        - JW
  56. ;  6 NOV 87 -- MDISK now allocated from next available TPA slot - GMS
  57. ;        hi memory on XM EMM or 386 if available.
  58. ;  5 NOV 87 -- disable page 1 on hercules before color check    - GMS
  59. ;  3 NOV 87 -- disable INT 14 for com1/com2 if serial console    - GMS    
  60. ;  1 NOV 87 -- join 386 hi partitions, split in MEM_ALLOC(0h)   - JW
  61. ; 31 Oct 87 -- HI_MFL_START renamed XIOS_MFL, moved into SYSDAT - JW
  62. ; 30 OCT 87 -- XIOS no longer patches Int 1Bh vector        - GMS
  63. ; 29 OCT 87 -- move hi_mfl_root onto hi_mfl_start after io_protect - GMS
  64. ; 28 OCT 87 -- relocate PS/2 BIOS data before MP_CHECK        - JW
  65. ; 27 OCT 87 -- link INIT code into HI_MFL_START            - JW
  66. ;           write protect RAM BIOS on COMPAQ & Sprite (386)
  67. ;           check for 80386 CPU for CDOS 386
  68. ; 20 OCT 87 -- set disk change mask for model 30        - GMS
  69. ; 19 OCT 87 -- mem_alloc made public for XM as well as 386    - GMS
  70. ; 18 OCT 87 -- mem_alloc function searches mfl and mwd        - GMS
  71. ;        if 386 all segment based allocations done
  72. ;        after protected mode initialisised.
  73. ;        if XM MMU then seg based allocations done
  74. ;        after MWD setup.
  75. ; 15 OCT 87 -- use high end of SYSDAT for hd login buffer    - JW
  76. ;           just set buffer variables, BDOS will allocate
  77. ;           let BDOS take care of DOS media hash setup
  78. ; 21 SEP 87 -- insert dummy DPB offset in floppy DPH's        - GMS
  79. ; 16 SEP 87 -- logical to physical console mapping included    - GMS
  80. ;  9 SEP 87 -- test setup bit before checking for EEMS boards    - GMS
  81. ; 28 AUG 87 -- Zero DDSC area                    - GMS
  82. ;  6 AUG 87 -- added code for CDOS 386 version 2.0 support    - GMS
  83. ;  5 AUG 87 -- TMPS' now spawn themselves so do not build    - GMS
  84. ;  4 AUG 87 -- IO_PROTECT added for Cdos 386 init        - GMS
  85. ;  3 AUG 87 -- change # of buffers based on sector size        - JW
  86. ;  3 AUG 87 -- Bug fix for multi port cards init.        - SAC
  87. ; 17 JUL 87 -- small model XIOS conversion            - JW
  88. ; 21 JUN 87 -- use Q buffer space for login local_buffer$    - JW
  89. ; 18 JUN 87 -- check for COMPAQ & SPRITE shadowed 256 K        - JW
  90. ; 13 JUN 87 -- support for PS/2 Model 30 + MCGA, VGA modes    - JW
  91. ; 12 JUN 87 -- enabled INT 15 flag stuff -            - JW
  92. ;        only do one flag wait per INT 13h
  93. ; 10 JUN 87 -- support for RAM at E000-F000 in COMPAQ 386    - JW
  94. ;        also added test for IBM PS/2 Model 80
  95. ;  9 JUN 87 -- support for RAM at E000-F000 in Sprite 386    - JW
  96. ;
  97. ; 5.2
  98. ; ===
  99. ; 20 MAY 87 -- if COMPAQ test if 9*14 CGA present.        - GMS
  100. ; 14 MAY 87 -- read real time clock uses ROS int 1ah        - GMS
  101. ;        also called from statline not TICK routine.
  102. ; 5.2 beta 1
  103. ; 29 APR 87 -- "set_time" moved to safe area for use by TICK    - GMS
  104. ; 13 APR 87 -- fix bug re hardcard which writes to monitor    - GMS
  105. ;  6 APR 87 -- Olivetti 640*400 graphics modes support        - GMS
  106. ;  2 APR 87 -- Get hard disk sectors_per_track from BPB        - GMS
  107. ;  2 APR 87 -- Leave NMI vector if not pointing at ROS seg     - GMS
  108. ;        (autoswitch ega's)    
  109. ;  2 MAR 87 -- Pallette save area fixed in VS structure        - GMS
  110. ; 27 FEB 87 -- If compaq 386 set mode to FAST.......        - GMS
  111. ;  9 FEB 87 -- Apricot 1.4meg 3.5inch drive is type 4        - GMS
  112. ;  5 FEB 87 -- skip buggy_string test re pc_at  -- to be cleaned up !!
  113. ; 28 JAN 87 -- MEM_ALLOC moved before INIT code for V386    - GMS
  114. ; 27 JAN 87 -- Test for EGA changed to use int 10h        - GMS
  115. ; 27 JAN 87 -- do_video inits both primary and secondary monitors GMS
  116. ;
  117. ; 5.1
  118. ; ===
  119. ; 16 JAN 87 -- Prevent the Boot Part on Drive 1 being Boot DRV  - GMS
  120. ; 13 JAN 87 -- Fix uart reset                    - GMS
  121. ;  8 JAN 87 -- Bug fix for hard disk sizes > 32meg         - GMS
  122. ; 10 DEC 86 -- Test byte in SETUP buffer for EGA autoswitch cards GMS
  123. ;  1 DEC 86 -- Restore var_cursor value for EGA's on COMPAQ    - GMS
  124. ; 11 NOV 86 -- Bug fix for old ros kb/buffer on old COMPAQ machines - GMS
  125. ; 13 NOV 86 -- Test byte in SETUP buffer to enable hercules check GMS
  126. ; 13 NOV 86 -- Changed hercules check, problem on Philips P3200    - GMS
  127. ; 29 OCT 86 -- 19.2 & 38.4 Kb for serial consoles added        - JW
  128. ; 27 OCT 86 -- Add retrace timing for hercules             - PAR
  129. ; 15 OCT 86 -- Bug fix for HP vectra machine            - GMS
  130. ; 14 OCT 86 -- Amstrad support added                - GMS
  131. ; 7  OCT 86 -- European Keyboard support added            - GMS
  132. ; 28 AUG 86 -- collapse parallel printer numbers
  133. ; 21 AUG 86 -- Large sector size support for DOS partition    - GMS
  134. ;        sizes greater than 32 megabytes.
  135. ; 18 AUG 86 -- Multiple DOS partition support added        - GMS
  136. ; 30 JUL 86 -- reinstall interrupt-driven serial output (thx AS)
  137. ; ?? JUL 86 -- dynamic DPB setup for 96 TPI & Sony support     - JW
  138. ; 18 JUL 86 -- set default printer in rsps to first actually present
  139. ; 18 JUL 86 -- support Olivetti M24 RTC             - JW
  140. ;
  141. ; 5.0
  142. ; ===
  143. ; 10 JUL 86 -- if debug, don't init int 3
  144. ; 27 JUN 86 -- add presence test for QXM
  145. ; 24 JUN 86 -- rework patch_mem to fix 64k wrap problem - ddb
  146. ; 20 JUN 86 -- conditional unexpected int. vector setup
  147. ; 17 JUN 86 -- point int 3 at iret
  148. ; 16 JUN 86 -- set parity-checking port as function of at or pc/xt
  149. ; 10 JUN 86 -- correct memory sizing for old PC's w/ int 12h bug
  150. ; 10 JUN 86 -- zero dph entries for non-existent partitions
  151. ;  3 JUN 86 -- support keyboard vector switching
  152. ; 28 MAY 86 -- change sign-on version if QXM
  153. ; 27 MAY 86 -- initialize cntl-break isr
  154. ; 14 MAY 86 -- wait for update bit in AT CMOS/tod before reading (thx JC)
  155. ; 12 MAY 86 -- new INIT signon plus color
  156. ; 29 APR 86 -- fix bus float on RAM check for ZDS (thx Mark Foster)
  157. ; 23 APR 86 -- save vectors (for LOADCCPM) before poking 1E
  158. ; 22 APR 86 -- fix do_one_port bug (thx JC)
  159. ; 15 APR 86 -- set up process-terminating isr address for seg overrun int (286)
  160. ; 16 APR 86 -- same for invalid-opcode int (286)
  161. ;  3 APR 86 -- explicitly mask a non-existent serial port at the PIC (thx JC)
  162. ; 24 MAR 86 -- remove JW DOS hash experiment
  163. ; 11 FEB 86 -- add JW DOS hash experiment ;;**
  164. ;  5 FEB 86 -- only use optimized XIOS hard disk driver if SETUP instructs
  165. ; 19 DEC 85 -- make screen buffers last-allocated non-SYSDAT for 4.0 group
  166. ; 18 DEC 85 -- allocate space for the EGA bit_plane save if EGA
  167. ; 18 DEC 85 -- force the default diskette EOT to 9
  168. ;  6 NOV 85 -- do or don't customize fdc based on su_fdc_check
  169. ; 24 OCT 85 -- support diskette int 1E + setup diskette parms
  170. ; 27 SEP 85 -- add Dev. Driver/SETUP SYSDAT space routine
  171. ; 20 SEP 85 -- add low memory space allocation routines, for
  172. ;        SYSDAT space and non-sysdat space, use for HASH,
  173. ;        HD ALV (CPM), data buffs, AUX buffs and screen buffs
  174. ; 17 SEP 85 -- remove previously installed AT HD POST/WAIT code
  175. ;  4 SEP 85 -- handle interrupt-driven hard disk code
  176. ; 28 AUG 85 -- handle Enhanced Graphics Adaptor
  177. ; 12 JUL 85 -- program the UARTS for ints. only on data-received
  178. ;  9 JUL 85 -- insert debug flag to control timer PIC mask
  179. ;  1 JUL 85 -- initialize the ROS interface vectors (ROSIF.A86)
  180. ;  6 JUN 85 -- update 4.1 ASM86 to 4.2 RASM86
  181.  
  182. ; include COPYRITE.TXT
  183.  
  184. nolist
  185. include CDOS.EQU
  186. include XIOS.EQU
  187. include PCHW.EQU
  188. include ASCII.EQU
  189. include ROSDATA.EQU
  190. if SR
  191. include SR.EQU
  192. endif
  193. list
  194. ; These have been included:
  195. ; include CDOS.EQU
  196. ; include XIOS.EQU
  197. ; include PCHW.EQU
  198. ; include ASCII.EQU
  199. ; include ROSDATA.EQU
  200.  
  201. CGROUP    group    init_cseg
  202. DGROUP    group    init_dseg
  203.  
  204. public    init@                        ; for HEADER.A86
  205. public    INIT_START, XIOS_END                ; for FIDD.A86
  206.  
  207. public    io_mem_alloc@                    ; for HEADER.A86
  208. public    mem_alloc_i@                    ; for V386.A86 and EMM
  209. public    hi_on$, hi_off$
  210. public    init_reuse@                    ; for EMM.A86
  211. if SR
  212. public    current_pc$
  213. public    pic_mask_image$
  214. public    put_in_s_o
  215. public    conv_digit@
  216. endif
  217.  
  218. eject
  219.  
  220. init_dseg    dseg
  221.  
  222. extrn      genccpm_buf$ :word
  223. extrn          dph_tbl$ :word,         nvcns$ :byte
  224.  
  225. extrn       su_md_size$ :word,       su_verf$ :byte
  226. extrn           su_mmp$ :word,        su_cf$ :byte
  227. extrn        su_scroll$ :byte,       su_hdst$ :byte
  228. extrn        su_config$ :word,       su_prot$ :byte
  229. extrn       su_pfk_tbl$ :byte,  su_ser_con$ :word
  230. extrn         su_check$ :word,        su_pf$ :byte
  231. extrn        su_sysdat$ :word, su_hard_driver$:byte
  232. extrn  su_timer_count$ :word,  su_fdc_check$ :byte
  233. extrn     su_fdc_spec1$ :byte,  su_fdc_spec2$ :byte
  234. extrn    su_fdc_settle$ :byte, su_fdc_spinup$ :byte
  235. extrn     su_flag_bits$ :word
  236. extrn       su_mu_data$ :word
  237. extrn         su_mu_vs$ :byte
  238. extrn      mu_com_type$ :byte
  239.  
  240. extrn      ndp_control$ :word,       num_ndp$ :word    ; in ISRS.A86
  241. extrn       parity_chk$ :word
  242. extrn         pfk_tbl0$ :byte                ; in CONIN.A86
  243. extrn        sl_attrib$ :byte                ; in STATLINE.A86
  244.  
  245. extrn        list_data$ :word,       list_stat$ :word    ; in LISTAUX.A86
  246. extrn         list_out$ :word, auxout_blk_ptr$:word
  247. extrn    aux_in_vector$ :word, aux_out_vector$:word
  248. extrn    auxin_stat_vector$:word, auxout_stat_vector$:word
  249. extrn    ser_conin_vec$ :word, ser_conout_vec$:word, ser_conout_stat_vec$:word
  250. extrn    auxin_blk_ptr$ :word
  251. extrn    port2pc_table$ :byte,  pc2port_table$:byte
  252. extrn    serdrv_vector$ :word
  253.  
  254. extrn         ccb_list$ :word, acb_list$:word, dummy_cb$:word ; in PUBDATA.A86
  255. extrn         lcb_list$ :word
  256. extrn           dph_md$ :word
  257. extrn          pcdpb9D$ :word
  258. extrn        next_flag$ :byte
  259. extrn        int14_ptr$ :byte, int17_ptr$ :byte
  260. extrn       save_equip$ :word
  261.  
  262. extrn         num_flop$ :word, num_flop_des$ :word
  263. extrn        num_print$ :word,     num_hard$ :word
  264. extrn         num_port$ :word
  265. extrn         num_mmkb$ :word
  266. extrn          iattrib$ :byte,         blank$ :word
  267.  
  268. extrn     disk_int_off$ :word, disk_int_seg$ :word
  269. extrn      timer_count$ :word
  270.  
  271. extrn       lo_mem_top$ :word, hi_mem_start$ :word
  272. extrn       hi_mem_top$ :word
  273. extrn     aux_prot_blk$ :word
  274. extrn           dsm_md$ :word
  275. extrn      nfatrecs_md$ :word
  276. extrn        nclust_md$ :word
  277.  
  278. extrn      ros_vectors$ :byte
  279. extrn        cloneflag$ :byte
  280. extrn          retrace$ :word
  281.  
  282. if V386
  283. extrn     hi_xmem_addr$ :word, hi_xmem_size$ :word    ; in V386.A86
  284. extrn     num_pages$:word
  285. extrn  pc_kbd_save$:word            ; in PCTERM.A86/SRTERM.A86
  286. extrn  save_kbdata$:word                ; in KEYBOARD.A86
  287. endif
  288.  
  289. if SR
  290. extrn    sr_vs_table$:byte, sr_pc_table$:byte        ; in PUBDATA.A86
  291. extrn    sr_table_vs$:word, SR_VS_TLEN:abs
  292. extrn    vc_seg_save$:word                ; in SRTERM.A86
  293. extrn    ptbl_bit_plane$:word ,ptbl_vc_save$:word
  294. endif
  295.  
  296. if XM
  297. extrn         num_pgkb$ :word                ; in EMM.A86
  298. endif
  299.  
  300. extrn     alpha_str_80$ :word,   compaq_str$ :byte    ; in WINDOWS1.A86
  301. extrn       mono_table$ :word,         video$ :byte
  302. extrn         ast_flag$ :byte
  303. extrn      mode_vector$ :word,     oli_vector$ :word
  304. extrn    bit_plane_seg$ :word
  305. extrn        local_ptr$ :word
  306.  
  307. extrn       var_cursor$ :word,       var_sync$ :byte    ; in WINDOWS3.A86
  308. extrn         table_vs$ :word,  scroll_mode$ :byte
  309. extrn       vc_map_seg$ :word,  vc_priority$ :byte
  310.  
  311. extrn         read_tbl$ :word,     write_tbl$ :word    ; in DISK.A86
  312. extrn       select_tbl$ :word
  313.  
  314. extrn       drive_type$ :byte,      data_rate$ :byte    ; in FLOPPY.A86
  315. extrn      motor_flags$ :byte,disk_chng_mask$:byte
  316. extrn      verify_flag$ :byte,        pc_at$ :byte
  317. extrn     int_1e_parms$ :byte
  318. extrn        settle_1e$ :byte
  319. extrn         dos_dpbs$ :word
  320.  
  321. extrn       hd_rom_seg$ :word,     hd_rom_ofs$ :word    ; in HDISK.A86
  322. extrn     hd_disk_info$ :byte,     hdinf_ptr$ :word
  323. extrn     hd_rom_entry$ :dword
  324.  
  325. if XM
  326. extrn       hd_cmd_blk$ :byte                ; not in CDOS 386
  327. endif
  328.  
  329. extrn     local_buffer$ :word
  330. extrn     hd_boot_flag$ :byte, hd_init_flag$ :byte
  331.  
  332. extrn   sysdat_buff_base$ :word                ; in FIDDS.A86
  333. extrn sysdat_buff_length$ :word, sysdat_buff_link$ :word
  334. extrn     prog_hist_base$  :word, comm_hist_base$ :word
  335. extrn      ser_hist_base$  :word
  336.  
  337. init_cseg    cseg
  338.  
  339. extrn          sysdat$ :word                ; in HEADER.A86
  340. extrn     supervisor_o$ :word, supervisor_s$ :word    ; in HEADER.A86
  341. extrn      disp_offset$ :word, disp_segment$ :word
  342. extrn        i_ndp@ :near, i_unexpected@ :near    ; in ISRS.A86
  343. extrn         i_divide@ :near,         i_nmi@ :near
  344. extrn          i_clock@ :near,          i_tick@ :near
  345. extrn       i_overflow@ :near
  346. extrn        i_seg_ovr@ :near, i_bad_opcode@ :near
  347.  
  348. extrn       i_keyboard@ :near                ; in KEYBOARD.A86
  349. extrn          NX_init@ :near                ;    
  350. extrn     keyboard_isr$ :dword                ; in KEYBOARD.A86
  351. extrn        z_sl_mono@ :near,    z_sl_color@ :near    ; in STATLINE.A86
  352.  
  353. extrn        point_aux@ :near,  aux_port_in@ :near    ; in LISTAUX.A86
  354. extrn         aux_null@ :near, parallel_out@ :near
  355. extrn     aux_port_out@ :near,parallel_stat@ :near
  356. extrn           aux_in@ :near,        aux_out@ :near,    term_auxout_stat@ :near
  357. extrn          i_aux_0@ :near,        i_aux_1@ :near
  358.  
  359. extrn      select_flop@ :near,     read_flop@ :near    ; in FLOPPY.A86
  360. extrn       write_flop@ :near
  361. extrn     flop_specify@ :near,          i_disk@:near
  362.  
  363. extrn     hd_dummy_int@ :near                ; in HDISK.A86
  364. extrn     pc_select_hd@ :near,     pc_read_hd@ :near
  365. extrn      pc_write_hd@ :near
  366. if XM
  367. extrn           hd_isr@ :near,     xt_driver@ :near
  368. endif
  369.  
  370. extrn           hd_rom@ :near,    int15_isr@ :near
  371.  
  372. extrn    i_dummy_fidds@ :near, i_fidds_flag@ :near    ; in FIDDS.A86
  373. extrn check_init_reuse@:near
  374.  
  375. extrn           set_mono@:near,     set_color@:near    ; in WINDOWS1.A86
  376. extrn          io_conout@:near, screen_set_only@:near
  377. extrn         bw_640_400@:near,     bw_640_400_t@:near
  378.  
  379. extrn         point_vs@ :near,  new_monitor@ :near    ; in WINDOWS2.A86
  380. extrn        video_int@ :near                ; in PCVIDEO.A86
  381. extrn        async_int@ :near                ; in LISTAUX.A86
  382.  
  383. extrn     vector_table$ :word,   NUM_VECTORS :abs    ; in ROSIF.A86
  384. extrn     int10_isr$:word
  385.  
  386. extrn        old_int15$ :word                ; in HDISK.A86
  387.  
  388. public    set_time@                    ; for STATLINE.A86
  389.  
  390. if XM
  391. extrn         mp_check@ :near,    mp_config@ :near    ; in EMM.A86
  392. endif
  393.  
  394. if V386
  395. extrn    init_386@:near                    ; in V386.A86
  396. extrn    alloc_tmp@:near
  397. public    io_protect@
  398. endif
  399. if SR
  400. extrn    sr_init@:near                    ; in SRTERM.A86
  401. extrn    sr_fix_crt@:near
  402. endif
  403. eject
  404.  
  405. init_cseg cseg
  406.       hard8087
  407.  
  408. ; The following routine is used to initialize any required
  409. ; data areas, and alter any peripheral chip programming when
  410. ; starting up CPCDOS.  This code is called once from the
  411. ; SUP(ERVISOR) after the SUP has called the RTM, CIO, MEM and
  412. ; BDOS initialization routines, and before SUP has created
  413. ; the RSP processes.
  414.  
  415. ; We are again hoping that the DL register is preserved through
  416. ; the init process, because we are setting sysdisk to A: when
  417. ; we boot from floppy to ease the installation procedures.
  418.  
  419. ; Read real time clock and set sysdat TOD
  420. set_time@:
  421. ;---------
  422.     or    cx,0ffffh        ; Invalidate Hours and Minutes
  423.     mov    ah,02h            ; and RESET the carry flag
  424.     int    TOD_INT            ; get Time of day from ROS    
  425.      jc    bad_time        ; Bad function or clock inoperative
  426.     cmp    ch,24h            ; Check for a Valid BCD Hour
  427.      jae    bad_time
  428.     cmp    cl,60h            ; Check for a Valid BCD Minute
  429.      jae    bad_time
  430.     mov    tod_sec$,dh        ; Real Time Clock Function
  431.     mov    tod_min$,cl
  432.     mov    tod_hour$,ch
  433.  
  434.     mov    ah,04
  435.     int    TOD_INT            ; get date from ROS
  436.     push    cx            ; save CL
  437.     mov    al,dl            ; day in bcd
  438.     call    conv_bcd
  439.     mov    tod_day$,ax        ; initial set
  440.     mov    al,dh            ; month in bcd
  441.     call    conv_bcd
  442.     mov    ch,0            ; assume march-dec
  443.     cmp    al,3            ; and if true
  444.      jae    check_286_leap        ;   skip
  445.  
  446.     mov    ch,1            ; jan-feb leap correct
  447. check_286_leap:
  448.     dec ax ! shl ax,1        ; zero base and word index
  449.     xchg    ax,bx
  450.     mov    ax,month_length[bx]    ; days in prior months
  451.     add    tod_day$,ax        ; add days up to now
  452.  
  453.     pop    ax            ; saved year into al
  454.     call    conv_bcd
  455.     sub    al,78            ; cpm base year
  456.     push    ax
  457.     mov    dx,365
  458.     mul    dx            ; convert to days
  459.     add    tod_day$,ax        ; here's the biggie
  460.     pop    ax
  461.     add    al,2            ; 78 -> 80
  462.     sub    al,ch            ; dec if jan or feb
  463.     shr ax,1 ! shr ax,1        ; every 4 years
  464.     add    tod_day$,ax        ;   gives us a day
  465. bad_time:
  466.     ret
  467.  
  468.  
  469. conv_bcd:
  470. ; convert bcd in AL to binary in AX:
  471.  
  472.     mov    ah,al
  473.     mov    cl,4
  474.     shr    ah,cl            ; ms nib to ah
  475.     and    al,0Fh            ; ls nib in al
  476.     aad                ; ax = 10*ah + al
  477.     ret
  478.  
  479.  
  480.  
  481. io_mem_alloc@:                    ; entry point from HEADER.A86
  482. ;-------------                    ; used during initialisation
  483. ; Entry: DX = <> 0 - paragraphs required
  484. ;        = 0 no further mem_alloc calls
  485. ;     CX = 0 no alignment
  486. ;          <> alignment mask
  487. ; Exit:  AX = segment base freed for caller
  488.  
  489.     test    dx,dx            ; test for final allocation
  490.      jnz    do_mem_alloc        ; skip if normal allocation
  491. mem_cleanup1:
  492.     mov    bx,xios_mfl        ; get first entry in XIOS_MFL or 0000h
  493.     test    bx,bx            ; test if XIOS_MFL empty
  494.      jz    mem_cleanup5        ; done if empty
  495.     mov    ax,MD_LINK[bx]        ; else get remainder of list
  496.     mov    xios_mfl,ax        ; remove this item from the list
  497.     mov    dx,MD_START[bx]        ; get base of this block
  498.     mov    cx,MD_LENGTH[bx]    ; get size of this block
  499.     mov    ax,mdul
  500.     mov    MD_LINK[bx],ax        ; release this item into MDUL
  501.     mov    mdul,bx
  502. mem_cleanup2:                ; DX = base, CX = size
  503.     cmp    cx,MIN_PART_LEN        ; remaining size too small to bother
  504.      jb    mem_cleanup1        ; drop it, try next block
  505.     mov    bx,mdul            ; else get an unused MD from MDUL
  506.     mov    ax,MD_LINK[bx]
  507.     mov    mdul,ax
  508.  
  509.     mov    di,offset mfl        ; find end of MFL
  510. mem_cleanup3:
  511.     mov    si,di            ; save previous item
  512.     mov    di,MD_LINK[si]        ; get next item
  513.     test    di,di            ; end of MFL found yet?
  514.      jnz    mem_cleanup3        ; no, try next one
  515.     mov    MD_LINK[si],bx        ; link new MD to current end of MFL
  516.  
  517.     mov    si,cx            ; assume we use up whole block
  518.     cmp    si,400h            ; compare with normal size
  519.      jbe    mem_cleanup4        ; if less than normal, use it
  520.     mov    si,400h            ; else chop it up into 16K blocks
  521. mem_cleanup4:
  522.     sub    ax,ax
  523.     mov    MD_LINK[bx],ax        ; make us the last entry
  524.     mov    MD_START[bx],dx        ; set base address of block
  525.     mov    MD_LENGTH[bx],si    ; set size of this block
  526.     mov    6[bx],ax        ; reserved = 0000h
  527.     mov    8[bx],ax        ; reserved = 0000h
  528.     add    dx,si            ; increment the base address
  529.     sub    cx,si            ; decrement the block sizethe 
  530.     jmps    mem_cleanup2        ; check if more space in block
  531.  
  532. mem_cleanup5:                ; all blocks moved to MFL
  533.     mov    bx,mfl$
  534.     or    bx,bx
  535.     jz    mem_clean_exit
  536.     cmp    MD_LENGTH[bx],MIN_PART_LEN
  537.     jae    mem_clean_exit
  538.     mov    bx,MD_LINK[bx]        ; if first entry too small
  539.     mov    mfl$,bx            ; remove from mfl
  540. mem_clean_exit:
  541.     sub    ax,ax            ; return O.K. code
  542.     ret
  543.  
  544.     
  545. do_mem_alloc:                ; real memory allocation
  546.  
  547. if V386                    ; aligned allocations on 386 only
  548.     jcxz    mem_alloc_i@        ; skip if unaliged
  549.     mov    si,offset xios_mfl
  550. align_hi:
  551.     mov    si,MD_LINK[si]        ; get next entry
  552.     test    si,si
  553.      jz    no_hi_mem        ; align high MFL
  554.     cmp    dx,MD_LENGTH[si]    ; will this block fit?
  555.      ja    align_hi        ; no, check next one
  556.     mov    ax,MD_START[si]        ; check aligned
  557.     add    ax,MD_LENGTH[si]
  558.     test    ax,cx
  559.     jnz    align_hi
  560.     sub    MD_LENGTH[si],dx    ; else allocate it from top end
  561.     mov    ax,MD_START[si]        ;   to leave end page aligned
  562.     add    ax,MD_LENGTH[si]    ; AX = base of allocated block
  563.     ret
  564.     
  565. no_hi_mem:                ; if no high memory partition
  566.     mov    si,mfl$            ;  then check low mem alignment
  567.     or    si,si
  568.     jz    mem_alloc_i@        ; only banked memory left
  569.     mov    ax,MD_LENGTH[si]
  570.     and    ax,cx
  571.     add    MD_START[si],ax
  572.     sub    MD_LENGTH[si],ax
  573.      jnz    mem_alloc_i@
  574.     mov    ax,MD_LINK[si]        ; not enough aligned memory in 
  575.     mov    mfl$,ax            ; partition, so waste it
  576.     jmps    mem_alloc1
  577. endif
  578.  
  579. mem_alloc_i@:
  580. ;------------
  581. ; Internal entry point to do memory trimming 
  582. ; first from high memory free list (if available)
  583. ; and then from bottom of TPA first from MFL and then
  584. ; MWD list.
  585. ; hi_mfl contains entries of discontiguous memory
  586. ; of varying length which can be used for segment
  587. ; based buffer allocations.
  588. ; Entry: DX = paragraphs wanted from base of TPA list
  589. ; Exit:  AX = segment base freed for caller
  590. ;     DX = preserved
  591. ;     BX = preserved
  592. ;      AX = 0ffffh no memory available
  593. ; No error checking.
  594.     push    bx
  595.     mov    bx,offset xios_mfl
  596. mem_alloc1a:
  597.     mov    di,bx                ; DI = previous
  598.     mov    bx,MD_LINK[bx]
  599.     test    bx,bx                ; end of list ?
  600.      jz    end_hi_mfl
  601.     cmp    dx,MD_LENGTH[bx]        ; is entry big enough
  602.      ja    mem_alloc1a            ; no try next    
  603.     mov    ax,MD_START[bx]            ; start segment to AX
  604.     sub    MD_LENGTH[bx],dx        ; reduce partition size
  605.      jz    mem_alloc1b            ; completely used
  606.     add    MD_START[bx],dx            ; else increase start seg
  607.     jmps    mem_ret
  608. mem_alloc1b:
  609.     mov    si,MD_LINK[bx]            ; remove entry when all used
  610.     mov    MD_LINK[di],si            ; link next into previous
  611. mem_ret:
  612.     pop    bx                ; restore bx
  613.     ret                    ; and return
  614.     
  615. end_hi_mfl:
  616.     pop    bx
  617. mem_alloc1:
  618.     push    bx
  619.     push    dx                ; save 
  620.     mov    bx,mfl$
  621.     or    bx,bx
  622.      jz    get_mwd
  623.     mov    si,MD_START[bx]            ; save it for below
  624.     mov    bp,si                ; save for exit
  625.     call    common_trim            ; returns ax=0000 MFL exhausted
  626.     or    ax,ax
  627.      jnz    trim_exit
  628.     jmps    do_mwd
  629. get_mwd:
  630.     mov    bx,mwdr$
  631.     mov    si,MD_START[bx]            ; start seg off MWD list
  632.     mov    bp,si                ; start seg for exit
  633. do_mwd:
  634.     mov    bx,mwdr$
  635.     mov    si,MD_START[bx]            ; start seg for trim
  636.     call    trim_mwd
  637.     or    ax,ax
  638.     jnz    err_exit
  639. trim_exit:
  640.     mov    ax,bp                ; return seg. addr.
  641. err_exit:
  642.     pop    dx                ; restore input params
  643.     pop    bx
  644.  
  645.     ret
  646.  
  647.  
  648. common_trim:
  649. ;-----------
  650. ; Entry:  DX = paragraphs wanted
  651. ;      SI = start buffer paragraph.
  652. ;      BX = root MD.
  653. ; Exit:  MD and mfl$ updated
  654. ; No error checking.
  655.  
  656. ; Init for trim algorithm:
  657.     mov    bx,offset mfl$            ; init for algorithm below
  658. ;    sub    bx,MD_LINK            ; (MD_LINK equ 0)
  659.     sub    ax,ax                ; init cumulative length
  660.  
  661. chop_loop:
  662.     mov    bx,MD_LINK[bx]
  663.     or    bx,bx
  664.     jz    exit_mfl_loop            ; mfl exhausted
  665.     add    ax,MD_LENGTH[bx]
  666.     cmp    ax,dx
  667.      jb    chop_loop
  668.  
  669.     sub    ax,dx                ; sub. requested from cum.
  670.     mov    MD_LENGTH[bx],ax        ;  and adjust MD
  671.     add    dx,si                ; add start to total length
  672.     mov    MD_START[bx],dx            ; gives new start
  673.     mov    mfl$,bx
  674.  
  675. ; One final check:
  676.     test    ax,ax
  677.     jnz    length_ok
  678.     mov    bx,MD_LINK[bx]            ; then skip to next MD
  679.     mov    mfl$,bx                ; and bump root
  680. length_ok:
  681.  
  682.     mov    al,0ffh
  683.     ret
  684.  
  685. exit_mfl_loop:
  686.     mov    mfl$,0000            ; remove completely
  687.     sub    dx,ax                ; DX = remaining paragraphs
  688.     sub    ax,ax                ; return state
  689.     ret
  690.  
  691.  
  692. trim_mwd:
  693. ;--------
  694. ; Entry:  DX = paragraphs wanted
  695. ;      SI = start buffer paragraph.
  696. ;      BX = root MD.
  697. ; Exit:  MD , mwd$ and mfl$ updated
  698. ;      AX = 0ffffh if no memory left
  699.  
  700.     mov    bx,offset mwdr$            ; init for algorithm below
  701.     sub    ax,ax                ; init cumulative length
  702.  
  703. mwd_loop:
  704.     mov    bx,MD_LINK[bx]
  705.     or    bx,bx                ; we should never 
  706.     jz    mwd_error            ; get zero
  707.     add    ax,MD_LENGTH[bx]
  708.     cmp    ax,dx
  709.     jb    mwd_loop
  710.  
  711.     sub    ax,dx                ; sub. requested from cum.
  712.     mov    MD_LENGTH[bx],ax        ;  and adjust MD
  713.     add    dx,si                ; add start to total length
  714.     mov    MD_START[bx],dx            ; gives new start
  715.     mov    mwdr$,bx            ;  place in root pointer
  716.     cmp    ax,400h                ; 16k block ?
  717.     je    mwd_done            ; yes .. leave all on MWD list
  718.     cmp    ax,MIN_PART_LEN            ;  else check if big enough
  719.     ja    put_mfl                ;  for entry on MFL
  720.     mov    bx,MD_LINK[bx]            ; if not then add to next entry
  721.     add    MD_LENGTH[bx],ax
  722.     mov    MD_START[bx],dx
  723. put_mfl:
  724.     mov    mfl$,bx                ; new mfl start
  725.     xor    di,di                ; with one entry only
  726.     xchg    di,MD_LINK[bx]            ; so terminate link get next
  727.     mov    mwdr$,di            ;  as start of MWD
  728. mwd_done:
  729.     xor    ax,ax
  730.     ret
  731. mwd_error:
  732.     mov    ax,0ffffh
  733.     ret
  734.  
  735.  
  736. eject
  737.  
  738. INITCODE_START    equ    $        ; start of reusable code space
  739.  
  740. init@:
  741. ;-----
  742.  
  743. if V386
  744. ;    We need to check for an 386 CPU as our XIOS assumes
  745. ;    that processor even before MEM has a chance to check
  746. ;    for its presence...
  747.  
  748.     push    sp
  749.     pop    ax            ; AX != SP if 8086/88/186/V20/30/...
  750.     cmp    ax,sp            ; AX == SP if 80286 or 80386
  751.      jne    need_386        ; skip if not even 286
  752.     pushf                ; save current CPU state
  753.     pop    ax            ; AX = default flags
  754.     or    ah,30h            ; try to set IOPL == 3
  755.     push    ax            ; push image back on stack
  756.     popf                ; try to change IOPL in flags
  757.     pushf                ; push current flags
  758.     pop    ax            ; AX == 3xxx if 386 or 0xxx if 286
  759.     and    ah,30h            ; isolate IOPL bits in flags
  760.     cmp    ah,30h            ; could be set IOPL = 3?
  761.      je    got_386            ; yes, must have 386 (or 486?)
  762. need_386:
  763.     mov    si,offset need_386_msg    ; else print error message
  764. need_386_loop:
  765.     lods    cs:al            ; get next character
  766.     test    al,al
  767.      jz    need_386_done        ; skip if message done
  768.     mov    bl,07h            ; normal attribute
  769.     mov    ah,14            ; write TTY
  770.     int    VIDEO_INT        ; call ROS
  771.     jmps    need_386_loop        ; get next character
  772. need_386_done:
  773.     sti                ; turn on ints for keyboard
  774.     jmps    need_386_done        ; hang for Ctl/Alt/Del
  775.  
  776. need_386_msg    db 13,10,'Requires Intel 80386 to run.'
  777.         db 13,10,'   Press Ctrl/Alt/Del. ', 0
  778.  
  779. got_386:                ; O.K. if we've got one
  780. endif
  781.     cli
  782.     push    es
  783.     call    set_sys_vars        ; set up system variables
  784.     call    do_ros_ints        ; store some vectors
  785.     call    set_ros_data        ; set some ros data variables
  786.     call    check_286        ; see if we're AT or clone
  787.     call    equip_check        ; see what we've got
  788. if XM
  789.     call    reloc_disk_params    ; reloc fixed disk table if not ROM
  790.     call    reloc_ext_BIOS        ; relocate PS/2 extended BIOS data
  791.     test    su_flag_bits$, EEMS_ENABLE_BIT
  792.      jz    no_mpcheck
  793.     call    mp_check@        ; check for EEMS boards
  794. no_mpcheck:
  795. endif
  796.     call    check_hi_mem        ; from C000 up
  797.     call    ndp_init        ; check for an 8087
  798.     call    compaq            ; do before any video setup
  799. if V386
  800.     call    sprite386        ; check for Jarogate machine
  801. endif
  802. if XM                    ; non-386 only...
  803.     call    amstrad            ; check for Amstrad 1512
  804.     call    check_8530        ; check for The Orphan (Model 30)
  805.     call    olivetti        ; check for Olivetti M24
  806. endif
  807.     call    fix_crt            ; mono/color vs_ variables
  808.     call    get_dph_seg        ; get temp SEG address for DPH's
  809.     call    fix_disk_tables        ; match disk tables to equip
  810.     call    do_int_1e        ; dos support
  811.     call    printer_init        ; reset the parallel printers
  812.     call    do_setup        ; customize XIOS
  813.     call    flop_off        ; turn off the floppy motors
  814.     call    find_dskbuf        ; find SYSDAT buffer for HD_INIT
  815.     call    hd_init            ; get hard disk partitions
  816.     call    alloc_dskbuf        ; find SYSDAT buffer for deblocking
  817.     call    trim_memory        ; fix up the partition list
  818.  
  819.     call    alloc_setup_buff    ; get user-requested buffer for FIDDS
  820.  
  821.  
  822. ;********** last SYSDAT allocation **********
  823.  
  824. if V386                ; switch into protected mode and continue
  825.                 ; XIOS init on return through io_protect
  826.     call    init_386@        ; prepare for switch into virtual mode
  827.     pop    es            ; restore Init UDA
  828.     sti
  829.     retf                ; Part 1 initialization done
  830.  
  831.  
  832. io_protect@:            ; Re-enter in protected mode
  833. ;----------            ; for all segment based allocations
  834.     pop    ax            ; clean return offset
  835.     push    es            ; for common exit from INIT
  836. ;                    ;  continue with initialisation
  837.  
  838.     call    align_dskbuf        ; align deblocking buffer
  839.                     ; (in case we've relocated SYSDAT)
  840.     call    alloc_tmp@        ; find TMP window
  841.     cmp    ega_remap,FALSE
  842.      je    not_remap
  843.     call    compaq_protect        ; map 32 bit EGA copy over 8 bit
  844. not_remap:
  845. endif
  846.  
  847. if XM                    ; create MWDR if resident EEMS
  848.     call    mp_config@        ; done before all segment based
  849.                     ;    allocations
  850.  
  851. else                    ; if MMU, we've done this earlier on
  852.     call    reloc_disk_params    ; reloc fixed disk table if not ROM
  853.     call    reloc_ext_BIOS        ; relocate PS/2 extended BIOS data
  854. endif
  855.     call    fix_ega_pal        ; setup local save area for palettes
  856.     call    do_aux_ports        ; serial port int init
  857. if SR
  858.     call    sr_init@        ; initialise SUN RIVER cygna card
  859. endif
  860.     call    alloc_tmp_buffs        ; allocate space for history buffers
  861.     call    alloc_non_sysdat    ; get hash tables, etc.
  862.     call    floppy_hash        ; get floppy hash tables/FAT buffers
  863.     call    alloc_fat_buffs        ; allocate FAT buffers
  864.     call    alloc_ser_rsps        ; make serial PCTmps and PINs
  865.     call    alloc_virt_screens    ; do it ourselves (no GENCCPM)
  866. if SR
  867.     call    sr_fix_crt@        ; fix up VS_ variables
  868. endif
  869.     call    do_interrupts        ; do all of the int stuff
  870.     call    NX_init@        ; Initialise international keyboard
  871.     call    do_video        ; initial mode setup
  872.     call    sign_on            ; print signon message
  873.     call    default_prnt        ; poke default printers
  874.     call    enable_ints        ; interrupts back on
  875.     call    herc_check        ; check for hercules
  876.  
  877. init_ret:
  878. ; move built DPH's into SYSDAT Segment
  879. ; must be last function before returning from INIT
  880. ; as the INIT code area is overwritten..
  881.  
  882.     push ds ! push es
  883.     push ds ! pop es        ; move to SYSDAT
  884.     mov    cx,dph_count        ; total number of bytes allocated to DPH's
  885.      jcxz    no_hd_dos_dph        ; no hard disk DOS partitions ......
  886.     mov    di,pc_hd_dph_start    ; pointer to first hard disk DPH entry
  887.     mov    si,dph_tbl$[di]        ; get offset of drive DPH
  888.     mov    di,si            ; same offset in both segments
  889.     mov    ax,dph_seg        ; temp seg. address
  890.     mov    ds,ax
  891.     cld
  892.     rep    movsb
  893. no_hd_dos_dph:
  894.     pop es ! pop ds    
  895.  
  896. ;; clear out DDSC for all drives
  897.     push    es
  898.     mov    cx,16            ; all drives
  899.     mov    bx,offset dph_tbl$    ; DPH table
  900. zero_loop:
  901.     push    cx
  902.     mov    si,[bx]            ; point to the dph
  903.     test    si,si            ; DPH ??
  904.     jz    next_dph
  905.     mov    es,DPH_HSTBL[si]    ; hash table seg
  906.     sub    di,di
  907.     mov    cx,32/2            ; clear two paras
  908.     xor    ax,ax
  909.     rep    stosw
  910. next_dph:
  911.     pop    cx
  912.     inc bx ! inc bx            ; point to next dph
  913.     loop    zero_loop        ; and do another
  914.     pop    es
  915.  
  916.  
  917. ;    Build memory descriptor for XIOS init code and
  918. ;    link it into high memory list so it can be reused
  919. ;    for Q buffers, disk buffers and hash tables.
  920. ;    Note that this assumes the code segment is not
  921. ;    write protected, which may change in future versions.
  922.     
  923.     mov    si,offset INITCODE_START
  924.     mov    di,offset INITCODE_END    ; DI = address of 1st resident byte
  925.     call    init_reuse@
  926.     pop    es            ; restore Init UDA
  927.     sti
  928.     retf                ; initialization done
  929.  
  930.  
  931. init_reuse@:
  932. ;-----------
  933. ;    entry:    SI -> first reusable byte code segment
  934. ;        DI -> first resident byte in code segment
  935.  
  936.     mov    bx,mdul            ; steal MD from MD unused list
  937.     mov    ax,MD_LINK[bx]        ; (no CLI/STI as we're the only
  938.     mov    mdul,ax            ;  process running here)
  939.  
  940.     mov    dx,cs            ; DX = paragraph address of XIOS code
  941.     mov    cl,4
  942.     add    si,15
  943.     shr    si,cl            ; SI = paragraph offset
  944.     add    si,dx            ; SI = address of reuseable space
  945.     mov    MD_START[bx],si
  946.     shr    di,cl
  947.     add    di,dx            ; DI = address of resident code
  948.     sub    di,si            ; DI = # of reusable paragraphs
  949.     mov    MD_LENGTH[bx],di
  950.  
  951.     mov    ax,xios_mfl        ; link us into high memory free list
  952.     mov    MD_LINK[bx],ax        ;   for use by future IO_MEMALLOCs
  953.     mov    xios_mfl,bx
  954.  
  955.     ret
  956.  
  957.  
  958. dph_count    dw    0        ; leave here before INIT_START
  959. dph_seg        rw    1
  960.  
  961.  
  962. get_dph_seg:
  963. ;-----------
  964.     mov    ax,memory_top
  965.     mov    dx,(8*(PC_HD_DPH_SIZE+PC_HD_DPB_SIZE)/16) + 1
  966.                     ; reserved space for max 8 drives
  967.                     ; in paras.
  968.     sub    ax,dx
  969.     mov    dx,XIOS_END
  970.     mov    cl,3
  971.     shr    dx,cl            ; div by 16
  972.     inc    dx            ; round up
  973.     sub    ax,dx
  974.     mov    dph_seg,ax        ; temp SAFE seg address for building
  975.     ret                ; DOS hard disk DPH's
  976.  
  977. eject
  978.  
  979. ;    Allocate a couple of F_DOS deblocking buffers
  980.  
  981. ;    Currently, we use about 8 Kb for buffers,
  982. ;    which gives a variable # of buffers depending
  983. ;    on the maximum sector size to support.
  984.  
  985. alloc_fat_buffs:
  986.     mov    ax,16 shl 2        ; give us 16*512 bytes of buffers
  987.     mov    cl,maxpsh        ; (2 = 512, 3 = 1024, 4 = 2048, ...)
  988.     shr    ax,cl            ; AX = 16, 8, 4, etc.
  989.     cmp    ax,5            ; check if minimum for performance
  990.      jae    alloc_fat1        ; O.K. if at least 5 buffers
  991.     mov    ax,5            ; else get us at least minimum #
  992. alloc_fat1:
  993.     cmp    ax,nbuffers$        ; less than what's configured already?
  994.      jb    alloc_fat2        ; no, s.o. wants more than default
  995.     mov    nbuffers$,ax        ; set SYSDAT variable
  996. alloc_fat2:
  997.     mov    ax,128            ; bytes in basic sector size
  998.     mov    cl,maxpsh        ; adjust for physical sector size
  999.     shl    ax,cl            ; AX = sector size in bytes
  1000.     cmp    ax,sec_size$        ; less than what's configured already?
  1001.      jb    alloc_fat3        ; no, s.o. wants more than defult
  1002.     mov    sec_size$,ax        ; set sector size for buffer alloc
  1003. alloc_fat3:
  1004.     ret
  1005.  
  1006.  
  1007. do_int_1e:
  1008. ;---------
  1009. ; Copy and point int 1Eh:
  1010.  
  1011. ; The 11 disk-parm. bytes pointed to by int 1E are copied to our
  1012. ; local XIOS string.  The initialized values in the XIOS correspond to
  1013. ; DOS 2.1 parms.
  1014.  
  1015.     push    ds
  1016.     xor    ax,ax            ; point to vectors
  1017.     mov    ds,ax                ; source
  1018.     lds    si,dword ptr .INT_1E_VEC_OFF    ; possibly ROM
  1019.     pop es ! push es            ; destination
  1020.     mov    di,offset int_1e_parms$        ; in XIOS RAM
  1021.     mov    cx,11
  1022.     cld
  1023.     rep    movsb                ; to our local area
  1024.  
  1025.     mov    es:byte ptr MIN_7[di],18    ; force EOT to 18
  1026.  
  1027.     mov    ds,ax                ; = 0
  1028.     mov    word ptr .INT_1E_VEC_SEG,es    ; new vector
  1029.     mov    word ptr .INT_1E_VEC_OFF,offset int_1e_parms$
  1030.     pop    ds
  1031.     ret
  1032.  
  1033.  
  1034. set_sys_vars:
  1035. ;------------
  1036. ; Set up initial system variables:
  1037.  
  1038.     mov    boot_drive,dl            ; back to this old trick
  1039.     cld                    ; Sup saves DS,ES on INIT call 
  1040.     in     al,PIC_MASK            ; get the current interrupt mask
  1041.     mov    pic_mask_image$,al        ; and save it for restoration
  1042.     mov    al,0FFh
  1043.     out    PIC_MASK,al            ; mask off all interrupts
  1044.  
  1045. ;    mov    sysdat$,ds            ; save System Data Segment 
  1046. ;    mov    bx,offset supmod$        ; save Sup entry double word
  1047. ;    mov    ax,[bx]                ; get offset from Sys Data Seg
  1048. ;    mov    supervisor_o$,ax        ; save it
  1049. ;    mov    ax,2[bx]            ; get the segment
  1050. ;    mov    supervisor_s$,ax        ; save it
  1051.  
  1052.     mov    si,offset dispatcher$        ; get dispatcher double word
  1053.     lodsw
  1054.     mov    disp_offset$,ax            ; get offset
  1055.     lodsw
  1056.     mov    disp_segment$,ax        ; get segment
  1057.  
  1058.     mov    owner_8087$,0FFFFh        ; 8087's owner's pd
  1059.     ret
  1060. eject
  1061. check_286:
  1062. ;---------
  1063. ; Check to see if we're running on the PC-AT or compatible:
  1064.  
  1065.     mov    ax,0FFFFh        ; top of rom
  1066.     mov    es,ax
  1067.     mov    al,es:.0Eh        ; get IBM model byte
  1068.     cmp    al,0FCh            ; AT clone (incl. XT 286 + PS/2 50/60)
  1069.      je    yes_at            ; yes, read CMOS RAM
  1070.     cmp    al,0F8h            ; also check for PS/2 Model 70/80
  1071.      jne    check_286_done        ; no, return
  1072. yes_at:                    ; AT or clone, XT286, PS/2 50/60/70/80
  1073.     mov    ah,0C0h            ; get machine architecture info
  1074.     int    15H            ;   via the ROM BIOS
  1075.      jc    not_ps2            ; skip if old ROM BIOS version
  1076.     cmp    es:word ptr 2[bx],09FCh    ; is it PS/2 model 30 - 286
  1077.     jne    test_ps2
  1078.     mov    disk_chng_mask$,80h    ; set disk change polarity mask
  1079. test_ps2:
  1080.     test    es:byte ptr 5[bx],2    ; test if MCA implemented
  1081.      jz    not_ps2            ; skip if not
  1082.     or    pc_at$,02h        ; indicate it is a PS/2
  1083.     mov    hi_off$,000ffh         ; nothing above E000 on PS/2 range
  1084. ;    mov    hi_on$, 00000h        ; no "guaranteed good" areas
  1085.  
  1086. not_ps2:
  1087.     or    pc_at$,01h        ; we are with a member of AT family...
  1088.  
  1089.     mov    al,not 04h
  1090.     out    PIC_MASK,al        ; enable slave PIC for HP VECTRA
  1091.  
  1092. ; Now check to see if we are running on an at with the buggy hard disk
  1093. ; code which has prevented us from doing multi-sector i/o on an AT:
  1094. if XM
  1095.     push    es
  1096.     mov    ax,AT_HDROS_SEG
  1097.     mov    es,ax
  1098.     mov    di,AT_HDROS_OFF
  1099.     mov    si,offset buggy_string
  1100.     mov    cx,length buggy_string
  1101.  
  1102.     repe    cmpsb            ; z flag will be reset if no match
  1103.     pop    es
  1104.      jnz    no_match
  1105. endif
  1106.  
  1107. ; Since we matched the bytes, indicate by setting the bit:
  1108. match:
  1109.     or    pc_at$,80h
  1110. no_match:
  1111. ;
  1112. ; Set up the vector for the segment overrun interrupt on a 286,
  1113. ;  and the Invalid Opcode int:
  1114. ; (Ints are CLIed at the top of INIT)
  1115. T1 equ 13*4 ! T2 equ T1 + 2        ; int. # 13(d)
  1116. O1 equ  6*4 ! O2 equ O1 + 2        ; int. #  6(d)
  1117.     sub    ax,ax            ; point at vectors
  1118.     push    ds
  1119.     mov    ds,ax
  1120.     mov    .T1,offset i_seg_ovr@
  1121.     mov    .T2,cs
  1122.     mov    .O1,offset i_bad_opcode@
  1123.     mov    .O2,cs
  1124.     pop    ds
  1125.  
  1126. ;Change the port to detect parity errors:
  1127.     mov    parity_chk$,PORT_B        ; 61h on ATs, 62h on pcs.
  1128. check_286_done:
  1129.     ret
  1130.  
  1131.  
  1132. ; Read PC AT cmos ram port in al:
  1133.  
  1134. read_286_cmos:
  1135.     out    CMOS_ADDR,al        ; set address
  1136.     jmps    $ + 2            ; pause
  1137.     in    al,CMOS_DATA        ; read the rom
  1138.     ret
  1139.  
  1140.  
  1141. eject
  1142. ; set ROS data variables
  1143. ; some clones don't do this
  1144. ; and save Keyboard data area locally
  1145. ; for CDOS 386
  1146. set_ros_data:
  1147.     push    ds
  1148.     push ds ! pop es
  1149.     mov    ax,PC_SEGMENT        
  1150.     mov    ds,ax            ; point to the nether region
  1151.     mov    buffer_start_40,1eh    ; setup these pointers for the
  1152.     mov    buffer_end_40,3eh    ; sake of the old COMPAQ ROS
  1153.     mov    ax,equip_flag_40
  1154.     mov    es:save_equip$,ax    ; save equipment flag for PC terminals
  1155.     pop    ds
  1156. if V386
  1157.     push     ds            
  1158.     mov    ax,PC_SEGMENT        ;* in buffer 
  1159.     mov    ds,ax            ;* point to the nether region
  1160.     mov    si,offset kb_flag_40     ; save ROS params for PC terminals
  1161.     mov    di,offset pc_kbd_save$
  1162.     mov    cx,39
  1163.     rep    movsb
  1164.     mov    si,offset kb_flag_40     ; save ROS params for main terminal
  1165.     mov    di,offset save_kbdata$
  1166.     mov    cx,39
  1167.     rep    movsb
  1168.     pop    ds
  1169. endif
  1170.     ret
  1171.  
  1172.  
  1173. equip_check:
  1174. ;-----------
  1175. ; Check IBM equipment word, set number variables:
  1176.  
  1177.     int    EQUIP_INT        ; return equip word
  1178.     mov    dx,ax
  1179.  
  1180.     mov    cl,4
  1181.     shr    dx,cl            ; shift down init_video
  1182.     mov    al,dl
  1183.     and    al,03h
  1184.     mov    init_video_mode,al    ; save for crt setup
  1185.  
  1186.     mov    cl,2
  1187.     shr    dx,cl            ; shift down floppy bits
  1188.     mov    ax,dx
  1189.     and     ax,03h            ; mask for floppy
  1190.     inc    ax            ; correct 0 based code
  1191.     mov    num_flop$,ax
  1192.  
  1193.     cmp    al,1            ; if there is only one floppy
  1194.      jnz    equip_check_des        ;   then use 2 designators
  1195.  
  1196.     mov    al,2            ; this fakes a B: drive
  1197.  
  1198. equip_check_des:            ;   in single drive systems
  1199.     mov    num_flop_des$,ax
  1200.  
  1201.     mov    cl,3
  1202.     shr    dx,cl            ; shift down port bits
  1203.     mov    ax,dx
  1204.     and    ax,07h            ; mask for serial ports
  1205.     mov    num_port$,ax
  1206.  
  1207.     mov    cl,5
  1208.     shr    dx,cl            ; shift down printer bits
  1209.     mov    ax,dx
  1210.     and    ax,03h            ; mask for printer
  1211.     mov    num_print$,ax
  1212.  
  1213.     mov    ah,8            ; XT param check
  1214.     mov    dl,80h            ; first hard disk code
  1215.     int    DISK_INT
  1216.      jnc    equip_ch1        ; skip if dl good
  1217.     mov    dl,0            ; else no hard disks
  1218. equip_ch1:
  1219.     mov    dh,0
  1220.     mov    num_hard$,dx
  1221.  
  1222.     sub    dx,dx            ; start off with first floppy
  1223. equip_loop:
  1224.     mov    si,dx            ; SI = DX = drive type
  1225.     push    dx            ; save drive number
  1226.     mov    ah,8            ; get drive parameters (supported if
  1227.     int    DISK_INT        ;   ROS handles 3.5" Sony drives)
  1228.     pop    dx            ; restore drive number
  1229.      jc    equip_ft_change        ; ROS doesn't support 3.5", check hyper
  1230.     cmp    ch,TOP_CYLIN_48        ; is this a 48 TPI 5.25" drive?
  1231.      je    equip_ft_next        ; yes, this is the default
  1232.     cmp    cl,EOT_HYPER_96        ; check for 5.25" hyper drives (1.2 Mb)
  1233.      je    equip_ft_hyper        ; yes, this is a hyper drive
  1234.     mov    drive_type$[si],SONY_DRIVE
  1235.     jmps    equip_ft_next        ; must be 720K or 1.44Mb 3.5" drive
  1236.  
  1237. equip_ft_change:            ; ROS version doesn't support 3.5"
  1238.     mov    ah,15H            ; maybe hyper, read DASD type
  1239.     int    DISK_INT        ; call floppy ROM BIOS
  1240.      jc    equip_ft_next        ; must be 360 K if hyper not supported
  1241.     cmp    ah,2            ; disk change line available?
  1242.      jne    equip_ft_next        ; must be 360 K if no change line
  1243.  
  1244. equip_ft_hyper:                ; this drive is a hyper drive (1.2 Mb)
  1245.     mov    drive_type$[si],HYPER_DRIVE
  1246.     mov    data_rate$[si],RATE_HYPER_48
  1247.  
  1248. equip_ft_next:
  1249.     inc    dx            ; next physical drive
  1250.     cmp    dx,num_flop$        ; all floppy drives checked?
  1251.      jb    equip_loop        ; repeat until all floppies done
  1252.  
  1253.     call    set_time@        ; get the time and date
  1254.  
  1255. ; Check RAM size.  Int 12h (MEM_INT) is reliable except for old 64k PCs.
  1256. ; The ROS in those machines had a wrap problem, where if you set the DIPS
  1257. ; to say 576, 608, or 640k, int 12 returned that minus 512k.  The ROS would
  1258. ; never initialize that 96k above 544, and parity errors could result, since
  1259. ; the memory needs to be written with something prior to reading.
  1260.  
  1261.     int    MEM_INT            ; check total memory size
  1262.  
  1263. if XM                    ; skip this for 386's
  1264.     push    ds            ; check machine type
  1265.     mov    cx,0FFFFh
  1266.     mov    ds,cx
  1267.     cmp    byte ptr .0Eh,PC_TYPE
  1268.     pop    ds
  1269.      jne    not_pc
  1270.  
  1271. ; If ax = 544k, or ax = 64, 96, or 128 k, play the special memory tricks:
  1272.     cmp    ax,128
  1273.      jbe    patch_mem
  1274.     cmp    ax,544
  1275.      jb    not_problem
  1276.  
  1277. ; Look for memory from 544 to 640 and initialize it if found
  1278. patch_mem:
  1279.     push    es            ; use to reach more than 64k
  1280.     mov    ax,544 shl 6        ; starting segment = 544k
  1281.     mov    es,ax
  1282.     mov    bx,640 - 544        ; number of Kbytes to check
  1283.     mov    dx,0DBDBh        ; ancient druidic tradition
  1284.     sub    ax,ax            ; fill word
  1285.  
  1286. hi_tpa_lp:
  1287.     sub    di,di            ; start of 1K block
  1288.     mov    es:[di],dx        ; set the test pattern
  1289.     push    ax            ; wipe out bus float
  1290.     pop    ax
  1291.     cmp    es:[di],dx        ; see if memory is real
  1292.     jnz    ram_done        ;   and skip if it isn't
  1293.  
  1294.     mov    cx,512            ; words per Kbyte
  1295.     rep    stosw            ; zero a 1K block
  1296.     mov    cx,es            ; now, bump the es register
  1297.     add    cx,1024 shr 4        ;   to let us get to more
  1298.     mov    es,cx            ;   than 64k of memory
  1299.     dec    bx            ; Kbyte count
  1300.     jnz    hi_tpa_lp        ; continue up to 640k
  1301.  
  1302. ; bx = # kbs to subtract from 640kb to get our total ram:
  1303. ram_done:
  1304.     mov    ax,640
  1305.     sub    ax,bx
  1306.     pop    es        
  1307.  
  1308. not_problem:
  1309. not_pc:
  1310.  
  1311. endif                    ; endif XM
  1312.  
  1313.     ; On the IBM PS/2 range, handle extended BIOS data
  1314.     ;   at the top of the first (usually) 640 Kb:
  1315.     ; (Otherwise, we'd have problems with paging on a 639 K machine)
  1316.  
  1317.     mov    cx,PC_SEGMENT        ; DS:0000 -> ROM BIOS data segment
  1318.     push    ds
  1319.     mov    ds,cx
  1320.     mov    cx,extended_BIOS_40    ; get extended BIOS segment
  1321.      jcxz    no_ext_BIOS        ; skip if no extended BIOS data
  1322.     mov    ds,cx            ; else DS:0 -> extended data segment
  1323.     add    al,.0            ; add extended BIOS into memory size
  1324.     adc    ah,0            ; (in case there ever is a carry)
  1325. no_ext_BIOS:
  1326.     pop    ds
  1327.  
  1328.     xor    cx,cx
  1329.     mov    es,cx
  1330.     mov    si,HD_PARAM_INTERRUPT*4
  1331.     mov    cx,es:2[si]        ; get pointer segment
  1332.     cmp    cx,08000h
  1333.     jbe    no_disk_reloc        ; too low
  1334.     mov    dx,0A000h
  1335.     cmp    cx,dx
  1336.     jae    no_disk_reloc        ; not in TPA
  1337.     sub    dx,cx            ; dx = number of paras to move
  1338.     mov    reloc_disk$,dx        ; save number for move
  1339.     mov    cl,6
  1340.     shr    dx,cl            ; DL= size in 1k blocks
  1341.     add    al,dl
  1342.     adc    ah,0
  1343. no_disk_reloc:
  1344.  
  1345.     mov    num_mmkb$,ax        ; save kilobytes
  1346.     mov    cl,6
  1347.     shl    ax,cl            ; change to paragraph count
  1348.     mov    memory_top,ax        ; save for memory trim
  1349.     mov    lo_mem_top$,ax        ; keep a permanent copy
  1350.     ret
  1351.  
  1352.  
  1353. crt_check:
  1354. ;---------
  1355. ; Do a memory check on the crt ram:
  1356.  
  1357.     mov    es,ax            ; crt segment
  1358.     mov    cx,1234h        ; dummy pattern for ..
  1359.     mov    ax,0DDB2h        ; bit pattern
  1360.     mov    es:[bx],ax        ; store it
  1361.      push    cx            ; ... bus float protection
  1362.      pop    cx
  1363.     sub    ax,es:[bx]        ; check it
  1364.      jnz    crt_chk1        ; and skip if not there
  1365.  
  1366.     mov    ax,blank$        ; once more for
  1367.     mov    es:[bx],ax        ;   good measure
  1368.      push    cx
  1369.      pop    cx
  1370.     sub    ax,es:[bx]
  1371.      jnz    crt_chk1
  1372.  
  1373.     inc    ax            ; only one
  1374.     ret
  1375. crt_chk1:
  1376.     sub    ax,ax            ; nobody home
  1377.     ret
  1378.  
  1379.  
  1380.  
  1381. herc_check:
  1382. ;----------
  1383. ;     Get hercules card text retrace timing 
  1384.  
  1385.     test    video$,MONO
  1386.      jz    no_check        ; only check if we have mono
  1387.     test    word ptr su_flag_bits$, HERC_ENABLE_BIT    ; retrace timing enabled ??
  1388.      jnz    herc_check1
  1389. no_check:
  1390.     jmp    no_herc_exit        ; not enabled
  1391. herc_check1:
  1392.     mov    cx,20            ; 20 times to find min value
  1393. herc_check_loop:
  1394.     push    cx
  1395.     mov    si,2            ; outer timeout counter
  1396.     mov    cx,0
  1397. herc_check2:
  1398.     mov    dx,MONO_PORT+6        ; status port
  1399.     mov    di,0            ; timeout count
  1400. herc_check_active:
  1401.     sti
  1402.     nop                ; interrupt window
  1403.     cli    
  1404.     in    al,dx
  1405.     rol    al,1            ; wait for active (bit 7 set)
  1406.      jnc    herc_next_check        
  1407.     in    al,dx
  1408.     rol    al,1            ; wait for retrace (bit 7 clr)
  1409.      jc    herc_next_check
  1410.     
  1411.             ;read timer at start of retrace
  1412.     mov    al,0
  1413.     out    TIMER_CMND_REG,al    ; latch timer 0
  1414.     in    al,TIMER_0_REG        ; lsb
  1415.     mov    ah,al            
  1416.     in    al,TIMER_0_REG        ; msb
  1417.     xchg    al,ah            ; swap to word value
  1418.     mov    bx,ax            ; save value 
  1419. herc_retrace_wait:
  1420.     in    al,dx
  1421.     rol    al,1            ; wait for active ( bit 7 set)
  1422.      jc    herc_retrace
  1423.     loop     herc_retrace_wait
  1424.     jmp    no_herc            ; this is taking too long.... exit
  1425.  
  1426. herc_retrace:            ;read timer at end of retrace
  1427.     mov    al,0
  1428.     out    TIMER_CMND_REG,al    ; latch timer 0
  1429.     in    al,TIMER_0_REG        ; lsb
  1430.     mov    ah,al            
  1431.     in    al,TIMER_0_REG        ; msb
  1432.     xchg    al,ah            ; swap to word value
  1433.     sti
  1434.                     ; BX = old value...
  1435.     sub    bx,ax            ; BX = time difference
  1436.      jc    herc_next_check        ; oops.. looped try again
  1437.     cmp    word ptr retrace$,0eeeeh
  1438.     je    set_retrace
  1439.     mov    ax,retrace$
  1440.     mov    dx,bx            ; new value
  1441.     sub    dx,ax            ; lets do a range check
  1442.     jnc    test_range        ; new value < or > 20h previous value
  1443.     neg    dx
  1444. test_range:
  1445.     cmp    dx,20h            ; if values wildly different
  1446.      jg    no_herc            ; then something is not quite right
  1447.     cmp    bx,retrace$        ; else compare with previous
  1448.      jnb    herc_next_try        ; if this time is smaller....
  1449. set_retrace:
  1450.     mov    retrace$,bx        ; then update LOWEST value
  1451. herc_next_try:
  1452.     pop     cx
  1453.     loop    herc_check_loop        ; and try again...    
  1454.     sub    retrace$,8        ; based on experiment 
  1455.     sti                ; of hercules & clones
  1456.     ret
  1457.  
  1458. herc_next_check:
  1459.     inc    di            
  1460.      jnz    herc_check_active    ; else try again
  1461.     dec    si
  1462.      jnz    herc_check2
  1463. no_herc:
  1464.     pop    cx
  1465. no_herc_exit:
  1466.     mov    retrace$,0EEEEh        ; no hercules...
  1467.     sti
  1468.     ret
  1469.         
  1470.     
  1471.  
  1472.  
  1473. check_hi_mem:
  1474. ;------------
  1475. ; Check for memory at or above C000:0000:
  1476.  
  1477.     mov    dx,0C000h        ; starting segment
  1478.     mov    cx,(0F000h-0C000h)/400h    ; 16k block count
  1479.     test    pc_at$,0FFh        ; test up to F000 on PC's
  1480.      jz    ch_hi_mem0
  1481.     mov    cx,(0E000h-0C000h)/400h    ; above E000 taboo for RAM on AT's
  1482. ch_hi_mem0:
  1483.     mov    ax,0DDB2h        ; check pattern
  1484.     mov    bx,1234h        ;  dummy for bus float
  1485. ch_hi_mem1:
  1486.     call    ch_hi_word        ; is there RAM ?
  1487.      jz    ch_hi_mem2        ; if so, skip
  1488.     add    dx,400h            ; check next 16k
  1489.     loop    ch_hi_mem1        ; up to F000
  1490.     ret                ; if none there, return
  1491.  
  1492. ch_hi_mem2:
  1493.     mov    hi_mem_start$,dx    ; there is some memory
  1494. ch_hi_mem3:
  1495.     add    dx,400h            ; up 16k
  1496.     call    ch_hi_word        ; as long as it's good
  1497.      jz    ch_hi_mem3        ;   keep on going
  1498.     mov    hi_mem_top$,dx        ; and save the top
  1499.     ret
  1500.  
  1501. ch_hi_word:
  1502.     sub    si,si            ; zero index
  1503.     mov    es,dx            ; set check segment
  1504.     mov    bp,es:[si]        ; save data
  1505.      push bx ! pop bx        ; bus float
  1506.     mov    es:[si],ax        ; store check pattern
  1507.      push bx ! pop bx
  1508.     cmp    es:[si],ax        ; and see if it matches
  1509.     mov    es:[si],bp        ; restore data
  1510.     ret                ; return with zf set
  1511. eject
  1512.  
  1513. ndp_init:
  1514. ;--------
  1515. ; 8087 Numeric Data Processor initiation routine:
  1516.  
  1517.     test    pc_at$,0ffh        ; find 287 differently
  1518.      jz    no_286
  1519.     int    11h            ; equipment determination
  1520.     test    ax,2            ; 2nd bit set means present
  1521.      jnz    found_ndp        ; show it
  1522.     jmps    ndp_init_done
  1523.         
  1524. no_286:
  1525.     FNINIT                ; init and check for 8087
  1526.     xor    ax,ax            ; stall for time
  1527.     mov    ndp_control$,ax        ;   and clear control word
  1528.     FNSTCW    ndp_control$        ; get 8087 control word
  1529.     or    ax,ndp_control$        ; test for 8087 presence
  1530.      jz    ndp_init_done        ; if not there, skip
  1531.  
  1532. found_ndp:
  1533.     mov    num_ndp$,1        ; we've got one!
  1534.     mov    owner_8087$,0        ; tell the system about it
  1535.  
  1536.     mov    ndp_int_off$,NMI_INTERRUPT * 4
  1537.     mov    ndp_int_seg$,0        ; save the vector location
  1538.     mov    ndp_vec_off$,offset i_ndp@
  1539.     mov    ndp_vec_seg$,cs        ; and the interrupt vector
  1540. ndp_init_done:
  1541.     ret
  1542.  
  1543.  
  1544.  
  1545. eject
  1546.  
  1547. compaq:
  1548. ;------
  1549. ; If this is the compaq, change cursor, sync and sl_attrib$:
  1550.  
  1551.     mov    ax,0F000h
  1552.     mov    es,ax            ; ROM segment
  1553.     mov    di,0FFEAh        ; ID offset
  1554.     mov    si,offset compaq_name
  1555.     mov    cx,length compaq_name
  1556.     repz    cmpsb            ; look for a match
  1557.      je    compaq1
  1558.     ret                ; no, ain't a COMPAQ
  1559. compaq1:
  1560.     mov    cloneflag$,IS_COMPAQ    ; remember, it's a COMPAQ
  1561.     push    ds
  1562.     sub    bx,bx
  1563.     mov    ds,bx            ; point to int vectors
  1564.     lds    bx,VIDEO_PARMS_INTERRUPT*4[bx]    ; ds:bx = param table start
  1565.     cmp    word ptr 1ah[bx],0706h        ; is it 8*8 CGA mode
  1566.     pop    ds
  1567.      je    not_cmpq_cga            ; yes - do not set special
  1568.     mov    var_cursor$,COMPAQ_CURSOR    ;   Compaq values
  1569.     mov    var_sync$,0        ; no retrace sync on dual mode CGA
  1570.     mov    sl_attrib$,0Fh        ; enhanced white
  1571.     mov    alpha_str_80$,offset compaq_str$
  1572. not_cmpq_cga:
  1573.  
  1574. if V386
  1575.     mov    ega_remap,TRUE        ; allow EGA remap from E000 to C000
  1576.  
  1577.     mov    hi_off$,00fffh         ; nothing above F000 on COMPAQ
  1578.     mov    hi_on$, 00f00h        ; always enable E000-EFFF
  1579.  
  1580.     mov    dx,00FAh        ; initialize memory at 00FA0000h
  1581.     call    xmem_256k        ; try to find extra memory up there
  1582. endif
  1583.  
  1584. compaq_done:
  1585.     ret                ; all for now
  1586.  
  1587. if V386
  1588. compaq_protect:
  1589. ;#IJ    test    video$,EGA+VGA        ; do we have EGA
  1590. ;#IJ     jz    not_ega_compaq        ; (we may have an inactive one !)
  1591.  
  1592.     cmp    int10_isr$+2,0e000h    ; (CODE SEG) was it pointing to RAM copy
  1593.      jne    not_ega_compaq        ; no leave well alone
  1594.     mov    ax,0c000h
  1595.     mov    es,ax            ; Rom address
  1596.     mov    int10_isr$+2,ax        ; (CODE SEG) point back to 8 bit rom
  1597.     push    ds            ; in our copy
  1598.     xor    dx,dx            ; and interrupt vectors
  1599.     mov    ds,dx    
  1600.     mov    bx,((1fh*4)+2)
  1601.     mov    [bx],ax
  1602.     mov    bx,((43h*4)+2)
  1603.     mov    [bx],ax
  1604.     pop    ds
  1605.  
  1606.     xor    ah,ah
  1607.     mov    al,es:.02h        ; get # of 512 byte pages in ROM
  1608.     add    al,((16384/512)-1)
  1609.     shr    al,5            ; AL = # of 16 Kb pages
  1610.     shl    al,2            ; 4 page table entries per 16 kb page
  1611.     mov    cx,ax            ; cx = number of page table entries
  1612.     
  1613.     mov    bx,v386_ptr        ; get page table address thru table
  1614.     mov    es,ptbl_seg
  1615.     mov    bx,(0c000h shr 6)+1    ; get entry for 8 bit EGA rom
  1616.     mov    ax,0e00h        ; and replace with new linear address
  1617. ega_rom_loop:
  1618.     mov    es:[bx],ax
  1619.     add    bx,4            ; next page table entry
  1620.     add    ax,10h            ; and address
  1621.     loop    ega_rom_loop
  1622.  
  1623. not_ega_compaq:
  1624.     ret
  1625. endif
  1626.  
  1627.  
  1628. eject
  1629.  
  1630. if V386
  1631. sprite386:
  1632. ;---------
  1633.     mov    ax,0F000h
  1634.     mov    es,ax            ; ROM segment
  1635.     mov    di,0E076h        ; ID offset
  1636.     mov    si,offset sprite_name
  1637.     mov    cx,length sprite_name
  1638.     repe    cmpsb            ; look for a match
  1639.      jnz    sprite_done
  1640.  
  1641.     push    ds
  1642.     mov    si,0C000h        ; copy EGA ROM in case there is one
  1643.     mov    ds,si            ;    move from C000:0000 to E000:0000
  1644.     sub    si,si
  1645.     mov    di,0E000h        ; copy to E000h:0000h
  1646.     mov    es,di
  1647.     sub    di,di
  1648.     mov    cx,32*(1024/WORD)
  1649.     call    rom_to_ram        ; copy 32 Kb of EGA/VGA ROM
  1650.  
  1651.     mov    si,0F000h
  1652.     mov    ds,si
  1653.     mov    es,si
  1654.     sub    si,si
  1655.     sub    di,di
  1656.     mov    cx,64*(1024/WORD)    ; copy 64 Kb of Phoenix ROM BIOS
  1657.     call    rom_to_ram        ;   from ROM to RAM at same address
  1658.     pop    ds
  1659.  
  1660.     cmp    int10_isr$+2,0C000h    ; is it pointing at EGA ROM?
  1661.      jne    fix_sprite_ega        ; skip if not EGA ROM at usual place
  1662.     push    ds
  1663.     mov    si,0C000h
  1664.     mov    ds,si            ; test if we could relocate EGA
  1665.     mov    di,0E000h
  1666.     mov    es,di            ;   to COMPAQ compatible address
  1667.     sub    si,si
  1668.     sub    di,di            ; compare C000:0000 to E000:0000
  1669.     mov    cx,(16*1024)/2        ; compare first 16 K
  1670.     repe    cmpsw            ; check if ROM copied alright
  1671.     pop    ds
  1672.      jne    fix_sprite_ega        ; skip if ROM copy failed
  1673.     mov    int10_isr$+2,0E000h    ; point it to where COMPAQ has it
  1674.     mov    ega_remap,TRUE        ; allow EGA remapping
  1675. fix_sprite_ega:
  1676.  
  1677. ;;    mov    dx,0F800h
  1678. ;;    mov    cx,00800h        ; write protect last 32K
  1679. ;;    call    write_protect
  1680.  
  1681.     mov    hi_off$,03fffh         ; nothing above F800 on Sprite 386
  1682.     mov    hi_on$, 03f00h        ; always enable E000-F800
  1683.  
  1684.     mov    dx,00CAh        ; initialize memory at 00CA0000h
  1685.     call    xmem_256k        ; try to find extra memory up there
  1686.  
  1687. sprite_done:
  1688.     ret
  1689.  
  1690.  
  1691.  
  1692. ;    Entry:    DS:SI -> source of ROM block
  1693. ;        ES:DI -> destination of ROM block
  1694. ;        CX = # of words to move
  1695. ;    Exit:    SI, DI updated
  1696. ;        ROM copied to RAM
  1697.  
  1698. rom_to_ram:
  1699.     mov    dx,0318h        ; standard Sprite ROM switch port
  1700. rom_to_ram_lp:
  1701.     mov    al,1            ; select ROM
  1702.     out    dx,al
  1703.     jmps    $+2            ; i/o delay
  1704.     lodsw                ; read a word from ROM
  1705.     push    ax            ; save word
  1706.     mov    es:[di],ax
  1707.     mov    al,2            ; select RAM
  1708.     out    dx,al
  1709.     pop    ax            ; get data word
  1710.     stosw                ; write it to RAM
  1711.     loop    rom_to_ram_lp        ; repeat for entire ROM
  1712.     ret
  1713.  
  1714.  
  1715. xmem_256k:
  1716. ;---------
  1717. ;    Check for 256 K of RAM shadowed out from A000-E000
  1718. ;    to allow for video memory and adapter space. On some
  1719. ;    386 ATs (eg. COMPAQ) this memory is relocated to one
  1720. ;    of the top megabytes and can be put to good use by CDOS 386.
  1721.  
  1722. ;    Entry:    DX = A16..A31 where memory might reside
  1723. ;    Exit:    hi_xmem_size$ updated if memory found
  1724.  
  1725.     mov    ah,88h            ; extended memory size determine
  1726.     int    15H            ; AX = Kb of extended memory
  1727.     add    ax,1024h        ; AX = Kb address of end of RAM
  1728.     shr    ax,6            ; AX = A16..A31 of end of linear RAM
  1729.     cmp    ax,dx            ; RAM higher than 256K extension?
  1730.      jae    xmem_256k_done        ; skip 256K test if yes
  1731.  
  1732.     mov    hi_xmem_addr$,dx    ; set potential high memory
  1733.     mov    cx,256/64        ; 4 banks of 64K (256K total)
  1734. xmem_256k_lp1:
  1735.     push    cx ! push dx        ; save count, base address
  1736.     sub    bx,bx
  1737.     mov    es,bx            ; move from ES:BX -> 0000:0000
  1738.     sub    ax,ax            ;   to DX*10000h
  1739.     mov    cx,8000h        ; move 64 Kb to initialize parity
  1740.     call    xmem_write        ; move to high memory
  1741.     pop    dx ! pop cx        ; restore address, count
  1742.     inc    dx            ; next 64K bank
  1743.     loop    xmem_256k_lp1        ; repeat for all banks
  1744.  
  1745.     mov    dx,hi_xmem_addr$    ; get potential high memory
  1746.     mov    cx,256/64        ; now check banks for presence
  1747. xmem_256k_lp2:
  1748.     push    cx ! push dx        ; save count, address
  1749.     mov    ax,055AAh        ; get test pattern #1
  1750.     call    test_256k        ; perform read/write test
  1751.      jnz    xmem_256k_bad        ; give up if no RAM
  1752.     mov    ax,0AA55h        ; get test pattern #2
  1753.     call    test_256k        ; perform read/write test
  1754.      jnz    xmem_256k_bad        ; give up if no RAM
  1755.     add    hi_xmem_size$,(64/16)    ; number of extra pages up there
  1756.     cmp    ax,ax            ; set ZF = 1 for good test
  1757. xmem_256k_bad:
  1758.     pop    dx ! pop cx        ; restore address, count
  1759.      jnz    xmem_256k_done        ; break out if test failed
  1760.     inc    dx            ; next 64K bank to test
  1761.     loop    xmem_256k_lp2        ; repeat for all banks
  1762. xmem_256k_done:                ; high memory test done
  1763.     ret
  1764.  
  1765.  
  1766. test_256k:
  1767. ;    Entry:    AX = 16 bit test pattern
  1768. ;        DX = A16-A31 for memory block to test
  1769. ;    Exit:    ZF = 1 if test succeeded
  1770. ;        AX, DX preserved
  1771.  
  1772.     push    ax ! push dx        ; save pattern, address
  1773.     mov    int15_config,ax        ; save store for move
  1774.     call    int15_setup        ; setup pointers for move
  1775.     call    xmem_write        ; move pattern to extended memory
  1776.     not    int15_config        ; negate pattern in case move fails
  1777.     pop    dx ! push dx        ; recover & save value A16-A31
  1778.     call    int15_setup        ; setup pointers for move
  1779.     call    xmem_read        ; read back test pattern
  1780.     pop    dx ! pop ax        ; restore address, original pattern
  1781.     cmp    ax,int15_config        ; check if read back O.K.
  1782.     ret                ; ZF = 1 if memory O.K.
  1783.  
  1784. int15_setup:
  1785. ;    Entry:    DX = A16..A31 for extended move
  1786. ;    Exit:    AX/DX = 32 bit address
  1787. ;        ES:BX = 8086 address
  1788. ;        CX = 1
  1789.  
  1790.     sub    ax,ax            ; A0..A16 = 0000h
  1791.     push    ds ! pop es
  1792.     mov    bx,offset int15_config    ; ES:BX -> int15_config
  1793.     mov    cx,1            ; CX = word count
  1794.     ret
  1795.  
  1796. xmem_read:
  1797. ;---------
  1798. ;    Entry:    ES:BX -> destination (1st Mb)
  1799. ;        AX/DX = 32 bit source address (anywhere)
  1800. ;        CX = word count for block move
  1801.  
  1802.     mov    si,offset int15_gdt+10h    ; source selector
  1803.     mov    di,offset int15_gdt+18h    ; destination selector
  1804.     jmps    xmem_rw            ; make a move...
  1805.  
  1806. xmem_write:
  1807. ;----------
  1808. ;    Entry:    AX/DX = 32 bit destination address (anywhere)
  1809. ;        ES:BX -> source (1st Mb)
  1810.  
  1811.     mov    di,offset int15_gdt+10h    ; source selector
  1812.     mov    si,offset int15_gdt+18h    ; destination descriptor
  1813. ;    jmps    xmem_rw            ; make a move
  1814.  
  1815. xmem_rw:
  1816.     mov    2[si],ax        ; set A0-A15
  1817.     mov    4[si],dl        ; set A15-A23
  1818.     mov    7[si],dh        ; set A24-A31
  1819.  
  1820.     mov    ax,es            ; get segment in 1st Mb
  1821.     mov    dx,16            ; bytes per paragraph
  1822.     mul    dx            ; AX/DX = 32 bit address of ES
  1823.     add    ax,bx            ; add in the offset within segment
  1824.     adc    dx,0            ; add in the carry
  1825.     mov    2[di],ax        ; set A0-A15
  1826.     mov    4[di],dl        ; set A15-A23
  1827.     mov    7[di],dh        ; set A14-A31
  1828.  
  1829.     mov    ah,87H            ; extended memory move function
  1830.     push    ds ! pop es
  1831.     mov    si,offset int15_gdt    ; ES:SI -> GDT for ROS use
  1832.     int    15H            ; call AT compatible ROS
  1833.     ret
  1834.  
  1835. write_protect:
  1836. ;-------------
  1837. ;    entry:    DX = segment address to protect
  1838. ;        CX = # of paragraphs to protect
  1839. ;        (both must be multiple of 100h)
  1840.  
  1841.     mov    bx,mdul            ; steal entry from MDUL
  1842.     mov    ax,MD_LINK[bx]        ; (no CLI/STI as we're only process
  1843.     mov    mdul,ax            ;  running here)
  1844.  
  1845.     mov    MD_START[bx],dx        ; set start of block to protect
  1846.     mov    MD_LENGTH[bx],cx    ; set length of block to protect
  1847.     mov    si,v386_ptr        ; get 386 structure
  1848.     mov    ax,ro_mem_root[si]    ; get current R/O list
  1849.     mov    MD_LINK[bx],ax        ; append it to our entry
  1850.     mov    ro_mem_root[si],bx    ; link us into R/O list
  1851.  
  1852.     ret                ; MEM will make these pages R/O
  1853.  
  1854. endif
  1855.  
  1856. eject
  1857.  
  1858. if XM
  1859. ;    Now check for a couple of 8086-2 machines (XM only, not 386)
  1860. ;    to make use of any useful special features (RTC, etc.)
  1861.  
  1862. amstrad:
  1863. ;-------
  1864.     mov    ax,0F000h
  1865.     mov    es,ax            ; ROM segment
  1866.     mov    si, offset amstrad_name
  1867.     mov    di, 0C016h        ; ID offset
  1868.     mov    cx, 7
  1869.     repz    cmpsb            ; look for a match
  1870.      jnz    amstrad_done
  1871.  
  1872.     mov    cloneflag$, IS_AMSTRAD    ; is Amstrad so
  1873.     call    set_time@        ; set the system time from RTC
  1874.     mov    var_sync$,0        ; no retrace syncing - wide open
  1875.  
  1876. ; Get Default Attributes from the RTC
  1877.     mov    al,RTC_VDU
  1878.     call    read_286_cmos
  1879.     mov    iattrib$,al        ; save initial attribute
  1880.  
  1881. amstrad_done:
  1882.     ret
  1883.     
  1884. eject
  1885. check_8530:        ; check for PS/2 model 30
  1886. ;----------
  1887. ; Check to see if we're running on the PS/2 Model 30
  1888.  
  1889.     mov    ax,0FFFFh        ; top of rom
  1890.     mov    es,ax
  1891.     mov    al,es:.0Eh        ; get IBM model byte
  1892.     cmp    al,0FAh            ; check if on PS/2 model 30
  1893.      jne    not_8530
  1894.  
  1895.     mov    var_sync$,0        ; no syncing w/ MCGA
  1896.     or    video$,MCGA        ; yes, we've got MCGA
  1897.  
  1898.     mov    disk_chng_mask$,80h    ; disk change mask
  1899.     mov    dx,FDC_RATE        ; initialize the data rate to 250 Kbit
  1900.     mov    al,RATE_SLOW_48        ;    as our disk code won't
  1901.     out    dx,al            ;    set it up on non-AT machines
  1902.  
  1903.     jmp    set_time@        ; set current time & date
  1904.  
  1905. not_8530:
  1906.     ret
  1907.  
  1908.  
  1909. eject
  1910.  
  1911. olivetti:        ; check for Olivetti M24 or M24SP
  1912. ;--------
  1913.     mov    ax,0F000h
  1914.     mov    es,ax            ; ROM segment
  1915.     mov    di,0C050H        ; ID offset
  1916.     mov    si,offset olivetti_name
  1917.     mov    cx,8
  1918.     repz    cmpsb            ; look for a match
  1919.      jnz    olivetti_done
  1920.  
  1921.     mov    si,offset oli_vector$        ; setup extra video modes
  1922.     mov    [si],offset bw_640_400@        ; ROS mode 64
  1923.     mov    1*2[si],offset bw_640_400_t@    ; ROS mode 72
  1924.     mov    cloneflag$, IS_M24        ; support video modes on M24/M28
  1925.  
  1926.     cmp    pc_at$,0        ; treat M28 like an IBM AT
  1927.      jne    olivetti_done        ;   not like an M24...
  1928.     mov    ax,0FFFFh        ; top of rom
  1929.     mov    es,ax
  1930.     mov    al,es:.0Eh        ; get model byte
  1931.     cmp    al,0FBh            ; XT with 640k = M240
  1932.      je    oli_48_tpi
  1933.     in    al,67h            ; read the motherboard switches
  1934.     test    al,01h            ; test SW1: 96 TPI option installed
  1935.      jz    oli_48_tpi        ; skip if normal 48 TPI drives
  1936.     mov    al,HYPER_DRIVE        ; else 80 tracks, double step magic
  1937.     mov    drive_type$+0,al    ;   required for reading 48 TPI media
  1938.     mov    drive_type$+1,al    ;   on both A: and B: (if we have both)
  1939. oli_48_tpi:
  1940.  
  1941. ;    M24 has battery backed up real time clock
  1942.  
  1943.     mov    ah,0FEh            ; get time in clock chip
  1944.     int    TOD_INT            ; read battery backed up time
  1945.  
  1946.     push    ds ! pop es        ; point ES to SYSDAT for string op's
  1947.  
  1948.     mov    di,offset tod_day$    ; point to SYSDAT time
  1949.     add    bx,365*5+366        ; days from 1/1/78 to 1/1/84
  1950.     inc    bx            ; rel to 1
  1951.     mov    ax,bx
  1952.     stosw
  1953.  
  1954.     push    cx
  1955.     mov    al,ch
  1956.     call    o_mk_bcd
  1957.     pop    cx
  1958.  
  1959.     mov    al,cl
  1960.     call    o_mk_bcd
  1961.  
  1962.     mov    al,dh
  1963. ;    call    o_mk_bcd
  1964. ;    ret
  1965.  
  1966.  
  1967. o_mk_bcd:
  1968. ;--------
  1969. ;    entry:    AL = binary
  1970. ;    exit:    BCD equivalent stored at DI
  1971.  
  1972.     xor    ah,ah            ;0 tens count
  1973. mb_tens:
  1974.     cmp    al,15
  1975.      jbe    mb_aaa
  1976.     sub    al,10
  1977.     inc    ah
  1978.     jmps    mb_tens
  1979. mb_aaa:
  1980.     add    al,0            ;make into packed BCD
  1981.     aaa
  1982.     mov    cl,4
  1983.     shl    ah,cl
  1984.     or    al,ah
  1985.     stosb                ;and save it
  1986.  
  1987. olivetti_done:
  1988.     ret
  1989.  
  1990. endif                    ; endif XM
  1991.  
  1992. eject
  1993.  
  1994. fix_crt:
  1995. ;-------
  1996. ; Set up the mono/color vs_ variables and test for EGA:
  1997.  
  1998. ; These things need to be determined for EGA support:
  1999. ;    1.  Is an EGA present?
  2000. ;    2.  Is it the "primary" display (default on boot)?
  2001. ;    3.  Is it acting as a color card or a mono card?
  2002. ;    4.  Is the Enhanced Color Display attached if in color card mode?
  2003.  
  2004. ; An EGA is present if int 10 function 12h does not alter BX.
  2005.  
  2006. ; An EGA is the "primary" display if an int 10h (alternate select)
  2007. ;  returns cl > 5 on bl = 10h.
  2008. ;  and EGA type = MONO if BH = 1, COLOR if BH = 0.
  2009.  
  2010.  
  2011. ; Get EGA information
  2012.     mov    ax,1Ah*256+0        ; get display type combination
  2013.     int    VIDEO_INT
  2014.     cmp    al,1Ah            ; 0 if not implemented, 1Ah if OK
  2015.      jne    check_ega        ; skip if not PS/2 video adapter
  2016.     cmp    bl,2
  2017.      jbe    no_ega            ; if primary = MDA or CGA, ignore VGA
  2018. check_ega:
  2019.  
  2020.     mov    bh,0ffh
  2021.     mov    ax,1200h            ; alternate select
  2022.     mov    bl,10h                ; return EGA info
  2023.     int    VIDEO_INT            ; BH = 0 color, 1 mono
  2024.                         ; BH unchanged = no EGA
  2025.                         ; BL = memsize
  2026.                         ; CH = feature bits
  2027.                         ; CL = switch settings
  2028.     cmp    bh,0ffh
  2029.     jne    ega_here
  2030.     jmp    no_ega
  2031.  
  2032. ; Here if we've got an EGA.  See if it's color or mono:
  2033. ega_here:
  2034.     or    video$,EGA            ; set video flag
  2035.     
  2036. ; First replace the "mode_not_supported" vectors in the mode vector table
  2037. ; with the routines for the ega modes:
  2038.     mov    var_cursor$,COLOR_CURSOR        ; overwrite COMPAQ value
  2039.     mov    al,MONO                ; assume mono
  2040.     cmp    bh,1
  2041.      je    ega_mono            ; Mono monitor EGA 
  2042.     mov    al,COLOR            ; indicate color
  2043.     mov    var_sync$,0            ; no syncing w/ ega
  2044. ega_mono:
  2045.     or    video$,al            ; byte now set up
  2046.  
  2047. ; If the ega is mono, skip the ECD stuff:
  2048.     test    video$,MONO
  2049.      jnz    ecd_done
  2050.  
  2051. ; Check for the enhanced modes:
  2052.     cmp    cl,0010b  ! je ecd        ; bit set (1) = SW off
  2053.     cmp    cl,0011b  ! je ecd
  2054.     cmp    cl,1000b  ! je ecd
  2055.     cmp    cl,1001b  ! jne ecd_done
  2056. ecd:
  2057. ; Here if the Enhanced Color Display is attached:
  2058.     or    video$,ECD            ; set bit
  2059.     
  2060. ecd_done:
  2061.     mov    ax,1Ah*256+0        ; get display type combination
  2062.     int    VIDEO_INT
  2063.     cmp    al,1Ah            ; 0 if not implemented, 1Ah if OK
  2064.      jne    no_ega            ; skip if not PS/2 video adapter
  2065.     cmp    bl,7            ; PS/2 w/ VGA and mono monitor
  2066.      je    vga_here
  2067.     cmp    bl,8            ; PS/2 w/ VGA and color monitor
  2068.      jne    no_ega            ; else we can't cope...
  2069. vga_here:
  2070.     or    video$,VGA        ; set VGA bit
  2071.  
  2072. no_ega:
  2073.     mov    si,offset set_mono@    ; assume monochrome
  2074.     mov    di,offset z_sl_mono@    ; for status line too
  2075.     cmp    init_video_mode,03h    ; if mono switched on
  2076.     jnz    fix_color
  2077.     test    video$,EGA
  2078.     jnz    fix_crt1
  2079.     or    video$,MONO        ; set mono bit
  2080.      jmps    fix_crt1        ;   then skip
  2081.  
  2082. fix_color:
  2083.     mov    si,offset set_color@    ; else color
  2084.     mov    di,offset z_sl_color@    ; and color status
  2085.     test    video$,EGA
  2086.     jnz    fix_crt1
  2087.     or    video$,COLOR        ; set color bit
  2088. fix_crt1:
  2089.     push    si
  2090.     call    di            ; set status line
  2091.     pop    si
  2092.     sub    dl,dl            ; first vc number
  2093. fix_crt2:
  2094.     push    dx ! push si
  2095.     call    point_vs@        ; bx -> structure
  2096.     call    si            ; mono or color
  2097.     pop    si ! pop dx
  2098.     inc    dx            ; next vc
  2099.     cmp    dl,NUM_VIR_CONS        ; through the last
  2100.      jb    fix_crt2
  2101.  
  2102.     test    video$,EGA+VGA+MCGA+MONO ; make sure it is possibly AST COLOR
  2103.     jnz    not_ast
  2104.     mov    ast_flag$,0ffh        ; set AST colorcard possible flag
  2105. not_ast:
  2106.     ret
  2107.  
  2108.  
  2109. fix_ega_pal:
  2110.     test    video$,EGA+VGA
  2111.     jz    no_ega1
  2112.     push    ds
  2113.     push ds ! pop es
  2114.     mov    ax,PC_SEGMENT
  2115.     mov    ds,ax
  2116.     lds    si,dword ptr .0a8h    ; get pointer to save_ptr in EGA ROS
  2117.     mov    di,offset local_ptr$
  2118.     mov    cx,16
  2119.     push    di
  2120.     cld
  2121.     rep    movsw            ; move table locally
  2122.     pop    di
  2123.     mov    ds,ax
  2124.     mov    .0a8h,di        ; save our pointer in ROS data
  2125.     mov    .0a8h + 2,es
  2126.     pop    ds
  2127.     mov    dx,256/16        ; ega spec specifies 256
  2128.     call    mem_alloc_i@        ; for pallette save area
  2129.     mov    local_ptr$+6,ax        ; save segment save area in local ptr
  2130.     mov    local_ptr$+4,0000
  2131.     mov    ax,0f00h        ; get current video mode
  2132.     pushf
  2133.     callf    cs:dword ptr int10_isr$
  2134.     
  2135.     mov    ah,0
  2136.     or    al,80h            ; reset mode without clearing screen
  2137.     pushf
  2138.     callf    cs:dword ptr int10_isr$ ; to initialise palette save area
  2139.                     ; into our local table
  2140.  
  2141.     xor    bx,bx            ; start with virtual console 0
  2142.     mov    cx,NUM_VIR_CONS
  2143. init_pal:
  2144.     push     bx ! push cx
  2145.     mov    bx,table_vs$[bx]
  2146.     lea    di,VS_PALLETTE        ; get save area
  2147.     xor    si,si
  2148.     push    ds
  2149.     mov    ds,local_ptr$+6        ; get pallette segment save area
  2150.     mov    cx,17
  2151.     rep    movsb
  2152.     pop    ds
  2153.     pop    cx ! pop bx
  2154.     add    bx,2            ; next VC_
  2155.     loop    init_pal        ; save for all vs's
  2156.  
  2157. no_ega1:
  2158.     ret
  2159.  
  2160.  
  2161. eject
  2162.  
  2163. fix_disk_tables:
  2164. ;---------------
  2165. ; Correct the disk tables to match physical configuration:
  2166.  
  2167.     sub    bx,bx            ; start with 1st drive
  2168. dos_dpb_alloc:
  2169.     push    bx            ; save the drive index
  2170.     mov    dx,29            ; allocate one DPB/drive
  2171.     call    sysdat_mem_alloc    ; returns offset in AX
  2172.     pop    bx            ; restore drive index
  2173.     mov    si,bx            ; make bx+si = 2*bx
  2174.     mov    dos_dpbs$[bx+si],ax    ; save DPB for dynamic DPBs
  2175.     inc    bx            ; point to next drive
  2176.     cmp    bx,num_flop$        ; all floppies done?
  2177.      jne    dos_dpb_alloc        ; loop back if more
  2178.  
  2179.     sub    ax,ax            ; ax = 0; al = A:
  2180.     mov    temp_disk$,al        ; tempory disk default
  2181.  
  2182.     push ds ! pop es        ; local extra segment
  2183.     mov    di,offset dph_tbl$    ; first we must zap the
  2184.     mov    cx,num_flop$
  2185. alloc_flop_dphs:
  2186.     push cx ! push di
  2187.     mov    dx,DPH_SIZE+8        ; allocate DPH plus some extra data
  2188.     call    sysdat_ext_alloc    ; grow SYSDAT by DX bytes, return in AX
  2189.     pop    di            ; restore address of next DPH
  2190.     stosw                ; save address of DPH in DPH table
  2191.     push    di            ; save address of next DPH table entry
  2192.     xchg    ax,di            ; DI -> new DPH
  2193.     push    di
  2194.     sub    ax,ax            ; get a zero to initialize it
  2195.     mov    cx,(DPH_SIZE+8)/WORD    ; size of DPH in byte
  2196.     rep    stosw            ; zero out new DPH
  2197.     pop    di            ; start of DPH
  2198.     mov    ax,offset pcdpb9D$    ; insert temp DPB pointer into DPH
  2199.     mov    DPH_DPB[di],ax
  2200.     pop di ! pop cx            ; restore DPH pointer, loop count
  2201.     loop    alloc_flop_dphs        ; do next disk parameter header
  2202.     mov    cx,8
  2203.     sub    cx,num_flop$        ; number of drives remaining
  2204.     sub    ax,ax            ; get a zero to initialize it
  2205.     rep    stosw            ; zero out all other DPHs
  2206.  
  2207.  
  2208. ; Now, set up the true dph and branch vector tables:
  2209.  
  2210.     sub    di,di            ; di = 0, first entry
  2211.     mov    cx,num_flop$        ; first the floppies
  2212.     mov    bx,offset dph_tbl$    ; list of floppy dph's
  2213. fix_flops:
  2214.     mov    si,offset flop_vectors    ; select, read, write flops
  2215.     call    fix_one_disk        ; set dph and vectors
  2216.     loop    fix_flops
  2217.  
  2218.     cmp    num_flop$,1        ; now, if only one floppy
  2219.      jnz    fix_flop_done        ;   then we special case
  2220.     inc di ! inc di            ;   by skipping B:
  2221.  
  2222. fix_flop_done:
  2223.  
  2224.                     ; Hard disk setup moved to hd_init
  2225.     mov    pc_hd_dph_start,di    ; save pointer to first DOS partition DPH
  2226.  
  2227.     ret                
  2228.  
  2229. ; Set up table entries for one disk:
  2230.  
  2231. fix_one_disk:
  2232.     mov    ax,[bx]            ; get the dph offset
  2233.     mov    dph_tbl$[di],ax        ; set dph
  2234.     lodsw                ; fetch the select vector
  2235.     mov    select_tbl$[di],ax
  2236.     lodsw                ; fetch the read vector
  2237.     mov    read_tbl$[di],ax
  2238.     lodsw                ; fetch the write vector
  2239.     mov    write_tbl$[di],ax
  2240.     inc bx    ! inc bx        ; to next dph entry
  2241.     inc di    ! inc di        ; to next vector entry
  2242.     ret
  2243.  
  2244.  
  2245. eject
  2246.  
  2247. printer_init:
  2248. ;------------
  2249. ; Reset all parallel printer ports:
  2250. ; Set up list_out$ and list_stat$ tables:
  2251. ; Collapse parallels:
  2252.  
  2253.     cmp    num_print$,0        ; test count
  2254.     mov    cx,3            ; total number
  2255.     jne    pr_par_loop
  2256.     xor    di,di
  2257. pr_loop:
  2258.     mov    bx,lcb_list$[di]    ; get pointer to LCB
  2259.     mov    LCB_ATTACH[bx],UNAVAILABLE ; mark for TMP
  2260.     inc di ! inc di
  2261.     loop    pr_loop
  2262.     jmp    pr_par_done
  2263.     
  2264. pr_par_loop:
  2265.     sub    dx,dx            ; first is zero
  2266. pr_par_loop1:
  2267.     mov    ah,1            ; reset code
  2268.     int    PRINT_INT
  2269.     inc    dx            ; next printer
  2270.     loop    pr_par_loop1
  2271.  
  2272.     mov    ax,40h            ; look into base page
  2273.     mov    es,ax
  2274.     mov    si,8            ; printer address list
  2275.     mov    di,0            ; logical number index
  2276.     mov    bx,0
  2277.     mov    cx,3
  2278. pr_par_loop2:
  2279.     push    cx
  2280.     push    bx
  2281.     mov    ax,es:[si]        ; fetch printer address
  2282.     or    ax,ax            ; anything there?
  2283.     jnz    pr_par_set
  2284.     mov    bx,lcb_list$[bx]    ; get pointer to LCB
  2285.     mov    LCB_ATTACH[bx],UNAVAILABLE ; mark for TMP
  2286.     jmps    pr_par_next
  2287.  
  2288. pr_par_set:
  2289.     mov    list_data$[di],ax
  2290.     mov    list_out$[di],offset parallel_out@
  2291.     mov    list_stat$[di],offset parallel_stat@
  2292.  
  2293.     mov    ax,di
  2294.     shr    al,1
  2295.     call    conv_digit@
  2296.     call    put_in_s_o        ; put in sign-on
  2297.  
  2298.     inc di ! inc di            ; next logical number
  2299. pr_par_next:
  2300.     inc    si
  2301.     inc    si            ; next list entry
  2302.     pop    bx
  2303.     inc     bx
  2304.     inc    bx
  2305.     pop    cx
  2306.     loop    pr_par_loop2
  2307.  
  2308. ; We don't do this for serial printers any more...
  2309. ; Do_aux_ports takes care of it for us.
  2310.  
  2311. pr_par_done:
  2312.     ret
  2313.  
  2314.  
  2315. put_in_s_o:
  2316. ; al,ah = ascii printer number
  2317.     push    bx
  2318.     mov    bx,offset sign_on_prnum
  2319.     mov    dx,bx
  2320.     mov    cx,8*3            ; 8 per line
  2321.     call    find_lp
  2322.     cmp    ch,0ffh
  2323.     jne    put_done
  2324.     mov    bx,offset sign_on_prnum1
  2325.     mov    dx,bx
  2326.     mov    cx,8            ; 8 per line
  2327.     call    find_lp
  2328. put_done:
  2329.     pop    bx
  2330.     ret    
  2331.  
  2332. find_lp:
  2333.     cmp    byte ptr [bx],' '
  2334.      je    find_lp1        ; try next if already taken  
  2335.     inc    bx
  2336.     loop    find_lp
  2337.     mov    ch,0ffh            ; error exit
  2338.     ret
  2339. find_lp1:
  2340.     cmp    bx,dx            ; is this the first number ?
  2341.      je    find_lp5        ; yes, just get on with it
  2342.     call    test_next_in_seq    ; is it the next in a sequence ?
  2343.      jne    find_lp3        ; no, we add a ","
  2344.     call    rewind_if_dash        ; have we already got a "-" ?
  2345.     mov    byte ptr [bx],'-'    ; is so rewind, then do this one
  2346.      jmps    find_lp4
  2347. find_lp3:
  2348.     mov    byte ptr [bx],','
  2349. find_lp4:
  2350.     inc    bx
  2351. find_lp5:
  2352.     mov    [bx],al
  2353.     or    ah,ah            ; two digit number
  2354.     jz    find_lp6        ; no exit all done
  2355.     mov    1[bx],ah
  2356. find_lp6:
  2357.     ret
  2358.  
  2359. test_next_in_seq:
  2360. ; on entry BX = 1st space, DX = start, AX = number
  2361. ; on exit we set Z flag if the previous number is the immediately
  2362. ; preceeding one in the sequence
  2363.     push    ax
  2364.     push    bx
  2365.     push    cx
  2366.     mov    cx,ax        ; save the number (in ASCII form)
  2367.     dec    bx
  2368.     mov    al,[bx]        ; get the number
  2369.     sub    al,'0'        ; do the ascii adjust
  2370.     cmp    bx,dx        ; at the start yet ?
  2371.      jle    test_next_in_seq1 ; yes, no dash use old BX
  2372.     dec    bx
  2373.     cmp    byte ptr [bx],'0'
  2374.      jl    test_next_in_seq1 ; are we looking at a number
  2375.     cmp    byte ptr [bx],'9' ; if not, we already have the whole lot
  2376.      jg    test_next_in_seq1 ; otherwise we need to add a digit
  2377.     mov    bl,[bx]
  2378.     xchg    al,bl
  2379.     sub    al,'0'
  2380.     mov    ah,10
  2381.     mul    ah
  2382.     add    al,bl        ; the lot    
  2383. test_next_in_seq1:
  2384.     inc    al        ; this is the next in the sequence
  2385.     call    conv_digit@    ; see what the ascii is
  2386.     cmp    ax,cx        ; does it match our number ?
  2387.     pop    cx
  2388.     pop    bx
  2389.     pop    ax
  2390.     ret
  2391.  
  2392. rewind_if_dash:
  2393. ; on entry BX = 1st space, DX = start
  2394. ; on exit BX = where we want to start writing
  2395. ; we have already determined the previous number immediately preceeds
  2396. ; the one we are doing, but here we check to see if it is already part
  2397. ; of a sequence.
  2398. ; we look before the previous number to see if it has a "-", if so we rewind
  2399. ; BX to point at it ready to overwrite with the new number.
  2400.     push    ax        ; save it...
  2401.     mov    ax,bx        ; old BX here
  2402. rewind1:
  2403.     dec    bx
  2404.     cmp    bx,dx        ; before the start yet ?
  2405.      jl    rewind3        ; yes, no dash use old BX
  2406.     cmp    byte ptr [bx],'0'
  2407.      jl    rewind2        ; are we looking at a number
  2408.     cmp    byte ptr [bx],'9' ; if not, check for the '-'
  2409.      jg    rewind2        ; otherwise go back another
  2410.     jmps    rewind1
  2411. rewind2:
  2412.     cmp    byte ptr[bx],'-' ; have we found a dash ?
  2413.     je    rewind4        ; bingo - use new BX value
  2414. rewind3:
  2415.     mov    bx,ax        ; restore old BX value
  2416. rewind4:
  2417.     pop    ax        ; restore it
  2418.     ret
  2419.  
  2420. ; convert hex number in al to ascii in ah and al
  2421. ; return tens in AL if AH<>0
  2422. conv_digit@:
  2423.     xor    ah,ah
  2424. do_tens:
  2425.     cmp    al,9
  2426.     jbe    do_digit
  2427.     sub    al,10
  2428.     inc    ah                ; increment tens
  2429.     jmps    do_tens
  2430. do_digit:
  2431.     or      al,'0'              ; convert to ascii
  2432.     or    ah,ah
  2433.     jz    do_al
  2434.     or    ah,'0'
  2435.     xchg    al,ah                ; make al tens
  2436. do_al:
  2437.     ret
  2438.  
  2439.  
  2440. eject
  2441.  
  2442. do_video:    
  2443. ;--------
  2444. ; Initialise primary monitor
  2445.  
  2446.     test    video$,COLOR
  2447.      jnz    do_color            ; skip mono if in color mode
  2448. do_mono:
  2449.     sub    dl,dl
  2450.     call    point_vs@            ; point bx at top structure
  2451.     mov    cl,7                ; ROS mode 7 (mono 80)
  2452.     call    screen_set_only@        ; set default mode
  2453.      jmps    do_vid_done
  2454.           
  2455. do_color:
  2456.     sub    dl,dl
  2457.     call    point_vs@            ; point bx at top structure
  2458.     mov    cl,3                ; ROS mode 3 (color 80)
  2459.     call    screen_set_only@        ; set default mode
  2460.  
  2461. do_vid_done:
  2462.     ret
  2463.  
  2464. eject
  2465.  
  2466. RSPH_LINK    equ    es:word ptr .00h
  2467. RSPH_NCP    equ    es:byte ptr .04h
  2468. RSPH_CGSIZE    equ    es:word ptr .0Ch
  2469. RSPH_DGSIZE    equ    es:word ptr .0Eh
  2470. RSPH_PDNAM    equ    es:byte ptr .18h
  2471. RSPH_PCNS    equ    es:byte ptr .30h
  2472. RSPH_INITDS    equ    es:word ptr .92h
  2473. RSPH_INITES    equ    es:word ptr .94h
  2474. RSPH_INITSS    equ    es:word ptr .96h
  2475.  
  2476.  
  2477. alloc_ser_rsps:        ; allocate serial TMPs and PINs
  2478. ;--------------
  2479.     mov    cl,NUM_VIR_CONS        ; default start
  2480.     mov    ncondev$,cl        ; update # of virtual consoles
  2481.     mov    nvcons$,cl        ; update SYSDAT
  2482.     mov    nvcns$,cl        ; update XIOS header
  2483.     mov    npcons$,1        ; master console
  2484.     sub    di,di            ; physical port number
  2485.  
  2486. alloc_ser_loop:
  2487.     mov    dl,port2pc_table$[di]    ; physical console number
  2488.     cmp    dl,0ffh            ; allocated
  2489.     jne    alloc_ser1
  2490.      jmp    alloc_ser_next        ; no get next possible    
  2491. alloc_ser1:
  2492.     inc    npcons$            ; number of physical consoles
  2493. ;#IJ    call    build_pin        ; build a PIN RSP
  2494.     mov    al,1            ; default 1 virtual console 
  2495.                     ; per physical console
  2496.  
  2497. if not SR    ; *** do not allow PCTERM and SRTERM for now ***
  2498. if V386
  2499.     test    su_mu_vs$[di],PCTERM_EMU ; test setup bit for installed port
  2500.     jz    no_pcterm        ;  to see if pcterm emulation required
  2501.     call    build_flush        ; if yes then build FLUSH RSP and
  2502.     mov    al,su_mu_vs$[di]    ; get number of virtuals per physical
  2503.     and    al,07h            ;  mask number of virtuals
  2504. no_pcterm:
  2505. endif
  2506. endif
  2507.  
  2508. if SR
  2509.     test    su_mu_vs$[di],VTERM_EMU ; test setup bit for installed port
  2510.     jz    no_vterm        ;  to see if sun river emulation required
  2511.     mov    al,su_mu_vs$[di]    ; get number of virtuals per physical
  2512.     and    al,07h            ;  mask number of virtuals
  2513.     push    ax
  2514.     push    cx
  2515.  
  2516.     mov    bx,offset sr_pc_table$-1 ; Sun River physical console table
  2517. find_free_pc:
  2518.     inc    bx
  2519.     cmp    byte ptr[bx],0ffh    ; free ?
  2520.     jne    find_free_pc
  2521.     mov    [bx],dl            ; current PC number
  2522.     
  2523.     mov    bx,offset sr_vs_table$-1 ; Sun River virtual console table
  2524. find_free_vs:
  2525.     inc     bx
  2526.     cmp    byte ptr[bx],0ffh    ; free ?
  2527.     jne    find_free_vs
  2528. insert_vs:
  2529.     mov    [bx],cl            ; current VS number
  2530.     inc    cl
  2531.     inc    bx
  2532.     dec    al            ; number of virtual per physical
  2533.     jnz    insert_vs
  2534.     pop    cx
  2535.     pop    ax
  2536.  
  2537. no_vterm:
  2538. endif
  2539.  
  2540. build_ccb:            ; re-allocate the CCB's
  2541.     mov    bl,cl            ; current VS number to assign
  2542.     xor    bh,bh
  2543.     shl    bx,1
  2544.     mov    si,ccb_list$[bx]    ; get free CCB
  2545.     mov    C_PC[si],dl        ; insert physical console number
  2546.     mov    C_VC[si],cl        ;  and virtual console number
  2547. if V386
  2548.                 ; If PCTERM or SunRiver then setup CCBs
  2549.     test    su_mu_vs$[di],PCTERM_EMU or VTERM_EMU
  2550.                     ; test setup bit for installed port
  2551.     jz    no_pcterm1        ;  to see if pcterm emulation required
  2552.     mov    C_ATTR[si],CA_25LINES + CA_ANSI+ CA_ROS + CA_HARDWARE
  2553.     push    si
  2554.     push    ax
  2555.     mov    al,int17_ptr$        ; get count of LPT's
  2556.     mul    cl            ; * VS number
  2557.     mov    si,offset int17_ptr$
  2558.     inc    si
  2559.     add    si,ax            ; point to table for VS
  2560.     mov    ax,di            ; current port number
  2561.     add    al,3            ; main box parallel printer numbers
  2562.     mov    [si],al            ; LPT1 = parallel on terminal
  2563.     test    su_mu_vs$[di],VTERM_EMU    ; test if SR terminal
  2564.     jz    pcterm1a        ; no leave COM settings
  2565.  
  2566.     mov    al,int14_ptr$        ; get count of COM's
  2567.     mul    cl            ; * VS number
  2568.     mov    si,offset int14_ptr$    ; COM table
  2569.     inc    si
  2570.     add    si,ax            ; point to table for VS
  2571.     mov    ax,di            ; current port number
  2572.     inc     al            ; next port number
  2573.     mov    [si],al            ; COM1 
  2574.     inc si ! inc al
  2575.     mov    [si],al            ; COM2
  2576. pcterm1a:
  2577.     pop    ax
  2578.     pop    si
  2579.  
  2580. no_pcterm1:
  2581. endif
  2582.     inc    cl            ; next VS
  2583.     inc    ncondev$        ; update # of virtual consoles
  2584.     inc    nvcons$            ; update SYSDAT
  2585.     inc    nvcns$            ; update XIOS header
  2586.     dec    al            ; number of virtuals
  2587.     jz    term_ccb        ; no more...
  2588.     inc bx ! inc bx            ; pointer to next free CCB    
  2589.     mov    bx,ccb_list$[bx]    ; offset of next free CCB
  2590.     mov    C_LINK[si],bx        ;  and link to current
  2591.     mov    C_STATE[bx],CSM_BACKGROUND ; set to background
  2592.     jmps    build_ccb
  2593.  
  2594. term_ccb:
  2595.     mov    C_LINK[si],0000h    ; terminate CCB    
  2596. alloc_ser_next:
  2597.     inc    di            ; pointer to next serial port
  2598.  
  2599. if SR
  2600.     cmp    di,NUM_AUX_PORTS + NUM_SR_PORTS    ; for SUN RIVER system
  2601. else
  2602.     cmp    di,NUM_AUX_PORTS
  2603. endif
  2604.      je    alloc_ser_end
  2605.      jmp    alloc_ser_loop        ; do more
  2606. alloc_ser_end:
  2607.     ret
  2608.  
  2609. if V386
  2610. build_flush:
  2611.     push    di
  2612.     mov    bx,offset flushstr
  2613.     call    make_rsp        ; create flush process for this console
  2614.     pop    di
  2615.     ret
  2616. endif
  2617.  
  2618. if 0 ;#IJ
  2619. build_pin:
  2620.     push    di
  2621.     mov    bx,offset pinstr
  2622.     call    make_rsp        ; use common V5.x code
  2623.     pop    di
  2624.     ret
  2625. endif
  2626.  
  2627. make_rsp:
  2628. ;--------
  2629. ;    entry:    BX = offset of RSP name string
  2630. ;        DL = physical console number
  2631. ;        CL = virtual console number
  2632. ;    note:    This code only works for up to 10 copies
  2633. ;        of an RSP (as it uses single digit #'s).
  2634.  
  2635.     push     es        
  2636.     push    cx            ; save virtual
  2637.     push    dx            ; and physical
  2638.     add    dl,'0'            ; convert to ASCII digit
  2639.     mov    si,bx            ; find copy number in RSP name
  2640. make_rsp1:
  2641.     lodsb                ; get character from RSP name
  2642.     cmp    al,'0'            ; is it a digit?
  2643.      jb    make_rsp1        ; get next one if not
  2644.     cmp    al,'9'            ; is it a digit?
  2645.      ja    make_rsp1        ; get next one if not
  2646.     dec    si            ; SI -> digit in name
  2647.     mov    [si],dl            ; update the name with copy #
  2648.     call    find_rsp        ; does the RSP exist already?
  2649.      jnc    make_rsp9        ; don't create if already exists
  2650.  
  2651.     mov    byte ptr [si],'0'    ; look for 1st copy of RSP in system
  2652.     call    find_rsp        ; locate "<rsp>0"
  2653.      jnc    found_rsp        ; if no RSP 0 then try RSP 1
  2654.  
  2655.     mov    byte ptr [si],'1'    ; look for 1st copy of RSP in system
  2656.     call    find_rsp        ; locate "<rsp>1"
  2657.      jc    make_rsp9        ; if no RSP 1 then exit
  2658.  
  2659. found_rsp:
  2660.     ; Concurrent 6.0 GENSYS stores the group sizes
  2661.     ; in the RSP header. Much more convenient...
  2662.  
  2663.     push    es
  2664.     mov    es,ax            ; AX = base of 1st RSP
  2665.     mov    dx,RSPH_DGSIZE        ; DX = size of RSP data segment
  2666.     pop    es
  2667.     sub    si,bx            ; SI = offset of number in name
  2668.     push    si            ; save ASCII digit index
  2669.  
  2670.     push dx ! push ax        ; save size & base of RSP
  2671.     call    mem_alloc_i@        ; allocate one RSP (DX paragraphs)
  2672.     mov    es,ax            ; ES -> space for new RSP image
  2673.     pop  dx ! pop  cx        ; restore base & size of RSP
  2674.  
  2675.     push    ds            ; save our data segment
  2676.     mov    ds,dx            ; DS = existing RSP
  2677.     shl    cx,1            ; copy 8 words per paragraphs
  2678.     shl    cx,1
  2679.     shl    cx,1
  2680.     sub    si,si            ; copy from beginning of segment
  2681.     sub    di,di            ;        to beginning of segment
  2682.     rep    movsw            ; make an identical copy of the RSP
  2683.     pop    ds
  2684.  
  2685.     pop    si            ; restore ASCII digit address
  2686.     pop    ax            ; AX = physical console number
  2687.     pop    cx            ; and virtual console number
  2688.     push    cx
  2689.     push    ax            ; and resave
  2690.     mov    RSPH_NCP,al        ; set NCP field to physical console #
  2691.     mov    RSPH_PCNS,cl        ; put VC number in RSP
  2692.     add    al,'0'            ; ASCII console #
  2693.     mov    RSPH_PDNAM[si],al    ; set physical console # in PD name
  2694.     mov    ax,es            ; get RSP data segment
  2695.     mov    RSPH_INITDS,ax        ; set initial DS in UDA
  2696.     mov    RSPH_INITES,ax        ; set initial ES in UDA
  2697.     mov    RSPH_INITSS,ax        ; set initial SS in UDA
  2698.     mov    ax,rspseg$
  2699.     mov    RSPH_LINK,ax        ; link RSP into linked list
  2700.     mov    rspseg$,es
  2701. make_rsp9:
  2702.     pop dx ! pop cx            ; retore physical and virtual consoles
  2703.     pop    es 
  2704.     ret
  2705.  
  2706. find_rsp:                    ; BX = modified name
  2707. ;--------
  2708. ;    entry:    BX -> 8 byte RSP name to locate
  2709. ;    exit:    AX = data segment of RSP, CY = 0
  2710. ;        or CY = 1, RSP not found
  2711. ;    note:    BX,SI preserved
  2712.  
  2713.     mov    cx,rspseg$            ; search through RSP list
  2714.     call    find_rsp2            ; try to locate RSP in phase 2
  2715.      jc    find_rsp1            ; skip if not in phase 2 list
  2716.     ret                    ; else return with AX = RSP seg
  2717. find_rsp1:
  2718.     mov    cx,phase1_root$            ; search trough phase 1 RSPs
  2719. ;    call    find_rsp2            ; try to locate RSP in phase 1
  2720. ;    ret                    ; return with AX = RSP or CY on
  2721.  
  2722. find_rsp2:                    ; locate RSP name BX in list CX
  2723.      jcxz    find_rsp4            ; RSP not found
  2724.     mov    es,cx                ; ES = next RSP to check
  2725.     push    si
  2726.     mov    si,bx                ; DS:SI = name
  2727.     mov    di,offset RSPH_PDNAM        ; ES:DI -> RSP name
  2728.     mov    cx,4                ; check if 8 byte match
  2729.     repe    cmpsw                ; is this the name we want?
  2730.     pop    si
  2731.      je    find_rsp3            ; yes, found the RSP
  2732.     mov    cx,RSPH_LINK            ; else get the next one
  2733.     jmps    find_rsp2            ; and try again
  2734. find_rsp3:
  2735.     mov    ax,es                ; return RSP segment in ES & AX
  2736.     clc
  2737.     ret
  2738. find_rsp4:                    ; RSP not found
  2739.     stc
  2740.     ret
  2741.  
  2742. eject
  2743.  
  2744. alloc_virt_screens:
  2745. ;------------------
  2746.     test    video$,EGA+VGA+MCGA    ; do we have MCGA/EGA or VGA?
  2747.      jz    init_v0            ; skip if no EGA/VGA
  2748.                     ; We want a buffer to save the
  2749.                     ;   2nd bit plane on screen
  2750.                     ;   switches...allocate:
  2751.     mov    dx,PLANE2_LENGTH/16    ; get size required - 8k
  2752. if SR
  2753.     mov    cx,(PAGE_SIZE)/16 -1    ; align on 4k boundary    
  2754.     call    io_mem_alloc@        ; to allow SR pc's to be mapped
  2755.     mov    cx,ax
  2756.     shr    cx,6            ; (/100h*4) - page table entry
  2757.     mov    ptbl_bit_plane$,cx    ; save in SRTERM.A86
  2758.  
  2759. else
  2760.     call    mem_alloc_i@
  2761. endif
  2762.     mov    bit_plane_seg$,ax    ; save segment for IO_SWITCH
  2763. init_v0:
  2764.  
  2765. ; Set up the virtual screen structures (one per virtual console)
  2766. ; and blank out their screen save areas.
  2767. ; We now call the low-mem allocator at INIT time rather than letting
  2768. ; GENCCPM put the buffers at the end of the system image.
  2769.  
  2770.     xor    bx,bx            ; 1st VC
  2771.     mov    cx,NUM_VIR_CONS
  2772. if SR
  2773.     xor    di,di
  2774. endif
  2775. init_v1:
  2776.     push    cx ! push bx
  2777. if V386
  2778.     push    di
  2779.     mov    dx,1024*4/16        ; allocate 4k VC buffer
  2780.      mov    cx,(1 shl 12)/16 -1    ;(PAGE_SIZE)/16 -1    
  2781.                     ; align on 4k boundary    for mapping
  2782.      call    io_mem_alloc@
  2783.     pop     di
  2784. if SR
  2785.     mov    cx,ax
  2786.     shr    cx,6            ; (/100h*4) - page table entry
  2787.     mov    ptbl_vc_save$[di],cx    ; save in SRTERM.A86
  2788.     mov    vc_seg_save$[di],ax    ; save for SRTERM.A86
  2789.     add    di,2
  2790. endif
  2791. else
  2792.     mov    dx,((CRT_ROWS_P*CRT_COLS+15) shr 4) * 2    ; segment size
  2793.     call    mem_alloc_i@
  2794. endif
  2795.     pop    bx ! push bx
  2796.     mov    bx,table_vs$[bx]    ; get VS_
  2797.     mov    VS_VC_SEG,ax        ; tell each vs_ where to find
  2798.     pop    bx ! pop cx        ;   its buffer segment
  2799.     add    bx,2            ; next VC_
  2800.     cmp    cx,NUM_VIR_CONS
  2801.      jne    init_v2            ; skip if not first VC
  2802.     mov    genccpm_buf$,ax        ; in case someone wants it
  2803. init_v2:
  2804.     loop    init_v1
  2805.  
  2806.  
  2807.     mov    dx,((CRT_ROWS_P*CRT_COLS+15) shr 4) * 1    ; for vc_map_seg
  2808.     call    mem_alloc_i@
  2809.     mov    vc_map_seg$,ax        ; ownership map segment
  2810.  
  2811.     mov    es,ax            ; now set up the initial map
  2812.     sub    di,di            ; top left corner
  2813.     mov    cx,CRT_ROWS_P*CRT_COLS
  2814.     mov    al,(1 shl NUM_VIR_CONS)-1    ; all bits on
  2815.     cld
  2816.     rep    stosb                ; fill the map
  2817.  
  2818.     xor    bx,bx            ; 1st VC
  2819.     mov    cx,NUM_VIR_CONS
  2820.     mov    ah,iattrib$        ; get default atribute
  2821.     mov    dx,save_equip$        ; get PC equipment flag
  2822. init_v3:
  2823.     push    bx ! push cx
  2824.     mov    bx,table_vs$[bx]    ; get VS_
  2825.     mov    VS_ATTRIB,ah        ; Save the default attribute 
  2826.     mov    VS_PC_EQUIP,dx        ; save power up equipment word
  2827.     mov    es,VS_VC_SEG        ; point to image
  2828.     sub    di,di
  2829.     mov    cx,CRT_ROWS_P*CRT_COLS
  2830.     mov    al,' '            ; default attribute + space
  2831.     rep    stosw            ; fill with blanks
  2832.     pop    cx ! pop bx
  2833.     add    bx,2            ; next virtual console
  2834.     loop    init_v3
  2835.  
  2836.     push    ds ! pop es        ; local extra segment
  2837.     mov    di,offset vc_priority$    ; vc priority list
  2838.     mov    al,NUM_VIR_CONS-1
  2839. init_v4:
  2840.     stosb                ; lowest priority first
  2841.     dec    al
  2842.      jns    init_v4            ; do through zero
  2843.     jmp    new_monitor@        ; set up initial windows
  2844. eject
  2845. do_setup:
  2846. ;--------
  2847. ; Do the SETUP customizing of the XIOS:
  2848.     cmp    su_check$,0DDB2h        ; check for secret code
  2849.      jmpnz    setup_done            ; if bad, bag it
  2850.  
  2851. ; At this point, the SETUP block is a winner.
  2852.     mov    ax,su_timer_count$
  2853.     mov    timer_count$,ax            ; for a dif. clock
  2854.     mov    al,su_verf$
  2855.     mov    verify_flag$,al            ; whether to verf after write
  2856.     mov    ax,su_mmp$            ; max mem per process
  2857.     mov    mmp$,ax                ; tell the system
  2858.     mov    al,su_scroll$
  2859.     mov    scroll_mode$,al            ; for the color monitor
  2860.     mov    ax,su_ser_con$
  2861.     mov    word ptr term_data,ax        ; for COM1/COM2 consoles
  2862.  
  2863. ; Serial com setup is done in do_aux_ports.
  2864.  
  2865. ; Adjust the floppy parameter string from the setup info.
  2866.  
  2867.     test    su_fdc_check$,0ffh        ; did the user change it?
  2868.      jz    fdc_done            ; no...don't use them
  2869.     mov    dl,su_fdc_spec1$        ; head step code
  2870.     mov    dh,su_fdc_spec2$
  2871.     mov    cl,su_fdc_settle$        ; head settle
  2872.     mov    ch,su_fdc_spinup$
  2873.  
  2874.     push    es
  2875.      sub    ax,ax
  2876.      mov    es,ax
  2877.      les    si,es:dword ptr.INT_1E_VEC_OFF
  2878.      mov    es:[si],dx            ; store specify bytes
  2879.      mov    es:9[si],cx            ; and timing bytes
  2880.     pop    es
  2881.  
  2882.     call    flop_specify@            ; set head step speed
  2883.  
  2884. fdc_done:
  2885.     cmp    su_cf$,0            ; check the config flag
  2886.      jz    setup_pfks            ; if not saved, skip
  2887.  
  2888.     mov    ax,su_config$
  2889.     mov    config_data,ax            ; save both codes
  2890.  
  2891. ; Move the SETUP protocol bytes to the aux blocks:
  2892.     push ds ! pop es            ; local move
  2893.     mov    cx,4                ; bytes to move
  2894.     mov    bx,0
  2895.     mov    si,offset su_prot$
  2896. setup_prot:
  2897.     mov    di,aux_prot_blk$[bx]        ; get block prot pointer
  2898.     movsb                    ; put the byte
  2899.     dec    di
  2900. ;;    test    byte ptr [di],XON_XOFF        ; software protocol ?
  2901. ;;    jz    setup_prot1
  2902.     mov    word ptr (AUX_ON - AUX_PROT)[di], XON + 256*XOFF
  2903.     push    di                ; if not a PCTERM then we
  2904.     mov    di,bx                ; leave XON/XOFF, else
  2905.     shr    di,1                ; we want XPC protocols
  2906.     and    di,1
  2907.     test    mu_com_type$[di],1        ; is it a terminal ?
  2908.      jz    setup_port2
  2909.     test    su_mu_vs$[di],PCTERM_EMU    ; is it a PC terminal ?
  2910. setup_port2:
  2911.     pop    di
  2912.      jz    setup_prot1            ; then we use XPC protocols
  2913.     mov    word ptr (AUX_ON - AUX_PROT)[di], XPCON + 256*XPCOFF
  2914. setup_prot1:
  2915.     inc bx ! inc bx                ; next pointer
  2916.     loop    setup_prot            ; next block
  2917.  
  2918. setup_pfks:
  2919.     cmp    su_pf$,0            ; check the pfk flag
  2920.      jz    setup_done            ; if not saved, finished
  2921.  
  2922.     push ds ! pop es            ; local es
  2923.     mov    di,offset pfk_tbl0$        ; first pfk
  2924.     mov    bx,NUM_VIR_CONS            ; number of pfk tables
  2925. setup_pfk_loop:
  2926.     mov    si,offset su_pfk_tbl$        ; the saved values
  2927.     mov    cx,180                ; words per pfk table
  2928.     rep    movsw                ; copy 'em
  2929.     dec    bx
  2930.      jnz    setup_pfk_loop            ; for each console
  2931. setup_done:
  2932.     ret
  2933. eject
  2934.  
  2935. flop_off:
  2936. ;--------
  2937. ; Turn off the floppy motors before taking over interrupts:
  2938.  
  2939.     mov    dx,FDC_PORT
  2940.     mov    al,FDC_ON        ; turn off floppy motors
  2941.     mov    motor_flags$,al        ; or they may stay on forever
  2942.     out    dx,al
  2943.     ret
  2944.  
  2945.  
  2946. eject
  2947.  
  2948. floppy_hash:
  2949. ;-----------
  2950. ; Allocate hash tables/FAT buffers/DDSC structures for the real floppies:
  2951.  
  2952.     mov    cx,num_flop$        ; how many are there
  2953.      jcxz    flop_hash_done        ; skip if nobody
  2954.  
  2955.     mov    bx,offset dph_tbl$    ; floppies are first here
  2956. flop_hash_loop:
  2957.     push    bx ! push cx        ; preserve loop variables
  2958.     mov    si,[bx]            ; point to the dph
  2959.                     ; sectors_per_track * nheads * ntracks
  2960.                     ; / sectors_per_clusters
  2961.                     ; / (sectors_size/2)
  2962.                     ; / (words_per_paragraph)
  2963.                     ; + 3 extra paragraphs
  2964.     mov    dx,(18*2*80/1/256/8)+3    ; big enough for 1.44 Mb drives
  2965.     push    si
  2966.     call    mem_alloc_i@        ; allocate block for hash table (CP/M)
  2967.     pop    si            ;    or FAT image (DOS) or DDSC (6.0)
  2968.     mov    DPH_HSTBL[si],ax
  2969.     mov    dx,(9*2+224/4+15)/16    ; max = 9 FAT sects, 224 dir entries
  2970.     push    si
  2971.     call    mem_alloc_i@        ; allocate check sum vector
  2972.     pop    si
  2973.     mov    DPH_CSV[si],ax        ; CSVs are segment based in 6.0
  2974.     pop    cx ! pop bx        ; restore loop variables
  2975.     inc bx ! inc bx            ; point to next dph
  2976.     loop    flop_hash_loop        ; and do another
  2977. flop_hash_done:
  2978.     ret
  2979.  
  2980.  
  2981. pc_hash_alloc:
  2982. ;-------------
  2983. ; Subroutine to allocate a hash table for a pc hard disk partition
  2984. ; Entry:    es:si -> dph
  2985.  
  2986.     mov    di,es:DPH_DPB[si]        ; point to dpb
  2987.     mov    ax,es:PCDPB_NCLSTRS[di]        ; get number of clusters
  2988.     mov    cl,es:PCDPB_PSH[di]        ; get sector shift
  2989.     add    cl,6+3                ; log2(words/sect) + log2(word/para)
  2990.     shr    ax,cl                ; AX = # of words
  2991.     add    ax,3                ; round up + DDSC
  2992. ;    jmps    hash_alloc            ; fall through
  2993.  
  2994. hash_alloc:
  2995. ; Subroutine to allocate one hash table at top of available memory:
  2996. ; That's what the 4 commented instructions would do.  Now we (eventually)
  2997. ; call the allocator to put them low.  More buggy programs destroy high memory
  2998. ; than low. (Thx GP)  Here we just store the addresses and sizes to be
  2999. ; actually allocated at the END of INIT, when all allocations which require
  3000. ; SYSDAT space have hopefully been done.
  3001.  
  3002. ; entry:    es:si -> dph
  3003. ;        ax = hash table size in paragraphs
  3004.  
  3005.     push    bx
  3006.     mov    bx,offset alloc_table - 6    ; 1st find space in the table
  3007. lph:
  3008.     add    bx,6
  3009.     test    word ptr [bx],0ffffh        ; anyone there?
  3010.      jnz    lph
  3011.  
  3012.     mov    4[bx],ax            ; store size required
  3013.     lea    ax,DPH_HSTBL[si]        ; where will it go
  3014.     mov    2[bx],es            ; segment
  3015.     mov    [bx],ax                ; and offset
  3016.     pop    bx
  3017.     ret
  3018.  
  3019.  
  3020.  
  3021. eject
  3022.  
  3023. ;    The following  function  locates a 512 byte block in SYSDAT which
  3024. ;    can be used as a temporary buffer for logging in hard disks.  Any
  3025. ;    such buffer  must not cross  a 64K boundary  in case the ROM BIOS
  3026. ;    doesn't  support disk transfers  across 64K banks (e.g. IBM XT).
  3027.  
  3028. ;    After  the XIOS initialization  is done,  local_buffer$  will  be
  3029. ;    pointing  at reused  space  inside  the INIT module.   Therefore,
  3030. ;    local_buffer$ has to point to a temporary buffer at INIT time for
  3031. ;    any code that might  reference  local_buffer$,  such  as the hard
  3032. ;    disk login code.
  3033.  
  3034. find_dskbuf:
  3035. ;-----------
  3036.  
  3037.     mov    bx,62*1024        ; use high end of SYSDAT segment
  3038.                     ; we normally only use the 1st half
  3039.     mov    ax,ds
  3040.     mov    cl,4
  3041.     shl    ax,cl            ; AX = offset of SYSDAT in 64 K bank
  3042.     add    ax,bx            ; AX = offset of buffer in 64 K bank
  3043.     cmp    ax,(-512)        ; will one physical sector fit?
  3044.      jb    find_buf1        ; no, try next buffer
  3045.     neg    ax            ; AX = # of bytes til 64K boundary
  3046.     add    bx,ax            ; move BX up to 64K boundary
  3047. find_buf1:
  3048.     mov    local_buffer$,bx    ; set pointer to local buffer
  3049.     ret
  3050.  
  3051.  
  3052. alloc_dskbuf:
  3053. ;------------
  3054. if V386
  3055.     mov    dx,local_bsize        ; 1 Kb/2 Kb deblocking buffer
  3056.     shl    dx,1            ; make it twice as large
  3057.     add    dx,16            ;   and a bit more
  3058.                     ;   as we might move SYSDAT on 386
  3059.                     ;   and we could then have to move
  3060.                     ;   LOCAL_BUFFER$ to avoid DMA trouble
  3061.     call    sysdat_mem_alloc    ; allocate in SYSDAT
  3062.     mov    local_buffer$,ax    ; save for FLOPPY/HDISK code
  3063. endif
  3064. if XM
  3065.     mov    dx,local_bsize        ; 1 Kb local deblocking buffer
  3066.     call    sysdat_mem_alloc    ; allocate in SYSDAT
  3067.     mov    local_buffer$,ax    ; save for FLOPPY/HDISK code
  3068.     mov    dx,ds
  3069.     mov    cl,4
  3070.     shl    dx,cl            ; DX = offset of SYSDAT in 64K bank
  3071.     add    ax,dx            ; AX = offset of buffer in 64K bank
  3072.     add    ax,local_bsize        ; check for DMA boundary problem
  3073.      jc    alloc_dskbuf        ; if any problem, redo it
  3074. endif
  3075.     ret
  3076.  
  3077.  
  3078. if V386
  3079. align_dskbuf:
  3080. ;------------
  3081.     mov    ax,ds
  3082.     mov    cl,4
  3083.     shl    ax,cl            ; AX = A0..A15 of DS base address
  3084.     add    ax,local_buffer$    ; AX = A0..A15 of local_buffer base
  3085.     or    ax,0C000h        ; make any 16K boundary look like 64K
  3086.     not    ax            ; AX = # of bytes left in 16K page
  3087.     cmp    ax,local_bsize        ; enough space in page for DMA?
  3088.      jae    align_dskbuf1        ; yes, use current buffer offset
  3089.     inc    ax
  3090.     and    ax,-2            ; else round up to next even number
  3091.     add    local_buffer$,ax    ; move buffer past the DMA boundary
  3092. align_dskbuf1:
  3093.     mov    ax,ds            ; get XIOS data segment
  3094.     push    ds
  3095.     sub    cx,cx
  3096.     mov    ds,cx            ; DS -> 8086 interrupt vectors
  3097.     mov    .INT_1E_VEC_SEG,ax    ; relocate ROS floppy paramters 
  3098.     pop    ds            ;  in case we've been moved
  3099.     ret
  3100. endif
  3101.  
  3102.  
  3103. hd_init: 
  3104. ;-------
  3105.  
  3106. ; Cold start setup for XT hard disk driver;
  3107. ; needs to do these things:
  3108. ;    0)    setup int 15 vector if AT (int POST and WAIT)
  3109. ;    .5)    setup hd hard interrupt if XT
  3110. ;    1)    setup floppy interrupt trap
  3111. ;    2)    save disk interrupt vector for far call usage
  3112. ;    2.5)     or insert our own XT driver
  3113. ;    3)    initialize HDINF vectors about physical drive char.
  3114. ;    4)    try to login both hard disks
  3115. ;    5)    decide who will be system disk and temp disk
  3116. ;
  3117. ;    ALSO builds hard disk DPH's and DPB's dynamically
  3118. ;    and disk table setup moved from fix_disk_tables routine.
  3119. ;
  3120. ; This code assumes that it is running in XIOS codeseg and that
  3121. ; the floppy initialization has already been done.
  3122.  
  3123.     push    ds
  3124.     push    es
  3125.     xor    ax,ax
  3126.     mov    es,ax                ;point to vector seg
  3127.  
  3128. ;hd_patch_step_rate:                ;step option bits off
  3129. ;    and    es:byte ptr .HD_CONTROL_BYTE,0F8h or (not SLOW_SEEK)
  3130. ; Why the and w/ FF instruction above?
  3131.  
  3132.     les    ax,es:.HD_PTR            ;get hard disk sw int ptr
  3133.     mov    hd_rom_seg$,es
  3134.     mov    hd_rom_ofs$,ax            ;to local link address
  3135.  
  3136.     mov    disk_int_off$,ax        ;save for dskmaint too
  3137.     mov    disk_int_seg$,es
  3138.  
  3139. ; See if we have any hard disks at all:
  3140.  
  3141.     mov    cx,num_hard$
  3142.     or    cx,cx
  3143.     jnz    fix_hd
  3144.     jmp    hd_init_done
  3145.  
  3146. fix_hd:
  3147.     mov    al,0            ; first hard disk
  3148.     mov    di,pc_hd_dph_start    ; pointer to DPH next entry
  3149. fix_disk_loop:
  3150.     mov    drive_num,al        ; store current drive number
  3151.     push    cx            ; save number of disks
  3152.     push    di            ; and DPH pointer
  3153.  
  3154.     mov    dl,al
  3155.     or    dl,80h                ;ask about 1st drive
  3156.     mov    ah,8
  3157.     push    ax
  3158. ;    pushf ! callf hd_rom_entry$        ;if a drive is present
  3159.     int    DISK_INT
  3160.     pop    ax
  3161.      jnc    hd_init_pc0            ;  then try to log pc part
  3162.     pop    di
  3163.     jmp    fix_disk1            ;  else try next drive
  3164.  
  3165. ; Now try to log in first pc dos partition:
  3166.  
  3167. hd_init_pc0:
  3168.     mov    dl,HDINF_SIZE
  3169.     xor    ah,ah
  3170.     mul    dl
  3171.     lea    si,hd_disk_info$    ; if drive is there then
  3172.     add    si,ax
  3173.     call    hd_init_hdinf        ;  set its info vector
  3174.  
  3175.     call    read_sector0        ; read master partition table
  3176.     pop    di
  3177.     or    al,al            ; physical disk error ?
  3178.      jnz    fix_disk1        ; yes, skip the drive
  3179.     mov    bx,local_buffer$
  3180.     cmp    XTLBL_ID[bx],IBM_SYS_ID    ; does it have IBM label?
  3181.      jnz    fix_disk1
  3182.     lea    bx,XTLBL_PART1[bx]    ; setup to scan for DOS partition
  3183.     mov    cx,4            ; four partitions possible
  3184. do_all_parts:
  3185.     mov    al,XT_PT_SYSTEM[bx]    ; fetch SYS ID
  3186.     cmp    al,HD_DOS_ID1        ; type 1
  3187.      je    pc_hd_dos_found
  3188.     cmp    al,HD_DOS_ID4        ; type 4
  3189.      je    pc_hd_dos_found
  3190.     cmp    al,HD_DOS_ID6        ; type 6
  3191.      je    pc_hd_dos_found
  3192.     jmps    next_pc_part        ; go search next partition
  3193. pc_hd_dos_found:            ; found a DOS partition
  3194.     mov    hd_dos_sys_id,al    ; save for extflag
  3195.     mov    al,XT_PT_BOOTFL[bx]    ; get boot flag
  3196.     cmp    al,80h            ; is it a bootable partition
  3197.      jne    setup_pt        ; no 
  3198.     cmp    drive_num,0        ; Check that only partitions
  3199.      jne    setup_pt        ; on drive zero are made the
  3200.     mov    ax,di            ; boot drive.
  3201.     shr    al,1            ; DI = word pointer to current drive
  3202.     mov    hd_boot_flag$,al    ; save boot drive so
  3203.                     ;   init can pick up sysdisk
  3204. setup_pt:
  3205.     push    cx
  3206.     call    fix_pc_hd        ; set dph, dpb and vectors
  3207.     push bx ! push di
  3208.     call    read_sector0        ; re-read sector 0 into local_b
  3209.     pop di ! pop bx
  3210.     pop    cx            ; restore partition count
  3211.     or    al,al            ; physical disk error ?
  3212.      jnz    fix_disk1        ; yes, done with drive
  3213.                     ; login drive DPB and alloc hash
  3214. next_pc_part:
  3215.     add    bx,XT_PT_REC_SIZE    ; point to next partition entry
  3216.     loop    do_all_parts        ; repeat for all partitions
  3217.  
  3218.     call    do_ext_part        ; handle extended partitions
  3219. fix_disk1:
  3220.     pop    cx            ; restore drive count
  3221.     mov    al,1            ; second drive number
  3222.     dec    cx
  3223.      jz    fix_done
  3224.     jmp    fix_disk_loop        ; setup second Hard disk
  3225.  
  3226. ;*****
  3227. fix_done:
  3228.     mov    al,hd_boot_flag$        ; save the boot drive in case we
  3229.     mov    pc_pt_bootable,al         ;   want to override cp/m sysdisk
  3230.     mov    dsrchdisk$,al             ; SYS and TEMP disks now
  3231.     mov    temp_disk$,al             ;   point to boot dos partition
  3232.  
  3233.     mov    hd_dph_start,di            ; pointer to DPH next entry
  3234.  
  3235.  
  3236. hd_init_done:
  3237.     mov    hd_init_flag$,0ffh        ; set XIOS initialized flag
  3238.     pop    es                ; (which enables error handler)
  3239.     pop    ds
  3240.  
  3241.     test    boot_drive,80h            ; if we booted from hard disk
  3242.      jnz    hd_init_vect            ;  then skip sys_disk poke
  3243.     mov    al,boot_drive
  3244.     mov    dsrchdisk$,al            ; system disk = entry drive
  3245.  
  3246. hd_init_vect:
  3247.     push    es
  3248.     sub    ax,ax
  3249.     mov    es,ax
  3250.  
  3251. if XM                        ; -not on CDOS 386-
  3252.     test    pc_at$,01h            ; if XT, not AT, stick in
  3253.      jnz    at_int15            ; our own hd hw interrupt
  3254.     cmp    su_hard_driver$,0        ; but only if our SETUP
  3255.      je    at_int15            ; option tells us so
  3256.  
  3257. ;    mov    es:word ptr .HD_HARD_INTERRUPT*4, offset hd_isr@ ; handler
  3258. ;    mov    es:word ptr .HD_HARD_INTERRUPT*4 +2,cs
  3259. TARGET equ HD_HARD_INTERRUPT * 4
  3260. TARGET1 equ TARGET + 2                ; thanks RASM
  3261.  
  3262.     mov    es:word ptr .TARGET,offset hd_isr@
  3263.     mov    es:.TARGET1,cs
  3264.  
  3265.     mov    al,es:control_byte_40 + 400h    ; and get the step bits
  3266.     mov    hd_cmd_blk$ + 5,al        ; into our command string
  3267.  
  3268.     mov    hd_rom_seg$,cs            ; we now have our own driver
  3269.     mov    hd_rom_ofs$,offset xt_driver@
  3270. ;    jmps    hd_init_quit
  3271. endif                        ; endif XM
  3272.  
  3273. at_int15:
  3274. ; Here we must save and set the int 15h vector.  This int is used on
  3275. ; the AT for the hard disk device-post/wait idea.
  3276. ; Removed:   17 SEP 85
  3277. ; Reenabled: 12 JUN 87
  3278.  
  3279. TARGET2 equ 15h*4
  3280. TARGET3 equ TARGET2 + 2
  3281.     mov    ax,es:.TARGET2            ; save int 15 address
  3282.     mov    word ptr old_int15$,ax
  3283.     mov    ax,es:.TARGET3
  3284.     mov    word ptr old_int15$ +2,ax
  3285.  
  3286.     mov    es:word ptr .TARGET2,offset int15_isr@
  3287.     mov    es:.TARGET3,cs
  3288.  
  3289. hd_init_quit:
  3290.     pop    es
  3291.     ret
  3292.  
  3293.  
  3294.  
  3295. ; Handle extended partitioning scheme in DOS 3.3:
  3296. ; Entry: local_buffer$ contains master partition table
  3297.  
  3298. do_ext_part:
  3299. ;-----------
  3300.                     ; now check for 3.3 extended partitions
  3301.                     ; local_buffer$ contains either
  3302.                     ;   the master partition table (1st time)
  3303.                     ;   or an extended partition table
  3304.     mov    bx,local_buffer$    ; get local deblocking buffer
  3305.     lea    bx,XTLBL_PART1[bx]    ; setup to scan through table
  3306.     mov    cx,4            ; scan up to four entries
  3307. extscn_lp1:
  3308.     mov    al,XT_PT_SYSTEM[bx]    ; fetch SYS ID
  3309.     cmp    al,5            ; 3.3 extended partition?
  3310.      jne    extscn_nxt2        ; no, go & check next one
  3311.     mov    cl,XT_PT_START_SECTOR[bx]
  3312.     mov    ch,XT_PT_START_CYLINDER[bx]
  3313.     mov    dh,XT_PT_START_HEAD[bx]    ; starting head (<> 0)
  3314.     push    cx ! push dx        ; save this for re-reading sector
  3315.                     ;   after logging in DOS partition
  3316.     push    bx ! push di
  3317.     call    read_sector        ; read 1st sector of extended partition
  3318.     pop    di ! pop bx
  3319.                     ; now scan for DOS partition in there:
  3320.     mov    bx,local_buffer$    ; get local deblocking buffer
  3321.     lea    bx,XTLBL_PART1[bx]    ; setup to scan through table
  3322.     mov    cx,4            ; scan up to four entries
  3323. extscn_lp2:
  3324.     mov    al,XT_PT_SYSTEM[bx]    ; fetch SYS ID
  3325.     cmp    al,HD_DOS_ID1        ; type 1 (12 bit FAT)
  3326.      je    extscn_dos        ; yes, log in the partition
  3327.     cmp    al,HD_DOS_ID4        ; type 4 (16 bit FAT)
  3328.      je    extscn_dos        ; yes, log in the partition
  3329.     cmp    al,HD_DOS_ID6        ; type 6 (16 bit FAT)
  3330.      jne    extscn_nxt1        ; no, try next table entry
  3331. extscn_dos:                ; DOS partition in extended partition
  3332.     mov    hd_dos_sys_id,al    ; save for extflag
  3333.     call    fix_pc_hd        ; set dph, dpb and vectors
  3334.     pop    dx ! pop cx        ; restore extended system
  3335.     push    di
  3336.     call    read_sector        ; read extended partition table
  3337.     pop    di            ; might have another type 5 in there...
  3338.     jmps    do_ext_part        ; so go and scan it again
  3339.  
  3340. extscn_nxt1:                ; entry in ext.part. is not DOS
  3341.     add    bx,XT_PT_REC_SIZE    ; next partition
  3342.     loop    extscn_lp2        ; until all partitions done
  3343.     pop    dx ! pop cx        ; discard address of ext. part.
  3344.     jmps    do_ext_part        ; so go and scan it again
  3345.  
  3346. extscn_nxt2:
  3347.     add    bx,XT_PT_REC_SIZE    ; next partition
  3348.     loop    extscn_lp1        ; until all partitions done
  3349.  
  3350.     ret
  3351.  
  3352.  
  3353. ; Setup table entries for 1 Hard disk DOS partition
  3354. ; build the DPH, DPB  and allocate FAT space.
  3355. ; Entry: BX -> partition table entry for DOS partition
  3356. ;     DI = logical drive*2 (e.g. 2=C:, 3=D:, etc.)
  3357.  
  3358. fix_pc_hd:
  3359.     push    di ! push bx
  3360.     mov    dx,PC_HD_DPH_SIZE+PC_HD_DPB_SIZE
  3361.     add    dph_count,dx        ; total amount reserved
  3362.     call    sysdat_mem_alloc    ; reserve space in sysdat for
  3363.     pop    bx            ; DPH + partition info + DPB
  3364. ;;    or    ax,ax            ;; hope it never rains...
  3365. ;;     jnz    alloc_ok
  3366. ;;    jmp    go_no_more        ; HALT no sysdat space
  3367. ;;alloc_ok:
  3368.     mov    si,dph_tbl$        ; drive A: DPH - use for copy
  3369.     mov    di,ax            ; DPH offset in ES:
  3370.     mov    es,dph_seg        ; temp DPH segment address
  3371.     cld
  3372.     mov    cx,DPH_SIZE        ; size of A: DPH to copy
  3373.     rep    movsb            ; copy A: DPH to share buffers
  3374.     mov    si,bx            ; SI -> part entry in local buffer 
  3375.     mov    cx,XT_PT_REC_SIZE    ; size of one entry in partition table
  3376.     rep    movsb            ; save partition entry for later
  3377.     pop     di            ; restore table pointer (drive*2)
  3378.     mov    si,offset pc_hd_vectors    ; select, read, write pc part
  3379.     push es ! push bx
  3380.     mov    es,dph_seg        ; get DPH temp Seg
  3381.     mov    dph_tbl$[di],ax        ; set dph in header
  3382.     lodsw                ; fetch the select vector
  3383.     mov    select_tbl$[di],ax
  3384.     lodsw                ; fetch the read vector
  3385.     mov    read_tbl$[di],ax
  3386.     lodsw                ; fetch the write vector
  3387.     mov    write_tbl$[di],ax
  3388.  
  3389. ; Now build the DPH
  3390.     push    di
  3391.     mov    di,dph_tbl$[di]        ; get dph offset
  3392.     sub    ax,ax
  3393.     mov    es:DPH_CSV[di],ax    ; no checksum vectors - fixed
  3394.     mov    es:DPH_ALV[di],ax    ; no allocation vectors - DOS media
  3395.     lea    ax,PC_HD_DPH_SIZE[di]    ; AX -> DPB address (after part info)
  3396.     mov    es:DPH_DPB[di],ax    ; save DPB offset in DPH    
  3397.  
  3398. ; Log in the drive DPB
  3399.     push    di            ; save DPH ->
  3400.     call    pc_hd_login        ; Build DPB
  3401.     pop    si            ; restore DPH -> 
  3402.     or    al,al
  3403.      jz    login_ok
  3404.     pop    di            ; login error so
  3405.     mov    dph_tbl$[di],0000    ; reset DPH table for drive
  3406.     jmps    login_exit
  3407.  
  3408. ; Login is successful, allocate the hash table (for FAT):
  3409. login_ok:    
  3410.     mov    es,dph_seg        ; get DPH temp Seg
  3411.     call    pc_hash_alloc        ; save some hash space es:si->DPH
  3412.     pop    di
  3413.  
  3414.     mov    bx,di            ; current pointer
  3415.     mov    si,pc_hd_dph_start    ; pointer to first HD DPH entry
  3416.     sub    bx,si            ; make zero relative table pointer
  3417.     mov    dl,HDINF_SIZE
  3418.     xor    ah,ah
  3419.     mov    al,drive_num        ; current physical drive number
  3420.     mul    dl
  3421.     lea    si,hd_disk_info$    ;if drive is there then
  3422.     add    si,ax            ; setup info vector pointer
  3423.     mov    hdinf_ptr$[bx],si    ; for logical drive number
  3424.  
  3425.     inc di    ! inc di        ; to next vector entry
  3426. login_exit:
  3427.     pop bx ! pop es    
  3428.     ret
  3429.  
  3430.  
  3431. pc_hd_login:
  3432. ;-----------
  3433. ; Builds dpb for DOS partition
  3434.  
  3435. ; ENTRY:    ES:DI -> PC DPH + partition data + DPB
  3436. ; EXIT:        AL = 0 if success, else NZ
  3437.  
  3438.     mov    si,di            ; save DPH ->
  3439.     add    di,DPH_SIZE        ; point to start of saved partition info
  3440.     mov    bx,offset pc_part_table_iopb    ; make boot record IOPB
  3441.     mov    cl,es:XT_PT_START_SECTOR[di]
  3442.     mov    ch,es:XT_PT_START_CYLINDER[di]
  3443.     mov    dh,es:XT_PT_START_HEAD[di]    ; starting head (<> 0)
  3444.     push    bx ! push di ! push si
  3445.     call    read_sector        ; read boot record
  3446.     pop    si ! pop di ! pop bx
  3447.     or    al,al
  3448.      jnz    pc_hd_login_fail
  3449.     mov    di,local_buffer$            ; di -> boot record
  3450.     cmp    word ptr 510[di],IBM_SYS_ID        ; check for signature
  3451.      jne    pc_hd_login_fail            ; abort if not found
  3452.  
  3453.     mov    bx,es:DPH_DPB[si]            ; point es:bx -> dpb
  3454.  
  3455.     mov    es:PCDPB_EXTFLAG[bx],EXTFLAG1        ; assume 1.5 bytes per
  3456.     cmp    hd_dos_sys_id,HD_DOS_ID1
  3457.      je    pc_hd_build                ; if its a 2 byte per
  3458.     mov    es:PCDPB_EXTFLAG[bx],EXTFLAG2        ;  entry fat, flag it
  3459.  
  3460. pc_hd_build:
  3461.     mov    al,PC_BR_NFATS[di]
  3462.     sub    ah,ah                    ; build the dpb
  3463.     mov    es:PCDPB_NFAT[bx],ax
  3464.  
  3465.     mov    ax,PC_BR_FATSEC[di]
  3466.     mov    es:PCDPB_FATREC[bx],ax            ; size factor
  3467.  
  3468.     mov    ax,PC_BR_RESERVED[di]
  3469.     mov    es:PCDPB_FATADD[bx],ax
  3470.  
  3471.     call    pc_hd_cluster_count            ; calculate # of clstrs
  3472.     
  3473.     cmp    es:PCDPB_NCLSTRS[bx],0FF6h        ; max. size for 12 bit
  3474.      jbe    pc_hd_is12                ; if its a 2 byte per
  3475.     mov    es:PCDPB_EXTFLAG[bx],EXTFLAG2        ;  entry fat, flag it
  3476. pc_hd_is12:
  3477.     mov    ax,PC_BR_SECS[di]            ; get sectors per track
  3478.     mov    es:PCDPB_SPT[bx],ax            ; from DOS BPB
  3479.     mov    ax,PC_BR_DIRMAX[di]
  3480.     dec    ax
  3481.     mov    es:PCDPB_DIRSIZ[bx],ax
  3482.     mov    es:PCDPB_CKSIZ[bx],PERM            ; fixed disk only
  3483.  
  3484.     call    pc_hd_dpb_fix                ; patch up for show
  3485.  
  3486.     sub    ax,ax
  3487.     jmps    pc_hd_login_exit
  3488. pc_hd_login_fail:
  3489.     mov    ax,-1
  3490. pc_hd_login_exit:
  3491.     ret
  3492.  
  3493.  
  3494. pc_hd_cluster_count:
  3495. ; Calculate number of clusters:
  3496. ; Enter : ES:BX = DPB ->
  3497.                             ; calculate # of clstrs
  3498.  
  3499.     mov    ax,32            ; bytes per directory entry
  3500.     mul    PC_BR_DIRMAX[di]
  3501.     div    PC_BR_SECSIZ[di]
  3502.     test    dx,dx            ; test if incomplete sector
  3503.      jz    pc_hd_clu1        ; skip if even sector number
  3504.     inc    ax            ; round up to next full sector
  3505. pc_hd_clu1:
  3506.     xchg    ax,cx            ; CX = sectors in directory
  3507.     mov    ax,PC_BR_FATSEC[di]    ; assume < 256
  3508.     mul    PC_BR_NFATS[di]        ; AX = sectors of fats
  3509.     add    cx,ax            ; CX = sectors in FATs + directories
  3510.     add    cx,PC_BR_RESERVED[di]    ;      + boot
  3511.  
  3512.     xor    dx,dx
  3513.     mov    ax,PC_BR_TOTSEC[di]    ; get total
  3514.     or    ax,ax            ;  is it valid ?
  3515.     jnz    calc_clusters    
  3516.     mov    ax,PC_BR_BTOTSEC[di]    ; no must be >32meg partition
  3517.     mov    dx,PC_BR_BTOTSEC+2[di]    ; so use big total sectors value
  3518.  
  3519. calc_clusters:                ; DX:AX = total # of sectors
  3520.     sub    ax,cx            ; minus directory, FATs and boot
  3521.     jnc    calc_1
  3522.     dec    dx
  3523. calc_1:
  3524.     mov    cl,PC_BR_ALLOCSIZ[di]    ; sectors per cluster
  3525.     xor    ch,ch            ; shift mask
  3526. get_mask:
  3527.     shr    cl,1
  3528.     jc    end_mask
  3529.     inc    ch            ; mask
  3530.     jmps    get_mask
  3531. end_mask:
  3532.     mov    cl,ch
  3533.     xor    ch,ch            ; cx = divide loop count
  3534.     
  3535. calc_2:
  3536.     clc
  3537.     rcr    dx,1
  3538.     rcr    ax,1
  3539.     loop    calc_2
  3540.     inc    ax ! inc ax        ; + 2 (rsvd clusters)
  3541.     mov    es:PCDPB_NCLSTRS[bx],ax    ; set num of clusters
  3542.  
  3543.  
  3544.     mov    cl,PC_BR_ALLOCSIZ[di]    ; sectors per cluster
  3545.     xor    ch,ch
  3546.     mov    ax,PC_BR_SECSIZ[di]
  3547.     mul    cx
  3548.     mov    es:PCDPB_CLSIZE[bx],ax    ; and clustersize
  3549.  
  3550.     mov    ax,0302h        ; assume 512 byte default values
  3551.     mov    cx,PC_BR_SECSIZ[di]    ; get logical sector size
  3552. pc_hd_clu2:
  3553.     cmp    cx,BYTES_PER_SECTOR    ; logical = physical sector size?
  3554.      je    pc_hd_clu3        ; yes, continue
  3555.     add    ah,ah            ; else ...
  3556.     add    ax,0101h        ; PSH++, PRM = PRM*2+1
  3557.     shr    cx,1            ; halve the logical size
  3558.     jmps    pc_hd_clu2        ; until it matches physical size
  3559. pc_hd_clu3:
  3560.     mov    es:PCDPB_PSH[bx],al    ; AL = log2 (sectorsize/128)
  3561.     mov    es:PCDPB_PRM[bx],ah    ; AH = (sectorsize/128) - 1
  3562.     cmp    al,maxpsh        ; check if new maximum
  3563.      jbe    pc_hd_clu4        ; skip if same or smaller
  3564.     mov    maxpsh,al        ; else save new max. sector size
  3565. pc_hd_clu4:
  3566.     ret
  3567. eject
  3568.  
  3569. pc_hd_dpb_fix:
  3570. ; Fix up the pc partitions dpb for show dsk:
  3571. ; Enter : ES:BX = -> DPB
  3572.     push    si                    ; save for indexing
  3573.     mov    ax,es:PCDPB_CLSIZE[bx]
  3574.     dec    ax                    ; align msb
  3575.     mov    cx,6                    ; to shift out > 1024
  3576. pd_hd_fix_loop:
  3577.     shl    ax,1                    ; march the msb out
  3578.      jc    pc_hd_fix_it                ; skip when out
  3579.     loop    pd_hd_fix_loop                ; fall through if < 1024
  3580. pc_hd_fix_it:
  3581.     mov    si,cx
  3582.     shl    si,1                    ; block size index
  3583.  
  3584.     mov    cx,pc_blk_size[si]            ; get the block size
  3585.      mov    ax,es:PCDPB_NCLSTRS[bx]
  3586.     mul    es:PCDPB_CLSIZE[bx]
  3587.     div    cx                    ; number of allocation blocks
  3588.     dec    ax                    ; calculated dsm
  3589.  
  3590.     cmp    cx,1024                    ; if the block size is 1k and
  3591.      jne    pc_hd_fix_ok                ;   we've more than 255 blocks,
  3592.     cmp    ax,255                    ;   then pretend that we've got
  3593.      jbe    pc_hd_fix_ok                ;   2k blocks
  3594.  
  3595.     inc si ! inc si                    ; move our index to 2k
  3596.     shr    ax,1                    ;   and correct dsm
  3597. pc_hd_fix_ok:
  3598.     mov    es:PCDPB_DSM[bx],ax            ; fill in DSM value
  3599.  
  3600.     mov    ax,pc_bsh_blm[si]            ; fetch both
  3601.     mov    es:PCDPB_BSH[bx],al            ; block shift
  3602.     mov    es:PCDPB_BLM[bx],ah            ; block mask
  3603.  
  3604.     mov    es:PCDPB_EXM[bx],0            ; build remainder of
  3605.     mov    es:PCDPB_OFF[bx],0            ; DPB paramaters...
  3606.     pop    si                    ; restore index
  3607.     ret
  3608.  
  3609.  
  3610.  
  3611. ; Read first sector from a hard disk
  3612. ; into local_buffer area
  3613. ; Enter : drive_num = drive number
  3614. ; Exit :  AL = return error code
  3615. read_sector0:
  3616.     mov    cx,1            ; CH: cylinder 0,  CL: sector 1
  3617.     mov    dh,0            ; DH: head 0 of current drive
  3618. ;    jmps    read_sector        ; read one sector via ROM BIOS
  3619.  
  3620. ; Read one sector into local buffer
  3621. ; Entry:  CH = cylinder
  3622. ;      CL = sector (bits 0-5)/hi cyl (bits 6-7)
  3623. ;      DH = head
  3624. ;      drive_num = 0 or 1 for 1st/2nd hd
  3625. ; Exit:   AL = return error code
  3626. read_sector:
  3627.     mov    bx,offset pc_part_table_iopb
  3628.     mov    IBM_HEAD[bx],dh        ;  not equal zero
  3629.     mov    al,cl
  3630.     and    al,3fh            ; bottom 5 bits are sector #
  3631.     mov    IBM_SECTOR[bx],al    ; set sector number
  3632.     mov    al,ch            ; bits 0-7 of cylinder #
  3633.     mov    ah,cl            ; bits 8-9 of cylinder #
  3634.     rol ah,1 ! rol ah,1        ; shift them into place
  3635.     and    ah,3            ; isolate MSB cylinder #
  3636.     mov    IBM_CYLINDER[bx],ax    ; 16 bit cylinder #
  3637.     mov    ax,local_buffer$
  3638.     mov    IBM_XFER_OFS[bx],ax    ; read to local buffer
  3639.     mov    IBM_XFER_SEG[bx],ds
  3640.     mov    al,drive_num
  3641.     mov    IBM_LUN[bx],al        ; set logical unit #
  3642.     jmp    hd_rom@
  3643.  
  3644. hd_init_hdinf:
  3645. ; Subroutine sets up physical information vector about a drive:
  3646. ; entry:    registers as returned from ROM call
  3647.  
  3648.     mov    HDINF_EXISTS[si],0ffh        ; it at least exists
  3649.     inc    dh                ; change last hd to # of hds
  3650.     mov    HDINF_HEADS[si],dh
  3651.     mov    al,3fh
  3652.     and    al,cl                ; sectors is already # of spt
  3653.     mov    HDINF_SPT[si],al
  3654.     rol    cl,1
  3655.     rol    cl,1
  3656.     and    cl,3
  3657.     xchg    ch,cl                ; unpack max cyl address
  3658.     mov    HDINF_CYL[si],cx        ; and save it
  3659.     mov    cl,drive_num
  3660.     mov    HDINF_PC_DRIVE[si],cl        ; save physical drive number
  3661.     ret
  3662. eject
  3663.  
  3664. trim_memory:
  3665. ;-----------
  3666. ; Trim the memory partion list to match physical memory:
  3667.  
  3668.     mov    cx,memory_top            ; top segment address
  3669.     lea    bx,mfl$                ; memory free list root
  3670. trim_next:
  3671.     mov    si,bx                ; save previous link
  3672.     mov    bx,MD_LINK[bx]            ; link to next
  3673.     test    bx,bx
  3674.      jz    trim_done            ; 0 => end of list
  3675.  
  3676.     mov    ax,MD_START[bx]            ; memory block start seg
  3677.     cmp    ax,cx                ; is start past mem top?
  3678.      jae    trim_clip            ; if yes, end the list
  3679.  
  3680.     add    ax,MD_LENGTH[bx]         ; get to the end
  3681.     cmp    ax,cx                 ; is end past mem top?
  3682.      jbe    trim_next             ; if not, link to next
  3683.  
  3684.     mov    ax,cx
  3685.     sub    ax,MD_START[bx]             ; ax=usable memory left
  3686.     mov    MD_LENGTH[bx],ax         ; shorten up this block
  3687.     jmps    trim_next             ;   and link to next
  3688.  
  3689. trim_clip:
  3690.     mov    MD_LINK[si],0            ; previous is now the last
  3691.     mov    si,bx                ; save start of severed list
  3692.  
  3693. trim_scan:
  3694.     mov    di,bx                ; save last link
  3695.     mov    bx,MD_LINK[bx]            ; look for the end of the
  3696.     test    bx,bx                ;   severed list
  3697.      jnz    trim_scan
  3698.  
  3699.     mov    ax,mdul$            ; save md unused root
  3700.     mov    mdul$,si            ; redo the root
  3701.     mov    MD_LINK[di],ax            ; and re-attach original
  3702. trim_done:
  3703.     ret
  3704. eject
  3705.  
  3706. do_aux_ports:
  3707. ;------------
  3708. ; Set up the auxiliary ports:
  3709.  
  3710.     call    check_multi_port    ; try to find multi-port board
  3711.  
  3712.     sub    dx,dx            ; start with 1st serial port
  3713. do_aux_lp1:
  3714.     mov    bx,dx
  3715.     mov    al,config0_data[bx]    ; get config data (if COM1 or COM2)
  3716.     call    point_aux@        ; get auxiliary port structure
  3717.     mov    cx,AUX_PORT_ADDR[bx]    ; get hardware base port
  3718.     test    ch,ch            ; no card (0000) or generic (00xx)?
  3719.      jz    do_aux_p2        ; skip if no hardware setup
  3720.     push    dx ! push ds
  3721.     mov    bx,PC_SEGMENT
  3722.     mov    ds,bx            ; trick the ROS into using our port #
  3723.     xchg    cx,rs232_base_40    ; get their #, give them ours
  3724.     sub    dx,dx            ; dx -> port 0
  3725.     mov    ah,0            ; init code
  3726.     int    ASYNC_INT        ; through the ROS
  3727.     mov    rs232_base_40,cx    ; restore ROS port number
  3728.     pop    ds ! pop dx
  3729. do_aux_p2:
  3730.     inc    dx            ; next serial port
  3731.     cmp    dx,NUM_AUX_PORTS    ; all possible ports done?
  3732.      jne    do_aux_lp1        ; loop back for more ports
  3733.  
  3734. ; Now we set up for interrupt driven auxin auxout:
  3735.  
  3736.     cli                ; best not be disturbed
  3737. ; First turn both off (thx JC & JW):
  3738.     or    pic_mask_image$,(not (AUX_PIC0 and AUX_PIC1)) and 0ffh
  3739.     sub    dx,dx            ; dx = 0
  3740.     mov    cl,AUX_PIC0        ; port 0 pic mask
  3741. do_aux_lp2:
  3742.     push    dx
  3743.     call    do_one_port        ; if existent, enable ints
  3744.     mov    cl,AUX_PIC1        ; port 2 pic mask
  3745.     pop    dx
  3746.     inc    dx            ; next port
  3747.     cmp    dx,NUM_AUX_PORTS    ; try all possible ports
  3748.      jne    do_aux_lp2        ; repeat if more ports
  3749.     ret
  3750.  
  3751.  
  3752. do_one_port:
  3753. ; Set up interrupts for one aux port:
  3754. ;    entry:    dx = port number (0..NUM_AUX_PORTS-1)
  3755. ;        cl = pic mask
  3756.  
  3757. ; Same test that ROS does:
  3758.     call    point_aux@            ; bx -> aux block
  3759.     mov    ax,AUX_PORT_ADDR[bx]        ; get serial port address
  3760.     test    ax,ax                ; was serial port card found?
  3761.      je    erase_port            ; no, none of the ports there
  3762.     test    ah,ah                ; test if generic card
  3763.      jz    do_one_gen            ; yes, skip hardware setup
  3764.     push    dx
  3765.     mov    dx,AUX_PORT_INT_ID
  3766.     call    aux_port_in@            ; get test int ident
  3767.     test    al,0F8h                ; zf set if present
  3768.     pop    dx
  3769.      jnz    erase_port            ; hardware is absent
  3770.  
  3771.     call    do_one_alloc            ; allocate i/o buffers
  3772.     call    do_aux_int            ; set up port hardware
  3773. do_one_gen:
  3774.     mov    bx,dx                ; bx = port number
  3775.     cmp    term_data[bx],0FFh        ; if serial console..
  3776.      jz    y_con                ;  jump
  3777. add_printer:
  3778.     mov    al,bl
  3779.     add    al,3                ; start w/ 3 for ser printers
  3780.     call    conv_digit@
  3781.     jmp    put_in_s_o            ; show it
  3782.                         ; we're finished
  3783.  
  3784. ; According to setup data, dedicate this port to a serial console:
  3785. y_con:
  3786. if V386
  3787.     test    su_mu_vs$[bx],PCTERM_EMU     ; test setup bit for PCTerm
  3788.      jz    y_con1
  3789.     push    dx                ; it's a PCTerminal
  3790.     call    add_printer            ; so we can have a printer on
  3791.     pop    dx                ; its aux port
  3792. y_con1:
  3793. endif
  3794.     call    erase_port            ; dx=port,wipe out the aux vectors
  3795.     jmp    set_ser_con            ; set up serial console vectors
  3796.  
  3797.  
  3798. erase_port:
  3799. ; If port is not present, wipe out this port's branch vectors:
  3800. ;    entry:    dx = port number
  3801.  
  3802.     mov    bx,dx
  3803.     shl    bx,1                  ; bx = port word index
  3804.     mov    ax,offset aux_null@          ; address of null aux routine
  3805.     mov    aux_in_vector$[bx],ax          ; zap auxin calls
  3806.     mov    aux_out_vector$[bx],ax          ; zap auxout calls
  3807.     mov    auxin_stat_vector$[bx],ax    ; zap input status
  3808.     mov    auxout_stat_vector$[bx],ax    ; zap output status
  3809.     mov    bx,acb_list$[bx]        ; get pointer to ACB
  3810.     mov    LCB_ATTACH[bx],UNAVAILABLE    ; mark for TMP
  3811.     ret                      ; that's it
  3812.  
  3813.  
  3814. check_multi_port:    ; check if multi-port card is installed
  3815. ;----------------
  3816. ;    Note:    If the base port address configured by SETUP
  3817. ;        is 00xxh (0000-00FFh) then the actual I/O routines
  3818. ;        will be provided by an external device driver
  3819. ;        installed after the XIOS initialization. In this
  3820. ;        case, all hardware setup is skipped in the XIOS
  3821. ;        and only RSP duplication & other data setup is performed.
  3822. ;        Otherwise, the port address is the address of the
  3823. ;        first of several 8250 chips on a multi-port card.
  3824.  
  3825.     mov    serdrv_vector$+2,cs    ; point default to XIOS handler
  3826.  
  3827.     mov    bx,offset su_mu_data$    ; BX -> SETUP info for card
  3828.                     ; first initialize the card
  3829.                     ;  in case it needs a reset
  3830.     mov    dx,MU_RESET[bx]        ; does the card need reset?
  3831.     test    dx,dx            ; no reset port otherwise
  3832.      jz    chk_mp_nores        ; skip read/write from/to reset port
  3833.     mov    ax,MU_RESDAT[bx]    ; get reset r/w flag and data
  3834.     test    ah,ah            ; AH = 0 if read, AH = FF if write
  3835.      jz    chk_mp_in        ; skip if read from port req'd
  3836. chk_mp_out:                ; else need to write to it
  3837.     out    dx,al            ; write reset value
  3838.     jmps    chk_mp_nores        ; done it
  3839. chk_mp_in:                ; else read from port required
  3840.     in    al,dx            ; to initialize board
  3841. chk_mp_nores:                ; card reset completed
  3842.                     ; now check for presence of card
  3843.     mov    dx,MU_PORT[bx]        ; get base address
  3844.     test    dx,dx            ; any card configured?
  3845.      jz    chk_mp_ret        ; skip if not
  3846.     test    dh,dh            ; generic port card (dummy addr 00xx)?
  3847.      jz    chk_mp_init        ; yes, assume ports are there
  3848.     mov    cx,MU_NPORTS[bx]    ; there should be 1-8 8250 UARTs
  3849.     add    dx,AUX_PORT_INT_ID    ; check interrupt ID as for COM1/COM2
  3850. chk_mp_lp1:
  3851.     in    al,dx            ; 00000xxxb if 8250 chip responds
  3852.     test    al,0F8h            ; zf set if present
  3853.      jnz    chk_mp_ret        ; hardware is absent
  3854.     add    dx,8            ; 8250s must be at every 8 i/o ports
  3855.     loop    chk_mp_lp1
  3856.     jmps    chk_mp_init
  3857.  
  3858. chk_mp_ret:                ; return if card not present
  3859.     ret
  3860.  
  3861. chk_mp_init:
  3862.     cmp    num_port$,2        ; can't have COM2 (cos of IRQ3) & AST
  3863.      jb    chk_mp_com2        ; installed together - too messy for us
  3864.     dec    num_port$
  3865. chk_mp_com2:
  3866.     mov    ax,MU_NPORTS[bx]    ; get # of ports on card (4 or 8)
  3867.     add    num_port$,ax        ; add in all the ports on our card
  3868.  
  3869.     mov    dx,MU_PORT[bx]        ; get base port address
  3870.     test    dh,dh            ; generic multi-port card?
  3871.      jz    chk_mp_gen        ; yes, don't check for latch
  3872.     cmp    MU_LATCH[bx],0        ; do we have an IRQ latch port
  3873.      jnz    chk_mp_gen
  3874.     jmp    chk_mp_nolatch        ; skip if not (req'd if NPORTS > 1)
  3875. chk_mp_gen:
  3876.     mov    cx,MU_NPORTS[bx]    ; get # of ports on board (4 or 8)
  3877.     mov    di,1*WORD        ; skip COM1, modify remaining ports
  3878. chk_mp_lp2:                
  3879.     lea    ax,MU_LATCH[bx]        ; get IRQ info for multi-port card
  3880.     mov    si,MU_NPORTS[bx]
  3881.     sub    si,cx            ; SI = relative port index
  3882.     push    bx
  3883.     mov    bl,MU_PROT[bx+si]    ; BL = protocol for our port
  3884.     mov    bh,bl
  3885.     shr    bl,1 ! shr bl,1        ; 4 MSB = input protocol
  3886.     shr    bl,1 ! shr bl,1
  3887.     and    bh,0Fh            ; 4 LSB = output protocol
  3888.     mov    si,auxin_blk_ptr$[di]
  3889.     mov    AUX_PORT_ADDR[si],dx    ; fill in port address (input)
  3890.     mov    AUX_LATCH[si],ax    ; fill in IRQ latch data
  3891.     mov    AUX_PROT[si],bl        ; input protocol
  3892.     test    bl,XON_XOFF        ; software protocol ?
  3893.     jz    chk_mp_lp3
  3894.     mov    word ptr AUX_ON[si], XON + 256*XOFF
  3895.     push    di            ; if a PCTERM then we
  3896.     shr    di,1            ; we want XPC protocols
  3897.     test    mu_com_type$[di],1    ; is it a terminal ?
  3898.      jz    chk_mp_lp2a
  3899.     test    su_mu_vs$[di],PCTERM_EMU ; is it a PC terminal ?
  3900. chk_mp_lp2a:
  3901.     pop    di
  3902.     jz    chk_mp_lp3        ;  to see if pcterm emulation required
  3903.     mov    word ptr AUX_ON[si], XPCON + 256*XPCOFF
  3904. chk_mp_lp3:
  3905.     mov    si,auxout_blk_ptr$[di]
  3906.     mov    AUX_PORT_ADDR[si],dx    ; fill in port address (output)
  3907.     mov    AUX_LATCH[si],ax    ; fill in IRQ latch data
  3908.     mov    AUX_PROT[si],bh        ; output protocol
  3909.     test    bh,XON_XOFF        ; software protocol ?
  3910.     jz    chk_mp_lp4
  3911.     mov    word ptr AUX_ON[si], XON + 256*XOFF
  3912.     push    di            ; if a PCTERM then we
  3913.     shr    di,1            ; we want XPC protocols
  3914.     test    mu_com_type$[di],1    ; is it a terminal ?
  3915.      jz    chk_mp_lp3a
  3916.     test    su_mu_vs$[di],PCTERM_EMU ; is it a PC terminal ?
  3917. chk_mp_lp3a:
  3918.     pop    di
  3919.     jz    chk_mp_lp4        ;  to see if pcterm emulation required
  3920.     mov    word ptr AUX_ON[si], XPCON + 256*XPCOFF
  3921. chk_mp_lp4:
  3922.     pop    bx
  3923.     inc    di ! inc di
  3924.     add    dx,8            ; next 8250A/B-16450 chip on board
  3925.     loop    chk_mp_lp2        ; repeat for all comms chips
  3926.  
  3927.     lea    si,MU_CONFIG[bx]    ; SI -> baud rate table for our ports
  3928.     lea    di,config1_data        ; DI -> baud rates for initialization
  3929.     mov    cx,MU_NPORTS[bx]    ; number of ports that we support
  3930.     push    es
  3931.     push    ds ! pop es
  3932.     rep    movsb            ; copy SETUP info across
  3933.     pop    es
  3934.  
  3935. chk_mp_nolatch:
  3936.     mov    cx,MU_NPORTS[bx]    ; # of serial terminals
  3937.     mov    si,1            ; skip COM1 port
  3938.     mov    dl,MU_CONAUX[bx]    ; get console/printer bit map
  3939. cmp_mp_lp3:                ; is next port console or printer?
  3940.     shr    dx,1            ; shift next bit in CY flag
  3941.     sbb    al,al            ; AL = FF if CY on, 00 if CY off
  3942.     mov    term_data[si],al    ; update the flag (FF = terminal)
  3943.     inc    si            ; next port
  3944.     loop    cmp_mp_lp3        ; repeat for all of them
  3945.     ret
  3946.  
  3947. eject
  3948.  
  3949. do_one_alloc:        ; allocate I/O buffers for serial port
  3950. ;------------
  3951. ;    entry:    DX = port number
  3952.                     ; Setup output buffers:
  3953.     call    point_aux@        ; BX -> I buf ctl, DI -> O buf ctl
  3954.     xchg    bx,di            ; BX -> output buffer control structure
  3955. ;;    mov    AUX_PROT[bx],PROT_T_INIT; default protocol unless SETUP
  3956.     mov    si,dx
  3957.     cmp    term_data[si],0
  3958.     mov    ax,AUXOUT_BUF_SIZE/16    ; # of paragraphs for buffer
  3959.      jz    do_one_alloc1
  3960.     mov    ax,CONOUT_BUF_SIZE/16    ; # of paragraphs for buffer
  3961. do_one_alloc1:
  3962.     call    do_one_alloc3        ; allocate buffer, setup ctrl structure
  3963.                     ; Setup input buffers:
  3964.     call    point_aux@        ; BX -> I buf ctl, DI -> O buf ctl
  3965. ;;    mov    AUX_PROT[bx],PROT_R_INIT; default protocol unless SETUP
  3966.     mov    si,dx
  3967.     cmp    term_data[si],0
  3968.     mov    ax,AUXIN_BUF_SIZE/16    ; # of paragraphs for buffer
  3969.      jz    do_one_alloc2
  3970.     mov    ax,CONIN_BUF_SIZE/16    ; # of paragraphs for buffer
  3971. do_one_alloc2:
  3972. ;    call    do_one_alloc3        ; allocate buffer, setup ctrl structure
  3973. ;    ret
  3974.  
  3975. do_one_alloc3:        ; allocate input or output buffer
  3976. ;-------------
  3977. ;    entry:    AX = # of paragraphs to allocate for buffer
  3978. ;        BX -> buffer control structure
  3979. ;
  3980. ;    saved:    BX,CX,DX
  3981.  
  3982.     push    cx ! push dx        ; save CX, DX for caller
  3983.     push    bx            ; preserve control block
  3984.     xchg    ax,dx            ; DX = # of paragraphs wanted
  3985.     call    mem_alloc_i@        ; allocate memory block
  3986.     mov    cl,4            ; AX = segment of new buffer
  3987.     shl    dx,cl            ; convert buffer size to bytes
  3988.     dec    dx            ; make it offset of last byte
  3989.     pop    bx
  3990.  
  3991.     mov    AUX_BUF_BASE[bx],ax    ; setup buffer segment
  3992.     mov    AUX_BUF_TOP[bx],dx    ; offset of last byte in buffer
  3993.  
  3994.     sub    ax,ax
  3995.     mov    AUX_IN_PTR[bx],ax    ; reset input & output pointers
  3996.     mov    AUX_OUT_PTR[bx],ax
  3997.     mov    AUX_BUF_COUNT[bx],ax    ;   & buffer count
  3998.  
  3999.     call    alloc_flag@        ; get an unused flag
  4000.     mov    AUX_FLAG[bx],al        ; save this flag for syncronization
  4001.  
  4002.     pop    dx ! pop cx        ; restore DX, CX for caller
  4003.     ret
  4004.  
  4005.  
  4006. do_aux_int:
  4007. ; Set up the aux interrupt hardware:
  4008. ;    entry:    BX -> buffer structure
  4009. ;        CL = PIC mask
  4010. ;        DX = port number
  4011.  
  4012.     call    point_aux@        ; set BX, DI = input/output structures
  4013.  
  4014.     push    dx
  4015.     and    pic_mask_image$,cl    ; mask in our interrupt
  4016.  
  4017.     mov    dx,AUX_PORT_INT_EN    ; here we enable interrupts
  4018.     mov    al,R_ERR_MASK        ; for rcv and errors
  4019.     call    aux_port_out@
  4020.  
  4021.     mov    dx,AUX_PORT_M_CTRL    ; now we set the modem control
  4022.     mov    al,I_EN + DTR_BIT + RTS_BIT    ;   register to enable ints
  4023.     cmp    AUX_PORT_ADDR[bx],AUX_PORT1    ; if COM0 or COM1
  4024.      jae    set_prot        ; enable I_EN bit
  4025.     mov    al,DTR_BIT + RTS_BIT    ; else leave for multi-port cards
  4026. set_prot:                ; as it screws some cards up.(AST)
  4027.     call    aux_port_out@        ;   with all protocol on.
  4028.  
  4029.     mov    dx,AUX_PORT_INT_ID    ; reading the int ident reg
  4030.     call    aux_port_in@        ;   clears pending xmit ints
  4031.     pop    dx
  4032.     ret
  4033.  
  4034. set_ser_con:
  4035. ; Set up the serial console jump vectors:
  4036. ;    entry:    dx = port number
  4037.  
  4038.     mov    bx,dx            ; BX = port index (0..8)
  4039.     inc    current_pc$        ; first serial is physical console 1
  4040.     mov    al,current_pc$        ; get next physical console to use
  4041.     mov    port2pc_table$[bx],al    ; save console # for this serial port
  4042.     cbw                ; make console # a word
  4043.     xchg    ax,di            ; DI = physical console #
  4044.     mov    pc2port_table$[di],dl    ; save port # for this console
  4045.     shl    bx,1            ; bx = port word index
  4046.     mov    ser_conin_vec$[bx],offset aux_in@
  4047.     mov    ser_conout_vec$[bx],offset aux_out@
  4048.     mov    ser_conout_stat_vec$[bx],offset term_auxout_stat@
  4049.     mov    di,auxout_blk_ptr$[bx]    ; di -> auxout block
  4050.     push    dx            ; save port index
  4051.     mov    dx,AUX_PORT_ADDR[di]    ; get the 8250 port address
  4052.     test    dh,dh            ; generic serial port?
  4053.      jz    set_ser_serdrv        ; yes, skip baud rate setup
  4054.                     ; else do high baud rate kludge
  4055.     add    dx,3            ; DX = line control port
  4056.     in    al,dx            ; read line control values
  4057.     jmps    $+2            ; I/O delay (just in case)
  4058.     xchg    ax,cx            ; save them in CL
  4059.     mov    al,80h
  4060.     out    dx,al            ; DLAB = 1 to set baud rate
  4061.     jmps    $+2            ; I/O delay (just in case)
  4062.     sub    dx,2            ; DX = divisor latch high (DLM)
  4063.     in    al,dx            ; read back DLM
  4064.     jmps    $+2            ; I/O delay (just in case)
  4065.     mov    ah,al            ; save in AH
  4066.     dec    dx            ; DX = didvisor latch low (DLL)
  4067.     in    al,dx            ; AX = baud rate divisor value
  4068.     jmps    $+2            ; I/O delay (just in case)
  4069.                     ; 110bd=1047 150bd=768 300bd=384
  4070.     cmp    ax,500            ; very low baud rate (110, 150)?
  4071.      jb    set_ser_con_new        ; don't modify if > 150 baud
  4072.     cmp    ax,800            ; < 800 => 150 baud => 19.2 KBd
  4073.     mov    ax,6            ; 1.8432 Mhz/(16 * 6) = 19.2 KBd
  4074.      jae    set_ser_con_new        ; skip if 19.2 requested
  4075.     mov    ax,3            ; 1.8432 Mhz/(16 * 3) = 38.4 KBd
  4076. set_ser_con_new:
  4077.     out    dx,al            ; LSB of divisor for baud rate
  4078.     jmps    $+2            ; I/O delay (just in case)
  4079.     inc    dx            ; DX = divisor latch high
  4080.     mov    al,ah            ; divisor value high
  4081.     out    dx,al
  4082.     jmps    $+2            ; I/O delay (just in case)
  4083.     add    dx,2            ; DX = line control port
  4084.     xchg    ax,cx            ; AL = orig. line control value
  4085.     out    dx,al            ; DLAB in line control port = 0
  4086.  
  4087. set_ser_serdrv:                ; baud rate fixed up
  4088.     pop    dx            ; restore port index
  4089.  
  4090.     cmp    dl,9            ; above range of AUX devices?
  4091.      jae    skip_acb_init        ; yes, don't touch ACBs then
  4092.     mov    di,dx
  4093.     test    su_mu_vs$[di],PCTERM_EMU ; look at setup byte for serial port
  4094.      jz    skip_acb_init        ; if not PCTERM leave as UNAVAILABLE
  4095.     shl    di,1
  4096.     push    di
  4097.     mov    di,acb_list$[di]    ; get pointer to ACB
  4098.     mov    LCB_ATTACH[di],0    ; it's available after all
  4099.     pop    di            ; now point acb at a dummy
  4100.     mov    acb_list$[di], offset dummy_cb$
  4101. skip_acb_init:
  4102.     ret                ; that's it
  4103.  
  4104. eject
  4105.  
  4106. do_ros_ints:
  4107. ;-----------
  4108. ; Store several of the initial ROS entry points to allow the XIOS to
  4109. ; use the ROS drivers:
  4110.     mov    ax,ds
  4111.     mov    es,ax                ; point ES here
  4112.     push    ds
  4113.     sub    ax,ax
  4114.     mov    ds,ax                ; point DS at int. vectors
  4115.  
  4116.     push    es
  4117.     push    cs ! pop es            ; vector_table$ in CS
  4118.     mov    di,offset vector_table$        ; table of ints to save
  4119.     mov    cx,NUM_VECTORS            ; loop count
  4120.     cld
  4121. ros_lp:
  4122.     mov    si,es:[di]            ; get vector address
  4123.     inc di ! inc di                ; point to save area
  4124.     movsw  ! movsw                ; move segment and offset
  4125.     loop    ros_lp                ; do them all
  4126.     pop    es
  4127.  
  4128. ; The required vectors have now been stored.
  4129.  
  4130. ; One more special case:
  4131. TARGETT equ KEYBOARD_INTERRUPT * 4
  4132.     mov    ax,.TARGETT            ; offset
  4133.     mov    word ptr keyboard_isr$,ax
  4134.     mov    ax,.TARGETT+2
  4135.     mov    word ptr keyboard_isr$+2,ax
  4136.  
  4137. ; Now, although redundant, save another set for LOADCCPM:
  4138.     sub    si,si
  4139.     mov    di,offset ros_vectors$
  4140.     mov    cl,es:[di]            ; get count
  4141.     inc    di
  4142.     sub    ch,ch
  4143.     shl    cx,1                ; 2 words per vector
  4144.     rep    movsw                ; and move into place
  4145.  
  4146.     pop    DS                ; point it back here
  4147.     ret
  4148.  
  4149.  
  4150. alloc_non_sysdat:
  4151. ;----------------
  4152. ; Routine to trim memory from low TPA and give it to whoever requested:
  4153. ; alloc_table    dw    ptr_addr_offset, ptr_addr_segment, paras_req'd
  4154. ;              ...           ...
  4155. ;  where ptr_addr is a word containing the offset in SYSDAT which must
  4156. ;  receive the segment address of the allocated space.
  4157.  
  4158.     push    es
  4159.     mov    bx,offset alloc_table
  4160. alp:
  4161.     mov    dx,4[bx]            ; get amount requested
  4162.     or    dx,dx                ; end of table?
  4163.      jz    aret                ; jump if so
  4164.     push    bx
  4165.     call    mem_alloc_i@            ; else get the mem.
  4166.     pop    bx
  4167.     les    di,[bx]                ; get segment & offset
  4168.     stosw                    ; put returned seg address
  4169.     add    bx,6                ;    in place
  4170.     jmps    alp
  4171. aret:
  4172.     pop    es
  4173.  
  4174.     ret
  4175.     
  4176. reloc_ext_BIOS:        ; relocate PS/2 extended BIOS data
  4177. ;--------------
  4178.     push    ds
  4179.     mov    cx,PC_SEGMENT
  4180.     mov    ds,cx
  4181.     mov    cx,extended_BIOS_40    ; get extended BIOS data segment
  4182.      jcxz    reloc_ret        ; skip if none (non-PS/2 ROS)
  4183.     mov    ds,cx            ; DS:0 -> extended BIOS data
  4184.     sub    dx,dx
  4185.     mov    dl,.0            ; size of data in 1 K blocks
  4186.     mov    cl,6
  4187.     shl    dx,cl            ; DX = # of paragraphs in extended data
  4188.     push    ds
  4189.     mov    ds,sysdat$        ; restore data segment
  4190.     call    mem_alloc_i@        ; allocate segment address
  4191.     mov    es,ax            ; ES = alternate BIOS segment
  4192.     pop    ds            ; DS = current extended data
  4193.     mov    cl,3
  4194.     shl    dx,cl            ; size of data segment in words
  4195.     mov    cx,dx            ; CX = # of words to move
  4196.     sub    si,si
  4197.     sub    di,di
  4198.     rep    movsw            ; relocate BIOS segment to low memory
  4199.     mov    ax,PC_SEGMENT
  4200.     mov    ds,ax            ; DS = ROM BIOS data segment
  4201.     mov    extended_BIOS_40,es    ; set new BIOS data segment address
  4202.  
  4203. reloc_ret:
  4204.     pop    ds            ; restore data segment
  4205.     ret
  4206.  
  4207. reloc_disk_params:        ; relocate hard disk parameter tables
  4208. ;-----------------        ; if in TPA space
  4209.     push    ds
  4210.     cmp    word ptr reloc_disk$,00 ; do we have to move tables
  4211.     je    reloc_ret1
  4212.     xor    ax,ax
  4213.     mov    es,ax
  4214.     mov    si,HD_PARAM_INTERRUPT*4
  4215.     mov    ax,es:2[si]        ; get pointer segment
  4216.     push    ax            ; ax = tables segment
  4217.     mov    dx,reloc_disk$        ; dx = number of paras to move
  4218. if XM
  4219.     mov    cx,4
  4220.     shl    dx,cl            ; size in bytes
  4221.     call    sysdat_ext_alloc    ; allocate para aligned buffer in sysdat
  4222.     mov    cl,4            ; ax= offset of buffer
  4223.     shr    ax,cl
  4224.     mov    cx,ds
  4225.     add    ax,cx
  4226. endif
  4227. if V386
  4228.     call    mem_alloc_i@        ; allocate segment address- non sysdat
  4229. endif
  4230.     mov    es,ax            ; ES = alternate segment
  4231.     pop    ds            ; DS = current tables segment
  4232.     mov    cl,3
  4233.     shl    dx,cl            ; size of data segment in words
  4234.     mov    cx,dx            ; CX = # of words to move
  4235.     sub    si,si
  4236.     sub    di,di
  4237.     rep    movsw            ; relocate segment to low/hi memory
  4238.     xor    ax,ax
  4239.     mov    ds,ax
  4240.     mov    si,HD_PARAM_INTERRUPT*4
  4241.     mov    ax,2[si]        ; get original
  4242.     mov    2[si],es        ; set new pointer segment
  4243.     mov    si,HD_PARAM_INTERRUPT1*4 ; second hard disk pointer
  4244.     cmp    2[si],ax
  4245.     jne    reloc_ret0        ; also moved ?
  4246.     mov    2[si],es        ; set new pointer segment
  4247. reloc_ret0:
  4248.     mov    cx,PC_SEGMENT
  4249.     mov    ds,cx
  4250. ;;    cmp    [si],ax
  4251. ;;    jne    reloc_ret1
  4252.     mov    hd_param_40,es            ; used so update
  4253. reloc_ret1:
  4254.     pop    ds            ; restore data segment
  4255.     ret
  4256.  
  4257.  
  4258. sysdat_ext_alloc:
  4259. ;----------------
  4260. ; Routine to trim the low end of the TPA to return the offset of a SYSDAT-
  4261. ;  inclusive buffer to the caller.
  4262. ; Entry:  DX = # bytes wanted
  4263. ; Exit:   AX = offset of area freed for caller;
  4264. ;         = 0 if some SYSDAT space left, but < DX
  4265. ;         = FFFF if no SYSDAT space left at all
  4266. ; Assumptions:
  4267. ;  MD chain goes from low addresses to high w/ no gaps.
  4268. ;  SYSDAT < TPA.
  4269.  
  4270.     mov    bp,dx                ; copy requested size in bytes
  4271.     add    dx,15                ; round up to
  4272.     mov    cl,4                ; nearest paragraph
  4273.     shr    dx,cl
  4274.     jmps    sysdat_mem_chop
  4275.  
  4276. sysdat_mem_alloc:
  4277. ;----------------
  4278. ; Routine to trim the low end of the TPA to return the offset of a SYSDAT-
  4279. ;  inclusive buffer to the caller.
  4280. ; Entry:  DX = # bytes wanted
  4281. ; Exit:   AX = offset of area freed for caller;
  4282. ;         = 0 if some SYSDAT space left, but < DX
  4283. ;         = FFFF if no SYSDAT space left at all
  4284. ; Assumptions:
  4285. ;  MD chain goes from low addresses to high w/ no gaps.
  4286. ;  SYSDAT < TPA.
  4287.  
  4288.     mov    bp,dx                ; copy requested size in bytes
  4289.     add    dx,15                ; round up to
  4290.     mov    cl,4                ; nearest paragraph
  4291.     shr    dx,cl
  4292.  
  4293. ; First try to reuse the init space:
  4294.     call    check_init_reuse@
  4295.      jnc    good_ret            ; then we got it
  4296.     
  4297. ; Get start of chain:
  4298.  
  4299. sysdat_mem_chop:
  4300.     mov    bx,mfl$                ; root
  4301.     mov    si,MD_START[bx]            ; save for below
  4302.  
  4303. ; Is lowest TPA partition already out of reach?
  4304.     mov    ax,ds
  4305.     add    ax,1000h            ; ax = 64k away
  4306.     cmp    ax,si
  4307.      jbe    ffff_ret
  4308.  
  4309. ; Check for start + requested length in sysdat:
  4310.     mov    di,dx                ; DI = scratch
  4311.     add    di,si
  4312.     cmp    ax,di
  4313.      jb    zero_ret
  4314.  
  4315. ; Trim the MDs:
  4316.     call    common_trim
  4317.  
  4318. ; Return offset of base paragraph:
  4319.     mov    ax,si                ; start paragraph
  4320.     mov    si,ds
  4321.     sub    ax,si
  4322. ;    mov    cl,4
  4323.     shl    ax,cl                ; start byte
  4324.  
  4325. good_ret:
  4326.     mov    dx,bp                ; restore req. bytes
  4327.     ret
  4328.  
  4329. ffff_ret:
  4330.     mov    dx,bp                ; restore req. bytes
  4331.     mov    ax,0FFFFh
  4332.     ret
  4333. zero_ret:
  4334.     mov    dx,bp                ; restore req. bytes
  4335.     sub    ax,ax
  4336.     ret
  4337.  
  4338.  
  4339. eject
  4340.  
  4341. alloc_tmp_buffs:
  4342. ;---------------
  4343. ; Allocate the history buffers for the tmps.
  4344. ; This system uses common buffers for the 4 virtual screens, and
  4345. ; separate buffers for each serial terminal.
  4346.  
  4347.     mov    dx,HIST_PROG_SIZE
  4348.     call    hist_init
  4349.     mov    prog_hist_base$,ax
  4350.  
  4351.     mov    dx,HIST_COMM_SIZE
  4352.     call    hist_init
  4353.     mov    comm_hist_base$,ax
  4354.  
  4355.     sub    di,di            ; physical port number
  4356. ser_hist_loop:
  4357.     cmp    port2pc_table$[di],0ffh    ; physical console number allocated ?
  4358.      je    ser_hist_next        ; no get next possible    
  4359.     push    di
  4360.     mov    dx,HIST_SER_SIZE    ; allocate & initialize buffer
  4361.     call    hist_init
  4362.     pop    di
  4363.     mov    bl,port2pc_table$[di]    ; get logical console number
  4364.     dec    bl            ; zero relative
  4365.     xor    bh,bh
  4366.     shl    bx,1
  4367.     mov    ser_hist_base$[bx],ax    ; save serial history buffer
  4368. ser_hist_next:
  4369.     inc    di            ; next port number
  4370.  
  4371. if SR
  4372.     cmp    di,NUM_AUX_PORTS + NUM_SR_PORTS    ; for SUN RIVER system
  4373. else
  4374.     cmp    di,NUM_AUX_PORTS    ; all console ports done?
  4375. endif
  4376.      jne    ser_hist_loop        ; loop back if more
  4377.     ret
  4378.  
  4379.  
  4380. hist_init:
  4381. ;---------
  4382. ;    entry:    DX = # of paragraphs for history buffer
  4383. ;    exit:    AX = segment address of history buffer
  4384.  
  4385.     call    mem_alloc_i@            ; allocate DX paragraphs
  4386.     push    es
  4387.      sub    bx,bx
  4388.      mov    es,ax                ; set up segment
  4389.      mov    es:word ptr  [bx],bx
  4390.      mov    es:byte ptr 4[bx],bl
  4391.      shl dx,1 ! shl dx,1
  4392.      shl dx,1 ! shl dx,1              ; para. to bytes
  4393.      sub    dx,5                ; size of header
  4394.      mov    es:word ptr 2[bx],dx
  4395.     pop    es
  4396.     ret
  4397.  
  4398. alloc_setup_buff:
  4399. ;----------------
  4400. ; This routine looks in the setup buffer for amount of SYSDAT space
  4401. ; requested for device drivers, etc., allocates it, and updates the
  4402. ; variables for the XIOS sysdat_alloc call:
  4403.     cmp    su_check$,0DDB2h        ; is the buffer valid?
  4404.      jne    asb_done
  4405.     mov    dx,su_sysdat$            ; get BYTES requested
  4406.     or    dx,dx                ; anything?
  4407.      jz    asb_done            ; jump if no
  4408. asb_retry:
  4409.     call    sysdat_mem_alloc
  4410.     inc    ax                ; FFFF -> 0 if none at all
  4411.      jz    asb_done
  4412.     dec    ax
  4413.     cmp    ax,0                ; some?
  4414.      jnz    store_addr            ; jump if a good alloc
  4415.     sub    dx,10h                ; drop down a para and retry
  4416.      jbe    asb_done            ; if negative or 0, leave
  4417.     jmps    asb_retry
  4418.  
  4419. store_addr:
  4420.     mov    sysdat_buff_base$,ax        ; initted to 0
  4421.     mov    sysdat_buff_length$,dx
  4422.     mov    si,sysdat_mem$            ; sysdat memory allocation block
  4423.     mov    sysdat_buff_link$,si        ; and store in our block
  4424.     mov    sysdat_mem$,offset sysdat_buff_link$    ; set link to free block
  4425. asb_done:
  4426.     ret
  4427. eject
  4428.  
  4429. do_interrupts:
  4430. ;-------------
  4431. ; Take care of all of the interrupt stuff...
  4432. ; if an interrupt vector is currently zero (uninitialized)
  4433. ; then set it to the unexpected interrupt handler:
  4434. ; 20 JUN 86--to support some more dumb apps, set up our unexpected handler
  4435. ; only if a developer has tweeked the patch byte: 
  4436.  
  4437.     cli                    ; an interrupt now would be bad
  4438.  
  4439.     sub    di,di                ; int vector pointer
  4440.     mov    es,di                ; int vector base address
  4441.     cmp    unexp_byte,0BBh            ; do we put in our handler?
  4442.      je    int_setup1            ; if different, don't skip
  4443.     mov    cx,256                ; number of interrupts
  4444. int_save_loop:
  4445.     mov    ax,es:[di]            ; fetch the current vector
  4446.     or    ax,es:2[di]            ;   and if it has a value
  4447.      jnz    int_save_next            ;   then leave it alone
  4448.  
  4449.     mov    es:[di],offset i_unexpected@
  4450.     mov    es:2[di],cs            ; if not, fill it in
  4451. int_save_next:
  4452.     add    di,4                ; to the next vector
  4453.     loop    int_save_loop            ; through the whole table
  4454.  
  4455. ; Now set up our particular interrupts:
  4456.  
  4457. int_setup1:
  4458.     mov    si,offset int_tbl        ; offsets and vectors
  4459.     mov    cx,INT_TBL_LEN            ; number of entries
  4460.     mov    ax,ds
  4461.     cmp    ax,3000h            ; debug sys?
  4462.      jb    no_int3_fix
  4463.     dec    cx
  4464. no_int3_fix:
  4465.     cld
  4466.     lodsw                    ; first check if NMI ->
  4467.     mov    di,ax                ; to ROS. If not then leave
  4468.     lodsw                    ; well alone (autoswitch cards)
  4469.     cmp    es:word ptr 2[di],0e000h    ; ROS segment ?? watch 386's
  4470.     jb    int_setup_dec            ; not pointing to ROS
  4471.     jmps    int_store
  4472. int_setup_loop:
  4473.     lodsw                    ; get destination
  4474.     mov    di,ax                ;   and stash it
  4475.     lodsw                    ; get vector
  4476. int_store:
  4477.     stosw                    ;   and store it
  4478.     mov    ax,cs                ; all vectors to sysdat
  4479.     stosw
  4480. int_setup_dec:
  4481.     loop    int_setup_loop            ; through the table
  4482.  
  4483. ; Now set up timer interrupt:
  4484.     mov    ax,timer_count$            ; variable timer count
  4485.     out    TIMER_0_REG,al
  4486.     xchg    ah,al
  4487.     out    TIMER_0_REG,al
  4488.     ret                    ; to main line
  4489.  
  4490. unexp_byte    db    0BBh            ; anything else, we'll install
  4491.                         ; the unexpected handler
  4492. eject
  4493.  
  4494. sign_on:
  4495. ;-------
  4496. ; Print the sign on message with equipment configuration:
  4497.  
  4498.     mov    dl,0                ; console 0
  4499.     call    point_vs@
  4500.     push    word ptr VS_ATTRIB        ; save initial one
  4501.     push    bx                ; save vs_pointer
  4502.     mov    al,iattrib$
  4503.     mov    VS_ATTRIB,al
  4504.  
  4505.     mov    si,offset banner
  4506.     call    print_msg            ; name, copyright, etc.
  4507.  
  4508.     pop    bx                ; restore vs_pointer
  4509.     pop    word ptr VS_ATTRIB        ; restore original attribute
  4510.  
  4511. if XM
  4512.     mov    si,offset num_pgkb$        ; address of paged memory count
  4513.     cmp    word ptr [si],0            ; any paged memory?
  4514.      je    sign_on_conv            ; no, all conventional
  4515.     mov    emm_fix,si            ; "paged" instead of "main"
  4516.     push    es
  4517.     push    ds ! pop es
  4518.     mov    si,offset emm_pag        ; print different message
  4519.     mov    di,offset emm_fix+4
  4520.     mov    cx,length emm_pag
  4521.     rep    movsb
  4522.     pop    es
  4523. sign_on_conv:
  4524. endif
  4525.     mov    si,offset hdware        ; Hardware supported:
  4526.     call    print_msg
  4527. sign_on_loop:
  4528.     cmp    word ptr [si],0            ; if next equip ptr = 0
  4529.      jz    sign_on_done            ;   then we're done
  4530.     push    si
  4531.     call    print_equip            ; print one item
  4532.     pop    si
  4533.     add    si,EQUIP_RECORD_LEN
  4534.     jmps    sign_on_loop            ; back for another
  4535. sign_on_done:
  4536.     lodsw                    ; clear the pointer
  4537.     call    print_msg            ; cr,lf,lf
  4538.  
  4539. ; Help 'em out by printing legal printer numbers:
  4540.     cmp    byte ptr sign_on_prnum1,' '    ; space in second line
  4541.     jne    print_2line
  4542.     mov    byte ptr end_prnum,0        ; terminate after first line
  4543. print_2line:
  4544.     mov    si,offset prnt_num_msg
  4545.     call    print_msg            ; and return
  4546.     ret
  4547.  
  4548.  
  4549. print_equip:
  4550.     lodsw
  4551.     xchg    ax,bx                ; bx -> equip count
  4552.     mov    ax,[bx]                ; ax = equip count
  4553.     test    ax,ax                ; if count = 0
  4554.      jz    pr_equip_done            ;   then don't print
  4555.     push    ax                ; save the count
  4556.     call    print_msg            ; print the name first
  4557.     pop    ax
  4558.     call    print_num            ;   and then the count
  4559. pr_equip_done:
  4560.     ret
  4561.  
  4562. print_msg:
  4563.     lodsb                    ; fetch a character
  4564. pr_msg_loop:
  4565.     push    si
  4566.     call    print_char            ; print just one
  4567.     pop    si
  4568.     lodsb                    ; fetch another
  4569.     test    al,al
  4570.      jnz    pr_msg_loop            ; when char = 0, done
  4571.     ret
  4572.  
  4573. print_num:
  4574.     sub    dx,dx                ; for 16-bit divide
  4575.     div    ten_thousand
  4576.     push    dx                ; save remainder
  4577.     sub    dh,dh                ; yes, zero blanking
  4578.     call    print_digit
  4579.     pop    ax                ; restore thou,hun,ten,ones
  4580.     mov    cx,dx                ; save leading digit's flag
  4581.     sub    dx,dx                ; for 16-bit divide
  4582.     div    one_thousand
  4583.     push    dx                ; save remainder
  4584.     mov    dx,cx                ; restore leading digit's flag
  4585.     call    print_digit
  4586.     pop    ax                ; restore hun,ten,ones
  4587.     div    one_hundred            ; al = hund's, ah = rem
  4588.     call    print_digit            ; print hundred's place
  4589.     mov    al,ah
  4590.     cbw                    ; ready for divide
  4591.     div    ten
  4592.     call    print_digit            ; print ten's place    
  4593.     mov    al,ah
  4594. ;    jmps    print_digit            ; print one's place
  4595.  
  4596. print_digit:
  4597.     push    ax                ; save the number
  4598.     or    dh,al                ; have we started printing
  4599.      jz    pr_digit_done            ;   skip if 0 and no
  4600.     push    dx
  4601.     or    al,'0'                ; make into ascii
  4602.     call    print_char            ; and print it
  4603.     pop    dx
  4604. pr_digit_done:
  4605.     pop    ax                ; restore number
  4606.     ret
  4607.  
  4608. print_char:
  4609.     mov    cl,al                ; char to cl
  4610.     mov    dl,0
  4611.     jmp    io_conout@            ; print it
  4612. eject
  4613.  
  4614. eject
  4615.  
  4616. default_prnt:
  4617. ;------------
  4618. ; Find lowest existing printer number and stick in the PDs of all
  4619. ; phase1 and phase2 RSPs.
  4620.  
  4621.     mov    bx,offset sign_on_prnum
  4622.     mov    cx,5
  4623. dp_lp:    
  4624.     mov    al,[bx]
  4625.     cmp    al,' '
  4626.      jne    found_prnt
  4627.     add    bx,2
  4628.     loop    dp_lp
  4629.     ret         
  4630.  
  4631. found_prnt:
  4632.     and    al,0fh            ; make binary
  4633.     push    es
  4634.     mov    bx,ds
  4635.     mov    es,bx
  4636.     mov    bx,rspseg$
  4637.     call    poke_prnt
  4638.     mov    bx,phase1_root$
  4639.     call    poke_prnt
  4640.     pop    es
  4641.     ret    
  4642.  
  4643. poke_prnt:
  4644. ; Entry: BX = RSP header segment
  4645.     or    bx,bx
  4646.      jz    end_poke
  4647.     mov    es,bx
  4648.     mov    es:.10h + P_LIST,al        ; skip RSP header.
  4649.     mov    bx,es:.0            ; get link
  4650.     jmps    poke_prnt
  4651. end_poke:
  4652.     ret
  4653.         
  4654.  
  4655. alloc_flag@:
  4656. ;-----------
  4657.     mov    al,next_flag$
  4658.     inc    next_flag$
  4659.     ret
  4660.  
  4661.  
  4662. enable_ints:
  4663. ;-----------
  4664. ; Finally, enable the interrupts:
  4665.  
  4666.     mov    dx,AUX_PORT0            ; clear pending ones
  4667.     call    reset_uarts
  4668.     mov    dx,AUX_PORT1
  4669.     call    reset_uarts
  4670.  
  4671.     mov    al,pic_mask_image$        ; restore the pic mask
  4672.     out    PIC_MASK,al
  4673.     sti                    ; now we can handle ints
  4674.     ret                    ; to main line
  4675.  
  4676. reset_uarts:
  4677. ;    add    dx,AUX_PORT_DATA        ; get any pending received
  4678.     in    al,dx                ; data
  4679.     jmps    $+2
  4680.     add    dx,2                ; IIR
  4681.     in    al,dx                ; reset trans-rdy int
  4682.     jmps    $+2
  4683.     add    dx,3                ; line status
  4684.     in    al,dx                ; reset error interrupt
  4685.     jmps    $+2
  4686.     inc    dx                ; modem status
  4687.     in    al,dx                ; reset protocol interrupt
  4688.     ret
  4689. eject
  4690.  
  4691. INITCODE_END    equ    $
  4692.  
  4693. ;************************************************
  4694. ;*                        *
  4695. ;*        INITIALIZATION DATA AREA        *
  4696. ;*                        *
  4697. ;************************************************
  4698.  
  4699. init_dseg dseg
  4700.  
  4701. INIT_START    equ    offset $
  4702.  
  4703. hi_on$        dw    00000h        ; on if high memory always OK
  4704. hi_off$        dw    0FFFFh        ; off if high memory never OK
  4705.  
  4706. alloc_table    rw    0
  4707.     dw    0,0,0,0,0,0,0,0,0,0    ; 30 entries
  4708.     dw    0,0,0,0,0,0,0,0,0,0
  4709.     dw    0,0,0,0,0,0,0,0,0,0
  4710.     dw    0,0,0,0,0,0,0,0,0,0
  4711.     dw    0,0,0,0,0,0,0,0,0,0
  4712.     dw    0,0,0,0,0,0,0,0,0,0
  4713.     dw    0,0,0,0,0,0,0,0,0,0
  4714.     dw    0,0,0,0,0,0,0,0,0,0
  4715.     dw    0,0,0,0,0,0,0,0,0,0
  4716.     dw    0,0,0,0,0,0,0,0,0,0
  4717.  
  4718.  
  4719. memory_top    rw    1    ; for memory_trim
  4720.  
  4721. config0_data    db    43h    ; 300 baud, 1, none, 8
  4722. config1_data    db    43h    ; same here
  4723. config_data    equ    word ptr config0_data
  4724.         rb    NUM_AUX_PORTS-2    ; all other serial ports go here
  4725.  
  4726. term_data    rb    NUM_AUX_PORTS    ; 0=LST/AUX, FF=CON (up to 9 ports)
  4727. current_pc$    db    0    ; current physical console number assigned
  4728.                 ; only used during INIT
  4729. if V386
  4730. ega_remap    db    FALSE    ; flag if we've moved the EGA ROS
  4731. endif
  4732.  
  4733. init_video_mode    rb    1    ; which crt to default
  4734. pic_mask_image$    rb    1    ; set at the top of init
  4735. pc_pt_bootable    db    0    ; <> 0 if pc partition bootable
  4736. boot_drive    rb    1    ; ROS code for the boot drive
  4737. reloc_disk$    dw    0    ; size of hard disk param table if moved
  4738.  
  4739. ; some pc hard disk data - moved from HDISK.A86
  4740.  
  4741. pc_blk_size    dw    0400h,0800h,1000h,2000h,4000h,4000h,4000h
  4742. pc_bsh_blm    dw    0703h,0F04h,1F05h,3F06h,7F07h,7F07h,7F07h
  4743. pc_hd_dph_start    rw    1
  4744. hd_dph_start    rw    1
  4745. hd_dos_sys_id    db    0            ; temporarily save system id code
  4746. drive_num    db    0            ; temp drive number storage
  4747. maxpsh        db    2            ; max. sector size (2 = 512)
  4748. local_bsize    dw    2*512            ; 1 Kb unless CP/M hard disks
  4749.  
  4750. pc_part_table_iopb:
  4751.     db    HD_ROS_READ,0,0,0        ; fn,err,lun,head
  4752.     dw    0                ; cyl
  4753.     db    0,1                ; sector, count
  4754.     dw    0,0                ; must be preset to ds
  4755.  
  4756. ; String to look for at AT_HDROS_SEG:AT_HDROS_OFF to identify the
  4757. ; multi-sector bug:
  4758.  
  4759. buggy_string db    47h,0E2h,0F9h,0E8h,2Dh,1,75h,7,0F6h,6,8Ch,0,80h,75h,0CDh,0C3h
  4760.  
  4761. ; Lists of dph offsets:
  4762.  
  4763.  
  4764. ; Lists of branch vector offsets:
  4765.  
  4766. flop_vectors    dw    select_flop@, read_flop@, write_flop@
  4767. pc_hd_vectors    dw    pc_select_hd@, pc_read_hd@, pc_write_hd@
  4768. eject
  4769.  
  4770. ; The following structure is used to write to the COMPAQ
  4771. ; memory configuration register in order to permit writing
  4772. ; to COMPAQ 32-bit RAM at E000:0-FFFF:0
  4773.  
  4774. if V386
  4775.         ;-----------------------;
  4776. int15_gdt    rb    8        ; null entry - dummy
  4777.         ;-----------------------;
  4778.         rb    8        ; GDT entry - filled in by ROS
  4779.         ;-----------------------;
  4780.         dw    -1        ; segment limit = 64K
  4781.         db    0,0,0,93H    ; base address, attribute
  4782.         db    0, 0        ; 386 extension
  4783.         ;-----------------------;
  4784.         dw    -1        ; segment limit = 64K
  4785.         db    0,0,0,93H    ; base address, attribute
  4786.         db    0, 0        ; 386 extension
  4787.         ;-----------------------;
  4788.         rb    8        ; BIOS CS entry - filled in by ROS
  4789.         ;-----------------------;
  4790.         rb    8        ; BIOS SS entry - filled in by ROS
  4791.         ;-----------------------;
  4792.  
  4793.                     ; Compaq memory control port value:
  4794. int15_config    dw    0FEFEh        ; map RAM, don't write protect
  4795.  
  4796. endif
  4797.  
  4798. LUC equ 201 ! LLC equ 200 ! RUC equ 187 ! RLC equ 188
  4799. HU equ 205  ! HL equ 205
  4800. VVR equ 186 ! VVL equ 186
  4801.  
  4802. banner    db ESC,'H'        ; home cursor
  4803.     db LUC
  4804.     db HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU    ;20
  4805.     db HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU    ;20
  4806.     db HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU,HU            ;15
  4807.     db RUC,CR,LF
  4808.     
  4809.  
  4810. ;banner    db '-----------------------------------------------------',CR,LF
  4811. if XM
  4812.     db VVL,' Concurrent DOS XM for the IBM PC, XT, AT     9-Jan-89 ',VVR,CR,LF
  4813. endif
  4814. if V386
  4815.     db VVL,' Concurrent DOS 386 for Intel 386 based PC''s  9-Jan-89 ',VVR,CR,LF
  4816. endif
  4817.     db VVL,' Copyright(C) 1982-89              All Rights Reserved ',VVR,CR,LF
  4818.     db VVL,' Digital Research, Inc.      Monterey, California, USA ',VVR,CR,LF
  4819.  
  4820.     db LLC
  4821.     db HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL    ;20
  4822.     db HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL    ;20
  4823.     db HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL            ;15
  4824.     db RLC,CR,LF;LF
  4825.  
  4826.     db    0
  4827. hdware:
  4828.     db       '            Hardware Supported :',CR,LF,0
  4829.  
  4830.     dw num_flop$
  4831.     db CR,LF,'             Diskette Drive(s) : ',0
  4832.     dw num_hard$
  4833.     db CR,LF,'                  Hard Disk(s) : ',0
  4834.     dw num_print$
  4835.     db CR,LF,'      Parallel Printer Port(s) : ',0
  4836.     dw num_port$
  4837.     db CR,LF,'                Serial Port(s) : ',0
  4838.     dw num_ndp$
  4839.     db CR,LF,'        Numeric Data Processor : ',0
  4840. last_eq        rw    0
  4841. if XM
  4842. emm_fix    dw num_mmkb$
  4843.     db CR,LF,'              Main Memory (Kb) : ',0
  4844. endif
  4845. if V386
  4846.     dw num_pages$
  4847.     db CR,LF,'         386 Paged Memory (Kb) : ', 0
  4848. endif
  4849.  
  4850. EQUIP_RECORD_LEN    equ    offset $ - offset last_eq
  4851.     dw 0                ; equipment end
  4852.     db CR,LF,0            ; last message
  4853.  
  4854. prnt_num_msg    rb    0
  4855.     db       '               Printer Numbers : '
  4856. sign_on_prnum    db    '                           '    ; printers + spaces
  4857.     db    CR,LF
  4858. end_prnum    db       '                                 '    ; padding
  4859. sign_on_prnum1    db    '                           '    ; printers + spaces
  4860.     db    CR,LF,0
  4861.  
  4862. ;    db CR,LF,'              Main Memory (Kb) : ',0
  4863. ;    db CR,LF,'        EEMS Paged Memory (Kb) : ',0
  4864. emm_pag    db       '        EEMS Paged'    ; remainder same as "Main Memory (Kb)"
  4865.  
  4866.  
  4867. ten_thousand    dw    10000    ; for print_number divisions
  4868. one_thousand    dw    1000
  4869. one_hundred    db    100
  4870. ten        db    10
  4871. eject
  4872.  
  4873. ;    Interrupt setup table
  4874.  
  4875. int_tbl    dw    NMI_INTERRUPT*4,    i_nmi@        ; MUST be first in list
  4876.     dw    DIVIDE_INTERRUPT*4,    i_divide@
  4877.     dw    OVERFLOW_INTERRUPT*4,    i_overflow@
  4878.     dw    CLOCK_INTERRUPT*4,    i_clock@
  4879.     dw    TICK_INTERRUPT*4,    i_tick@
  4880.     dw    KEYBOARD_INTERRUPT*4,    i_keyboard@
  4881.     dw    AUX1_INTERRUPT*4,    i_aux_1@
  4882.     dw    AUX0_INTERRUPT*4,    i_aux_0@
  4883.     dw    DISK_INTERRUPT*4,    i_disk@
  4884.     dw    HD_CODE_INTERRUPT*4,    hd_dummy_int@
  4885. ;;    dw    BREAK_INTERRUPT*4,    i_cntl_brk@
  4886.     dw    VIDEO_INT*4,        video_int@
  4887.     dw    ASYNC_INT*4,        async_int@
  4888.     dw    FLAG_INTERRUPT*4,    i_fidds_flag@
  4889.     dw    FIDDS_INTERRUPT*4,    i_dummy_fidds@
  4890.     dw    ONE_BYTE_INTERRUPT*4,    iret_op@    ; must be last!
  4891.  
  4892. INT_TBL_LEN    equ    (offset $ - offset int_tbl) / 4
  4893.  
  4894. month_length    dw    0,31,59,90,120,151    ; days in prior months
  4895.         dw    181,212,243,273,304,334
  4896.  
  4897. if 0 ;#IJ
  4898. pctmpstr    db    'PCTmp0  '        ; PCTmp0 - PCTmp#
  4899. pinstr        db    'PIN0    '        ; PIN0 - PIN#
  4900. endif
  4901.  
  4902. if V386
  4903. flushstr    db    'Flush1  '        ; Flush1 - Flush#
  4904. endif
  4905.  
  4906. compaq_name    db    'COMPAQ'
  4907. if V386
  4908. sprite_name    db    'JAROGATE'
  4909. endif
  4910. if XM
  4911. amstrad_name    db    'Amstrad'
  4912. olivetti_name    db    'OLIVETTI'
  4913. endif
  4914.  
  4915.  
  4916.  
  4917. XIOS_END    equ    offset $
  4918.  
  4919. end
  4920. ;END OF INIT.A86
  4921.