Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Added (not yet tested) PXE API entry point and support functions.
  • Loading branch information
Michael Brown committed Aug 8, 2006
1 parent d12383f commit 18c112d
Show file tree
Hide file tree
Showing 2 changed files with 300 additions and 0 deletions.
108 changes: 108 additions & 0 deletions src/arch/i386/interface/pxe/pxe_call.c
Expand Up @@ -18,13 +18,29 @@

#include <gpxe/uaccess.h>
#include <registers.h>
#include <biosint.h>
#include <pxe.h>

/** @file
*
* PXE API entry point
*/

/** Vector for chaining INT 1A */
extern struct segoff __text16 ( pxe_int_1a_vector );
#define pxe_int_1a_vector __use_text16 ( pxe_int_1a_vector )

/** INT 1A handler */
extern void pxe_int_1a ( void );

/** !PXE structure */
extern struct s_PXE __text16 ( pxe );
#define pxe __use_text16 ( pxe )

/** PXENV+ structure */
extern struct s_PXENV __text16 ( pxenv );
#define pxenv __use_text16 ( pxenv )

/** A function pointer to hold any PXE API call
*
* Used by pxe_api_call() to avoid large swathes of duplicated code.
Expand Down Expand Up @@ -288,3 +304,95 @@ void pxe_api_call ( struct i386_all_regs *ix86 ) {
copy_to_user ( parameters, 0, &pxenv_any, param_len );
ix86->regs.ax = ret;
}

/**
* Hook INT 1A for PXE
*
*/
void pxe_hook_int ( void ) {
hook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a,
&pxe_int_1a_vector );
}

/**
* Unhook INT 1A for PXE
*
* @ret rc Return status code
*/
int pxe_unhook_int ( void ) {
return unhook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a,
&pxe_int_1a_vector );
}

/**
* Calculate byte checksum as used by PXE
*
* @v data Data
* @v size Length of data
* @ret sum Checksum
*/
static uint8_t pxe_checksum ( void *data, size_t size ) {
uint8_t *bytes = data;
uint8_t sum = 0;

while ( size-- ) {
sum += *bytes++;
}
return sum;
}

/**
* Initialise PXE stack
*
*/
void init_pxe ( void ) {
uint32_t rm_cs_phys = ( rm_cs << 4 );
uint32_t rm_ds_phys = ( rm_ds << 4 );

/* Fill in missing segment fields */
pxe.EntryPointSP.segment = rm_cs;
pxe.EntryPointESP.segment = rm_cs;
pxe.Stack.segment_address = rm_ds;
pxe.Stack.Physical_address = rm_ds_phys;
pxe.UNDIData.segment_address = rm_ds;
pxe.UNDIData.Physical_address = rm_ds_phys;
pxe.UNDICode.segment_address = rm_cs;
pxe.UNDICode.Physical_address = rm_cs_phys;
pxe.UNDICodeWrite.segment_address = rm_cs;
pxe.UNDICodeWrite.Physical_address = rm_cs_phys;
pxenv.RMEntry.segment = rm_cs;
pxenv.StackSeg = rm_ds;
pxenv.UNDIDataSeg = rm_ds;
pxenv.UNDICodeSeg = rm_cs;
pxenv.PXEPtr.segment = rm_cs;

/* Update checksums */
pxe.StructCksum -= pxe_checksum ( &pxe, sizeof ( pxe ) );
pxenv.Checksum -= pxe_checksum ( &pxenv, sizeof ( pxenv ) );
}

/**
* Boot via PXE NBP
*
* @ret rc Return status code
*/
int pxe_boot ( void ) {
int discard_b, discard_c;
uint16_t rc;

/* Ensure that PXE stack is ready to use */
init_pxe();
pxe_hook_int();

/* Far call to PXE NBP */
__asm__ __volatile__ ( REAL_CODE ( "pushw %%cx\n\t"
"pushw %%ax\n\t"
"movw %%cx, %%es\n\t"
"lcall $0, $0x7c00\n\t" )
: "=a" ( rc ), "=b" ( discard_b ),
"=c" ( discard_c )
: "a" ( &pxe ), "b" ( &pxenv ), "c" ( rm_cs )
: "edx", "esi", "edi", "ebp", "memory" );

return rc;
}
192 changes: 192 additions & 0 deletions src/arch/i386/interface/pxe/pxe_entry.S
@@ -0,0 +1,192 @@
/*
* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/

.arch i386
.section ".text16", "awx", @progbits
.section ".text16.data", "aw", @progbits
.section ".data16", "aw", @progbits

/****************************************************************************
* !PXE structure
****************************************************************************
*/
.section ".text16.data"
.globl pxe
pxe:
.ascii "!PXE" /* Signature */
.byte pxe_length /* StructLength */
.byte 0 /* StructCksum */
.byte 0 /* StructRev */
.byte 0 /* reserved_1 */
.word 0, 0 /* UNDIROMID */
.word 0, 0 /* BaseROMID */
.word pxe_entry_sp, 0 /* EntryPointSP */
.word pxe_entry_esp, 0 /* EntryPointESP */
.word -1, -1 /* StatusCallout */
.byte 0 /* reserved_2 */
.byte SegDescCnt /* SegDescCnt */
.word 0 /* FirstSelector */
pxe_segments:
.word 0, 0, 0, _data16_size /* Stack */
.word 0, 0, 0, _data16_size /* UNDIData */
.word 0, 0, 0, _text16_size /* UNDICode */
.word 0, 0, 0, _text16_size /* UNDICodeWrite */
.word 0, 0, 0, 0 /* BC_Data */
.word 0, 0, 0, 0 /* BC_Code */
.word 0, 0, 0, 0 /* BC_CodeWrite */
.equ SegDescCnt, ( ( . - pxe_segments ) / 8 )
.equ pxe_length, . - pxe
.size pxe, . - pxe

/****************************************************************************
* PXENV+ structure
****************************************************************************
*/
.section ".text16.data"
.globl pxenv
pxenv:
.ascii "PXENV+" /* Signature */
.word 0x0201 /* Version */
.byte pxenv_length /* Length */
.byte 0 /* Checksum */
.word pxenv_entry, 0 /* RMEntry */
.long 0 /* PMEntry */
.word 0 /* PMSelector */
.word 0 /* StackSeg */
.word _data16_size /* StackSize */
.word 0 /* BC_CodeSeg */
.word 0 /* BC_CodeSize */
.word 0 /* BC_DataSeg */
.word 0 /* BC_DataSize */
.word 0 /* UNDIDataSeg */
.word _data16_size /* UNDIDataSize */
.word 0 /* UNDICodeSeg */
.word _text16_size /* UNDICodeSize */
.word pxe, 0 /* PXEPtr */
.equ pxenv_length, . - pxenv
.size pxenv, . - pxenv

/****************************************************************************
* pxenv_entry (16-bit far call)
*
* PXE API call PXENV+ entry point
*
* Parameters:
* %es:di : Far pointer to PXE parameter structure
* %bx : PXE API call
* Returns:
* %ax : PXE exit status
* Corrupts:
* none
****************************************************************************
*/
.section ".text16"
.code16
pxenv_entry:
pushl $pxe_api_call
pushw %cs
call prot_call
addl $4, %esp
lret
.size pxenv_entry, . - pxenv_entry

/****************************************************************************
* pxe_entry
*
* PXE API call !PXE entry point
*
* Parameters:
* stack : Far pointer to PXE parameter structure
* stack : PXE API call
* Returns:
* %ax : PXE exit status
* Corrupts:
* none
****************************************************************************
*/
.section ".text16"
.code16
pxe_entry:
pxe_entry_sp:
/* Preserve original %esp */
pushl %esp
/* Zero high word of %esp to allow use of common code */
movzwl %sp, %esp
jmp pxe_entry_common
pxe_entry_esp:
/* Preserve %esp to match behaviour of pxe_entry_sp */
pushl %esp
pxe_entry_common:
/* Save PXENV+ API call registers */
pushw %es
pushw %di
pushw %bx
/* Load !PXE parameters from stack into PXENV+ registers */
movw 16(%esp), %bx
movw %bx, %es
movw 14(%esp), %di
movw 12(%esp), %bx
/* Make call as for PXENV+ */
pushw %cs
call pxenv_entry
/* Restore PXENV+ registers */
popw %bx
popw %di
popw %es
/* Restore original %esp and return */
popl %esp
lret
.size pxe_entry, . - pxe_entry

/****************************************************************************
* pxe_int_1a
*
* PXE INT 1A handler
*
* Parameters:
* %ax : 0x5650
* Returns:
* %ax : 0x564e
* %es:bx : Far pointer to the PXENV+ structure
* CF cleared
* Corrupts:
* none
****************************************************************************
*/
.section ".text16"
.code16
pxe_int_1a:
pushfw
cmpw $0x5650, %ax
jne 1f
/* INT 1A,5650 - PXE installation check */
pushw %cs
popw %es
movw $pxenv, %bx
movw $0x564e, %ax
popfw
clc
lret $2
1: /* INT 1A,other - pass through */
popfw
ljmp *%cs:pxe_int_1a_vector

.section ".text16.data"
.globl pxe_int_1a_vector
pxe_int_1a_vector: .long 0

0 comments on commit 18c112d

Please sign in to comment.