From 9780fef360dc381ee6e4cd7e16f10990657eed83 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 5 Jan 2007 03:24:39 +0000 Subject: [PATCH] Partial implementation of UNDI loader caller. --- src/arch/i386/drivers/bus/pxedrv.c | 93 ++++++++++++++++++++++++++++-- src/arch/i386/include/bios.h | 1 + src/include/pxe.h | 2 +- src/include/pxe_api.h | 66 +++++---------------- 4 files changed, 107 insertions(+), 55 deletions(-) diff --git a/src/arch/i386/drivers/bus/pxedrv.c b/src/arch/i386/drivers/bus/pxedrv.c index 4e432574..3e663c75 100644 --- a/src/arch/i386/drivers/bus/pxedrv.c +++ b/src/arch/i386/drivers/bus/pxedrv.c @@ -21,6 +21,7 @@ #include #include #include +#include /** @file * @@ -62,14 +63,15 @@ static int pxedrv_parse_pxeromid ( struct pxe_driver *pxedrv, } /* Fill in PXE driver loader fields */ - pxedrv->loader.segment = pxedrv->rom_segment; - pxedrv->loader.offset = undiloader; + pxedrv->loader_entry.segment = pxedrv->rom_segment; + pxedrv->loader_entry.offset = undiloader; pxedrv->code_size = undi_rom_id.CodeSize; pxedrv->data_size = undi_rom_id.DataSize; DBGC ( pxedrv, "PXEDRV %p has UNDI loader at %04x:%04x " - "(code %04x data %04x)\n", pxedrv, pxedrv->loader.segment, - pxedrv->loader.offset, pxedrv->code_size, pxedrv->data_size ); + "(code %04x data %04x)\n", pxedrv, + pxedrv->loader_entry.segment, pxedrv->loader_entry.offset, + pxedrv->code_size, pxedrv->data_size ); return 0; } @@ -221,3 +223,86 @@ struct pxe_driver * pxedrv_find_pci_driver ( unsigned int vendor_id, vendor_id, device_id, rombase ); return NULL; } + +/** Parameter block for calling UNDI loader */ +static struct s_UNDI_LOADER __data16 ( undi_loader ); +#define undi_loader __use_data16 ( undi_loader ) + +/** UNDI loader entry point */ +static SEGOFF16_t __data16 ( undi_loader_entry ); +#define undi_loader_entry __use_data16 ( undi_loader_entry ) + +/** + * Call UNDI loader to create a pixie + * + * @v pxedrv PXE driver + * @v pxe PXE device to be created + * @v pci_busdevfn PCI bus:dev.fn (PCI devices only), or 0 + * @v isapnp_csn ISAPnP Card Select Number, or -1U + * @v isapnp_read_port ISAPnP read port, or -1U + * @ret rc Return status code + */ +static int pxedrv_load ( struct pxe_driver *pxedrv, struct pxe_device *pxe, + unsigned int pci_busdevfn, unsigned int isapnp_csn, + unsigned int isapnp_read_port ) { + int discard; + uint16_t exit; + uint16_t fbms; + unsigned int fbms_seg; + int rc; + + memset ( &undi_loader, 0, sizeof ( undi_loader ) ); + undi_loader.AX = pci_busdevfn; + undi_loader.BX = isapnp_csn; + undi_loader.DX = isapnp_read_port; + + /* Allocate base memory for PXE stack */ + get_real ( fbms, BDA_SEG, BDA_FBMS ); + fbms_seg = ( fbms << 6 ); + fbms_seg -= ( ( pxedrv->data_size + 0x0f ) >> 4 ); + undi_loader.UNDI_DS = fbms_seg; + fbms_seg -= ( ( pxedrv->code_size + 0x0f ) >> 4 ); + undi_loader.UNDI_CS = fbms_seg; + DBGC ( pxedrv, "PXEDRV %p loading to CS %04x and DS %04x\n", pxedrv, + undi_loader.UNDI_CS, undi_loader.UNDI_DS ); + + /* Call loader */ + undi_loader_entry = pxedrv->loader_entry; + __asm__ __volatile__ ( REAL_CODE ( "pushw %%ds\n\t" + "pushw %w0\n\t" + "lcall *%c3\n\t" + "addw $4, %%sp\n\t" ) + : "=a" ( exit ), "=r" ( discard ) + : "0" ( & __from_data16 ( undi_loader ) ), + "p" ( & __from_data16 ( undi_loader_entry ))); + if ( exit != PXENV_EXIT_SUCCESS ) { + rc = -undi_loader.Status; + if ( rc == 0 ) /* Paranoia */ + rc = -EIO; + DBGC ( pxedrv, "PXEDRV %p loader failed: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Update free base memory counter */ + fbms = ( fbms_seg >> 6 ); + put_real ( fbms, BDA_SEG, BDA_FBMS ); + + /* Record location of pixie in PXE device structure */ + pxe->pxenv = undi_loader.PXENVptr; + pxe->ppxe = undi_loader.PXEptr; + return 0; +} + +/** + * Call UNDI loader to create a pixie + * + * @v pxedrv PXE driver + * @v pxe PXE device to be created + * @v pci_busdevfn PCI bus:dev.fn + * @ret rc Return status code + */ +int pxedrv_load_pci ( struct pxe_driver *pxedrv, struct pxe_device *pxe, + unsigned int bus, unsigned int devfn ) { + return pxedrv_load ( pxedrv, pxe, ( ( bus << 8 ) | devfn ), -1U, -1U ); +} diff --git a/src/arch/i386/include/bios.h b/src/arch/i386/include/bios.h index 4b4b9d25..630a898b 100644 --- a/src/arch/i386/include/bios.h +++ b/src/arch/i386/include/bios.h @@ -2,6 +2,7 @@ #define BIOS_H #define BDA_SEG 0x0040 +#define BDA_FBMS 0x0013 #define BDA_NUM_DRIVES 0x0075 extern unsigned long currticks ( void ); diff --git a/src/include/pxe.h b/src/include/pxe.h index e85e7e27..003ebf12 100644 --- a/src/include/pxe.h +++ b/src/include/pxe.h @@ -155,7 +155,7 @@ struct pxe_driver { /** ROM segment address */ unsigned int rom_segment; /** UNDI loader entry point */ - SEGOFF16_t loader; + SEGOFF16_t loader_entry; /** Code segment size */ size_t code_size; /** Data segment size */ diff --git a/src/include/pxe_api.h b/src/include/pxe_api.h index 7256c57e..e6441325 100644 --- a/src/include/pxe_api.h +++ b/src/include/pxe_api.h @@ -1562,54 +1562,20 @@ extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ); * @{ */ -/** The UNDI ROM ID structure */ -struct s_UNDI_ROM_ID { - /** Signature - * - * Contains the bytes 'U', 'N', 'D', 'I'. - */ - UINT32_t Signature; - UINT8_t StructLength; /**< Length of this structure */ - /** Checksum - * - * The byte checksum of this structure (using the length in - * #StructLength) must be zero. - */ - UINT8_t StructCksum; - /** Revision of this structure - * - * For PXE version 2.1, this field must be zero. - */ - UINT8_t StructRev; - /** UNDI revision - * - * UNDI revision, least significant byte first. For UNDI - * version 2.1.0, this field will contain { 0x00, 0x01, 0x02 }. - */ - UINT8_t UNDIRev[3]; - /** UNDI loader routine entry point - * - * This is the entry point for calling undi_loader(). - */ - UINT16_t UNDILoader; - /** Minimum required stack segment size */ - UINT16_t StackSize; - /** Minimum required data segment size */ - UINT16_t DataSize; - /** Minimum required code segment size */ - UINT16_t CodeSize; -} PACKED; - -typedef struct s_UNDI_ROM_ID UNDI_ROM_ID_t; - /** Parameter block for undi_loader() */ struct s_UNDI_LOADER { - /** struct s_UNDI_LOADER starts with a struct s_PXENV_START_UNDI */ - union undi_loader_start_undi { - PXENV_STATUS_t Status; /**< PXE status code */ - /** Parameters to pass to pxenv_start_undi() */ - struct s_PXENV_START_UNDI start_undi; - } u; + /** PXE status code */ + PXENV_STATUS_t Status; + /** %ax register as for PXENV_START_UNDI */ + UINT16_t AX; + /** %bx register as for PXENV_START_UNDI */ + UINT16_t BX; + /** %dx register as for PXENV_START_UNDI */ + UINT16_t DX; + /** %di register as for PXENV_START_UNDI */ + OFF16_t DI; + /** %es register as for PXENV_START_UNDI */ + SEGSEL_t ES; /** UNDI data segment * * @note The PXE specification defines the type of this field @@ -1617,7 +1583,7 @@ struct s_UNDI_LOADER { * equivalent anyway; for other architectures #SEGSEL_t makes * more sense. */ - SEGSEL_t undi_ds; + SEGSEL_t UNDI_DS; /** UNDI code segment * * @note The PXE specification defines the type of this field @@ -1625,11 +1591,11 @@ struct s_UNDI_LOADER { * equivalent anyway; for other architectures #SEGSEL_t makes * more sense. */ - SEGSEL_t undi_cs; + SEGSEL_t UNDI_CS; /** Address of the !PXE structure (a struct s_PXE) */ - SEGOFF16_t pxe_ptr; + SEGOFF16_t PXEptr; /** Address of the PXENV+ structure (a struct s_PXENV) */ - SEGOFF16_t pxenv_ptr; + SEGOFF16_t PXENVptr; } PACKED; typedef struct s_UNDI_LOADER UNDI_LOADER_t;