summaryrefslogblamecommitdiffstats
path: root/src/arch/i386/prefix/romprefix.S
blob: baf98e6a69cf45665098b1513a6dccff41ff9e6b (plain) (tree)
1
2
3
4
5
6
7
8
9
10







                                                                        

                                                                            
                                                                            
                                                                          
                                
 


                  
                                           
        


                                                                      
                                                                     


                                                                   
                    
                          
                    



                                      






                                                                          


                                                       


                                                                    
                                                                       










                                                                               

                                         


                                                                          




                                        


                   
















                                                                            
                                                                   



                                                                               
 
                         


                                      






                                                                      
        





                                                                    




                                                                 

                                                                







                                                                      
                                           




                                                                      
   


                                                                   
                   
                   
                   
                   
           
                   
                   

                     
 







                                                                    
                        
 

                                                
                        
                             
                                  
 



                                                      
 

                                   
                        


                               




























                                                                           
                                
                                                                              
                                                                              
                                          


                                       
                        
                             
 
                           
                                                            


                                                    
                             
                       


                                      
                        




                                                  
                        
                             

                        

                                
                                                  

                                
         
 
                           
                                    
         
                   
                      
                        

                                     
                        


                          
                        



                                          
                        





                                                              
                      


                                                                             


                               
                      














                                                                         

                                       





                             
       




                                                                     







                                   


                        
 
                                        
                                         
                        







































                                                                     
 

                                                     
                        
                             
 
                               
                   
                   


                   
 
                                                              
                          
            


                            
                                                    
                                              


                                                      
                 
                      
                                                      

                      
                                                      
                 
                      
                                                      

                        






                                                            







                                                                        
 







                                                                     






                                               











                                                   


                                                                       



                    





                                                              

                                            


                                          









                                               
                        







                                                                     


                            
 




                                   
 



                                    
                                     
                   


                                            
                         
                     
                   
                         




                                                                      
 






                                             
                     

                 
             
                                 
                                            
 




                                                       
                            
                    




                                                                  

                                



                                                      

                                       














                                          
                    
            
                                        
/* At entry, the processor is in 16 bit real mode and the code is being
 * executed from an address it was not linked to. Code must be pic and
 * 32 bit sensitive until things are fixed up.
 *
 * Also be very careful as the stack is at the rear end of the interrupt
 * table so using a noticeable amount of stack space is a no-no.
 */

#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
#define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
#define PNP_GET_BBS_VERSION 0x60

	.text
	.code16
	.arch i386
	.section ".prefix", "ax", @progbits
	
	.org	0x00
romheader:
	.word	0xAA55			/* BIOS extension signature */
romheader_size:	.byte _load_size_sect	/* Size in 512-byte blocks */
	jmp	init			/* Initialisation vector */
checksum:
	.byte	0
	.org	0x16
	.word	undiheader
	.org	0x18
	.word	pciheader
	.org	0x1a
	.word	pnpheader
	.size romheader, . - romheader
	
	.section ".zinfo.fixup", "a"	/* Compressor fixup information */
	.ascii	"SUBB"
	.long	romheader_size
	.long	512
	.long	0
	.previous

pciheader:
	.ascii	"PCIR"			/* Signature */
	.word	pci_vendor_id		/* Vendor identification */ 
	.word	pci_device_id		/* Device identification */
	.word	0x0000			/* Device list pointer */
	.word	pciheader_len		/* PCI data structure length */
	.byte	0x03			/* PCI data structure revision */
	.byte	0x02, 0x00, 0x00	/* Class code */
pciheader_image_length:
	.word	_load_size_sect		/* Image length */
	.word	0x0001			/* Revision level */
	.byte	0x00			/* Code type */
	.byte	0x80			/* Last image indicator */
pciheader_runtime_length:
	.word	_load_size_sect		/* Maximum run-time image length */
	.word	0x0000			/* Configuration utility code header */
	.word	0x0000			/* DMTF CLP entry point */
	.equ pciheader_len, . - pciheader
	.size pciheader, . - pciheader
	
	.section ".zinfo.fixup", "a"	/* Compressor fixup information */
	.ascii	"SUBW"
	.long	pciheader_image_length
	.long	512
	.long	0
	.ascii	"SUBW"
	.long	pciheader_runtime_length
	.long	512
	.long	0
	.previous

pnpheader:
	.ascii	"$PnP"			/* Signature */
	.byte	0x01			/* Structure revision */
	.byte	( pnpheader_len	/ 16 )	/* Length (in 16 byte increments) */
	.word	0x0000			/* Offset of next header */
	.byte	0x00			/* Reserved */
	.byte	0x00			/* Checksum */
	.long	0x00000000		/* Device identifier */
	.word	mfgstr			/* Manufacturer string */
	.word	prodstr			/* Product name */
	.byte	0x02			/* Device base type code */
	.byte	0x00			/* Device sub-type code */
	.byte	0x00			/* Device interface type code */
	.byte	0x54			/* Device indicator */
	.word	0x0000			/* Boot connection vector */
	.word	0x0000			/* Disconnect vector */
	.word	bev_entry		/* Boot execution vector */
	.word	0x0000			/* Reserved */
	.word	0x0000			/* Static resource information vector*/
	.equ pnpheader_len, . - pnpheader
	.size pnpheader, . - pnpheader

/* Manufacturer string */
mfgstr:
	.asciz	"http://etherboot.org"
	.size mfgstr, . - mfgstr

/* Product string
 *
 * Defaults to "gPXE".  If the ROM image is writable at initialisation
 * time, it will be filled in to include the PCI bus:dev.fn number of
 * the card as well.
 */
prodstr:
	.ascii	"gPXE"
prodstr_separator:
	.byte	0
	.ascii	"(PCI "
prodstr_pci_id:
	.asciz	"xx:xx.x)"		/* Filled in by init code */
	.size prodstr, . - prodstr
	
undiheader:
	.ascii	"UNDI"			/* Signature */
	.byte	undiheader_len		/* Length of structure */
	.byte	0			/* Checksum */
	.byte	0			/* Structure revision */
	.byte	0,1,2			/* PXE version: 2.1.0 */
	.word	undiloader		/* Offset to loader routine */
	.word	_data16_size		/* Stack segment size */
	.word	_data16_size		/* Data segment size */
	.word	_text16_size		/* Code segment size */
	.equ undiheader_len, . - undiheader
	.size undiheader, . - undiheader

/* Initialisation (called once during POST)
 *
 * Determine whether or not this is a PnP system via a signature
 * check.  If it is PnP, return to the PnP BIOS indicating that we are
 * a boot-capable device; the BIOS will call our boot execution vector
 * if it wants to boot us.  If it is not PnP, hook INT 19.
 */
init:
	/* Preserve registers, clear direction flag, set %ds=%cs */
	pushaw
	pushw	%ds
	pushw	%es
	pushw	%fs
	pushw	%gs
	cld
	pushw	%cs
	popw	%ds
	pushw	$0x40
	popw	%fs

	/* Shuffle some registers around.  We need %di available for
	 * the print_xxx functions, and in a register that's
	 * addressable from %es, so shuffle as follows:
	 *
	 *    %di (pointer to PnP structure) => %bx
	 *    %bx (runtime segment address, for PCI 3.0) => %gs
	 */
	movw	%bx, %gs
	movw	%di, %bx

	/* Print message as early as possible */
	movw	$init_message, %si
	xorw	%di, %di
	call	print_message
	call	print_pci_busdevfn

	/* Fill in product name string, if possible */
	movw	$prodstr_pci_id, %di
	call	print_pci_busdevfn
	movb	$' ', prodstr_separator

	/* Print segment address */
	movb	$' ', %al
	xorw	%di, %di
	call	print_character
	movw	%cs, %ax
	call	print_hex_word

	/* Check for PCI BIOS version */
	pushl	%ebx
	pushl	%edx
	stc
	movw	$0xb101, %ax
	int	$0x1a
	jc	1f
	cmpl	$PCI_SIGNATURE, %edx
	jne	1f
	testb	%ah, %ah
	jnz	1f
	movw	$init_message_pci, %si
	xorw	%di, %di
	call	print_message
	movb	%bh, %al
	call	print_hex_nibble
	movb	$'.', %al
	call	print_character
	movb	%bl, %al
	call	print_hex_byte
	cmpb	$3, %bh
	jae	2f
1:	/* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
	pushw	%cs
	popw	%gs
2:	popl	%edx
	popl	%ebx

	/* Check for PnP BIOS */
	testw	$0x0f, %bx	/* PnP signature must be aligned - bochs    */
	jnz	hook_int19	/* uses unalignment to indicate 'fake' PnP. */
	cmpl	$PNP_SIGNATURE, %es:0(%bx)
	jne	hook_int19
	/* Is PnP: print PnP message */
	movw	$init_message_pnp, %si
	xorw	%di, %di
	call	print_message

	/* Check for BBS */
	pushw	%es:0x1b(%bx)	/* Real-mode data segment */
	pushw	%ds		/* &(bbs_version) */
	pushw	$bbs_version
	pushw	$PNP_GET_BBS_VERSION
	lcall	*%es:0xd(%bx)
	addw	$8, %sp
	testw	%ax, %ax
	jne	hook_int19
	movw	$init_message_bbs, %si
	xorw	%di, %di
	call	print_message
	jmp	hook_bbs
	/* Not BBS-compliant - must hook INT 19 */
hook_int19:
	movw	$init_message_int19, %si
	xorw	%di, %di
	call	print_message
	xorw	%ax, %ax
	movw	%ax, %es
	pushl	%es:( 0x19 * 4 )
	popl	orig_int19
	pushw	%gs /* %gs contains runtime %cs */
	pushw	$int19_entry
	popl	%es:( 0x19 * 4 )
hook_bbs:

	/* Check for PMM */
	movw	$( 0xe000 - 1 ), %bx
pmm_scan:
	incw	%bx
	jz	no_pmm
	movw	%bx, %es
	cmpl	$PMM_SIGNATURE, %es:0
	jne	pmm_scan
	xorw	%dx, %dx
	xorw	%si, %si
	movzbw	%es:5, %cx
1:	es lodsb
	addb	%al, %dl
	loop	1b
	jnz	pmm_scan
	/* PMM found: print PMM message */
	movw	$init_message_pmm, %si
	xorw	%di, %di
	call	print_message
	/* Try to allocate 2MB block via PMM */
	pushw	$0x0006		/* Aligned, extended memory */
	pushl	$0xffffffff	/* No handle */
	pushl	$( 0x00200000 / 16 ) /* 2MB in paragraphs */
	pushw	$0x0000		/* pmmAllocate */
	lcall	*%es:7
	addw	$12, %sp
	testw	%dx, %dx	/* %ax==0 even on success, since align=2MB */
	jnz	gotpmm
	movb	$'-', %al
	xorw	%di, %di
	call	print_character
	jmp	no_pmm
gotpmm:	/* PMM allocation succeeded: copy ROM to PMM block */
	pushal			/* PMM presence implies 1kB stack */
	movw	%ax, %es	/* %ax=0 already - see above */
	pushw	%dx
	pushw	%ax
	popl	%edi
	movl	%edi, image_source
	xorl	%esi, %esi
	movzbl	romheader_size, %ecx
	shll	$9, %ecx
	addr32 rep movsb	/* PMM presence implies flat real mode */
	movl	%edi, decompress_to
	/* Shrink ROM and update checksum */
	xorw	%bx, %bx
	xorw	%si, %si
	movw	$_prefix_size_sect, %cx
	movb	%cl, romheader_size
	shlw	$9, %cx
1:	lodsb
	addb	%al, %bl
	loop	1b
	subb	%bl, checksum
	popal
no_pmm:

	/* Copy self to option ROM space.  Required for PCI3.0, which
	 * loads us to a temporary location in low memory.  Will be a
	 * no-op for lower PCI versions.
	 */
	movb	$' ', %al
	xorw	%di, %di
	call	print_character
	movw	%gs, %ax
	call	print_hex_word
	movzbw	romheader_size, %cx
	shlw	$9, %cx
	movw	%ax, %es
	xorw	%si, %si
	xorw	%di, %di
	cs rep	movsb

	/* Prompt for POST-time shell */
	movw	$init_message_prompt, %si
	xorw	%di, %di
	call	print_message
	/* Empty the keyboard buffer before waiting for input */
empty_keyboard_buffer:
	movb	$0x01, %ah
	int	$0x16
	jz	1f
	xorw	%ax, %ax
	int	$0x16
	jmp	empty_keyboard_buffer
1:	/* Wait for up to 3s for a key press */
	movw	$(18 * 3), %cx	/* Approx 3s worth of timer ticks */
wait_for_key:
	decw	%cx
	jz	no_key_pressed
	/* Wait for timer tick to be updated */
	movl	%fs:(0x6c), %eax
1:	pushf
	sti
	hlt
	popf
	cmpl	%fs:(0x6c), %eax
	je	1b
	/* Check to see if a key was pressed */
	movb	$0x01, %ah
	int	$0x16
	jz	wait_for_key
	/* Check to see if key was Ctrl-B */
	cmpb	$0x02, %al
	je	1f
	/* Key was not Ctrl-B: remove from buffer and stop waiting */
	xorw	%ax, %ax
	int	$0x16
	jmp	no_key_pressed
1:	/* Key was Ctrl-B: leave in keyboard buffer and invoke gPXE.
	 * The keypress will be picked up by the initial shell
	 * prompt, and we will drop into a shell.
	 */
	pushw	%cs
	call	exec
no_key_pressed:

	/* Print blank lines to terminate messages */
	movw	$init_message_end, %si
	xorw	%di, %di
	call	print_message

	/* Restore registers */
	popw	%gs
	popw	%fs
	popw	%es
	popw	%ds
	popaw

	/* Indicate boot capability to PnP BIOS, if present */
	movw	$0x20, %ax
	lret
	.size init, . - init

init_message:
	.asciz	"gPXE (http://etherboot.org) - PCI "
	.size	init_message, . - init_message
init_message_pci:
	.asciz	" PCI"
	.size	init_message_pci, . - init_message_pci
init_message_pnp:
	.asciz	" PnP"
	.size	init_message_pnp, . - init_message_pnp
init_message_bbs:
	.asciz	" BBS"
	.size	init_message_bbs, . - init_message_bbs
init_message_pmm:
	.asciz	" PMM"
	.size	init_message_pmm, . - init_message_pmm
init_message_int19:
	.asciz	" INT19"
	.size	init_message_int19, . - init_message_int19
init_message_prompt:
	.asciz	"\nPress Ctrl-B to configure gPXE..."
	.size	init_message_prompt, . - init_message_prompt
init_message_end:
	.asciz	"\n\n\n"
	.size	init_message_end, . - init_message_end

/* ROM image location
 *
 * May be either within option ROM space, or within PMM-allocated block.
 */
image_source:
	.long	0
	.size	image_source, . - image_source

/* Temporary decompression area
 *
 * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
 */
decompress_to:
	.long	HIGHMEM_LOADPOINT
	.size	decompress_to, . - decompress_to

/* BBS version
 *
 * Filled in by BBS BIOS.  We ignore the value.
 */
bbs_version:
	.word	0

/* Boot Execution Vector entry point
 *
 * Called by the PnP BIOS when it wants to boot us.
 */
bev_entry:
	pushw	%cs
	call	exec
	lret
	.size	bev_entry, . - bev_entry

/* INT19 entry point
 *
 * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
 * attempt to return via the original INT 19 vector (if we were able to
 * store it).
 */
int19_entry:
	pushw	%cs
	call	exec
	movl	%cs:orig_int19, %eax
	testl	%eax, %eax
	je	1f
	/* Chain to original INT 19 vector */
	ljmp	*%cs:orig_int19
1:	/* No chained vector: issue INT 18 as a last resort */
	int	$0x18
	.size	int19_entry, . - int19_entry
orig_int19:
	.long	0
	.size	orig_int19, . - orig_int19

/* Execute as a boot device
 *
 */
exec:	/* Set %ds = %cs */
	pushw	%cs
	popw	%ds

	/* Print message as soon as possible */
	movw	$exec_message, %si
	xorw	%di, %di
	call	print_message

	/* Store magic word on BIOS stack and remember BIOS %ss:sp */
	pushl	$STACK_MAGIC
	movw	%ss, %dx
	movw	%sp, %bp

	/* Obtain a reasonably-sized temporary stack */
	xorw	%ax, %ax
	movw	%ax, %ss
	movw	$0x7c00, %sp

	/* Install gPXE */
	movl	image_source, %esi
	movl	decompress_to, %edi
	call	alloc_basemem
	call	install_prealloc

	/* Set up real-mode stack */
	movw	%bx, %ss
	movw	$_estack16, %sp

	/* Jump to .text16 segment */
	pushw	%ax
	pushw	$1f
	lret
	.section ".text16", "awx", @progbits
1:	/* Call main() */
	pushl	$main
	pushw	%cs
	call	prot_call
	/* No need to clean up stack; we are about to reload %ss:sp */
	
	/* Restore BIOS stack */
	movw	%dx, %ss
	movw	%bp, %sp

	/* Check magic word on BIOS stack */
	popl	%eax
	cmpl	$STACK_MAGIC, %eax
	jne	1f
	/* BIOS stack OK: return to caller */
	lret
1:	/* BIOS stack corrupt: use INT 18 */
	int	$0x18
	.previous

exec_message:
	.asciz	"Entering gPXE\n"
	.size exec_message, . - exec_message

/* UNDI loader
 *
 * Called by an external program to load our PXE stack.
 */
undiloader:
	/* Save registers */
	pushl	%esi
	pushl	%edi
	pushw	%es
	pushw	%bx
	/* UNDI loader parameter structure address into %es:%di */
	movw	%sp, %bx
	movw	%ss:16(%bx), %di
	movw	%ss:18(%bx), %es
	/* Install to specified real-mode addresses */
	pushw	%di
	movw	%es:12(%di), %bx
	movw	%es:14(%di), %ax
	movl	%cs:image_source, %esi
	movl	%cs:decompress_to, %edi
	call	install_prealloc
	popw	%di
	/* Call UNDI loader C code */
	pushl	$pxe_loader_call
	pushw	%cs
	pushw	$1f
	pushw	%ax
	pushw	$prot_call
	lret
1:	popw	%bx	/* discard */
	popw	%bx	/* discard */
	/* Restore registers and return */
	popw	%bx
	popw	%es
	popl	%edi
	popl	%esi
	lret
	.size undiloader, . - undiloader