#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.
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;
+}
--- /dev/null
+/*
+ * 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