$Revision$ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2007. 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 ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;========================================================================== ; ; 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 cmp al, 0 jnz @b popa ret getkey: ; 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 int 16h cmp al, bl jb getkey cmp al, bh ja getkey push ax call putchar pop ax and ax, 0Fh jnz @f mov al, 10 @@: 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 } 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 mov si, badsect sayerr_plain: call printplain jmp $ @@: pop si ret ;========================================================================= ; ; 16 BIT CODE ; ;========================================================================= start_of_code: cld ; \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 @@: ; \end{diamond}[02.12.2005] ; if bootloader sets cx = 'HA' and dx = 'RD', then bx contains identifier of source hard disk ; (see comment to bx_from_load) cmp cx, 'HA' jnz no_hd_load cmp dx,'RD' jnz no_hd_load mov word [cs:bx_from_load], bx ; {SPraid}[13.03.2007] no_hd_load: ; set up stack mov ax, 3000h mov ss, ax mov sp, 0EC00h ; set up segment registers push cs pop ds push cs pop es ; 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 sti ; set up esp movzx esp, sp push 0 pop es and word [es:0x9031], 0 ; \begin{Mario79} ; find HDD IDE DMA PCI device ; check for PCI BIOS mov ax, 0xB101 int 0x1A jc .nopci cmp edx, 'PCI ' jnz .nopci ; find PCI class code ; class 1 = mass storage ; subclass 1 = IDE controller ; a) class 1, subclass 1, programming interface 0x80 mov ax, 0xB103 mov ecx, 1*10000h + 1*100h + 0x80 xor si, si ; device index = 0 int 0x1A jnc .found ; b) class 1, subclass 1, programming interface 0x8A mov ax, 0xB103 mov ecx, 1*10000h + 1*100h + 0x8A xor si, si ; device index = 0 int 0x1A jnc .found ; c) class 1, subclass 1, programming interface 0x85 mov ax, 0xB103 mov ecx, 1*10000h + 1*100h + 0x85 xor si, si int 0x1A jc .nopci .found: ; get memory base mov ax, 0xB10A mov di, 0x20 ; memory base is config register at 0x20 int 0x1A jc .nopci and cx, 0xFFF0 ; clear address decode type mov [es:0x9031], cx .nopci: ; \end{Mario79} mov al, 0xf6 ; Ñáðîñ êëàâèàòóðû, ðàçðåøèòü ñêàíèðîâàíèå out 0x60, al xor cx, cx wait_loop: ; variant 2 ; reading state of port of 8042 controller in al, 64h and al, 00000010b ; ready flag ; wait until 8042 controller is ready loopnz wait_loop ; --------------- APM --------------------- and word [es:0x9044], 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:0x9044], ax ; Save APM Version mov [es:0x9046], 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:0x9040], ebx mov [es:0x9050], ax mov [es:0x9052], cx mov [es:0x9054], dx apm_end: _setcursor d80x25_top_num, 0 ; DISPLAY VESA INFORMATION mov ax, 0x4f00 mov di, 0xa000 int 0x10 cmp ax, 0x004f mov si, novesa jnz @f mov ax, [es:di+4] add ax, '0'*256+'0' mov si, vervesa mov [si+vervesa_off], ah mov [si+vervesa_off+2], al @@: call print ; \begin{diamond}[30.11.2005] cfgmanager: ; settings: ; a) preboot_graph = graphical mode ; preboot_gprobe = probe this mode? ; b) preboot_dma = use DMA access? ; c) preboot_vrrm = use VRR? ; d) preboot_device = from what boot? mov di, preboot_graph ; check bootloader block cmp [.loader_block], -1 jz .noloaderblock les bx, [.loader_block] cmp byte [es:bx], 1 mov si, loader_block_error jnz sayerr test byte [es:bx+1], 1 jz @f ; image in memory present cmp [di+preboot_device-preboot_graph], 0 jnz @f mov [di+preboot_device-preboot_graph], 3 @@: .noloaderblock: ; determine default settings mov [.bSettingsChanged], 0 cmp byte [di], 0 jnz .preboot_gr_end mov [di+preboot_gprobe-preboot_graph], 0 mov al, [vervesa+vervesa_off] cmp al, 'x' jz .novesa cmp al, '1' jz .vesa12 mov [di+preboot_gprobe-preboot_graph], 2 mov al, 3 jmp @f .vesa12: mov al, 7 jmp @f .novesa: mov al, 10 @@: mov [di], al .preboot_gr_end: cmp [di+preboot_dma-preboot_graph], 0 jnz @f mov [di+preboot_dma-preboot_graph], 3 ; DMA: defaults to none @@: ; following 4 lines set variables to 1 if its current value is 0 cmp [di+preboot_vrrm-preboot_graph], 1 adc [di+preboot_vrrm-preboot_graph], 0 cmp [di+preboot_device-preboot_graph], 1 adc [di+preboot_device-preboot_graph], 0 ; notify user mov si, linef call print 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 mov al, [preboot_graph] cmp al, 8 ja .pnovesa mov dl, al and eax, 3 mov si, [modes_msg+eax*2] call printplain mov si, modevesa20 cmp dl, 4 jbe @f mov si, modevesa12 @@: call printplain cmp dl, 4 ja .x mov si, probeno_msg cmp [preboot_gprobe], 2 jnz @f mov si, probeok_msg @@: call printplain .x: jmp .c .pnovesa: cmp al, 9 mov si, mode9 jz @b mov si, mode10 jmp @b .c: mov si, linef call printplain mov si, dma_msg call print cmp [preboot_dma], 2 mov si, on_msg jb @f mov si, off_msg ja @f mov si, readonly_msg @@: call printplain mov si, vrrm_msg cmp [preboot_vrrm], 1 call .say_on_off mov si, preboot_device_msg call print mov al, [preboot_device] and eax, 7 mov si, [preboot_device_msgs+eax*2] call printplain .wait: _setcursor 25,0 ; out of screen ; set timer interrupt handler cli push 0 pop es mov eax, [es:8*4] mov [.oldtimer], eax mov eax, [.timer] mov [es:8*4], eax sti ; wait for keypressed mov ah, 0 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 pop ax ; switch on key cmp al, 13 jz .continue or al, 20h cmp al, 'a' jz .change_a cmp al, 'b' jz .change_b cmp al, 'c' jz .change_c cmp al, 'd' jnz .wait _setcursor 15,0 mov si, bdev call print mov bx, '14' call getkey mov [preboot_device], al _setcursor 13,0 .d: mov [.bSettingsChanged], 1 mov si, space_msg call printplain _setcursor 15,0 mov cx, 6 @@: call printplain loop @b jmp .printcfg .change_a: _setcursor 15,0 mov si, gr_mode call printplain mov bx, '09' call getkey mov [preboot_graph], al cmp al, 4 ja @f mov si, probetext call printplain mov bx, '12' call getkey mov [preboot_gprobe], al @@: _setcursor 10,0 jmp .d .change_b: _setcursor 15,0 mov si, ask_dma call print mov bx, '13' call getkey mov [preboot_dma], al _setcursor 11,0 jmp .d .change_c: _setcursor 15,0 mov si, vrrmprint call print mov bx, '12' call getkey mov [preboot_vrrm], al _setcursor 12,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 ? .bSettingsChanged db ? .timer dd ? end virtual .loader_block dd -1 .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] sub ax, 18*5 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, 'ã' jz @f mov cl, 'ë' @@: mov [time_str+9], cl else if lang eq et cmp al, 1 ja @f mov [time_str+9], ' ' mov [time_str+10],' ' @@: 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 15,0 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 cmp al, 'y' jnz .waityn call putchar mov byte [space_msg+80], 186 pop eax push cs push .cont push eax retf .loadc: pop eax .cont: push cs pop ds mov si, space_msg mov byte [si+80], 0 _setcursor 15,0 call printplain _setcursor 15,0 .load: ; \end{diamond}[02.12.2005] ; ASK GRAPHICS MODE movzx ax, [preboot_graph] push 0 pop es ; address is gr_table+6*(ax-1) add ax, ax lea si, [gr_table + eax + eax*2 - 6] mov bx, [si+0] mov cx, [si+2] mov dx, [si+4] cmp al, 9*2 mov al, 32 ; BPP jb @f mov [es:0x9000], al or dword [es:0x9018], 0xFFFFFFFF; 0x800000 @@: mov [es:0x9008], bx mov [es:0x900A], cx mov [es:0x900C], dx test bh, bh jz nov ; USE DEFAULTS OR PROBE ; bx - mode : cx - x size : dx - y size cmp [preboot_gprobe], 1 jz noprobe mov bx, 0x100 newprobe: inc bx cmp bx, 0x17f mov si, prnotfnd jz invalid_video_mode probemore: push cx mov ax, 0x4f01 mov cx, bx mov di, 0xa000 int 0x10 pop cx test byte [es:di], 80h ; lfb? jz newprobe cmp [es:di+0x12], cx ; x size? jnz newprobe cmp [es:di+0x14], dx ; y size? jnz newprobe cmp byte [es:di+0x19], 32 ;24 jb newprobe ; add bx, 0100000000000000b or bh, 40h mov [es:0x9008], bx noprobe: ; FIND VESA 2.0 LFB & BPP mov ax, 0x4f01 mov cx, bx and cx, 0xfff mov di, 0xa000 int 0x10 ; LFB mov eax, [es:di+0x28] mov [es:0x9018], eax ; ---- vbe voodoo BytesPerLine equ 0x10 mov ax, [es:di+BytesPerLine] mov [es:0x9001], ax ; BPP mov al, byte [es:di+0x19] mov [es:0x9000], al nov: cmp al, 24 mov si, bt24 jz bppl cmp al, 32 mov si, bt32 jz bppl mov si, btns invalid_video_mode: call print _setcursor (d80x25_top_num+2), 0 mov si, start_msg call print jmp cfgmanager.printcfg bppl: call print ; FIND VESA 1.2 PM BANK SWITCH ADDRESS push es mov ax, 0x4f0A xor bx, bx int 0x10 xor eax, eax mov ax, es shl eax, 4 movzx ebx, di add eax, ebx mov bx, [es:di] add eax, ebx pop es mov [es:0x9014], eax ; GRAPHICS ACCELERATION ; force yes mov [es:0x901C], byte 1 ; DMA ACCESS TO HD mov al, [preboot_dma] mov [es:0x901F], al ; VRR_M USE mov al,[preboot_vrrm] mov [es:0x9030], al mov [es:0x901E], byte 1 ; BOOT DEVICE mov al, [preboot_device] dec al mov [boot_dev], al ; READ DISKETTE TO MEMORY ; cmp [boot_dev],0 jne no_sys_on_floppy mov si,diskload call print xor ax, ax ; reset drive xor dx, dx int 0x13 ; now load floppy image to memory ; at first load boot sector and first FAT table mov cx, 0x0001 ; startcyl,startsector xor dx, dx ; starthead,drive mov al, 1+9 ; no of sectors to read mov bx, 0xB000 ; es:bx -> data area call boot_read_floppy ; and copy them to extended memory mov si, movedesc mov [si+8*2+3], bh push es push ds pop es mov cx, 256*10 mov ah, 0x87 int 0x15 test ah, ah jz @f sayerr_floppy: mov dx, 0x3f2 mov al, 0 out dx, al mov si, memmovefailed jmp sayerr_plain @@: add dword [si+8*3+2], 512*10 ; copy FAT to second copy mov byte [si+8*2+3], 0xB2 mov cx, 256*9 mov ah, 0x87 int 0x15 pop es test ah, ah jnz sayerr_floppy add dword [si+8*3+2], 512*9 ; calculate total number of sectors to read mov ax, 1+9+14 ; boot+FAT+root mov di, 0xB203 .calc_loop: test word [es:di], 0xFFF jz @f inc ax @@: test word [es:di+1], 0xFFF0 jz @f inc ax @@: add di, 3 cmp di, 0xB200+1440*3 jb .calc_loop push ax mov bp, 1+9 ; already read sectors ; now read rest mov byte [si+8*2+3], 0xA0 mov di, 2-14 ; absolute sector-31 mov cx, 0x0002 ; cylinder=0, sector=2 mov dx, 0x0100 ; head=1, disk=0 .read_loop: ; determine whether sector must be read cmp di, 2 jl .read mov bx, di shr bx, 1 jnc .even test word [es:bx+di+0xB200], 0xFFF0 jmp @f .even: test word [es:bx+di+0xB200], 0xFFF @@: jz .skip .read: mov bx, 0xA000 mov al, 1 ; 1 sector call boot_read_floppy inc bp push es push ds pop es pusha mov cx, 256 mov ah, 0x87 int 0x15 test ah, ah popa pop es jnz sayerr_floppy .skip: add dword [si+8*3+2], 512 inc cx cmp cl, 19 jnz @f mov cl, 1 inc dh cmp dh, 2 jnz @f mov dh, 0 inc ch @@: pop ax push ax pusha ; draw percentage ; total sectors: ax ; read sectors: bp xchg ax, bp mov cx, 100 mul cx div bp 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, 2880-31 jnz .read_loop ; mov cx, 0x0001 ; startcyl,startsector ; xor dx, dx ; starthead,drive ; push word 80*2 ; read no of sect ; reads: ; pusha ; xor si,si ; newread: ; mov bx,0xa000 ; es:bx -> data area ; mov ax,0x0200+18 ; read, no of sectors to read ; int 0x13 ; test ah, ah ; jz goodread ; inc si ; cmp si,10 ; jnz newread ; mov si,badsect-0x10000 ;sayerr_plain: ; call printplain ; jmp $ ; goodread: ; ; move -> 1mb ; mov si,movedesc-0x10000 ; push es ; push ds ; pop es ; mov cx,256*18 ; mov ah,0x87 ; int 0x15 ; pop es ; ; test ah,ah ; was the move successfull ? ; je goodmove ; mov dx,0x3f2 ; floppy motor off ; mov al,0 ; out dx,al ; mov si,memmovefailed-0x10000 ; jmp sayerr_plain ; goodmove: ; ; add dword [movedesc-0x10000+0x18+2], 512*18 ; popa ; inc dh ; cmp dh,2 ; jnz bb2 ; mov dh,0 ; inc ch ; pusha ; print prosentage ; mov si,pros-0x10000 ; shr ch, 2 ; mov al, '5' ; test ch, 1 ; jnz @f ; mov al, '0' ;@@: ; mov [si+1], al ; shr ch, 1 ; add ch, '0' ; mov [si], ch ; call printplain ; popa ; bb2: ; pop ax ; dec ax ; push ax ; jnz reads ; readdone: ; pop ax 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 ; SET GRAPHICS xor ax, ax mov es, ax mov ax, [es:0x9008] ; 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 sayerr ; 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