Subversion Repositories Kolibri OS

Rev

Rev 1700 | Rev 1941 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2010. 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: 1703 $
  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.  
  51. setcursor:
  52. ; in: dl=column, dh=row
  53.         mov     ah, 2
  54.         mov     bh, 0
  55.         int     10h
  56.         ret
  57.  
  58. macro _setcursor row,column
  59. {
  60.         mov     dx, row*256 + column
  61.         call    setcursor
  62. }
  63.  
  64. boot_read_floppy:
  65.         push    si
  66.         xor     si, si
  67.         mov     ah, 2   ; read
  68. @@:
  69.         push    ax
  70.         int     0x13
  71.         pop     ax
  72.         jnc     @f
  73.         inc     si
  74.         cmp     si, 10
  75.         jnb     $
  76. @@:
  77.         pop     si
  78.         ret
  79.  
  80. sayerr_plain:
  81.         call    printplain
  82.         jmp     $
  83.  
  84. sayerr:
  85.         call    print
  86.         jmp     $
  87.  
  88.  
  89. ; convert abs. sector number (AX) to BIOS T:H:S
  90. ; sector number = (abs.sector%BPB_SecPerTrk)+1
  91. ; pre.track number = (abs.sector/BPB_SecPerTrk)
  92. ; head number = pre.track number%BPB_NumHeads
  93. ; track number = pre.track number/BPB_NumHeads
  94. ; Return: cl - sector number
  95. ;         ch - track number
  96. ;         dl - drive number (0 = a:)
  97. ;         dh - head number
  98. conv_abs_to_THS:
  99.         push    bx
  100.         mov     bx,word [BPB_SecPerTrk]
  101.         xor     dx,dx
  102.         div     bx
  103.         inc     dx
  104.         mov     cl, dl                          ; cl = sector number
  105.         mov     bx,word [BPB_NumHeads]
  106.         xor     dx,dx
  107.         div     bx
  108.         ; !!!!!!! ax = track number, dx = head number
  109.         mov     ch,al                           ; ch=track number
  110.         xchg    dh,dl                           ; dh=head number
  111.         mov     dl,0                            ; dl=0 (drive 0 (a:))
  112.         pop     bx
  113.         retn
  114. ; needed variables
  115. BPB_SecPerTrk   dw      0                       ; sectors per track
  116. BPB_NumHeads    dw      0                       ; number of heads
  117. BPB_FATSz16     dw      0                       ; size of FAT
  118. BPB_RootEntCnt  dw      0                       ; count of root dir. entries
  119. BPB_BytsPerSec  dw      0                       ; bytes per sector
  120. BPB_RsvdSecCnt  dw      0                       ; number of reserved sectors
  121. BPB_TotSec16    dw      0                       ; count of the sectors on the volume
  122. BPB_SecPerClus  db      0                       ; number of sectors per cluster
  123. BPB_NumFATs     db      0                       ; number of FAT tables
  124. abs_sector_adj  dw      0                       ; adjustment to make abs. sector number
  125. end_of_FAT      dw      0                       ; end of FAT table
  126. FirstDataSector dw      0                       ; begin of data
  127.  
  128. ;=========================================================================
  129. ;
  130. ;                           16 BIT CODE
  131. ;
  132. ;=========================================================================
  133.  
  134. include 'bootvesa.inc'                 ;Include source for boot vesa
  135.  
  136. start_of_code:
  137.         cld
  138. ; \begin{diamond}[02.12.2005]
  139. ; if bootloader sets ax = 'KL', then ds:si points to loader block
  140.         cmp     ax, 'KL'
  141.         jnz     @f
  142.         mov     word [cs:cfgmanager.loader_block], si
  143.         mov     word [cs:cfgmanager.loader_block+2], ds
  144. @@:
  145. ; \end{diamond}[02.12.2005]
  146.  
  147. ; if bootloader sets cx = 'HA' and dx = 'RD', then bx contains identifier of source hard disk
  148. ; (see comment to bx_from_load)
  149.         cmp     cx, 'HA'
  150.         jnz     no_hd_load
  151.         cmp     dx,'RD'
  152.         jnz     no_hd_load
  153.         mov     word [cs:bx_from_load], bx              ; {SPraid}[13.03.2007]
  154. no_hd_load:
  155.  
  156. ; set up stack
  157.         mov     ax, 3000h
  158.         mov     ss, ax
  159.         mov     sp, 0EC00h
  160. ; set up segment registers
  161.         push    cs
  162.         pop     ds
  163.         push    cs
  164.         pop     es
  165.  
  166. ; set videomode
  167.         mov     ax, 3
  168.         int     0x10
  169.  
  170. ; draw frames
  171.         push    0xb800
  172.         pop     es
  173.         xor     di, di
  174.         mov     ah, 1*16+15
  175.  
  176. ; draw top
  177.         mov     si, d80x25_top
  178.         mov     cx, d80x25_top_num * 80
  179. @@:
  180.         lodsb
  181.         stosw
  182.         loop    @b
  183. ; draw spaces
  184.         mov     si, space_msg
  185.         mov     dx, 25 - d80x25_top_num - d80x25_bottom_num
  186. dfl1:
  187.         push    si
  188.         mov     cx, 80
  189. @@:
  190.         lodsb
  191.         stosw
  192.         loop    @b
  193.         pop     si
  194.         dec     dx
  195.         jnz     dfl1
  196. ; draw bottom
  197.         mov     si, d80x25_bottom
  198.         mov     cx, d80x25_bottom_num * 80
  199. @@:
  200.         lodsb
  201.         stosw
  202.         loop    @b
  203.  
  204.         mov     byte [space_msg+80], 0    ; now space_msg is null terminated
  205.  
  206.         _setcursor d80x25_top_num,0
  207.  
  208. cpugood:
  209.  
  210.         push    0
  211.         popf
  212.         sti
  213.  
  214. ; set up esp
  215.         movzx   esp, sp
  216.  
  217.         push    0
  218.         pop     es
  219.         and     word [es:0x9031], 0
  220. ; \begin{Mario79}
  221. ; find HDD IDE DMA PCI device
  222. ; check for PCI BIOS
  223.         mov     ax, 0xB101
  224.         int     0x1A
  225.         jc      .nopci
  226.         cmp     edx, 'PCI '
  227.         jnz     .nopci
  228. ; find PCI class code
  229. ; class 1 = mass storage
  230. ; subclass 1 = IDE controller
  231. ; a) class 1, subclass 1, programming interface 0x80
  232.         mov     ax, 0xB103
  233.         mov     ecx, 1*10000h + 1*100h + 0x80
  234.         xor     si, si  ; device index = 0
  235.         int     0x1A
  236.         jnc     .found
  237. ; b) class 1, subclass 1, programming interface 0x8A
  238.         mov     ax, 0xB103
  239.         mov     ecx, 1*10000h + 1*100h + 0x8A
  240.         xor     si, si  ; device index = 0
  241.         int     0x1A
  242.         jnc     .found
  243. ; c) class 1, subclass 1, programming interface 0x85
  244.         mov     ax, 0xB103
  245.         mov     ecx, 1*10000h + 1*100h + 0x85
  246.         xor     si, si
  247.         int     0x1A
  248.         jc      .nopci
  249. .found:
  250. ; get memory base
  251.         mov     ax, 0xB10A
  252.         mov     di, 0x20        ; memory base is config register at 0x20
  253.         int     0x1A
  254.         jc      .nopci
  255.         and     cx, 0xFFF0      ; clear address decode type
  256.         mov     [es:0x9031], cx
  257. .nopci:
  258. ; \end{Mario79}
  259.  
  260. ; --------------- APM ---------------------
  261.         and     word [es:0x9044], 0     ; ver = 0.0 (APM not found)
  262.         mov     ax, 0x5300
  263.         xor     bx, bx
  264.         int     0x15
  265.         jc      apm_end                 ; APM not found
  266.         test    cx, 2
  267.         jz      apm_end                 ; APM 32-bit protected-mode interface not supported
  268.         mov     [es:0x9044], ax         ; Save APM Version
  269.         mov     [es:0x9046], cx         ; Save APM flags
  270.  
  271.         ; Write APM ver ----
  272.         and     ax, 0xf0f
  273.         add     ax, '00'
  274.         mov     si, msg_apm
  275.         mov     [si + 5], ah
  276.         mov     [si + 7], al
  277.         _setcursor 0, 3
  278.         call    printplain
  279.         ; ------------------
  280.  
  281.         mov     ax, 0x5304              ; Disconnect interface
  282.         xor     bx, bx
  283.         int     0x15
  284.         mov     ax, 0x5303              ; Connect 32 bit mode interface
  285.         xor     bx, bx
  286.         int     0x15
  287.  
  288.         mov     [es:0x9040], ebx
  289.         mov     [es:0x9050], ax
  290.         mov     [es:0x9052], cx
  291.         mov     [es:0x9054], dx
  292.  
  293. apm_end:
  294.         _setcursor d80x25_top_num, 0
  295.  
  296. ;CHECK current of code
  297.         cmp     [cfgmanager.loader_block], -1
  298.         jz      noloaderblock
  299.         les     bx, [cfgmanager.loader_block]
  300.         cmp     byte [es:bx], 1
  301.         mov     si, loader_block_error
  302.         jnz     sayerr
  303.         push    0
  304.         pop     es
  305.  
  306. noloaderblock:
  307. ; DISPLAY VESA INFORMATION
  308.          call    print_vesa_info
  309.          call    calc_vmodes_table
  310.          call    check_first_parm  ;check and enable cursor_pos
  311.  
  312. ; \begin{diamond}[30.11.2005]
  313. cfgmanager:
  314. ; settings:
  315. ; a) preboot_graph = graphical mode
  316. ;    preboot_gprobe = probe this mode?
  317. ; b) preboot_dma  = use DMA access?
  318. ; c) preboot_vrrm = use VRR?
  319. ; d) preboot_device = from what boot?
  320.  
  321. ; determine default settings
  322. ;        mov     [.bSettingsChanged], 0
  323.  
  324. ;.preboot_gr_end:
  325.         mov     di, preboot_device
  326. ; if image in memory is present and [preboot_device] is uninitialized,
  327. ; set it to use this preloaded image
  328.         cmp     byte [di], 0
  329.         jnz     .preboot_device_inited
  330.         cmp     [.loader_block], -1
  331.         jz      @f
  332.         les     bx, [.loader_block]
  333.         test    byte [es:bx+1], 1
  334.         jz      @f
  335.         mov     byte [di], 3
  336.         jmp     .preboot_device_inited
  337. @@:
  338. ; otherwise, set [preboot_device] to 1 (default value - boot from floppy)
  339.         mov     byte [di], 1
  340. .preboot_device_inited:
  341. ; following 4 lines set variables to 1 if its current value is 0
  342.         cmp     byte [di+preboot_dma-preboot_device], 1
  343.         adc     byte [di+preboot_dma-preboot_device], 0
  344.         cmp     byte [di+preboot_biosdisk-preboot_device], 1
  345.         adc     byte [di+preboot_biosdisk-preboot_device], 0
  346.  
  347.         _setcursor 7,0
  348.         mov     si, space_msg
  349.         call    printplain
  350. ;        pop     ax              ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ??
  351.         jmp     .continue
  352. .loader_block dd -1
  353. .continue:
  354.         sti
  355.         _setcursor 6,0
  356.         mov     si, space_msg
  357.         call    printplain
  358.         call    printplain
  359.         _setcursor 6,0
  360.         mov     si, loading_msg
  361.         call    print
  362.         _setcursor 15,0
  363.         jmp      .load
  364.  
  365. .loadc:
  366.         pop     eax
  367. .cont:
  368.         push    cs
  369.         pop     ds
  370.         mov     si, space_msg
  371.         mov     byte [si+80], 0
  372.         _setcursor 15,0
  373.         call    printplain
  374.         _setcursor 15,0
  375. .load:
  376.  
  377. ; ASK GRAPHICS MODE
  378.  
  379.         call    set_vmode
  380.  
  381. ; GRAPHICS ACCELERATION
  382. ; force yes
  383.         mov     [es:0x901C], byte 1
  384.  
  385. ; DMA ACCESS TO HD
  386.  
  387.         mov     al, [preboot_dma]
  388.         mov     [es:0x901F], al
  389.  
  390. ; VRR_M USE
  391.  
  392.         mov     al,[preboot_vrrm]
  393.         mov     [es:0x9030], al
  394.         mov     [es:0x901E], byte 1
  395.  
  396. ; BOOT DEVICE
  397.  
  398.         mov     al, [preboot_device]
  399.         dec     al
  400.         mov     [boot_dev], al
  401.  
  402. ; GET MEMORY MAP
  403. include 'detect/biosmem.inc'
  404.  
  405. ; READ DISKETTE TO MEMORY
  406.  
  407.         cmp     [boot_dev],0
  408.         jne     no_sys_on_floppy
  409.         mov     si,diskload
  410.         call    print
  411.         xor     ax, ax            ; reset drive
  412.         xor     dx, dx
  413.         int     0x13
  414. ; do we boot from CD-ROM?
  415.         mov     ah, 41h
  416.         mov     bx, 55AAh
  417.         xor     dx, dx
  418.         int     0x13
  419.         jc      .nocd
  420.         cmp     bx, 0AA55h
  421.         jnz     .nocd
  422.         mov     ah, 48h
  423.         push    ds
  424.         push    es
  425.         pop     ds
  426.         mov     si, 0xa000
  427.         mov     word [si], 30
  428.         int     0x13
  429.         pop     ds
  430.         jc      .nocd
  431.         push    ds
  432.         lds     si, [es:si+26]
  433.         test    byte [ds:si+10], 40h
  434.         pop     ds
  435.         jz      .nocd
  436. ; yes - read all floppy by 18 sectors
  437.  
  438. ; TODO: !!!! read only first sector and set variables !!!!!
  439. ; ...
  440. ; TODO: !!! then read flippy image track by track
  441.  
  442.         mov     cx, 0x0001      ; startcyl,startsector
  443. .a1:
  444.         push    cx dx
  445.         mov     al, 18
  446.         mov     bx, 0xa000
  447.         call    boot_read_floppy
  448.         mov     si, movedesc
  449.         push    es
  450.         push    ds
  451.         pop     es
  452.         mov     cx, 256*18
  453.         mov     ah, 0x87
  454.         int     0x15
  455.         pop     es
  456.         pop     dx cx
  457.         test    ah, ah
  458.         jnz     sayerr_floppy
  459.         add     dword [si+8*3+2], 512*18
  460.         inc     dh
  461.         cmp     dh, 2
  462.         jnz     .a1
  463.         mov     dh, 0
  464.         inc     ch
  465.         cmp     ch, 80
  466.         jae     ok_sys_on_floppy
  467.         pusha
  468.         mov     al, ch
  469.         shr     ch, 2
  470.         add     al, ch
  471.         aam
  472.         xchg    al, ah
  473.         add     ax, '00'
  474.         mov     si, pros
  475.         mov     [si], ax
  476.         call    printplain
  477.         popa
  478.         jmp     .a1
  479. .nocd:
  480. ; no - read only used sectors from floppy
  481. ; now load floppy image to memory
  482. ; at first load boot sector and first FAT table
  483.  
  484. ; read only first sector and fill variables
  485.         mov     cx, 0x0001      ; first logical sector
  486.         xor     dx, dx          ; head = 0, drive = 0 (a:)
  487.         mov     al, 1           ; read one sector
  488.         mov     bx, 0xB000      ; es:bx -> data area
  489.         call    boot_read_floppy
  490. ; fill the necessary parameters to work with a floppy
  491.         mov     ax, word [es:bx+24]
  492.         mov     word [BPB_SecPerTrk], ax
  493.         mov     ax, word [es:bx+26]
  494.         mov     word [BPB_NumHeads], ax
  495.         mov     ax, word [es:bx+17]
  496.         mov     word [BPB_RootEntCnt], ax
  497.         mov     ax, word [es:bx+14]
  498.         mov     word [BPB_RsvdSecCnt], ax
  499.         mov     ax, word [es:bx+19]
  500.         mov     word [BPB_TotSec16], ax
  501.         mov     al, byte [es:bx+13]
  502.         mov     byte [BPB_SecPerClus], al
  503.         mov     al, byte [es:bx+16]
  504.         mov     byte [BPB_NumFATs], al
  505. ;<Lrz> 18.11.2008
  506.         mov     ax, word [es:bx+22]
  507.         mov     word [BPB_FATSz16], ax
  508.         mov     cx, word [es:bx+11]
  509.         mov     word [BPB_BytsPerSec], cx
  510.  
  511. ; count of clusters in FAT12 ((size_of_FAT*2)/3)
  512. ;        mov     ax, word [BPB_FATSz16]
  513. ;        mov     cx, word [BPB_BytsPerSec]
  514. ;end <Lrz> 18.11.2008
  515.         xor     dx, dx
  516.         mul     cx
  517.         shl     ax, 1
  518.         mov     cx, 3
  519.         div     cx              ; now ax - number of clusters in FAT12
  520.         mov     word [end_of_FAT], ax
  521.  
  522. ; load first FAT table
  523.         mov     cx, 0x0002      ; startcyl,startsector          ; TODO!!!!!
  524.         xor     dx, dx          ; starthead,drive
  525.         mov     al, byte [BPB_FATSz16]     ; no of sectors to read
  526.         add     bx, word [BPB_BytsPerSec]  ; es:bx -> data area
  527.         call    boot_read_floppy
  528.         mov     bx, 0xB000
  529.  
  530. ; and copy them to extended memory
  531.         mov     si, movedesc
  532.         mov     [si+8*2+3], bh          ; from
  533.  
  534.         mov     ax, word [BPB_BytsPerSec]
  535.         shr     ax, 1                   ; words per sector
  536.         mov     cx, word [BPB_RsvdSecCnt]
  537.         add     cx, word [BPB_FATSz16]
  538.         mul     cx
  539.         push    ax                      ; save to stack count of words in boot+FAT
  540.         xchg    ax, cx
  541.  
  542.         push    es
  543.         push    ds
  544.         pop     es
  545.         mov     ah, 0x87
  546.         int     0x15
  547.         pop     es
  548.         test    ah, ah
  549.         jz      @f
  550. sayerr_floppy:
  551.         mov     dx, 0x3f2
  552.         mov     al, 0
  553.         out     dx, al
  554. ;        mov     si, memmovefailed
  555.         jmp     $
  556. @@:
  557.         pop     ax                      ; restore from stack count of words in boot+FAT
  558.         shl     ax, 1                   ; make bytes count from count of words
  559.         and     eax, 0ffffh
  560.         add     dword [si+8*3+2], eax
  561.  
  562. ; copy first FAT to second copy
  563. ; TODO: BPB_NumFATs !!!!!
  564.         add     bx, word [BPB_BytsPerSec]       ; !!! TODO: may be need multiply by BPB_RsvdSecCnt !!!
  565.         mov     byte [si+8*2+3], bh     ; bx - begin of FAT
  566.  
  567.         mov     ax, word [BPB_BytsPerSec]
  568.         shr     ax, 1                   ; words per sector
  569.         mov     cx, word [BPB_FATSz16]
  570.         mul     cx
  571.         mov     cx, ax                  ; cx - count of words in FAT
  572.  
  573.         push    es
  574.         push    ds
  575.         pop     es
  576.         mov     ah, 0x87
  577.         int     0x15
  578.         pop     es
  579.         test    ah, ah
  580.         jnz     sayerr_floppy
  581.  
  582.         mov     ax, cx
  583.         shl     ax, 1
  584.         and     eax, 0ffffh             ; ax - count of bytes in FAT
  585.         add     dword [si+8*3+2], eax
  586.  
  587. ; reading RootDir
  588. ; TODO: BPB_NumFATs
  589.         add     bx, ax
  590.         add     bx, 100h
  591.         and     bx, 0ff00h                      ; bx - place in buffer to write RootDir
  592.         push    bx
  593.  
  594.         mov     bx, word [BPB_BytsPerSec]
  595.         shr     bx, 5                           ; divide bx by 32
  596.         mov     ax, word [BPB_RootEntCnt]
  597.         xor     dx, dx
  598.         div     bx
  599.         push    ax                              ; ax - count of RootDir sectors
  600.  
  601.         mov     ax, word [BPB_FATSz16]
  602.         xor     cx, cx
  603.         mov     cl, byte [BPB_NumFATs]
  604.         mul     cx
  605.         add     ax, word [BPB_RsvdSecCnt]       ; ax - first sector of RootDir
  606.  
  607.         mov     word [FirstDataSector], ax
  608.         pop     bx
  609.         push    bx
  610.         add     word [FirstDataSector], bx      ; Begin of data region of floppy
  611.  
  612. ; read RootDir
  613.         call    conv_abs_to_THS
  614.         pop     ax
  615.         pop     bx                              ; place in buffer to write
  616.         push    ax
  617.         call    boot_read_floppy                ; read RootDir into buffer
  618. ; copy RootDir
  619.         mov     byte [si+8*2+3], bh             ; from buffer
  620.         pop     ax                              ; ax = count of RootDir sectors
  621.         mov     cx, word [BPB_BytsPerSec]
  622.         mul     cx
  623.         shr     ax, 1
  624.         mov     cx, ax                          ; count of words to copy
  625.         push    es
  626.         push    ds
  627.         pop     es
  628.         mov     ah, 0x87
  629.         int     0x15
  630.         pop     es
  631.  
  632.         mov     ax, cx
  633.         shl     ax, 1
  634.         and     eax, 0ffffh             ; ax - count of bytes in RootDir
  635.         add     dword [si+8*3+2], eax   ; add count of bytes copied
  636.  
  637. ; Reading data clusters from floppy
  638.         mov     byte [si+8*2+3], bh
  639.         push    bx
  640.  
  641.         mov     di, 2                   ; First data cluster
  642. .read_loop:
  643.         mov     bx, di
  644.         shr     bx, 1                   ; bx+di = di*1.5
  645.         jnc     .even
  646.         test    word [es:bx+di+0xB200], 0xFFF0  ; TODO: may not be 0xB200 !!!
  647.         jmp     @f
  648. .even:
  649.         test    word [es:bx+di+0xB200], 0xFFF   ; TODO: may not be 0xB200 !!!
  650.  
  651. @@:
  652.         jz      .skip
  653. ; read cluster di
  654. ;.read:
  655.         ;conv cluster di to abs. sector ax
  656.         ; ax = (N-2) * BPB_SecPerClus + FirstDataSector
  657.         mov     ax, di
  658.         sub     ax, 2
  659.         xor     bx, bx
  660.         mov     bl, byte [BPB_SecPerClus]
  661.         mul     bx
  662.         add     ax, word [FirstDataSector]
  663.         call    conv_abs_to_THS
  664.         pop     bx
  665.         push    bx
  666.         mov     al, byte [BPB_SecPerClus]       ; number of sectors in cluster
  667.         call    boot_read_floppy
  668.         push    es
  669.         push    ds
  670.         pop     es
  671.         pusha
  672. ;
  673.         mov     ax, word [BPB_BytsPerSec]
  674.         xor     cx, cx
  675.         mov     cl, byte [BPB_SecPerClus]
  676.         mul     cx
  677.         shr     ax, 1                           ; ax = (BPB_BytsPerSec * BPB_SecPerClus)/2
  678.         mov     cx, ax                          ; number of words to copy (count words in cluster)
  679. ;
  680.         mov     ah, 0x87
  681.         int     0x15                            ; copy data
  682.         test    ah, ah
  683.         popa
  684.         pop     es
  685.         jnz     sayerr_floppy
  686. ; skip cluster di
  687. .skip:
  688.         mov     ax, word [BPB_BytsPerSec]
  689.         xor     cx, cx
  690.         mov     cl, byte [BPB_SecPerClus]
  691.         mul     cx
  692.         and     eax, 0ffffh             ; ax - count of bytes in cluster
  693.         add     dword [si+8*3+2], eax
  694.  
  695.         mov     ax, word [end_of_FAT]   ; max cluster number
  696.         pusha
  697. ; draw percentage
  698. ; total clusters: ax
  699. ; read clusters: di
  700.         xchg    ax, di
  701.         mov     cx, 100
  702.         mul     cx
  703.         div     di
  704.         aam
  705.         xchg    al, ah
  706.         add     ax, '00'
  707.         mov     si, pros
  708.         cmp     [si], ax
  709.         jz      @f
  710.         mov     [si], ax
  711.         call    printplain
  712. @@:
  713.         popa
  714.         inc     di
  715.         cmp     di, word [end_of_FAT]   ; max number of cluster
  716.         jnz     .read_loop
  717.         pop     bx                      ; clear stack
  718.  
  719. ok_sys_on_floppy:
  720.         mov     si, backspace2
  721.         call    printplain
  722.         mov     si, okt
  723.         call    printplain
  724. no_sys_on_floppy:
  725.         xor     ax, ax          ; reset drive
  726.         xor     dx, dx
  727.         int     0x13
  728.         mov     dx, 0x3f2       ; floppy motor off
  729.         mov     al, 0
  730.         out     dx, al
  731.  
  732.  
  733. ; SET GRAPHICS
  734.  
  735.         xor     ax, ax
  736.         mov     es, ax
  737.  
  738.         mov     bx, [es:0x9008]         ; vga & 320x200
  739.         mov     ax, 0x4f02              ; Vesa
  740. setgr:
  741.         int     0x10
  742.         test    ah, ah
  743.         jnz     $
  744. gmok2:
  745.         push    ds
  746.         pop     es
  747.