;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; ;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;; BOOTCODE.INC ;; ;; ;; ;; KolibriOS 16-bit loader, ;; ;; based on bootcode for MenuetOS ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $Revision$ ;========================================================================== ; ; 16 BIT FUNCTIONS ; ;========================================================================== putchar: ; in: al=character mov ah, 0Eh mov bh, 0 int 10h ret print: ; in: si->string mov al, 186 call putchar mov al, ' ' call putchar printplain: ; in: si->string pusha lodsb @@: call putchar lodsb test al, al jnz @b popa ret getkey: ; Use BIOS INT 16h to read a key from the keyboard ; get number in range [bl,bh] (bl,bh in ['0'..'9']) ; in: bx=range ; out: ax=digit (1..9, 10 for 0) mov ah, 0 ; If 'int 16h' is called with 'ah' equal to zero, the BIOS will not return control to the caller int 16h ; until a key is available in the system type ahead buffer. On return, 'al' contains the ASCII cmp al, 27 ; code for the key read from the buffer and 'ah' contains the keyboard scan code. (27=>ESC) jz @f ; If ESC is pressed, return (user doesn't want to change any value). cmp al, bl ; Compare 'al' (ASCII code of key pressed) with 'bl' (lowest accepted char from the range). jb getkey ; ASCII code is below lowest accepted value => continue waiting for another key. cmp al, bh ; Compare 'al' (ASCII code of key pressed) with 'bh' (highest accepted char from the range). ja getkey ; ASCII code is above highest accepted value => continue waiting for another key. push ax ; If the pressed key is in the accepted range, save it on the stack and echo to screen. call putchar pop ax and ax, 0Fh ; Convert ASCII code to number: '1'->1, '2'->2, etc. 0Fh=1111b. jnz @f ; ASCII code for '0' is 48 (110000b). (110000b AND 1111b) = 0 mov al, 10 ; So if key '0' was entered, return 10 in 'ax' @@: ret setcursor: ; in: dl=column, dh=row mov ah, 2 mov bh, 0 int 10h ret macro _setcursor row,column { mov dx, row*256 + column call setcursor } macro _ask_question question,range,variable_to_set { _setcursor 16,0 mov si, question ; Print the question call print mov bx, range ; range accepted for answer call getkey cmp al, 27 ; If ESC was pressed, do not change the value jz .esc_pressed mov [variable_to_set], al } boot_read_floppy: push si xor si, si mov ah, 2 ; read @@: push ax int 0x13 pop ax jnc @f inc si cmp si, 10 jb @b sayerr_badsect: mov si, badsect sayerr_plain: call printplain jmp $ @@: pop si ret ; convert abs. sector number (AX) to BIOS T:H:S ; sector number = (abs.sector%BPB_SecPerTrk)+1 ; pre.track number = (abs.sector/BPB_SecPerTrk) ; head number = pre.track number%BPB_NumHeads ; track number = pre.track number/BPB_NumHeads ; Return: cl - sector number ; ch - track number ; dl - drive number (0 = a:) ; dh - head number conv_abs_to_THS: push bx mov bx, word [BPB_SecPerTrk] xor dx, dx div bx inc dx mov cl, dl ; cl = sector number mov bx, word [BPB_NumHeads] xor dx, dx div bx ; !!!!!!! ax = track number, dx = head number mov ch, al ; ch=track number xchg dh, dl ; dh=head number mov dl, 0 ; dl=0 (drive 0 (a:)) pop bx retn ; needed variables BPB_SecPerTrk dw 0 ; sectors per track BPB_NumHeads dw 0 ; number of heads BPB_FATSz16 dw 0 ; size of FAT BPB_RootEntCnt dw 0 ; count of root dir. entries BPB_BytsPerSec dw 0 ; bytes per sector BPB_RsvdSecCnt dw 0 ; number of reserved sectors BPB_TotSec16 dw 0 ; count of the sectors on the volume BPB_SecPerClus db 0 ; number of sectors per cluster BPB_NumFATs db 0 ; number of FAT tables abs_sector_adj dw 0 ; adjustment to make abs. sector number end_of_FAT dw 0 ; end of FAT table FirstDataSector dw 0 ; begin of data ;========================================================================= ; ; 16 BIT CODE ; ;========================================================================= include 'bootvesa.inc' ;Include source for boot vesa if defined extended_primary_loader include 'parsers.inc' end if start_of_code: if defined extended_primary_loader ; save data from primary loader mov word [cs:bootcallback], si mov word [cs:bootcallback+2], ds push cs pop ds mov [bootdevice], ax mov [bootfs], bx ; set up stack mov ax, (TMP_STACK_TOP and 0xF0000) shr 4 mov ss, ax mov sp, TMP_STACK_TOP and 0xFFFF ; try to load configuration file mov ax, 1 mov di, config_file_struct call [bootcallback] cld push cs pop es ; bx=0 - ok, bx=1 - part of file loaded, assume this is ok cmp bx, 1 ja .config_bad ; configuration file was loaded, parse ; if length is too big, use first 0FFFFh bytes test dx, dx jz @f mov ax, 0FFFFh @@: ; ds:si will be pointer to current data, dx = limit xchg ax, dx push 4000h pop ds xor si, si .parse_loop: ; skip spaces cmp si, dx jae .parse_done lodsb cmp al, ' ' jbe .parse_loop dec si ; loop over all possible configuration values mov bx, config_file_variables .find_variant: ; get length mov cx, [es:bx] ; zero length = end of list jecxz .find_newline ; skip over length inc bx inc bx mov di, bx ; skip over string add bx, cx ; test whether we have at least cx symbols left mov ax, cx add ax, si jc .next_variant1 cmp ax, dx jae .next_variant1 ; save current position push si ; compare strings repz cmpsb jnz .next_variant2 ; strings are equal; look for "=" with possible spaces before and after @@: cmp si, dx jae .next_variant2 lodsb cmp al, ' ' jbe @b cmp al, '=' jnz .next_variant2 ; ok, we found the true variant ; ignore saved position on the stack pop ax ; call the parser call word [es:bx] ; line parsed, find next .find_newline: cmp si, dx jae .parse_done lodsb cmp al, 13 jz .parse_loop cmp al, 10 jz .parse_loop jmp .find_newline .next_variant2: ; continue to the next variant, restoring current position pop si .next_variant1: ; continue to the next variant ; skip over the parser inc bx inc bx jmp .find_variant .parse_done: .config_bad: ; set up segment registers push cs pop ds else cld push 0 pop es ; \begin{diamond}[02.12.2005] ; if bootloader sets ax = 'KL', then ds:si points to loader block cmp ax, 'KL' jnz @f mov word [cs:cfgmanager.loader_block], si mov word [cs:cfgmanager.loader_block+2], ds mov word [es:BOOT_KERNEL_RESTART], kernel_restart_bootblock @@: ; \end{diamond}[02.12.2005] ; if bootloader sets cx = 'HA' and dx = 'RD', then bx contains identifier of source disk ; (see comment to BOOT_BX_FROM_LOAD and loader_doc.txt) mov word [es:BOOT_BX_FROM_LOAD], 'r1' ; default value: /rd/1 cmp cx, 'HA' jnz no_hd_load cmp dx, 'RD' jnz no_hd_load mov [es:BOOT_BX_FROM_LOAD], bx no_hd_load: ; set up stack mov ax, (TMP_STACK_TOP and 0xF0000) shr 4 mov ss, ax mov sp, TMP_STACK_TOP and 0xFFFF ; set up segment registers push cs pop ds push cs pop es end if ; set videomode mov ax, 3 int 0x10 if lang eq ru ; Load & set russian VGA font (RU.INC) mov bp, RU_FNT1 ; RU_FNT1 - First part mov bx, 1000h ; 768 bytes mov cx, 30h ; 48 symbols mov dx, 80h ; 128 - position of first symbol mov ax, 1100h int 10h mov bp, RU_FNT2 ; RU_FNT2 -Second part mov bx, 1000h ; 512 bytes mov cx, 20h ; 32 symbols mov dx, 0E0h ; 224 - position of first symbol mov ax, 1100h int 10h ; End set VGA russian font else if lang eq et mov bp, ET_FNT ; ET_FNT1 mov bx, 1000h ; mov cx, 255 ; 256 symbols xor dx, dx ; 0 - position of first symbol mov ax, 1100h int 10h end if ; draw frames push 0xb800 pop es xor di, di mov ah, 1*16+15 ; draw top mov si, d80x25_top mov cx, d80x25_top_num * 80 @@: lodsb stosw loop @b ; draw spaces mov si, space_msg mov dx, 25 - d80x25_top_num - d80x25_bottom_num dfl1: push si mov cx, 80 @@: lodsb stosw loop @b pop si dec dx jnz dfl1 ; draw bottom mov si, d80x25_bottom mov cx, d80x25_bottom_num * 80 @@: lodsb stosw loop @b mov byte [space_msg+80], 0 ; now space_msg is null terminated _setcursor d80x25_top_num,0 ; TEST FOR 386+ mov bx, 0x4000 pushf pop ax mov dx, ax xor ax, bx push ax popf pushf pop ax and ax, bx and dx, bx cmp ax, dx jnz cpugood mov si, not386 sayerr: call print jmp $ cpugood: push 0 popf ; set up esp movzx esp, sp push 0 pop es xor cx, cx @@: in al, 64h test al, 2 loopnz @b mov al, 0xf6 ; Сброс клавиатуры, разрешить сканирование out 0x60, al xor cx, cx @@: in al, 64h test al, 1 loopz @b in al, 0x60 ;;;/diamond today 5.02.2008 ; set keyboard typematic rate & delay mov al, 0xf3 out 0x60, al xor cx, cx @@: in al, 64h test al, 1 loopz @b in al, 0x60 mov al, 0 out 0x60, al xor cx, cx @@: in al, 64h test al, 1 loopz @b in al, 0x60 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; sti ; --------------- APM --------------------- and word [es:BOOT_APM_VERSION], 0 ; ver = 0.0 (APM not found) mov ax, 0x5300 xor bx, bx int 0x15 jc apm_end ; APM not found test cx, 2 jz apm_end ; APM 32-bit protected-mode interface not supported mov [es:BOOT_APM_VERSION], ax ; Save APM Version mov [es:BOOT_APM_FLAGS], cx ; Save APM flags ; Write APM ver ---- and ax, 0xf0f add ax, '00' mov si, msg_apm mov [si + 5], ah mov [si + 7], al _setcursor 0, 3 call printplain ; ------------------ mov ax, 0x5304 ; Disconnect interface xor bx, bx int 0x15 mov ax, 0x5303 ; Connect 32 bit mode interface xor bx, bx int 0x15 mov [es:BOOT_APM_ENTRY], ebx mov [es:BOOT_APM_CODE_32], ax mov [es:BOOT_APM_CODE_16], cx mov [es:BOOT_APM_DATA_16], dx apm_end: _setcursor d80x25_top_num, 0 if ~ defined extended_primary_loader ;CHECK current of code cmp [cfgmanager.loader_block], -1 jz noloaderblock les bx, [cfgmanager.loader_block] cmp byte [es:bx], 1 mov si, loader_block_error jnz sayerr push 0 pop es end if noloaderblock: ; DISPLAY VESA INFORMATION call print_vesa_info call calc_vmodes_table call check_first_parm ;check and enable cursor_pos ; \begin{diamond}[30.11.2005] cfgmanager: ; settings: ; a) preboot_graph = graphical mode ; preboot_gprobe = probe this mode? ; b) preboot_biosdisk = use BIOS disks through V86 emulation? // (earlier was: preboot_dma = use DMA access?) ; c) preboot_debug = duplicates kernel debug output to the screen ; d) preboot_launcher = start the first app (right now it's LAUNCHER) after kernel is loaded? ; e) preboot_device = from where to boot? ; determine default settings if ~ defined extended_primary_loader mov [.bSettingsChanged], 0 end if ;.preboot_gr_end: mov di, preboot_device ; if image in memory is present and [preboot_device] is uninitialized, ; set it to use this preloaded image cmp byte [di], 0 jnz .preboot_device_inited if defined extended_primary_loader inc byte [di] cmp byte [bootdevice], 'f' ; floppy? jz .preboot_device_inited inc byte [di] else cmp [.loader_block], -1 jz @f les bx, [.loader_block] test byte [es:bx+1], 1 jz @f mov byte [di], 3 jmp .preboot_device_inited @@: ; otherwise, set [preboot_device] to 1 (default value - boot from floppy) mov byte [di], 1 end if .preboot_device_inited: ; following 4 lines set variables to 1 if its current value is 0 cmp byte [di+preboot_dma-preboot_device], 1 adc byte [di+preboot_dma-preboot_device], 0 cmp byte [di+preboot_launcher-preboot_device], 1 ; Start LAUNCHER by default adc byte [di+preboot_launcher-preboot_device], 0 _setcursor 5,2 mov si, linef call printplain mov si, start_msg call print mov si, time_msg call print ; get start time call .gettime mov [.starttime], eax mov word [.timer], .newtimer mov word [.timer+2], cs .printcfg: _setcursor 9,0 mov si, current_cfg_msg call print mov si, curvideo_msg call print call draw_current_vmode mov si, usebd_msg cmp [preboot_biosdisk], 1 call .say_on_off mov si, debug_mode_msg cmp [preboot_debug], 1 call .say_on_off mov si, launcher_msg cmp [preboot_launcher], 1 call .say_on_off mov si, preboot_device_msg call print mov al, [preboot_device] if defined extended_primary_loader and eax, 3 else and eax, 7 end if mov si, [preboot_device_msgs+eax*2] call printplain .show_remarks: ; show remarks in gray color mov di, ((21-num_remarks)*80 + 2)*2 push 0xB800 pop es mov cx, num_remarks mov si, remarks .write_remarks: lodsw push si xchg ax, si mov ah, 1*16+7 ; background: blue (1), foreground: gray (7) push di .write_remark: lodsb test al, al jz @f stosw jmp .write_remark @@: pop di pop si add di, 80*2 loop .write_remarks .wait: _setcursor 25,0 ; out of screen ; set timer interrupt handler cli push 0 pop es push dword [es:8*4] pop dword [.oldtimer] push dword [.timer] pop dword [es:8*4] ; mov eax, [es:8*4] ; mov [.oldtimer], eax ; mov eax, [.timer] ; mov [es:8*4], eax sti ; wait for keypressed xor ax, ax int 16h push ax ; restore timer interrupt ; push 0 ; pop es mov eax, [.oldtimer] mov [es:8*4], eax mov [.timer], eax _setcursor 7,0 mov si, space_msg call printplain ; clear remarks and restore normal attributes push es mov di, ((21-num_remarks)*80 + 2)*2 push 0xB800 pop es mov cx, num_remarks mov ax, ' ' + (1*16 + 15)*100h @@: push cx mov cx, 76 rep stosw pop cx add di, 4*2 loop @b pop es pop ax ; switch on key cmp al, 13 jz .continue or al, 20h cmp al, 'a' ; select graphical mode jz .change_a cmp al, 'q' ; Trick to make 'A' key on azerty keyboard work je .change_a cmp al, 'b' ; use BIOS disks? // (selecting YES will make BIOS disks visible as /bd) jz .change_b cmp al, 'c' ; load kernel in debug mode? jz .change_c cmp al, 'd' ; start launcher after kernel is loaded? jz .change_d cmp al, 'e' ; select boot origin jnz .show_remarks ; e) preboot_device = from where to boot? if defined extended_primary_loader _ask_question bdev,'12',preboot_device ; range accepted for answer: 1-2 else _ask_question bdev,'14',preboot_device ; range accepted for answer: 1-4 end if _setcursor 14,0 .d: if ~ defined extended_primary_loader mov [.bSettingsChanged], 1 end if .esc_pressed: call clear_vmodes_table ;clear vmodes_table jmp .printcfg .change_a: call clear_vmodes_table ;clear vmodes_table mov si, word [cursor_pos] mov word [cursor_pos_old], si .loops: call draw_vmodes_table _setcursor 25,0 ; out of screen xor ax, ax int 0x16 ; call clear_table_cursor ;clear current position of cursor mov si, word [cursor_pos] cmp al, 27 ; If ESC was pressed, do not change the value jnz @f ; Just exit the resolution selection box mov si, word [cursor_pos_old] mov word [cursor_pos], si jmp .esc_pressed @@: cmp ah, 0x48;x,0x48E0 ; up jne .down cmp si, modes_table jbe .loops sub word [cursor_pos], size_of_step jmp .loops .down: cmp ah, 0x50;x,0x50E0 ; down jne .pgup cmp word[es:si+10], -1 je .loops add word [cursor_pos], size_of_step jmp .loops .pgup: cmp ah, 0x49 ; page up jne .pgdn sub si, size_of_step*long_v_table cmp si, modes_table jae @f mov si, modes_table @@: mov word [cursor_pos], si mov si, word [home_cursor] sub si, size_of_step*long_v_table cmp si, modes_table jae @f mov si, modes_table @@: mov word [home_cursor], si jmp .loops .pgdn: cmp ah, 0x51 ; page down jne .enter mov ax, [end_cursor] add si, size_of_step*long_v_table cmp si, ax jb @f mov si, ax sub si, size_of_step @@: mov word [cursor_pos], si mov si, word [home_cursor] sub ax, size_of_step*long_v_table add si, size_of_step*long_v_table cmp si, ax jb @f mov si, ax @@: mov word [home_cursor], si jmp .loops .enter: cmp al, 0x0D;x,0x1C0D ; enter jne .loops push word [cursor_pos] pop bp push word [es:bp] pop word [x_save] push word [es:bp+2] pop word [y_save] push word [es:bp+6] pop word [number_vm] mov word [preboot_graph], bp ;save choose jmp .d .change_b: ; b) preboot_biosdisk = use BIOS disks through V86 emulation? ; _setcursor 16,0 ; mov si, ask_dma // (earlier was: preboot_dma = use DMA access?) ; call print ; mov bx, '13' ; range accepted for answer: 1-3 ; call getkey ; mov [preboot_dma], al _ask_question ask_bd,'12',preboot_biosdisk ; range accepted for answer: 1-2 _setcursor 11,0 jmp .d .change_c: ; c) preboot_debug = duplicates kernel debug output to the screen _ask_question ask_debug,'12',preboot_debug ; range accepted for answer: 1-2 _setcursor 12,0 jmp .d .change_d: ; d) preboot_launcher = start the first app (right now it's LAUNCHER) after kernel is loaded? _ask_question ask_launcher,'12',preboot_launcher ; range accepted for answer: 1-2 _setcursor 13,0 jmp .d ;;;;;;;;;;;;;;;;;;;;;;;;;;;; .say_on_off: pushf call print mov si, on_msg popf jz @f mov si, off_msg @@: jmp printplain ; novesa and vervesa strings are not used at the moment of executing this code virtual at novesa .oldtimer dd ? .starttime dd ? if ~ defined extended_primary_loader .bSettingsChanged db ? end if .timer dd ? end virtual if ~ defined extended_primary_loader .loader_block dd -1 end if .gettime: mov ah, 0 int 1Ah xchg ax, cx shl eax, 10h xchg ax, dx ret .newtimer: push ds push cs pop ds pushf call [.oldtimer] pushad call .gettime sub eax, [.starttime] if defined extended_primary_loader sub ax, [preboot_timeout] else sub ax, 18*5 end if jae .timergo neg ax add ax, 18-1 mov bx, 18 xor dx, dx div bx if lang eq ru ; подождите 5 секунд, 4/3/2 секунды, 1 секунду cmp al, 5 mov cl, ' ' jae @f cmp al, 1 mov cl, 0xE3 ; 'у' in cp866 jz @f mov cl, 0xEB ; 'ы' in cp866 @@: mov [time_str+9], cl else if lang eq et cmp al, 1 ja @f mov byte [time_str+9], ' ' mov byte [time_str+10], ' ' @@: else if lang eq sp ; esperar 5/4/3/2 segundos, 1 segundo cmp al, 1 mov cl, 's' ja @f mov cl, ' ' @@: mov [time_str+10], cl else ; wait 5/4/3/2 seconds, 1 second cmp al, 1 mov cl, 's' ja @f mov cl, ' ' @@: mov [time_str+9], cl end if add al, '0' mov [time_str+1], al mov si, time_msg _setcursor 7,0 call print _setcursor 25,0 popad pop ds iret .timergo: push 0 pop es mov eax, [.oldtimer] mov [es:8*4], eax mov sp, 0EC00h .continue: sti _setcursor 6,0 mov si, space_msg call printplain call printplain _setcursor 6,0 mov si, loading_msg call print _setcursor 16,0 if ~ defined extended_primary_loader cmp [.bSettingsChanged], 0 jz .load cmp [.loader_block], -1 jz .load les bx, [.loader_block] mov eax, [es:bx+3] push ds pop es test eax, eax jz .load push eax mov si, save_quest call print .waityn: mov ah, 0 int 16h or al, 20h cmp al, 'n' jz .loadc if lang eq sp cmp al, 's' else cmp al, 'y' end if jnz .waityn call putchar mov byte [space_msg+80], 186 pop eax push cs push .cont push eax retf ;call back .loadc: pop eax .cont: push cs pop ds mov si, space_msg mov byte [si+80], 0 _setcursor 16,0 call printplain _setcursor 16,0 .load: end if ; \end{diamond}[02.12.2005] ; ASK GRAPHICS MODE call set_vmode ; GRAPHICS ACCELERATION ; force yes mov [es:BOOT_MTRR], byte 1 ; DMA ACCESS TO HD mov al, [preboot_dma] mov [es:BOOT_DMA], al ; Set kernel DEBUG mode - if nonzero, duplicates debug output to the screen. mov al, [preboot_debug] mov [es:BOOT_DEBUG_PRINT], al ;// 0x901E ; Start the first app (right now it's LAUNCHER) after kernel is loaded? mov al, [preboot_launcher] mov [es:BOOT_LAUNCHER_START], al ;// 0x901D ; BOOT DEVICE mov al, [preboot_device] dec al mov [es:BOOT_DEV], al ; GET MEMORY MAP include '../detect/biosmem.inc' ; READ DISKETTE TO MEMORY cmp byte [es:BOOT_DEV], 0 jne no_sys_on_floppy mov si, diskload call print xor ax, ax ; reset drive xor dx, dx int 0x13 ; do we boot from CD-ROM? mov ah, 41h mov bx, 55AAh xor dx, dx int 0x13 jc .nocd cmp bx, 0AA55h jnz .nocd mov ah, 48h push ds push es pop ds mov si, 0xa000 mov word [si], 30 int 0x13 pop ds jc .nocd push ds lds si, [es:si+26] test byte [ds:si+10], 40h pop ds jz .nocd ; yes - read all floppy by 18 sectors ; TODO: !!!! read only first sector and set variables !!!!! ; ... ; TODO: !!! then read flippy image track by track mov cx, 0x0001 ; startcyl,startsector .a1: push cx dx mov al, 18 mov bx, 0xa000 call boot_read_floppy mov si, movedesc push es push ds pop es mov cx, 256*18 mov ah, 0x87 int 0x15 pop es pop dx cx test ah, ah jnz sayerr_floppy add dword [si+8*3+2], 512*18 inc dh cmp dh, 2 jnz .a1 mov dh, 0 inc ch cmp ch, 80 jae ok_sys_on_floppy pusha mov al, ch shr ch, 2 add al, ch aam xchg al, ah add ax, '00' mov si, pros mov [si], ax call printplain popa jmp .a1 .nocd: ; no - read only used sectors from floppy ; now load floppy image to memory ; at first load boot sector and first FAT table ; read only first sector and fill variables mov cx, 0x0001 ; first logical sector xor dx, dx ; head = 0, drive = 0 (a:) mov al, 1 ; read one sector mov bx, 0xB000 ; es:bx -> data area call boot_read_floppy ; fill the necessary parameters to work with a floppy mov ax, word [es:bx+24] mov word [BPB_SecPerTrk], ax mov ax, word [es:bx+26] mov word [BPB_NumHeads], ax mov ax, word [es:bx+17] mov word [BPB_RootEntCnt], ax mov ax, word [es:bx+14] mov word [BPB_RsvdSecCnt], ax mov ax, word [es:bx+19] mov word [BPB_TotSec16], ax mov al, byte [es:bx+13] mov byte [BPB_SecPerClus], al mov al, byte [es:bx+16] mov byte [BPB_NumFATs], al ; 18.11.2008 mov ax, word [es:bx+22] mov word [BPB_FATSz16], ax mov cx, word [es:bx+11] mov word [BPB_BytsPerSec], cx ; count of clusters in FAT12 ((size_of_FAT*2)/3) ; mov ax, word [BPB_FATSz16] ; mov cx, word [BPB_BytsPerSec] ;end 18.11.2008 xor dx, dx mul cx shl ax, 1 mov cx, 3 div cx ; now ax - number of clusters in FAT12 mov word [end_of_FAT], ax ; load first FAT table mov cx, 0x0002 ; startcyl,startsector ; TODO!!!!! xor dx, dx ; starthead,drive mov al, byte [BPB_FATSz16] ; no of sectors to read add bx, word [BPB_BytsPerSec] ; es:bx -> data area call boot_read_floppy mov bx, 0xB000 ; and copy them to extended memory mov si, movedesc mov [si+8*2+3], bh ; from mov ax, word [BPB_BytsPerSec] shr ax, 1 ; words per sector mov cx, word [BPB_RsvdSecCnt] add cx, word [BPB_FATSz16] mul cx push ax ; save to stack count of words in boot+FAT xchg ax, cx push es push ds pop es mov ah, 0x87 int 0x15 pop es test ah, ah jz @f sayerr_floppy: mov dx, 0x3f2 mov al, 0 out dx, al sayerr_memmove: mov si, memmovefailed jmp sayerr_plain @@: pop ax ; restore from stack count of words in boot+FAT shl ax, 1 ; make bytes count from count of words and eax, 0ffffh add dword [si+8*3+2], eax ; copy first FAT to second copy ; TODO: BPB_NumFATs !!!!! add bx, word [BPB_BytsPerSec] ; !!! TODO: may be need multiply by BPB_RsvdSecCnt !!! mov byte [si+8*2+3], bh ; bx - begin of FAT mov ax, word [BPB_BytsPerSec] shr ax, 1 ; words per sector mov cx, word [BPB_FATSz16] mul cx mov cx, ax ; cx - count of words in FAT push es push ds pop es mov ah, 0x87 int 0x15 pop es test ah, ah jnz sayerr_floppy mov ax, cx shl ax, 1 and eax, 0ffffh ; ax - count of bytes in FAT add dword [si+8*3+2], eax ; reading RootDir ; TODO: BPB_NumFATs add bx, ax add bx, 100h and bx, 0ff00h ; bx - place in buffer to write RootDir push bx mov bx, word [BPB_BytsPerSec] shr bx, 5 ; divide bx by 32 mov ax, word [BPB_RootEntCnt] xor dx, dx div bx push ax ; ax - count of RootDir sectors mov ax, word [BPB_FATSz16] xor cx, cx mov cl, byte [BPB_NumFATs] mul cx add ax, word [BPB_RsvdSecCnt] ; ax - first sector of RootDir mov word [FirstDataSector], ax pop bx push bx add word [FirstDataSector], bx ; Begin of data region of floppy ; read RootDir call conv_abs_to_THS pop ax pop bx ; place in buffer to write push ax call boot_read_floppy ; read RootDir into buffer ; copy RootDir mov byte [si+8*2+3], bh ; from buffer pop ax ; ax = count of RootDir sectors mov cx, word [BPB_BytsPerSec] mul cx shr ax, 1 mov cx, ax ; count of words to copy push es push ds pop es mov ah, 0x87 int 0x15 pop es mov ax, cx shl ax, 1 and eax, 0ffffh ; ax - count of bytes in RootDir add dword [si+8*3+2], eax ; add count of bytes copied ; Reading data clusters from floppy mov byte [si+8*2+3], bh push bx mov di, 2 ; First data cluster .read_loop: mov bx, di shr bx, 1 ; bx+di = di*1.5 jnc .even test word [es:bx+di+0xB200], 0xFFF0 ; TODO: may not be 0xB200 !!! jmp @f .even: test word [es:bx+di+0xB200], 0xFFF ; TODO: may not be 0xB200 !!! @@: jz .skip ; read cluster di ;.read: ;conv cluster di to abs. sector ax ; ax = (N-2) * BPB_SecPerClus + FirstDataSector mov ax, di sub ax, 2 xor bx, bx mov bl, byte [BPB_SecPerClus] mul bx add ax, word [FirstDataSector] call conv_abs_to_THS pop bx push bx mov al, byte [BPB_SecPerClus] ; number of sectors in cluster call boot_read_floppy push es push ds pop es pusha ; mov ax, word [BPB_BytsPerSec] xor cx, cx mov cl, byte [BPB_SecPerClus] mul cx shr ax, 1 ; ax = (BPB_BytsPerSec * BPB_SecPerClus)/2 mov cx, ax ; number of words to copy (count words in cluster) ; mov ah, 0x87 int 0x15 ; copy data test ah, ah popa pop es jnz sayerr_floppy ; skip cluster di .skip: mov ax, word [BPB_BytsPerSec] xor cx, cx mov cl, byte [BPB_SecPerClus] mul cx and eax, 0ffffh ; ax - count of bytes in cluster add dword [si+8*3+2], eax mov ax, word [end_of_FAT] ; max cluster number pusha ; draw percentage ; total clusters: ax ; read clusters: di xchg ax, di mov cx, 100 mul cx div di aam xchg al, ah add ax, '00' mov si, pros cmp [si], ax jz @f mov [si], ax call printplain @@: popa inc di cmp di, word [end_of_FAT] ; max number of cluster jnz .read_loop pop bx ; clear stack ok_sys_on_floppy: mov si, backspace2 call printplain mov si, okt call printplain no_sys_on_floppy: xor ax, ax ; reset drive xor dx, dx int 0x13 mov dx, 0x3f2 ; floppy motor off mov al, 0 out dx, al if defined extended_primary_loader cmp [es:BOOT_DEV], 1 jne no_sys_from_primary ; load kolibri.img using callback from primary loader and word [movedesc + 24 + 2], 0 mov byte [movedesc + 24 + 4], 10h ; read in blocks of 64K until file is fully loaded mov ax, 1 .repeat: mov di, image_file_struct call [bootcallback] push cs pop ds push cs pop es cmp bx, 1 ja sayerr_badsect push bx mov si, movedesc and word [si + 16 + 2], 0 mov byte [si + 16 + 4], 4 mov ah, 87h mov cx, 8000h int 15h pop bx test ah, ah jnz sayerr_memmove inc byte [si + 24 + 4] test bx, bx jz no_sys_from_primary mov ax, 2 jmp .repeat no_sys_from_primary: end if ; SET GRAPHICS xor ax, ax mov es, ax mov ax, [es:BOOT_VESA_MODE] ; vga & 320x200 mov bx, ax cmp ax, 0x13 je setgr cmp ax, 0x12 je setgr mov ax, 0x4f02 ; Vesa setgr: int 0x10 test ah, ah mov si, fatalsel jnz v_mode_error ; set mode 0x12 graphics registers: cmp bx, 0x12 jne gmok2 mov al, 0x05 mov dx, 0x03ce push dx out dx, al ; select GDC mode register mov al, 0x02 inc dx out dx, al ; set write mode 2 mov al, 0x02 mov dx, 0x03c4 out dx, al ; select VGA sequencer map mask register mov al, 0x0f inc dx out dx, al ; set mask for all planes 0-3 mov al, 0x08 pop dx out dx, al ; select GDC bit mask register ; for writes to 0x03cf gmok2: push ds pop es