/* detect.S * * Scanning and Initialization of all Display adapters (13-Mar-2003) * * Copyright (C) 2003 -- 2003 Antonino Daplas * */ #define SAVE_SEGMENT 0x8000 #define SCRATCH_SEGMENT 0x7000 #define VROM_SEGMENT 0xc000 #define PCI_SIGNATURE (('P'<<0)+('C'<<8)+('I'<<16)+(' '<< 24)) init_video: pushw %ds # We use different segments pushw %ds # FS contains original DS popw %fs pushw %cs # DS is equal to CS popw %ds pushw %cs # ES is equal to CS popw %es xorw %ax, %ax movw %ax, %gs # GS is zero call find_pci_bios # check for PCI BIOS directory service cmpb $0, %ah # not available? jne init_video_done call save_video # save video state call disable_bridge # disable VGA routing on bridges call disable_all # disable all VGA class devices call controller_init # warmboot all VGA class devices call enable_bridge # reenable VGA routing on bridges call enable_all # reenable VGA class devices call restore_video # restore video state init_video_done: popw %ds ret #--------------------------------------------------------------- # ----------------------------------------------------------------------------- # disable_all: disables all VGA class devices #----------------------------------------------------------------------------- disable_all: movw $0, %si disable_all_loop: call find_vga_class # find all VGA class devices cmpb $0, %ah # no more devices? jne disable_all_done pushw %si call disable_dev #disable popw %si incw %si jmp disable_all_loop # do it again disable_all_done: ret # ----------------------------------------------------------------------------- # enable_all: enables all VGA class devices #----------------------------------------------------------------------------- enable_all: movw $0, %si enable_all_loop: call find_vga_class # find all VGA class devices cmpb $0, %ah # no more devices? jne enable_all_done pushw %si call enable_dev # and enable popw %si incw %si jmp enable_all_loop # do it again enable_all_done: ret # ----------------------------------------------------------------------------- # save_video: Saves current state of video controller # # USES: cursor, vid_state #----------------------------------------------------------------------------- save_video: movw $0x3, %ax # save cursor position int $0x10 movw %dx, cursor pushw %es # disable and save current state pushw %ds popw %es movw $0x1202, %ax movb $0x35, %bl leaw vid_state, %dx int $0x10 popw %es # save 64K at 0xc000:0000 pushw %ds pushw %es pushw $SAVE_SEGMENT # save a copy of original ROM popw %es pushw $VROM_SEGMENT popw %ds movw $0, %di movw $0, %si movw $0x4000, %cx rep movsl popw %es popw %ds ret # ----------------------------------------------------------------------------- # restore_video: Restores saved state of video controller # # USES: cursor, vid_state #----------------------------------------------------------------------------- restore_video: pushw %ds # restore ROM pushw %es pushw $SAVE_SEGMENT popw %ds pushw $VROM_SEGMENT popw %es movw $0, %di movw $0, %si movw $0x4000, %cx rep movsl popw %es popw %ds pushw %es # restore video state pushw %ds popw %es movw $0x1203, %ax movb $0x35, %bl leaw vid_state, %dx int $0x10 popw %es movw cursor, %dx # restore cursor movb $2, %ah int $0x10 ret # ----------------------------------------------------------------------------- # disable_bridge: disables VGA routing on bridges #----------------------------------------------------------------------------- disable_bridge: movw $0, %si movl $0x00060400, %ecx # find all PCI-PCI bridges int $0x1a cmp $0, %ah # no more devices? jnz bridge_done pushw %si movw $0xb10a, %ax # read command word movw $0x40, %di int $0x1a andl $(~(8 << 16)), %ecx # disable VGA routing movw $0xb10d, %ax movw $0x3c, %di int $0x1a popw %si inc %si jmp disable_bridge # do it again bridge_done: ret # ----------------------------------------------------------------------------- # enable_bridge: enables VGA routing on bridges #----------------------------------------------------------------------------- enable_bridge: movw $0, %si movl $0x00060400, %ecx # find all PCI-PCI bridges int $0x1a cmp $0, %ah # no more devices? jnz bridge1_done pushw %si movw $0xb10a, %ax # read command word movw $0x3c, %di int $0x1a orl $(8 << 16), %ecx # enable VGA routing movw $0xb10d, %ax movw $0x3c, %di int $0x1a popw %si inc %si jmp enable_bridge # do it again bridge1_done: ret # ----------------------------------------------------------------------------- # find_pci_bios: Check if PCI BIOS directory service is available on this # machine # RETURNS: AH = 0 - found : 1 - not found #----------------------------------------------------------------------------- find_pci_bios: movw $0xb101, %ax # detect PCI BIOS directory service int $0x1a jc bios_no_good # CF set, service not present cmpl $PCI_SIGNATURE, %edx # check for signature jne bios_no_good movb $0, %ah # return success ret bios_no_good: movb $1, %ah # return fail ret # ---------------------------------------------------------------------------- # find_vga_class: Check for PCI devices of VGA base class (3) # ENTRY: SI = index # RETURNS: AH = 0 - found : 1 - not found # BH = bus number # BL = device (3-7) and function number (0-2) # #----------------------------------------------------------------------------- find_vga_class: movw $0xb103, %ax movl $0x000030000, %ecx int $0x1a ret # ---------------------------------------------------------------------------- # disable_dev: disables all controllers # ENTRY: BX = bus, device and function number #----------------------------------------------------------------------------- disable_dev: movw $0xb10a, %ax #read Expansion Rom movw $0x30, %di int $0x1a movw $0xb10d, %ax movw $0x30, %di andw $(~1), %cx # disable expansion ROM int $0x1a movw $0xb109, %ax # read command word movw $0x04, %di int $0x1a movw $0xb10c, %ax # disable command word andw $(~3), %cx movw $0x04, %di int $0x1a ret # ---------------------------------------------------------------------------- # enable_dev: enables all controllers # ENTRY: BX = bus, device and function number #----------------------------------------------------------------------------- enable_dev: movw $0xb109, %ax #read command word movw $0x04, %di int $0x1a movw $0xb10c, %ax # enable bit 0,1 of command word orw $3, %cx movw $0x04, %di int $0x1a ret # ---------------------------------------------------------------------------- # controller_init: searches, verifies, copies and warmboots ROM #----------------------------------------------------------------------------- controller_init: movw $0, %si coninit_loop: pushw %si # find all VGA class devices movw $0xb103, %ax movl $0x000030000, %ecx int $0x1a cmpb $0, %ah # no more devices? jne coninit_done movw %bx, dev_num # save bus, device and func number call enable_dev # enable this device call check_rom cmpb $0, %ah # no ROM? je has_no_rom call copy_rom cmpb $0, %ah # copy failed? je has_no_rom call verify_rom cmpb $0, %ah # verify failed? je has_no_rom call post_rom movw dev_num, %bx call disable_dev # disable this device has_no_rom: popw %si incw %si jmp coninit_loop # do it again coninit_done: popw %si ret # ---------------------------------------------------------------------------- # check_rom: searches for valid ROM address # USES: dev_num - current bus, device and function number # RETURNS: AH - 0 none found, 1 found #----------------------------------------------------------------------------- check_rom: movw $0xb10a, %ax # read Expansion Rom movw dev_num, %bx # get current device movw $0x30, %di int $0x1a cmpl $0, %ecx # no ROM, check BAR je check_base_addr pushl %ecx movl %ecx, dev_addr # save ROM address check_rom_cont: movw $0xb109, %ax # read command word movw dev_num, %bx movw $0x04, %di int $0x1a movw $0xb10c, %ax # enabled bit 0,1 of command word movw dev_num, %bx movw $0x04, %di orw $0x3, %cx int $0x1a popl %ecx # enable expansion ROM movw $0xb10d, %ax movw dev_num, %bx movw $0x30, %di orl $1, %ecx int $0x1a movb $1, %ah # return success ret check_base_addr: movw $6, %cx # max 6 BAR's supported movw $0x10, %di # first BAR check_base_addr_loop: pushw %di pushw %cx movw $0xb10a, %ax # read BAR's movw dev_num, %bx int $0x1a testl $1, %ecx # check for IO jnz do_have_rom # is IO? assume ROM popw %cx popw %di addw $4, %di # check next BAR decw %cx jcxz no_rom_really jmp check_base_addr_loop do_have_rom: andl $(~1), %ecx # assume BAR is ROM movl %ecx, dev_addr # save BAR address movw $0xb10d, %ax # write BAR to expansion ROM movw dev_num, %bx movw $0x30, %di int $0x1a popw %cx popw %di jmp check_rom_cont # continue with initialization no_rom_really: movb $0, %ah # no ROM at all, return fail ret # ---------------------------------------------------------------------------- # copy_rom: copy ROM to SCRATCH_SEGMENT using int 10h, function 0x87 # USES: dev_num - current bus, device and function number # RETURNS: AH = 0 copy failed, AH = 1 copy successful #----------------------------------------------------------------------------- copy_rom: movl dev_addr, %eax # write ROM addr to GDT movw %ax, gdt_src1 shrl $16, %eax movb %al, gdt_src2 movb %ah, gdt_src3 pushw %es pushw %ds popw %es movw $4, %cx # zeroes first 16 bytes of gdt movl $0, %eax leaw gdt_p, %di cld rep stosl movw $4, %cx # zeroes last 16 bytes of gdt leaw gdt_dummy, %di cld rep stosl leaw gdt_p, %si # copy extended memory movw $0x8000, %cx movw $0x8700, %ax int $0x15 popw %es jc extcopy_fail movw $0xb10a, %ax # read Expansion Rom movw dev_num, %bx movw $0x30, %di int $0x1a movw $0xb10d, %ax # disable expansion ROM after copy movw dev_num, %bx movw $0x30, %di andw $(~1), %cx int $0x1a movb $1, %ah # return success ret extcopy_fail: movb $0, %ah # return failed ret # ---------------------------------------------------------------------------- # verify_rom: verifies ROM for signature bytes and size <= 64K # USES: dev_num - current bus, device and function number # RETURNS: AH = 0 verify failed, AH = size of ROM in 512-byte blocks #----------------------------------------------------------------------------- verify_rom: pushw %es movw $SCRATCH_SEGMENT, %ax movw %ax, %es movw %es:(0), %ax cmpw $0xaa55, %ax # check for rom sig bytes jne corrupt_rom movb %es:(2), %ah # put ROM size in AH cmpb $128, %ah # check if init size > 64K jns corrupt_rom popw %es ret corrupt_rom: popw %es movb $0, %ah # return fail ret # ---------------------------------------------------------------------------- # post_rom: warmboots ROM # USES: dev_num - current bus, device and function number #----------------------------------------------------------------------------- # FIXME: currently does not work as C000:0000 is write # protected by BIOS post_rom: xorl %ecx, %ecx movb %ah, %cl # AH has number of 512 bytes to copy shll $7, %ecx # number of dwords to copy pushw %ds pushw %es pushw $SCRATCH_SEGMENT # copy from scratch segment ... popw %ds pushw $VROM_SEGMENT # to 0xC000 - doesn't work as popw %es # 0xC000 is write-protected movw $0, %di movw $0, %si cld rep movsb popw %es popw %ds movw dev_num, %ax # putting device number to ax may help lcall $VROM_SEGMENT, $0x0003 # warmboot :) ret #------------------------------------------------------------ dev_addr: .long 0 # current ROM address dev_num: .word 0 # current bus, device, func number cursor: .word 0 # cursor state vid_state: .fill 128, 0 # video state # gdt table used for int 10h ah=87 (copy extended memory) gdt_p: .long 0,0,0,0 # fill with zeroes gdt_src_seg: .word 0xffff # segment limit gdt_src1: .word 0 # src address (0-15) gdt_src2: .byte 0 # src address (16-23) gdt_src_access: .byte 0x93 # access gdt_src_x: .byte 0 # extended access/segment limit gdt_src3: .byte 0 # src address (24-31) gdt_dst_seg: .word 0xffff gdt_dst1: .word 0x0000 gdt_dst2: .byte 0x07 gdt_dst_access: .byte 0x93 gdt_dst_x: .byte 0 gdt_dst3: .byte 0 gdt_dummy: .long 0,0,0,0 #------------------------------------------------------------