Added (not yet tested) PXE API entry point and support functions.
authorMichael Brown <mcb30@etherboot.org>
Tue, 8 Aug 2006 20:43:33 +0000 (20:43 +0000)
committerMichael Brown <mcb30@etherboot.org>
Tue, 8 Aug 2006 20:43:33 +0000 (20:43 +0000)
src/arch/i386/interface/pxe/pxe_call.c
src/arch/i386/interface/pxe/pxe_entry.S [new file with mode: 0644]

index 4d567bf..0d29699 100644 (file)
@@ -18,6 +18,7 @@
 
 #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.
@@ -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;
+}
diff --git a/src/arch/i386/interface/pxe/pxe_entry.S b/src/arch/i386/interface/pxe/pxe_entry.S
new file mode 100644 (file)
index 0000000..20ca423
--- /dev/null
@@ -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