linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Antonino Daplas <adaplas@pol.net>
To: Jon Smirl <jonsmirl@yahoo.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>,
	James Simmons <jsimmons@infradead.org>,
	Linux Fbdev development list
	<linux-fbdev-devel@lists.sourceforge.net>
Subject: Re: Reading the EDID block for x86 machines
Date: 19 Mar 2003 13:15:20 +0800	[thread overview]
Message-ID: <1048050587.1183.3.camel@localhost.localdomain> (raw)
In-Reply-To: <20030318170749.55622.qmail@web14904.mail.yahoo.com>

[-- Attachment #1: Type: text/plain, Size: 3120 bytes --]

On Wed, 2003-03-19 at 01:07, Jon Smirl wrote:
> Here is a description of how to control the shadow
> write protect for a SIS chipset. It is done by writing
> to PCI config space. There is a slim chance that this
> is a standard procedure.
> 
> http://www.missl.cs.umd.edu/Projects/sebos/winint/index1.html
> 

I tried this part, and it doesn't work with the chipset I'm using. 
Plus, PCI config space register 0x70 is device specific, only the first
64 bytes is defined generically.

> When you copied to 8000 ot 9000, did you copy the ROM
> or the image at C000? I compared a dump of C000 to the
> ROM and they don't match. ATI may have overlaid some
> code during the init procedure.

I copied the actual ROM (pointed to by Expansion ROM base address 0x30)
and placed it in 0xc000 and 0x8000.  0xc000 of course is write protected
by the BIOS, and it won't run in 0x8000.

Yes, the final BIOS image can be different from the initial image.  Most
of the time, the initial image is larger, or needs decompression.  Some 
of the newer ROM's may even use the POST Memory Manager Specification
(kinda like a POST-specific malloc and family) during INIT, but this is
available only during POST, and memory allocated by the PMM is
unavailable after POST.

> 
> So I guess we are stuck with a user space daemon.
> Athlon-64 and IA64 will require the entire VM86
> emulator. Last I checked the scitech emulator (ver8)
> han't implemented all of the instructions needed to
> run the ATI ROMs so it will need some work.
> 
> How do the Transmeta tools work? Could we turn the
> ROMs into a C program and compile them again? Or use
> something like use an emulator to capture the reset
> sequence and then compile it for protected mode. 
> 

That's another problem.  Some of the BIOS services used during INIT may
become unavailable after POST, so emulating ROM's can either be caused
by this or by an incomplete emulator.
 
> I tried a couple of reverse engineering tools on the
> ROMs but I didn't get very far. I don't have access to
> the ATI Radeon documentation so it is hard for me to
> tell what is going on.  
> 

Our best hope is for graphics manufacturer to drop VGA :-) which should
allow for relocatable ROM's and therefore initialization of multiple
graphics adapters.  Second best hope is for manufacturer's to open up
the source for initializing devices without having to initialize the VGA
BIOS. 

Anyway, attached is the code I'm using.  It basically saves the video
state, disables all VGA controllers, disables VGA routing on PCI-PCI
bridges, searches for valid expansion ROM addresss on VGA class devices,
copies it into a scratch segment, verifies the ROM, copies the verified
ROM to 0xc000 and call 0xc000:0003.  Of course, the "copies the verified
ROM to 0xc000" part will fail, so the "call 0xc000:0003" will just
warmboot your primary display again.

You have to place the file in linux/arch/i386/boot

Then in setup.S

add "include detect.S"

and 

call init_video #preferably before or after 'call video'

I'll probably drop effort on this (for now) and concentrate on adding a
userspace daemon.

Tony


[-- Attachment #2: detect.S --]
[-- Type: text/plain, Size: 13180 bytes --]

/*	detect.S
 *
 *	Scanning and Initialization of all Display adapters (13-Mar-2003)
 *
 *	Copyright (C) 2003 -- 2003 Antonino Daplas <adaplas@pol.net>
 *
 */

#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

#------------------------------------------------------------	


  reply	other threads:[~2003-03-19  5:18 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-03-11 12:49 Reading the EDID block for x86 machines Antonino Daplas
2003-03-11 15:49 ` James Simmons
2003-03-11 20:07   ` Antonino Daplas
2003-03-11 21:33   ` Antonino Daplas
2003-03-11 21:47     ` Antonino Daplas
2003-03-11 22:05     ` Jon Smirl
2003-03-11 22:33       ` Antonino Daplas
2003-03-11 22:54         ` Jon Smirl
2003-03-11 23:02           ` Antonino Daplas
2003-03-11 23:42             ` Jon Smirl
2003-03-12 17:38               ` Antonino Daplas
2003-03-12 18:16                 ` Jon Smirl
2003-03-12 22:38                   ` Antonino Daplas
2003-03-12 23:36                     ` Jon Smirl
2003-03-12 23:47                     ` Jon Smirl
2003-03-13  6:50                     ` Geert Uytterhoeven
2003-03-13 15:42                       ` Jon Smirl
2003-03-16 23:00                       ` Antonino Daplas
2003-03-17  4:00                         ` Jon Smirl
2003-03-17  7:00                           ` Antonino Daplas
2003-03-17 19:33                             ` Jon Smirl
2003-03-17 21:38                               ` Antonino Daplas
2003-03-17 22:02                                 ` Jon Smirl
2003-03-17 22:29                                   ` Antonino Daplas
2003-03-17 23:41                                     ` Jon Smirl
2003-03-18  9:06                                       ` Geert Uytterhoeven
2003-03-18 10:00                                       ` Antonino Daplas
2003-03-18 17:07                                         ` Jon Smirl
2003-03-19  5:15                                           ` Antonino Daplas [this message]
2003-03-19  6:07                                             ` Jon Smirl
2003-03-18  0:00                                     ` Jon Smirl
2003-03-11 23:54             ` Jon Smirl
2003-03-12 12:10 ` Ville Syrjälä
2003-03-12 17:38   ` Antonino Daplas
2003-03-12 18:47     ` Ville Syrjälä

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1048050587.1183.3.camel@localhost.localdomain \
    --to=adaplas@pol.net \
    --cc=geert@linux-m68k.org \
    --cc=jonsmirl@yahoo.com \
    --cc=jsimmons@infradead.org \
    --cc=linux-fbdev-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).