iPXE
Defines | Functions | Variables
pxe_call.c File Reference

PXE API entry point. More...

#include <ipxe/uaccess.h>
#include <ipxe/init.h>
#include <ipxe/profile.h>
#include <ipxe/netdevice.h>
#include <rmsetjmp.h>
#include <registers.h>
#include <biosint.h>
#include <pxe.h>
#include <pxe_call.h>

Go to the source code of this file.

Defines

#define EINFO_EPXENBP
#define EPXENBP(status)   EPLATFORM ( EINFO_EPXENBP, status )
#define pxe_int_1a_vector   __use_text16 ( pxe_int_1a_vector )
#define _text16_memsz   ( ( size_t ) _text16_memsz )
#define _data16_memsz   ( ( size_t ) _data16_memsz )

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
struct segoff __text16 (pxe_int_1a_vector)
 Vector for chaining INT 1A.
void pxe_int_1a (void)
 INT 1A handler.
static PXENV_EXIT_t pxenv_unknown (struct s_PXENV_UNKNOWN *pxenv_unknown)
 Handle an unknown PXE API call.
static struct pxe_api_callfind_pxe_api_call (uint16_t opcode)
 Locate PXE API call.
static struct profilerpxe_api_profiler (unsigned int opcode)
 Determine applicable profiler (for debugging)
__asmcall void pxe_api_call (struct i386_all_regs *ix86)
 Dispatch PXE API call.
int pxe_api_call_weak (struct i386_all_regs *ix86)
 Dispatch weak PXE API call with PXE stack available.
__asmcall void pxe_loader_call (struct i386_all_regs *ix86)
 Dispatch PXE loader call.
static uint8_t pxe_checksum (void *data, size_t size)
 Calculate byte checksum as used by PXE.
static void pxe_init_structures (void)
 Initialise !PXE and PXENV+ structures.
struct init_fn pxe_init_fn __init_fn (INIT_NORMAL)
 PXE structure initialiser.
void pxe_activate (struct net_device *netdev)
 Activate PXE stack.
int pxe_deactivate (void)
 Deactivate PXE stack.
int pxe_start_nbp (void)
 Start PXE NBP at 0000:7c00.
static int pxe_notify (struct net_device *netdev)
 Notify BIOS of existence of network device.
 REQUIRING_SYMBOL (pxe_api_call)
 REQUIRE_OBJECT (pxe_preboot)
 REQUIRE_OBJECT (pxe_undi)
 REQUIRE_OBJECT (pxe_udp)
 REQUIRE_OBJECT (pxe_tftp)
 REQUIRE_OBJECT (pxe_file)

Variables

static int int_1a_hooked = 0
 INT 1A hooked flag.
char _text16_memsz []
 Real-mode code segment size.
char _data16_memsz []
 Real-mode data segment size.
static struct profiler
pxe_api_tx_profiler 
__profiler
 PXENV_UNDI_TRANSMIT API call profiler.
struct pxe_api_call
pxenv_unknown_api 
__pxe_api_call
 Unknown PXE API call list.
rmjmp_buf pxe_restart_nbp
 Jump buffer for PXENV_RESTART_TFTP.
struct net_driver pxe_driver __net_driver
 PXE BIOS notification driver.

Detailed Description

PXE API entry point.

Definition in file pxe_call.c.


Define Documentation

#define EINFO_EPXENBP
Value:
__einfo_uniqify ( EINFO_EPLATFORM, 0x01,                        \
                          "External PXE NBP error" )

Definition at line 42 of file pxe_call.c.

#define EPXENBP (   status)    EPLATFORM ( EINFO_EPXENBP, status )

Definition at line 45 of file pxe_call.c.

Referenced by pxe_start_nbp().

Definition at line 49 of file pxe_call.c.

Referenced by pxe_activate(), and pxe_deactivate().

#define _text16_memsz   ( ( size_t ) _text16_memsz )

Definition at line 59 of file pxe_call.c.

#define _data16_memsz   ( ( size_t ) _data16_memsz )

Definition at line 63 of file pxe_call.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
struct segoff __text16 ( pxe_int_1a_vector  ) [read]

Vector for chaining INT 1A.

void pxe_int_1a ( void  )

INT 1A handler.

Referenced by pxe_activate(), and pxe_deactivate().

static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN pxenv_unknown) [static]

Handle an unknown PXE API call.

Parameters:
pxenv_unknownPointer to a struct s_PXENV_UNKNOWN
Return values:
PXENV_EXIT_FAILUREAlways
Exceptions:
PXENV_STATUS_UNSUPPORTEDAlways

Definition at line 92 of file pxe_call.c.

References PXENV_EXIT_FAILURE, PXENV_STATUS_UNSUPPORTED, and s_PXENV_UNKNOWN::Status.

                                                                            {
        pxenv_unknown->Status = PXENV_STATUS_UNSUPPORTED;
        return PXENV_EXIT_FAILURE;
}
static struct pxe_api_call* find_pxe_api_call ( uint16_t  opcode) [static, read]

Locate PXE API call.

Parameters:
opcodeOpcode
Return values:
callPXE API call, or NULL

Definition at line 107 of file pxe_call.c.

References for_each_table_entry, NULL, pxe_api_call::opcode, and PXE_API_CALLS.

Referenced by pxe_api_call().

                                                                   {
        struct pxe_api_call *call;

        for_each_table_entry ( call, PXE_API_CALLS ) {
                if ( call->opcode == opcode )
                        return call;
        }
        return NULL;
}
static struct profiler* pxe_api_profiler ( unsigned int  opcode) [static, read]

Determine applicable profiler (for debugging)

Parameters:
opcodePXE opcode
Return values:
profilerProfiler

Definition at line 123 of file pxe_call.c.

References PXENV_UNDI_ISR, PXENV_UNDI_TRANSMIT, and PXENV_UNKNOWN.

Referenced by pxe_api_call().

                                                                  {

        /* Determine applicable profiler */
        switch ( opcode ) {
        case PXENV_UNDI_TRANSMIT:
                return &pxe_api_tx_profiler;
        case PXENV_UNDI_ISR:
                return &pxe_api_isr_profiler;
        case PXENV_UNKNOWN:
                return &pxe_api_unknown_profiler;
        default:
                return &pxe_api_misc_profiler;
        }
}
__asmcall void pxe_api_call ( struct i386_all_regs ix86)

Dispatch PXE API call.

Parameters:
bxPXE opcode
es:diAddress of PXE parameter block
Return values:
axPXE exit code

Definition at line 145 of file pxe_call.c.

References i386_regs::ax, i386_regs::bx, copy_from_user(), copy_to_user(), DBGC, i386_regs::di, pxe_api_call::entry, i386_seg_regs::es, find_pxe_api_call(), opcode, pxe_api_call::params_len, profile_start(), profile_stop(), pxe_api_profiler(), pxe_netdev, PXENV_STATUS_FAILURE, real_to_user(), i386_all_regs::regs, ret, i386_all_regs::segs, and u_PXENV_ANY::Status.

Referenced by pxe_api_call_weak().

                                                           {
        uint16_t opcode = ix86->regs.bx;
        userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di );
        struct profiler *profiler = pxe_api_profiler ( opcode );
        struct pxe_api_call *call;
        union u_PXENV_ANY params;
        PXENV_EXIT_t ret;

        /* Start profiling */
        profile_start ( profiler );

        /* Locate API call */
        call = find_pxe_api_call ( opcode );
        if ( ! call ) {
                DBGC ( &pxe_netdev, "PXENV_UNKNOWN_%04x\n", opcode );
                call = &pxenv_unknown_api;
        }

        /* Copy parameter block from caller */
        copy_from_user ( &params, uparams, 0, call->params_len );

        /* Set default status in case child routine fails to do so */
        params.Status = PXENV_STATUS_FAILURE;

        /* Hand off to relevant API routine */
        ret = call->entry ( &params );

        /* Copy modified parameter block back to caller and return */
        copy_to_user ( uparams, 0, &params, call->params_len );
        ix86->regs.ax = ret;

        /* Stop profiling, if applicable */
        profile_stop ( profiler );
}
int pxe_api_call_weak ( struct i386_all_regs ix86)

Dispatch weak PXE API call with PXE stack available.

Parameters:
ix86Registers for PXE call
Return values:
presentZero (PXE stack present)

Definition at line 186 of file pxe_call.c.

References pxe_api_call().

Referenced by int22().

                                                     {
        pxe_api_call ( ix86 );
        return 0;
}
__asmcall void pxe_loader_call ( struct i386_all_regs ix86)

Dispatch PXE loader call.

Parameters:
es:diAddress of PXE parameter block
Return values:
axPXE exit code

Definition at line 197 of file pxe_call.c.

References i386_regs::ax, copy_from_user(), copy_to_user(), i386_regs::di, i386_seg_regs::ds, i386_seg_regs::es, ppxe, PXENV_STATUS_FAILURE, real_to_user(), i386_all_regs::regs, ret, i386_all_regs::segs, s_UNDI_LOADER::Status, and undi_loader.

                                                              {
        userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di );
        struct s_UNDI_LOADER params;
        PXENV_EXIT_t ret;

        /* Copy parameter block from caller */
        copy_from_user ( &params, uparams, 0, sizeof ( params ) );

        /* Fill in ROM segment address */
        ppxe.UNDIROMID.segment = ix86->segs.ds;

        /* Set default status in case child routine fails to do so */
        params.Status = PXENV_STATUS_FAILURE;

        /* Call UNDI loader */
        ret = undi_loader ( &params );

        /* Copy modified parameter block back to caller and return */
        copy_to_user ( uparams, 0, &params, sizeof ( params ) );
        ix86->regs.ax = ret;
}
static uint8_t pxe_checksum ( void *  data,
size_t  size 
) [static]

Calculate byte checksum as used by PXE.

Parameters:
dataData
sizeLength of data
Return values:
sumChecksum

Definition at line 226 of file pxe_call.c.

References bytes, and data.

Referenced by pxe_init_structures().

                                                        {
        uint8_t *bytes = data;
        uint8_t sum = 0;

        while ( size-- ) {
                sum += *bytes++;
        }
        return sum;
}
static void pxe_init_structures ( void  ) [static]

Initialise !PXE and PXENV+ structures.

Definition at line 240 of file pxe_call.c.

References ppxe, pxe_checksum(), pxenv, rm_cs, and rm_ds.

                                         {
        uint32_t rm_cs_phys = ( rm_cs << 4 );
        uint32_t rm_ds_phys = ( rm_ds << 4 );

        /* Fill in missing segment fields */
        ppxe.EntryPointSP.segment = rm_cs;
        ppxe.EntryPointESP.segment = rm_cs;
        ppxe.Stack.segment_address = rm_ds;
        ppxe.Stack.Physical_address = rm_ds_phys;
        ppxe.UNDIData.segment_address = rm_ds;
        ppxe.UNDIData.Physical_address = rm_ds_phys;
        ppxe.UNDICode.segment_address = rm_cs;
        ppxe.UNDICode.Physical_address = rm_cs_phys;
        ppxe.UNDICodeWrite.segment_address = rm_cs;
        ppxe.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 */
        ppxe.StructCksum -= pxe_checksum ( &ppxe, sizeof ( ppxe ) );
        pxenv.Checksum -= pxe_checksum ( &pxenv, sizeof ( pxenv ) );
}
struct init_fn pxe_init_fn __init_fn ( INIT_NORMAL  ) [read]

PXE structure initialiser.

void pxe_activate ( struct net_device netdev)

Activate PXE stack.

Parameters:
netdevNet device to use as PXE net device

Definition at line 276 of file pxe_call.c.

References __asm__(), __from_text16, devices_get(), hook_bios_interrupt(), int_1a_hooked, pxe_int_1a(), pxe_int_1a_vector, pxe_set_netdev(), pxenv, and REAL_CODE.

Referenced by pxe_exec(), pxe_notify(), pxenv_start_undi(), and startpxe_payload().

                                                {
        uint32_t discard_a;
        uint32_t discard_b;
        uint32_t discard_d;

        /* Ensure INT 1A is hooked */
        if ( ! int_1a_hooked ) {
                hook_bios_interrupt ( 0x1a, ( intptr_t ) pxe_int_1a,
                                      &pxe_int_1a_vector );
                devices_get();
                int_1a_hooked = 1;
        }

        /* Set PXE network device */
        pxe_set_netdev ( netdev );

        /* Notify BIOS of installation */
        __asm__ __volatile__ ( REAL_CODE ( "pushw %%cs\n\t"
                                           "popw %%es\n\t"
                                           "int $0x1a\n\t" )
                               : "=a" ( discard_a ), "=b" ( discard_b ),
                                 "=d" ( discard_d )
                               : "0" ( 0x564e ),
                                 "1" ( __from_text16 ( &pxenv ) ) );
}
int pxe_deactivate ( void  )

Deactivate PXE stack.

Return values:
rcReturn status code

Definition at line 307 of file pxe_call.c.

References DBGC, devices_put(), int_1a_hooked, NULL, pxe_int_1a(), pxe_int_1a_vector, pxe_netdev, pxe_set_netdev(), rc, strerror(), and unhook_bios_interrupt().

Referenced by pxe_exec(), pxe_notify(), pxenv_stop_undi(), and stoppxe_exec().

                            {
        int rc;

        /* Clear PXE network device */
        pxe_set_netdev ( NULL );

        /* Ensure INT 1A is unhooked, if possible */
        if ( int_1a_hooked ) {
                if ( ( rc = unhook_bios_interrupt ( 0x1a,
                                                    ( intptr_t ) pxe_int_1a,
                                                    &pxe_int_1a_vector ))!= 0){
                        DBGC ( &pxe_netdev, "PXE could not unhook INT 1A: %s\n",
                               strerror ( rc ) );
                        return rc;
                }
                devices_put();
                int_1a_hooked = 0;
        }

        return 0;
}
int pxe_start_nbp ( void  )

Start PXE NBP at 0000:7c00.

Return values:
rcReturn status code

Definition at line 337 of file pxe_call.c.

References __asm__(), __from_text16, _data16_memsz, _text16_memsz, DBGC, EPXENBP, jmp, net_device::name, ppxe, pxe_netdev, pxenv, REAL_CODE, rm_cs, rm_ds, rmsetjmp, status, and virt_to_phys().

Referenced by pxe_exec().

                           {
        int jmp;
        int discard_b, discard_c, discard_d, discard_D;
        uint16_t status;

        DBGC ( &pxe_netdev, "PXE NBP starting with netdev %s, code %04x:%04zx, "
               "data %04x:%04zx\n", ( pxe_netdev ? pxe_netdev->name : "<none>"),
               rm_cs, _text16_memsz, rm_ds, _data16_memsz );

        /* Allow restarting NBP via PXENV_RESTART_TFTP */
        jmp = rmsetjmp ( pxe_restart_nbp );
        if ( jmp )
                DBGC ( &pxe_netdev, "PXE NBP restarting (%x)\n", jmp );

        /* Far call to PXE NBP */
        __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
                                           "movw %%cx, %%es\n\t"
                                           "pushw %%es\n\t"
                                           "pushw %%di\n\t"
                                           "sti\n\t"
                                           "lcall $0, $0x7c00\n\t"
                                           "popl %%ebp\n\t" /* discard */
                                           "popl %%ebp\n\t" /* gcc bug */ )
                               : "=a" ( status ), "=b" ( discard_b ),
                                 "=c" ( discard_c ), "=d" ( discard_d ),
                                 "=D" ( discard_D )
                               : "a" ( 0 ), "b" ( __from_text16 ( &pxenv ) ),
                                 "c" ( rm_cs ),
                                 "d" ( virt_to_phys ( &pxenv ) ),
                                 "D" ( __from_text16 ( &ppxe ) )
                               : "esi", "memory" );
        if ( status )
                return -EPXENBP ( status );

        return 0;
}
static int pxe_notify ( struct net_device netdev) [static]

Notify BIOS of existence of network device.

Parameters:
netdevNetwork device
Return values:
rcReturn status code

Definition at line 380 of file pxe_call.c.

References pxe_activate(), pxe_deactivate(), and pxe_netdev.

                                                    {

        /* Do nothing if we already have a network device */
        if ( pxe_netdev )
                return 0;

        /* Activate (and deactivate) PXE stack to notify BIOS */
        pxe_activate ( netdev );
        pxe_deactivate();

        return 0;
}
REQUIRE_OBJECT ( pxe_preboot  )
REQUIRE_OBJECT ( pxe_undi  )
REQUIRE_OBJECT ( pxe_file  )

Variable Documentation

int int_1a_hooked = 0 [static]

INT 1A hooked flag.

Definition at line 55 of file pxe_call.c.

Referenced by pxe_activate(), and pxe_deactivate().

char _text16_memsz[]

Real-mode code segment size.

char _data16_memsz[]

Real-mode data segment size.

struct profiler pxe_api_misc_profiler __profiler [static]
Initial value:
        { .name = "pxeapi.tx" }

PXENV_UNDI_TRANSMIT API call profiler.

Miscellaneous PXE API call profiler.

PXE unknown API call profiler.

PXENV_UNDI_ISR API call profiler.

This profiler can be used to measure the overhead of a dummy PXE API call.

Definition at line 66 of file pxe_call.c.

struct pxe_api_call pxenv_unknown_api __pxe_api_call
Initial value:

Unknown PXE API call list.

Definition at line 98 of file pxe_call.c.

Jump buffer for PXENV_RESTART_TFTP.

PXENV_RESTART_TFTP jump buffer.

Definition at line 330 of file pxe_call.c.

Referenced by pxenv_restart_tftp().

struct net_driver pxe_driver __net_driver
Initial value:
 {
        .name = "PXE",
        .probe = pxe_notify,
}

PXE BIOS notification driver.

Definition at line 394 of file pxe_call.c.