Subversion Repositories Kolibri OS

Rev

Rev 9942 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
  4. ;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa      ;;
  5. ;; Distributed under terms of the GNU General Public License    ;;
  6. ;;                                                              ;;
  7. ;;  BOOTCODE.INC                                                ;;
  8. ;;                                                              ;;
  9. ;;  KolibriOS 16-bit loader,                                    ;;
  10. ;;                        based on bootcode for MenuetOS        ;;
  11. ;;                                                              ;;
  12. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  13.  
  14. $Revision: 9958 $
  15.  
  16.  
  17. ;==========================================================================
  18. ;
  19. ;                           16 BIT FUNCTIONS
  20. ;
  21. ;==========================================================================
  22.  
  23.  
  24. putchar:
  25. ; in: al=character
  26.         mov     ah, 0Eh
  27.         mov     bh, 0
  28.         int     10h
  29.         ret
  30.  
  31. print:
  32. ; in: si->string
  33.         mov     al, 186
  34.         call    putchar
  35.         mov     al, ' '
  36.         call    putchar
  37.  
  38. printplain:
  39. ; in: si->string
  40.         pusha
  41.         lodsb
  42. @@:
  43.         call    putchar
  44.         lodsb
  45.         test    al, al
  46.         jnz     @b
  47.         popa
  48.         ret
  49.  
  50. getkey:                         ; Use BIOS INT 16h to read a key from the keyboard
  51. ; get number in range [bl,bh] (bl,bh in ['0'..'9'])
  52. ; in: bx=range
  53. ; out: ax=digit (1..9, 10 for 0)
  54.         mov     ah, 0       ; If 'int 16h' is called with 'ah' equal to zero, the BIOS will not return control to the caller
  55.         int     16h         ; until a key is available in the system type ahead buffer. On return, 'al' contains the ASCII
  56.         cmp     al, 27      ; code for the key read from the buffer and 'ah' contains the keyboard scan code. (27=>ESC)
  57.         jz      @f          ; If ESC is pressed, return (user doesn't want to change any value).
  58.         cmp     al, bl      ; Compare 'al' (ASCII code of key pressed) with 'bl' (lowest accepted char from the range).
  59.         jb      getkey      ; ASCII code is below lowest accepted value => continue waiting for another key.
  60.         cmp     al, bh      ; Compare 'al' (ASCII code of key pressed) with 'bh' (highest accepted char from the range).
  61.         ja      getkey      ; ASCII code is above highest accepted value => continue waiting for another key.
  62.         push    ax          ; If the pressed key is in the accepted range, save it on the stack and echo to screen.
  63.         call    putchar
  64.         pop     ax
  65.         and     ax, 0Fh     ; Convert ASCII code to number: '1'->1, '2'->2, etc. 0Fh=1111b.
  66.         jnz     @f          ; ASCII code for '0' is 48 (110000b). (110000b AND 1111b) = 0
  67.         mov     al, 10      ; So if key '0' was entered, return 10 in 'ax'
  68. @@:
  69.         ret
  70.  
  71. setcursor:
  72. ; in: dl=column, dh=row
  73.         mov     ah, 2
  74.         mov     bh, 0
  75.         int     10h
  76.         ret
  77.  
  78. macro _setcursor row,column
  79. {
  80.         mov     dx, row*256 + column
  81.         call    setcursor
  82. }
  83.  
  84. macro _ask_question question,range,variable_to_set
  85. {
  86.         _setcursor 16,0
  87.         mov     si, question    ; Print the question
  88.         call    print
  89.         mov     bx, range       ; range accepted for answer
  90.         call    getkey
  91.         cmp     al, 27          ; If ESC was pressed, do not change the value
  92.         jz      .esc_pressed
  93.         mov     [variable_to_set], al
  94. }
  95.  
  96. clear_status_field:
  97.         mov     si, space_msg
  98.         mov     byte [si+80], 0
  99.         _setcursor 16,0
  100.         call    printplain
  101.         _setcursor 16,0
  102.         ret
  103.  
  104. boot_read_floppy:
  105.         push    si
  106.         xor     si, si
  107.         mov     ah, 2   ; read
  108. @@:
  109.         push    ax
  110.         int     0x13
  111.         pop     ax
  112.         jnc     @f
  113.         inc     si
  114.         cmp     si, 10
  115.         jb      @b
  116. sayerr_badsect:
  117.         mov     si, badsect
  118. sayerr_plain:
  119.         call    printplain
  120.         jmp     $
  121. @@:
  122.         pop     si
  123.         ret
  124.  
  125. ; convert abs. sector number (AX) to BIOS T:H:S
  126. ; sector number = (abs.sector%BPB_SecPerTrk)+1
  127. ; pre.track number = (abs.sector/BPB_SecPerTrk)
  128. ; head number = pre.track number%BPB_NumHeads
  129. ; track number = pre.track number/BPB_NumHeads
  130. ; Return: cl - sector number
  131. ;         ch - track number
  132. ;         dl - drive number (0 = a:)
  133. ;         dh - head number
  134. conv_abs_to_THS:
  135.         push    bx
  136.         mov     bx, word [BPB_SecPerTrk]
  137.         xor     dx, dx
  138.         div     bx
  139.         inc     dx
  140.         mov     cl, dl                          ; cl = sector number
  141.         mov     bx, word [BPB_NumHeads]
  142.         xor     dx, dx
  143.         div     bx
  144.         ; !!!!!!! ax = track number, dx = head number
  145.         mov     ch, al                          ; ch=track number
  146.         xchg    dh, dl                          ; dh=head number
  147.         mov     dl, 0                           ; dl=0 (drive 0 (a:))
  148.         pop     bx
  149.         retn
  150. ; needed variables
  151. BPB_SecPerTrk   dw      0                       ; sectors per track
  152. BPB_NumHeads    dw      0                       ; number of heads
  153. BPB_FATSz16     dw      0                       ; size of FAT
  154. BPB_RootEntCnt  dw      0                       ; count of root dir. entries
  155. BPB_BytsPerSec  dw      0                       ; bytes per sector
  156. BPB_RsvdSecCnt  dw      0                       ; number of reserved sectors
  157. BPB_TotSec16    dw      0                       ; count of the sectors on the volume
  158. BPB_SecPerClus  db      0                       ; number of sectors per cluster
  159. BPB_NumFATs     db      0                       ; number of FAT tables
  160. abs_sector_adj  dw      0                       ; adjustment to make abs. sector number
  161. end_of_FAT      dw      0                       ; end of FAT table
  162. FirstDataSector dw      0                       ; begin of data
  163.  
  164. ;=========================================================================
  165. ;
  166. ;                           16 BIT CODE
  167. ;
  168. ;=========================================================================
  169.  
  170. include 'bootvesa.inc'                 ;Include source for boot vesa
  171. if defined extended_primary_loader
  172. include 'parsers.inc'
  173. end if
  174.  
  175. start_of_code:
  176.  
  177. if defined extended_primary_loader
  178. ; save data from primary loader
  179.         mov     word [cs:bootcallback], si
  180.         mov     word [cs:bootcallback+2], ds
  181.         push    cs
  182.         pop     ds
  183.         mov     [bootdevice], ax
  184.         mov     [bootfs], bx
  185.  
  186. ; set up stack
  187.         mov     ax, (TMP_STACK_TOP and 0xF0000) shr 4
  188.         mov     ss, ax
  189.         mov     sp, TMP_STACK_TOP and 0xFFFF
  190.  
  191. ; try to load configuration file
  192.         mov     ax, 1
  193.         mov     di, config_file_struct
  194.         call    [bootcallback]
  195.         cld
  196.         push    cs
  197.         pop     es
  198. ; bx=0 - ok, bx=1 - part of file loaded, assume this is ok
  199.         cmp     bx, 1
  200.         ja      .config_bad
  201. ; configuration file was loaded, parse
  202. ; if length is too big, use first 0FFFFh bytes
  203.         test    dx, dx
  204.         jz      @f
  205.         mov     ax, 0FFFFh
  206. @@:
  207. ; ds:si will be pointer to current data, dx = limit
  208.         xchg    ax, dx
  209.         push    4000h
  210.         pop     ds
  211.         xor     si, si
  212. .parse_loop:
  213. ; skip spaces
  214.         cmp     si, dx
  215.         jae     .parse_done
  216.         lodsb
  217.         cmp     al, ' '
  218.         jbe     .parse_loop
  219.         dec     si
  220. ; loop over all possible configuration values
  221.         mov     bx, config_file_variables
  222. .find_variant:
  223. ; get length
  224.         mov     cx, [es:bx]
  225. ; zero length = end of list
  226.         jecxz   .find_newline
  227. ; skip over length
  228.         inc     bx
  229.         inc     bx
  230.         mov     di, bx
  231. ; skip over string
  232.         add     bx, cx
  233. ; test whether we have at least cx symbols left
  234.         mov     ax, cx
  235.         add     ax, si
  236.         jc      .next_variant1
  237.         cmp     ax, dx
  238.         jae     .next_variant1
  239. ; save current position
  240.         push    si
  241. ; compare strings
  242.         repz cmpsb
  243.         jnz     .next_variant2
  244. ; strings are equal; look for "=" with possible spaces before and after
  245. @@:
  246.         cmp     si, dx
  247.         jae     .next_variant2
  248.         lodsb
  249.         cmp     al, ' '
  250.         jbe     @b
  251.         cmp     al, '='
  252.         jnz     .next_variant2
  253. ; ok, we found the true variant
  254. ; ignore saved position on the stack
  255.         pop     ax
  256. ; call the parser
  257.         call    word [es:bx]
  258. ; line parsed, find next
  259. .find_newline:
  260.         cmp     si, dx
  261.         jae     .parse_done
  262.         lodsb
  263.         cmp     al, 13
  264.         jz      .parse_loop
  265.         cmp     al, 10
  266.         jz      .parse_loop
  267.         jmp     .find_newline
  268. .next_variant2:
  269. ; continue to the next variant, restoring current position
  270.         pop     si
  271. .next_variant1:
  272. ; continue to the next variant
  273. ; skip over the parser
  274.         inc     bx
  275.         inc     bx
  276.         jmp     .find_variant
  277. .parse_done:
  278. .config_bad:
  279.  
  280. ; set up segment registers
  281.         push    cs
  282.         pop     ds
  283. else
  284.         cld
  285.         push    0
  286.         pop     es
  287. ; if bootloader sets ax = 'KL', then ds:si points to loader block
  288.         cmp     ax, 'KL'
  289.         jnz     @f
  290.         mov     word [cs:cfgmanager.loader_block], si
  291.         mov     word [cs:cfgmanager.loader_block+2], ds
  292.         mov     word [es:BOOT_LO.kernel_restart], kernel_restart_bootblock
  293. @@:
  294. ; if bootloader sets cx = 'HA' and dx = 'RD', then bx contains identifier of source disk
  295. ; (see comment to BOOT_LO.sys_disk and loader_doc.txt)
  296.         mov     word [es:BOOT_LO.sys_disk], 'r1'  ; default value: /rd/1
  297.         cmp     cx, 'HA'
  298.         jnz     no_hd_load
  299.         cmp     dx, 'RD'
  300.         jnz     no_hd_load
  301.         mov     [es:BOOT_LO.sys_disk], bx
  302. no_hd_load:
  303.  
  304. ; set up stack
  305.         mov     ax, (TMP_STACK_TOP and 0xF0000) shr 4
  306.         mov     ss, ax
  307.         mov     sp, TMP_STACK_TOP and 0xFFFF
  308. ; set up segment registers
  309.         push    cs
  310.         pop     ds
  311.         push    cs
  312.         pop     es
  313. end if
  314.  
  315. ; set videomode
  316.         mov     ax, 3
  317.         int     0x10
  318.  
  319. if lang eq ru
  320.  ; Load & set russian VGA font (RU.INC)
  321.         mov     bp, RU_FNT1             ; RU_FNT1 - First part
  322.         mov     bx, 1000h               ; 768 bytes
  323.         mov     cx, 30h                 ; 48 symbols
  324.         mov     dx, 80h                 ; 128 - position of first symbol
  325.         mov     ax, 1100h
  326.         int     10h
  327.  
  328.         mov     bp, RU_FNT2             ; RU_FNT2 -Second part
  329.         mov     bx, 1000h               ; 512 bytes
  330.         mov     cx, 20h                 ; 32 symbols
  331.         mov     dx, 0E0h                ; 224 - position of first symbol
  332.         mov     ax, 1100h
  333.         int     10h
  334.  ; End set VGA russian font
  335. else if lang eq et
  336.         mov     bp, ET_FNT              ; ET_FNT1
  337.         mov     bx, 1000h               ;
  338.         mov     cx, 255                 ; 256 symbols
  339.         xor     dx, dx                  ; 0 - position of first symbol
  340.         mov     ax, 1100h
  341.         int     10h
  342. end if
  343.  
  344. ; draw frames
  345.         push    0xb800
  346.         pop     es
  347.         xor     di, di
  348.         mov     ah, 1*16+15
  349.  
  350. ; draw top
  351.         mov     si, d80x25_top
  352.         mov     cx, d80x25_top_num * 80
  353. @@:
  354.         lodsb
  355.         stosw
  356.         loop    @b
  357. ; draw spaces
  358.         mov     si, space_msg
  359.         mov     dx, 25 - d80x25_top_num - d80x25_bottom_num
  360. dfl1:
  361.         push    si
  362.         mov     cx, 80
  363. @@:
  364.         lodsb
  365.         stosw
  366.         loop    @b
  367.         pop     si
  368.         dec     dx
  369.         jnz     dfl1
  370. ; draw bottom
  371.         mov     si, d80x25_bottom
  372.         mov     cx, d80x25_bottom_num * 80
  373. @@:
  374.         lodsb
  375.         stosw
  376.         loop    @b
  377.  
  378.         mov     byte [space_msg+80], 0    ; now space_msg is null terminated
  379.  
  380.         _setcursor d80x25_top_num,0
  381.  
  382.  
  383. ; TEST FOR 386+
  384.  
  385.         mov     bx, 0x4000
  386.         pushf
  387.         pop     ax
  388.         mov     dx, ax
  389.         xor     ax, bx
  390.         push    ax
  391.         popf
  392.         pushf
  393.         pop     ax
  394.         and     ax, bx
  395.         and     dx, bx
  396.         cmp     ax, dx
  397.         jnz     cpugood
  398.         mov     si, not386
  399. sayerr:
  400.         call    print
  401.         jmp     $
  402.      cpugood:
  403.  
  404.         push    0
  405.         popf
  406.  
  407. ; set up esp
  408.         movzx   esp, sp
  409.  
  410.         push    0
  411.         pop     es
  412.  
  413.         xor     cx, cx
  414. @@:
  415.         in      al, 64h
  416.         test    al, 2
  417.         loopnz  @b
  418.  
  419.         mov     al, 0xf6        ; Сброс клавиатуры, разрешить сканирование
  420.         out     0x60, al
  421.         xor     cx, cx
  422. @@:
  423.         in      al, 64h
  424.         test    al, 1
  425.         loopz   @b
  426.         in      al, 0x60
  427.  
  428. ; set keyboard typematic rate & delay
  429.         mov     al, 0xf3
  430.         out     0x60, al
  431.         xor     cx, cx
  432. @@:
  433.         in      al, 64h
  434.         test    al, 1
  435.         loopz   @b
  436.         in      al, 0x60
  437.         mov     al, 0
  438.         out     0x60, al
  439.         xor     cx, cx
  440. @@:
  441.         in      al, 64h
  442.         test    al, 1
  443.         loopz   @b
  444.         in      al, 0x60
  445. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  446.         sti
  447. ; --------------- APM ---------------------
  448.         and     word [es:BOOT_LO.apm_version], 0     ; ver = 0.0 (APM not found)
  449.         mov     ax, 0x5300
  450.         xor     bx, bx
  451.         int     0x15
  452.         jc      apm_end                 ; APM not found
  453.         test    cx, 2
  454.         jz      apm_end                 ; APM 32-bit protected-mode interface not supported
  455.         mov     [es:BOOT_LO.apm_version], ax         ; Save APM Version
  456.         mov     [es:BOOT_LO.apm_flags], cx           ; Save APM flags
  457.  
  458.         ; Write APM ver ----
  459.         and     ax, 0xf0f
  460.         add     ax, '00'
  461.         mov     si, msg_apm
  462.         mov     [si + 5], ah
  463.         mov     [si + 7], al
  464.         _setcursor 0, 3
  465.         call    printplain
  466.         ; ------------------
  467.  
  468.         mov     ax, 0x5304              ; Disconnect interface
  469.         xor     bx, bx
  470.         int     0x15
  471.         mov     ax, 0x5303              ; Connect 32 bit mode interface
  472.         xor     bx, bx
  473.         int     0x15
  474.  
  475.         mov     [es:BOOT_LO.apm_entry], ebx
  476.         mov     [es:BOOT_LO.apm_code_32], ax
  477.         mov     [es:BOOT_LO.apm_code_16], cx
  478.         mov     [es:BOOT_LO.apm_data_16], dx
  479.  
  480. apm_end:
  481.         _setcursor d80x25_top_num, 0
  482.  
  483. ; --------------- ACPI ---------------------
  484. ACPI_LO_RSDP_WINDOW_END    = 0x000A0000
  485. ACPI_HI_RSDP_WINDOW_START  = 0x000E0000
  486.  
  487. acpi:
  488.         xor     eax, eax
  489.         mov     [es:BOOT_LO.devicesdat_data], eax
  490.         mov     [es:BOOT_LO.devicesdat_size], eax
  491.         mov     [es:BOOT_LO.acpi_rsdp], eax
  492.         push    ds
  493.         mov     ds, ax
  494.         mov     ax, word [40Eh]
  495.         add     ax, 64
  496. .check:
  497.         mov     ds, ax
  498.         cmp     [ds:0], dword 'RSD '
  499.         jne     .next
  500.         cmp     [ds:4], dword 'PTR '
  501.         jne     .next
  502.         shl     eax, 4
  503.         mov     [es:BOOT_LO.acpi_rsdp], eax
  504.         jmp     .end
  505. .next:
  506.         inc     ax
  507.         ; skip VRAM and ROM area A0000h to E0000h
  508.         cmp     ax, (ACPI_LO_RSDP_WINDOW_END shr 4)
  509.         jne     @f
  510.         add     ax, ((ACPI_HI_RSDP_WINDOW_START - ACPI_LO_RSDP_WINDOW_END) shr 4)
  511. @@:     ; end of 1Mb?
  512.         or      ax, ax
  513.         jnz     .check
  514. .end:
  515.         pop     ds
  516.  
  517. if ~ defined extended_primary_loader
  518. ;CHECK current of code
  519.         cmp     [cfgmanager.loader_block], -1
  520.         jz      noloaderblock
  521.         les     bx, [cfgmanager.loader_block]
  522.         cmp     byte [es:bx], 1
  523.         mov     si, loader_block_error
  524.         jnz     sayerr
  525.         push    0
  526.         pop     es
  527. end if
  528.  
  529. noloaderblock:
  530. ; DISPLAY VESA INFORMATION
  531.         call    print_vesa_info
  532.         call    calc_vmodes_table
  533.         call    check_first_parm   ;check and enable cursor_pos
  534.  
  535. cfgmanager:
  536. ; settings:
  537. ; a) preboot_graph = graphical mode
  538. ;    preboot_gprobe = probe this mode?
  539. ; b) preboot_biosdisk  = use BIOS disks through V86 emulation? // (earlier was: preboot_dma  = use DMA access?)
  540. ; c) preboot_debug = duplicates kernel debug output to the screen
  541. ; d) preboot_launcher = start the first app (right now it's LAUNCHER) after kernel is loaded?
  542. ; e) preboot_device = from where to boot?
  543.  
  544. ; determine default settings
  545. if ~ defined extended_primary_loader
  546.         mov     [.bSettingsChanged], 0
  547. end if
  548.  
  549. ;.preboot_gr_end:
  550.         mov     di, preboot_device
  551. ; if image in memory is present and [preboot_device] is uninitialized,
  552. ; set it to use this preloaded image
  553.         cmp     byte [di], 0
  554.         jnz     .preboot_device_inited
  555. if defined extended_primary_loader
  556.         inc     byte [di]
  557.         cmp     byte [bootdevice], 'f' ; floppy?
  558.         jz      .preboot_device_inited
  559.         inc     byte [di]
  560. else
  561.         cmp     [.loader_block], -1
  562.         jz      @f
  563.         les     bx, [.loader_block]
  564.         test    byte [es:bx+1], 1
  565.         jz      @f
  566.         mov     byte [di], 3
  567.         jmp     .preboot_device_inited
  568. @@:
  569. ; otherwise, set [preboot_device] to 1 (default value - boot from floppy)
  570.         mov     byte [di], 1
  571. end if
  572. .preboot_device_inited:
  573. ; following 4 lines set variables to 1 if its current value is 0
  574.         cmp     byte [di+preboot_dma-preboot_device], 1
  575.         adc     byte [di+preboot_dma-preboot_device], 0
  576.         cmp     byte [di+preboot_launcher-preboot_device], 1        ; Start LAUNCHER by default
  577.         adc     byte [di+preboot_launcher-preboot_device], 0
  578.         _setcursor 5,2
  579.  
  580.         mov     si, linef
  581.         call    printplain
  582.         mov     si, start_msg
  583.         call    print
  584.         mov     si, time_msg
  585.         call    print
  586. ; get start time
  587.         call    .gettime
  588.         mov     [.starttime], eax
  589.         mov     word [.timer], .newtimer
  590.         mov     word [.timer+2], cs
  591. .printcfg:
  592.  
  593.         _setcursor 9,0
  594.         mov     si, current_cfg_msg
  595.         call    print
  596.         mov     si, curvideo_msg
  597.         call    print
  598.  
  599.         call    draw_current_vmode
  600.  
  601.         mov     si, usebd_msg
  602.         cmp     [preboot_biosdisk], 1
  603.         call    .say_on_off
  604.         mov     si, debug_mode_msg
  605.         cmp     [preboot_debug], 1
  606.         call    .say_on_off
  607.         mov     si, launcher_msg
  608.         cmp     [preboot_launcher], 1
  609.         call    .say_on_off
  610.         mov     si, preboot_device_msg
  611.         call    print
  612.         mov     al, [preboot_device]
  613. if defined extended_primary_loader
  614.         and     eax, 3
  615. else
  616.         and     eax, 7
  617. end if
  618.         mov     si, [preboot_device_msgs+eax*2]
  619.         call    printplain
  620. .show_remarks:
  621. ; show remarks in gray color
  622.         mov     di, ((21-num_remarks)*80 + 2)*2
  623.         push    0xB800
  624.         pop     es
  625.         mov     cx, num_remarks
  626.         mov     si, remarks
  627. .write_remarks:
  628.         lodsw
  629.         push    si
  630.         xchg    ax, si
  631.         mov     ah, 1*16+7      ; background: blue (1), foreground: gray (7)
  632.         push    di
  633. .write_remark:
  634.         lodsb
  635.         test    al, al
  636.         jz      @f
  637.         stosw
  638.         jmp     .write_remark
  639. @@:
  640.         pop     di
  641.         pop     si
  642.         add     di, 80*2
  643.         loop    .write_remarks
  644. .wait:
  645.         _setcursor 25,0         ; out of screen
  646. ; set timer interrupt handler
  647.         cli
  648.         push    0
  649.         pop     es
  650.         push    dword [es:8*4]
  651.         pop     dword [.oldtimer]
  652.         push    dword [.timer]
  653.         pop     dword [es:8*4]
  654. ;        mov     eax, [es:8*4]
  655. ;        mov     [.oldtimer], eax
  656. ;        mov     eax, [.timer]
  657. ;        mov     [es:8*4], eax
  658.         sti
  659. ; wait for keypressed
  660.         xor     ax, ax
  661.         int     16h
  662.         push    ax
  663. ; restore timer interrupt
  664. ;        push    0
  665. ;        pop     es
  666.         mov     eax, [.oldtimer]
  667.         mov     [es:8*4], eax
  668.         mov     [.timer], eax
  669.  
  670.         _setcursor 7,0
  671.         mov     si, space_msg
  672.         call    printplain
  673. ; clear remarks and restore normal attributes
  674.         push    es
  675.         mov     di, ((21-num_remarks)*80 + 2)*2
  676.         push    0xB800
  677.         pop     es
  678.         mov     cx, num_remarks
  679.         mov     ax, ' ' + (1*16 + 15)*100h
  680. @@:
  681.         push    cx
  682.         mov     cx, 76
  683.         rep stosw
  684.         pop     cx
  685.         add     di, 4*2
  686.         loop    @b
  687.         pop     es
  688.         pop     ax
  689. ; switch on key
  690.         cmp     al, 13
  691.         jz      .continue
  692.         or      al, 20h
  693.         cmp     al, 'a'         ; select graphical mode
  694.         jz      .change_a
  695.         cmp     al, 'q'         ; Trick to make 'A' key on azerty keyboard work
  696.         je      .change_a
  697.         cmp     al, 'b'         ; use BIOS disks? // (selecting YES will make BIOS disks visible as /bd)
  698.         jz      .change_b
  699.         cmp     al, 'c'         ; load kernel in debug mode?
  700.         jz      .change_c
  701.         cmp     al, 'd'         ; start launcher after kernel is loaded?
  702.         jz      .change_d
  703.         cmp     al, 'e'         ; select boot origin
  704.         jnz     .show_remarks
  705. ; e) preboot_device = from where to boot?
  706. if defined extended_primary_loader
  707.         _ask_question bdev,'13',preboot_device  ; range accepted for answer: 1-3
  708. else
  709.         _ask_question bdev,'14',preboot_device              ; range accepted for answer: 1-4
  710. end if
  711.         _setcursor 14,0
  712.  
  713. .d:
  714. if ~ defined extended_primary_loader
  715.         mov     [.bSettingsChanged], 1
  716. end if
  717. .esc_pressed:
  718.         call    clear_vmodes_table             ;clear vmodes_table
  719.         jmp     .printcfg
  720.  
  721. .change_a:
  722.         call    clear_vmodes_table             ;clear vmodes_table
  723.  
  724.         mov     si, word [cursor_pos]
  725.         mov     word [cursor_pos_old], si
  726. .loops:
  727.         call    draw_vmodes_table
  728.         _setcursor 25,0         ; out of screen
  729.         xor     ax, ax
  730.         int     0x16
  731. ;        call    clear_table_cursor             ;clear current position of cursor
  732.  
  733.         mov     si, word [cursor_pos]
  734.  
  735.         cmp     al, 27              ; If ESC was pressed, do not change the value
  736.         jnz     @f                   ; Just exit the resolution selection box
  737.  
  738.         mov     si, word [cursor_pos_old]
  739.         mov     word [cursor_pos], si
  740.         jmp     .esc_pressed
  741. @@:
  742.         cmp     ah, 0x48;x,0x48E0               ; up
  743.         jne     .down
  744.         cmp     si, modes_table
  745.         jbe     .loops
  746.         sub     word [cursor_pos], size_of_step
  747.         jmp     .loops
  748.  
  749. .down:
  750.         cmp     ah, 0x50;x,0x50E0               ; down
  751.         jne     .pgup
  752.         cmp     word[es:si+10], -1
  753.         je      .loops
  754.         add     word [cursor_pos], size_of_step
  755.         jmp     .loops
  756.  
  757. .pgup:
  758.         cmp     ah, 0x49                ; page up
  759.         jne     .pgdn
  760.         sub     si, size_of_step*long_v_table
  761.         cmp     si, modes_table
  762.         jae     @f
  763.         mov     si, modes_table
  764. @@:
  765.         mov     word [cursor_pos], si
  766.         mov     si, word [home_cursor]
  767.         sub     si, size_of_step*long_v_table
  768.         cmp     si, modes_table
  769.         jae     @f
  770.         mov     si, modes_table
  771. @@:
  772.         mov     word [home_cursor], si
  773.         jmp     .loops
  774.  
  775. .pgdn:
  776.         cmp     ah, 0x51                ; page down
  777.         jne     .enter
  778.         mov     ax, [end_cursor]
  779.         add     si, size_of_step*long_v_table
  780.         cmp     si, ax
  781.         jb      @f
  782.         mov     si, ax
  783.         sub     si, size_of_step
  784. @@:
  785.         mov     word [cursor_pos], si
  786.         mov     si, word [home_cursor]
  787.         sub     ax, size_of_step*long_v_table
  788.         add     si, size_of_step*long_v_table
  789.         cmp     si, ax
  790.         jb      @f
  791.         mov     si, ax
  792. @@:
  793.         mov     word [home_cursor], si
  794.         jmp     .loops
  795.  
  796. .enter:
  797.         cmp     al, 0x0D;x,0x1C0D               ; enter
  798.         jne     .loops
  799.         push    word [cursor_pos]
  800.         pop     bp
  801.         push    word [es:bp]
  802.         pop     word [x_save]
  803.         push    word [es:bp+2]
  804.         pop     word [y_save]
  805.         push    word [es:bp+6]
  806.         pop     word [number_vm]
  807.         mov     word [preboot_graph], bp          ;save choose
  808.        
  809.         jmp     .d
  810.  
  811. .change_b:                      ; b) preboot_biosdisk  = use BIOS disks through V86 emulation?
  812. ;        _setcursor 16,0
  813. ;        mov     si, ask_dma    // (earlier was: preboot_dma  = use DMA access?)
  814. ;        call    print
  815. ;        mov     bx, '13'       ; range accepted for answer: 1-3
  816. ;        call    getkey
  817. ;        mov     [preboot_dma], al
  818.         _ask_question ask_bd,'12',preboot_biosdisk              ; range accepted for answer: 1-2
  819.         _setcursor 11,0
  820.         jmp     .d
  821. .change_c:                      ; c) preboot_debug = duplicates kernel debug output to the screen
  822.         _ask_question ask_debug,'12',preboot_debug              ; range accepted for answer: 1-2
  823.         _setcursor 12,0
  824.         jmp     .d
  825. .change_d:                      ; d) preboot_launcher = start the first app (right now it's LAUNCHER) after kernel is loaded?
  826.         _ask_question ask_launcher,'12',preboot_launcher        ; range accepted for answer: 1-2
  827.         _setcursor 13,0
  828.         jmp     .d
  829. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  830. .say_on_off:
  831.         pushf
  832.         call    print
  833.         mov     si, on_msg
  834.         popf
  835.         jz      @f
  836.         mov     si, off_msg
  837. @@:
  838.         jmp     printplain
  839. ; novesa and vervesa strings are not used at the moment of executing this code
  840. virtual at novesa
  841. .oldtimer dd ?
  842. .starttime dd ?
  843. if ~ defined extended_primary_loader
  844. .bSettingsChanged db ?
  845. end if
  846. .timer dd ?
  847. end virtual
  848. if ~ defined extended_primary_loader
  849. .loader_block dd -1
  850. end if
  851. .gettime:
  852.         mov     ah, 0
  853.         int     1Ah
  854.         xchg    ax, cx
  855.         shl     eax, 10h
  856.         xchg    ax, dx
  857.         ret
  858. .newtimer:
  859.         push    ds
  860.         push    cs
  861.         pop     ds
  862.         pushf
  863.         call    [.oldtimer]
  864.         pushad
  865.         call    .gettime
  866.         sub     eax, [.starttime]
  867. if defined extended_primary_loader
  868.         sub     ax, [preboot_timeout]
  869. else
  870.         ; bios 0x1A timer runs at ~18 ticks per second
  871.         sub     ax, 18*PREBOOT_TIMEOUT
  872. end if
  873.         jae     .timergo
  874.         neg     ax
  875.         add     ax, 18-1
  876.         mov     bx, 18
  877.         xor     dx, dx
  878.         div     bx
  879. if lang eq ru
  880. ; подождите 5 секунд, 4/3/2 секунды, 1 секунду
  881.         cmp     al, 5
  882.         mov     cl, ' '
  883.         jae     @f
  884.         cmp     al, 1
  885.         mov     cl, 0xE3 ; 'у' in cp866
  886.         jz      @f
  887.         mov     cl, 0xEB ; 'ы' in cp866
  888. @@:
  889.         mov     [time_str+9], cl
  890. else if lang eq et
  891.         cmp     al, 1
  892.         ja      @f
  893.         mov     byte [time_str+9], ' '
  894.         mov     byte [time_str+10], ' '
  895. @@:
  896. else if lang eq sp
  897. ; esperar 5/4/3/2 segundos, 1 segundo
  898.         cmp     al, 1
  899.         mov     cl, 's'
  900.         ja      @f
  901.         mov     cl, ' '
  902. @@:
  903.         mov     [time_str+10], cl
  904. else
  905. ; wait 5/4/3/2 seconds, 1 second
  906.         cmp     al, 1
  907.         mov     cl, 's'
  908.         ja      @f
  909.         mov     cl, ' '
  910. @@:
  911.         mov     [time_str+9], cl
  912. end if
  913.         add     al, '0'
  914.         mov     [time_str+1], al
  915.         mov     si, time_msg
  916.         _setcursor 7,0
  917.         call    print
  918.         _setcursor 25,0
  919.         popad
  920.         pop     ds
  921.         iret
  922. .timergo:
  923.         push    0
  924.         pop     es
  925.         mov     eax, [.oldtimer]
  926.         mov     [es:8*4], eax
  927.         mov     sp, 0EC00h
  928. .continue:
  929.         sti
  930.         _setcursor 6,0
  931.         mov     si, space_msg
  932.         call    printplain
  933.         call    printplain
  934.         _setcursor 6,0
  935.         mov     si, loading_msg
  936.         call    print
  937.         _setcursor 16,0
  938. if ~ defined extended_primary_loader
  939.         cmp     [.bSettingsChanged], 0
  940.         jz      .load
  941.         cmp     [.loader_block], -1
  942.         jz      .load
  943.         les     bx, [.loader_block]
  944.         mov     eax, [es:bx+3]
  945.         push    ds
  946.         pop     es
  947.         test    eax, eax
  948.         jz      .load
  949.         push    eax
  950.         mov     si, save_quest
  951.         call    print
  952. .waityn:
  953.         mov     ah, 0
  954.         int     16h
  955.         or      al, 20h
  956.         cmp     al, 'n'
  957.         jz      .loadc
  958.         if lang eq sp
  959.         cmp     al, 's'
  960.         else
  961.         cmp     al, 'y'
  962.         end if
  963.         jnz     .waityn
  964.         call    putchar
  965.         mov     byte [space_msg+80], 186
  966.  
  967.         pop     eax
  968.         push    cs
  969.         push    .cont
  970.         push    eax
  971.         retf                            ;call back
  972. .loadc:
  973.         pop     eax
  974. .cont:
  975.         push    cs
  976.         pop     ds
  977.  
  978.         push    es
  979.         les     bx, [.loader_block]
  980.         cmp     byte [es:bx+7], 0      ; get write error flag
  981.         pop     es
  982.         jz      .load
  983.         call    clear_status_field
  984.         mov     si, write_err_msg
  985.         call    print
  986. .wait_any_key:
  987.         xor     ax, ax
  988.         int     16h
  989.         test    ax, ax
  990.         jz      .wait_any_key
  991.  
  992. .load:
  993.         call    clear_status_field
  994. end if
  995.  
  996. ; ASK GRAPHICS MODE
  997.  
  998.         call    set_vmode
  999.  
  1000. ; GRAPHICS ACCELERATION
  1001. ; force yes
  1002.         mov     [es:BOOT_LO.mtrr], byte 1
  1003.  
  1004. ; DMA ACCESS TO HD
  1005.  
  1006.         mov     al, [preboot_dma]
  1007.         mov     [es:BOOT_LO.dma], al
  1008.  
  1009. ; Set kernel DEBUG mode - if nonzero, duplicates debug output to the screen.
  1010.         mov     al, [preboot_debug]
  1011.         mov     [es:BOOT_LO.debug_print], al       ;// 0x901E
  1012.  
  1013. ; Start the first app (right now it's LAUNCHER) after kernel is loaded?
  1014.         mov     al, [preboot_launcher]
  1015.         mov     [es:BOOT_LO.launcher_start], al    ;// 0x901D        
  1016.  
  1017. ; BOOT DEVICE
  1018.  
  1019.         mov     al, [preboot_device]
  1020. if defined extended_primary_loader
  1021.         cmp     al, RD_LOAD_FROM_MEMORY
  1022.         jnz     @f
  1023.         mov     al, RD_LOAD_FROM_NONE
  1024. @@:
  1025. end if
  1026.         mov     [es:BOOT_LO.rd_load_from], al
  1027.  
  1028. ; /sys path
  1029.         mov     eax, dword[preboot_syspath+0]
  1030.         mov     dword[es:BOOT_LO.syspath+0], eax
  1031.         mov     eax, dword[preboot_syspath+4]
  1032.         mov     dword[es:BOOT_LO.syspath+4], eax
  1033.         mov     eax, dword[preboot_syspath+8]
  1034.         mov     dword[es:BOOT_LO.syspath+8], eax
  1035.         mov     eax, dword[preboot_syspath+12]
  1036.         mov     dword[es:BOOT_LO.syspath+12], eax
  1037.  
  1038.  
  1039. ; GET MEMORY MAP
  1040. include '../detect/biosmem.inc'
  1041.  
  1042. ; READ DISKETTE TO MEMORY
  1043.  
  1044.         cmp     byte [es:BOOT_LO.rd_load_from], RD_LOAD_FROM_FLOPPY
  1045.         jne     no_sys_on_floppy
  1046.         mov     si, diskload
  1047.         call    print
  1048.         xor     ax, ax          ; reset drive
  1049.         xor     dx, dx          ; 1st floppy disk (0)
  1050.         int     0x13
  1051. ; do we boot from CD-ROM?
  1052.         mov     ah, 41h         ; check extended mode
  1053.         mov     bx, 55AAh       ; test 2 bytes to check that this function is supported
  1054.         xor     dx, dx          ; 1st floppy disk (0)
  1055.         int     0x13
  1056.         jc      .nocd           ; extended mode not supported
  1057.         cmp     bx, 0AA55h
  1058.         jnz     .nocd           ; extended mode not supported
  1059.         mov     ah, 48h         ; extended read drive parameters
  1060.         push    ds
  1061.         push    es
  1062.         pop     ds
  1063.         mov     si, 0xa000
  1064.         mov     word [si], 30   ; size of result buffer
  1065.         int     0x13
  1066.         pop     ds
  1067.         jc      .nocd           ; error getting parameters
  1068.         push    ds
  1069.         lds     si, [es:si+26]  ; pointer to Enhanced Disk Drive (EDD) configuration parameters
  1070.         test    byte [ds:si+10], 40h ; check ATAPI device
  1071.         pop     ds
  1072.         jz      .nocd
  1073.  
  1074. ; yes - read all floppy by 18 sectors
  1075.  
  1076. ; TODO: !!!! read only first sector and set variables !!!!!
  1077. ; ...
  1078. ; TODO: !!! then read flippy image track by track
  1079.  
  1080.         mov     cx, 0x0001      ; startcyl,startsector
  1081. .a1:
  1082.         push    cx dx
  1083.         mov     al, 18
  1084.         mov     bx, 0xa000
  1085.         call    boot_read_floppy
  1086.         mov     si, movedesc
  1087.         push    es
  1088.         push    ds
  1089.         pop     es
  1090.         mov     cx, 256*18
  1091.         mov     ah, 0x87
  1092.         int     0x15
  1093.         pop     es
  1094.         pop     dx cx
  1095.         test    ah, ah
  1096.         jnz     sayerr_floppy
  1097.         add     dword [si+8*3+2], 512*18
  1098.         inc     dh
  1099.         cmp     dh, 2
  1100.         jnz     .a1
  1101.         mov     dh, 0
  1102.         inc     ch
  1103.         cmp     ch, 80
  1104.         jae     ok_sys_on_floppy
  1105.         pusha
  1106.         mov     al, ch
  1107.         shr     ch, 2
  1108.         add     al, ch
  1109.         aam
  1110.         xchg    al, ah
  1111.         add     ax, '00'
  1112.         mov     si, pros
  1113.         mov     [si], ax
  1114.         call    printplain
  1115.         popa
  1116.         jmp     .a1
  1117. .nocd:
  1118. ; no - read only used sectors from floppy
  1119. ; now load floppy image to memory
  1120. ; at first load boot sector and first FAT table
  1121.  
  1122. ; read only first sector and fill variables
  1123.         mov     cx, 0x0001      ; first logical sector
  1124.         xor     dx, dx          ; head = 0, drive = 0 (a:)
  1125.         mov     al, 1           ; read one sector
  1126.         mov     bx, 0xB000      ; es:bx -> data area
  1127.         call    boot_read_floppy
  1128. ; fill the necessary parameters to work with a floppy
  1129.         mov     ax, word [es:bx+24]
  1130.         mov     word [BPB_SecPerTrk], ax
  1131.         mov     ax, word [es:bx+26]
  1132.         mov     word [BPB_NumHeads], ax
  1133.         mov     ax, word [es:bx+17]
  1134.         mov     word [BPB_RootEntCnt], ax
  1135.         mov     ax, word [es:bx+14]
  1136.         mov     word [BPB_RsvdSecCnt], ax
  1137.         mov     ax, word [es:bx+19]
  1138.         mov     word [BPB_TotSec16], ax
  1139.         mov     al, byte [es:bx+13]
  1140.         mov     byte [BPB_SecPerClus], al
  1141.         mov     al, byte [es:bx+16]
  1142.         mov     byte [BPB_NumFATs], al
  1143. ;<Lrz> 18.11.2008
  1144.         mov     ax, word [es:bx+22]
  1145.         mov     word [BPB_FATSz16], ax
  1146.         mov     cx, word [es:bx+11]
  1147.         mov     word [BPB_BytsPerSec], cx
  1148.  
  1149. ; count of clusters in FAT12 ((size_of_FAT*2)/3)
  1150. ;        mov     ax, word [BPB_FATSz16]
  1151. ;        mov     cx, word [BPB_BytsPerSec]
  1152. ;end <Lrz> 18.11.2008
  1153.         xor     dx, dx
  1154.         mul     cx
  1155.         shl     ax, 1
  1156.         mov     cx, 3
  1157.         div     cx              ; now ax - number of clusters in FAT12
  1158.         mov     word [end_of_FAT], ax
  1159.  
  1160. ; load first FAT table
  1161.         mov     cx, 0x0002      ; startcyl,startsector          ; TODO!!!!!
  1162.         xor     dx, dx          ; starthead,drive
  1163.         mov     al, byte [BPB_FATSz16]     ; no of sectors to read
  1164.         add     bx, word [BPB_BytsPerSec]  ; es:bx -> data area
  1165.         call    boot_read_floppy
  1166.         mov     bx, 0xB000
  1167.  
  1168. ; and copy them to extended memory
  1169.         mov     si, movedesc
  1170.         mov     [si+8*2+3], bh          ; from
  1171.        
  1172.         mov     ax, word [BPB_BytsPerSec]
  1173.         shr     ax, 1                   ; words per sector
  1174.         mov     cx, word [BPB_RsvdSecCnt]
  1175.         add     cx, word [BPB_FATSz16]
  1176.         mul     cx
  1177.         push    ax                      ; save to stack count of words in boot+FAT
  1178.         xchg    ax, cx
  1179.        
  1180.         push    es
  1181.         push    ds
  1182.         pop     es
  1183.         mov     ah, 0x87
  1184.         int     0x15
  1185.         pop     es
  1186.         test    ah, ah
  1187.         jz      @f
  1188. sayerr_floppy:
  1189.         mov     dx, 0x3f2
  1190.         mov     al, 0
  1191.         out     dx, al
  1192. sayerr_memmove:
  1193.         mov     si, memmovefailed
  1194.         jmp     sayerr_plain
  1195. @@:
  1196.         pop     ax                      ; restore from stack count of words in boot+FAT
  1197.         shl     ax, 1                   ; make bytes count from count of words
  1198.         and     eax, 0ffffh
  1199.         add     dword [si+8*3+2], eax
  1200.  
  1201. ; copy first FAT to second copy
  1202. ; TODO: BPB_NumFATs !!!!!
  1203.         add     bx, word [BPB_BytsPerSec]       ; !!! TODO: may be need multiply by BPB_RsvdSecCnt !!!
  1204.         mov     byte [si+8*2+3], bh     ; bx - begin of FAT
  1205.        
  1206.         mov     ax, word [BPB_BytsPerSec]
  1207.         shr     ax, 1                   ; words per sector
  1208.         mov     cx, word [BPB_FATSz16]
  1209.         mul     cx
  1210.         mov     cx, ax                  ; cx - count of words in FAT
  1211.  
  1212.         push    es
  1213.         push    ds
  1214.         pop     es
  1215.         mov     ah, 0x87
  1216.         int     0x15
  1217.         pop     es
  1218.         test    ah, ah
  1219.         jnz     sayerr_floppy
  1220.        
  1221.         mov     ax, cx
  1222.         shl     ax, 1
  1223.         and     eax, 0ffffh             ; ax - count of bytes in FAT
  1224.         add     dword [si+8*3+2], eax
  1225.        
  1226. ; reading RootDir
  1227. ; TODO: BPB_NumFATs
  1228.         add     bx, ax
  1229.         add     bx, 100h
  1230.         and     bx, 0ff00h                      ; bx - place in buffer to write RootDir
  1231.         push    bx
  1232.  
  1233.         mov     bx, word [BPB_BytsPerSec]
  1234.         shr     bx, 5                           ; divide bx by 32
  1235.         mov     ax, word [BPB_RootEntCnt]
  1236.         xor     dx, dx
  1237.         div     bx
  1238.         push    ax                              ; ax - count of RootDir sectors
  1239.  
  1240.         mov     ax, word [BPB_FATSz16]
  1241.         xor     cx, cx
  1242.         mov     cl, byte [BPB_NumFATs]
  1243.         mul     cx
  1244.         add     ax, word [BPB_RsvdSecCnt]       ; ax - first sector of RootDir
  1245.  
  1246.         mov     word [FirstDataSector], ax
  1247.         pop     bx
  1248.         push    bx
  1249.         add     word [FirstDataSector], bx      ; Begin of data region of floppy
  1250.        
  1251. ; read RootDir
  1252.         call    conv_abs_to_THS
  1253.         pop     ax
  1254.         pop     bx                              ; place in buffer to write
  1255.         push    ax
  1256.         call    boot_read_floppy                ; read RootDir into buffer
  1257. ; copy RootDir
  1258.         mov     byte [si+8*2+3], bh             ; from buffer
  1259.         pop     ax                              ; ax = count of RootDir sectors
  1260.         mov     cx, word [BPB_BytsPerSec]
  1261.         mul     cx
  1262.         shr     ax, 1
  1263.         mov     cx, ax                          ; count of words to copy
  1264.         push    es
  1265.         push    ds
  1266.         pop     es
  1267.         mov     ah, 0x87
  1268.         int     0x15
  1269.         pop     es
  1270.  
  1271.         mov     ax, cx
  1272.         shl     ax, 1
  1273.         and     eax, 0ffffh             ; ax - count of bytes in RootDir
  1274.         add     dword [si+8*3+2], eax   ; add count of bytes copied
  1275.  
  1276. ; Reading data clusters from floppy
  1277.         mov     byte [si+8*2+3], bh
  1278.         push    bx
  1279.  
  1280.         mov     di, 2                   ; First data cluster
  1281. .read_loop:
  1282.         mov     bx, di
  1283.         shr     bx, 1                   ; bx+di = di*1.5
  1284.         jnc     .even
  1285.         test    word [es:bx+di+0xB200], 0xFFF0  ; TODO: may not be 0xB200 !!!
  1286.         jmp     @f
  1287. .even:
  1288.         test    word [es:bx+di+0xB200], 0xFFF   ; TODO: may not be 0xB200 !!!
  1289.  
  1290. @@:
  1291.         jz      .skip
  1292. ; read cluster di
  1293. ;.read:
  1294.         ;conv cluster di to abs. sector ax
  1295.         ; ax = (N-2) * BPB_SecPerClus + FirstDataSector
  1296.         mov     ax, di
  1297.         sub     ax, 2
  1298.         xor     bx, bx
  1299.         mov     bl, byte [BPB_SecPerClus]
  1300.         mul     bx
  1301.         add     ax, word [FirstDataSector]
  1302.         call    conv_abs_to_THS
  1303.         pop     bx
  1304.         push    bx
  1305.         mov     al, byte [BPB_SecPerClus]       ; number of sectors in cluster
  1306.         call    boot_read_floppy
  1307.         push    es
  1308.         push    ds
  1309.         pop     es
  1310.         pusha
  1311. ;
  1312.         mov     ax, word [BPB_BytsPerSec]
  1313.         xor     cx, cx
  1314.         mov     cl, byte [BPB_SecPerClus]
  1315.         mul     cx
  1316.         shr     ax, 1                           ; ax = (BPB_BytsPerSec * BPB_SecPerClus)/2
  1317.         mov     cx, ax                          ; number of words to copy (count words in cluster)
  1318. ;
  1319.         mov     ah, 0x87
  1320.         int     0x15                            ; copy data
  1321.         test    ah, ah
  1322.         popa
  1323.         pop     es
  1324.         jnz     sayerr_floppy
  1325. ; skip cluster di
  1326. .skip:
  1327.         mov     ax, word [BPB_BytsPerSec]
  1328.         xor     cx, cx
  1329.         mov     cl, byte [BPB_SecPerClus]
  1330.         mul     cx
  1331.         and     eax, 0ffffh             ; ax - count of bytes in cluster
  1332.         add     dword [si+8*3+2], eax
  1333.  
  1334.         mov     ax, word [end_of_FAT]   ; max cluster number
  1335.         pusha
  1336. ; draw percentage
  1337. ; total clusters: ax
  1338. ; read clusters: di
  1339.         xchg    ax, di
  1340.         mov     cx, 100
  1341.         mul     cx
  1342.         div     di
  1343.         aam
  1344.         xchg    al, ah
  1345.         add     ax, '00'
  1346.         mov     si, pros
  1347.         cmp     [si], ax
  1348.         jz      @f
  1349.         mov     [si], ax
  1350.         call    printplain
  1351. @@:
  1352.         popa
  1353.         inc     di
  1354.         cmp     di, word [end_of_FAT]   ; max number of cluster
  1355.         jnz     .read_loop
  1356.         pop     bx                      ; clear stack
  1357.  
  1358. ok_sys_on_floppy:
  1359.         mov     si, backspace2
  1360.         call    printplain
  1361.         mov     si, okt
  1362.         call    printplain
  1363. no_sys_on_floppy:
  1364.         xor     ax, ax          ; reset drive
  1365.         xor     dx, dx
  1366.         int     0x13
  1367.         mov     dx, 0x3f2       ; floppy motor off
  1368.         mov     al, 0
  1369.         out     dx, al
  1370.  
  1371. if defined extended_primary_loader
  1372.         cmp     [es:BOOT_LO.rd_load_from], RD_LOAD_FROM_HD
  1373.         jne     no_sys_from_primary
  1374. ; load kolibri.img using callback from primary loader
  1375.         and     word [movedesc + 24 + 2], 0
  1376.         mov     byte [movedesc + 24 + 4], 10h
  1377. ; read in blocks of 64K until file is fully loaded
  1378.         mov     ax, 1
  1379. .repeat:
  1380.         mov     di, image_file_struct
  1381.         call    [bootcallback]
  1382.         push    cs
  1383.         pop     ds
  1384.         push    cs
  1385.         pop     es
  1386.         cmp     bx, 1
  1387.         ja      sayerr_badsect
  1388.         push    bx
  1389.         mov     si, movedesc
  1390.         and     word [si + 16 + 2], 0
  1391.         mov     byte [si + 16 + 4], 4
  1392.         mov     ah, 87h
  1393.         mov     cx, 8000h
  1394.         int     15h
  1395.         pop     bx
  1396.         test    ah, ah
  1397.         jnz     sayerr_memmove
  1398.         inc     byte [si + 24 + 4]
  1399.         test    bx, bx
  1400.         jz      no_sys_from_primary
  1401.         mov     ax, 2
  1402.         jmp     .repeat
  1403. no_sys_from_primary:
  1404. end if
  1405.  
  1406. ; SET GRAPHICS
  1407.  
  1408.         xor     ax, ax
  1409.         mov     es, ax
  1410.  
  1411.         mov     ax, [es:BOOT_LO.vesa_mode]         ; vga & 320x200
  1412.         mov     bx, ax
  1413.         cmp     ax, 0x13
  1414.         je      setgr
  1415.         cmp     ax, 0x12
  1416.         je      setgr
  1417.         mov     ax, 0x4f02              ; Vesa
  1418. setgr:
  1419.         int     0x10
  1420.         test    ah, ah
  1421.         mov     si, fatalsel
  1422.         jnz     v_mode_error
  1423. ; set mode 0x12 graphics registers:
  1424.         cmp     bx, 0x12
  1425.         jne     gmok2
  1426.  
  1427.         mov     al, 0x05
  1428.         mov     dx, 0x03ce
  1429.         push    dx
  1430.         out     dx, al      ; select GDC mode register
  1431.         mov     al, 0x02
  1432.         inc     dx
  1433.         out     dx, al      ; set write mode 2
  1434.  
  1435.         mov     al, 0x02
  1436.         mov     dx, 0x03c4
  1437.         out     dx, al      ; select VGA sequencer map mask register
  1438.         mov     al, 0x0f
  1439.         inc     dx
  1440.         out     dx, al      ; set mask for all planes 0-3
  1441.  
  1442.         mov     al, 0x08
  1443.         pop     dx
  1444.         out     dx, al      ; select GDC bit mask register
  1445.                            ; for writes to 0x03cf
  1446. gmok2:
  1447.         push    ds
  1448.         pop     es
  1449.