Implementing the OEMPlatformInit Function

Once you have initialized the CPU and core logic in the boot loader development process, you can focus on initializing board-level hardware by implementing the OEMPlatformInit function.

The purpose of OEMPlatformInit function is to initialize board-level hardware when necessary so that code added later can download over the Ethernet controller. This function is highly hardware or platform dependent.

The following list shows the tasks that the OEMPlatformInit function needs to perform:

  • Initialize the real-time clock (RTC) or any other timekeeping device used by the OEMEthGetSecs function. For this task, a second resolution is acceptable.

  • Initialize flash memory, or a flash memory controller in the case of NAND flash memory.

  • If the network device resides on a PCI bus, initialize the host PCI bridge, enumerate the buses to locate the network controller to be used for downloads, and only configure the PCI hardware required to enable the network controller to operate, that is, the network controller itself and any intermediate bridge logic.

    The PCI bus driver should configure the remainder of the PCI bus under the OS. For more information about the PCI bus driver, see PCI Device Support.

  • If the network device resides on a PCMCIA bus, initialize the PCMCIA bridge or controller.

  • Initialize the network controller to be used for downloading the image from the host machine. Microsoft provides a number of static libraries for various network controllers that can be used to initialize and communicate with the controller. If the hardware platform has a built-in network controller, that is, one soldered to the motherboard, then OEMPlatformInit can be simplified to assume that one controller will be used. If the hardware platform supports expansion buses, for example, PCMCIA or PCI, the implementation for OEMPlatformInit may need to allow for a variety of network controllers to be plugged in. Because the Ethernet controller libraries export a common interface, you can use function pointers to select among a number of controller libraries for the particular hardware not being used. You can use these function pointers throughout the boot loader in place of the actual network controller library call.

    The following code example shows how you can use function pointers:

    // Function pointers to the support library functions of the currently 
    // installed debug Ethernet controller.
    //
    PFN_EDBG_INIT             pfnEDbgInit;
    PFN_EDBG_INIT_DMABUFFER   pfnEDbgInitDMABuffer;
    PFN_EDBG_GET_FRAME        pfnEDbgGetFrame;
    PFN_EDBG_SEND_FRAME       pfnEDbgSendFrame;
    
    ...
        while(!bFoundCard) {
            // RNDIS has its own PCI scan routine.
            // 
            dwAddress =pBootArgs->dwEdbgBaseAddr;
            cIrq = pBootArgs->ucEdbgIRQ;
            cAdaptType=pBootArgs->ucEdbgAdapterType;
            if (!SelectPCINetCard(&dwAddress,&cIrq,&cAdaptType)) { // Cannot found a card match
                break;
            }
    
            // Set up EDBG driver callbacks based on Ethernet controller type.
            //
            bFoundCard=TRUE;
            switch (cAdaptType)
            {
            case EDBG_ADAPTER_NE2000:
                pfnEDbgInit           = NE2000Init;
                pfnEDbgInitDMABuffer  = NULL;
                pfnEDbgGetFrame       = NE2000GetFrame;       
                pfnEDbgSendFrame      = NE2000SendFrame;      
                break;
    
            case EDBG_ADAPTER_DP83815:
                pfnEDbgInit           = DP83815Init;
                pfnEDbgInitDMABuffer  = DP83815InitDMABuffer;
                pfnEDbgGetFrame       = DP83815GetFrame;
                pfnEDbgSendFrame      = DP83815SendFrame;
                break;
    
            case EDBG_ADAPTER_RTL8139:
                pfnEDbgInit           = RTL8139Init;
                pfnEDbgInitDMABuffer  = RTL8139InitDMABuffer;
                pfnEDbgGetFrame       = RTL8139GetFrame;       
                pfnEDbgSendFrame      = RTL8139SendFrame;      
                break;
    
            case EDBG_ADAPTER_3C90X:
                pfnEDbgInit           = D3C90XInit;
                pfnEDbgInitDMABuffer  = D3C90XInitDMABuffer;
                pfnEDbgGetFrame       = D3C90XGetFrame;       
                pfnEDbgSendFrame      = D3C90XSendFrame;      
                break;
    
            case EDBG_USB_RNDIS:
                pfnEDbgInit           = HostMiniInit;
                pfnEDbgInitDMABuffer  = NULL;
                pfnEDbgGetFrame       = RndisEDbgGetFrame;
                pfnEDbgSendFrame      = RndisEDbgSendFrame;
                dwAddress=0; // This forces RNDIS to scan the PCI bus.
                break ;
    
            default:
                UnsportedNicCardType(cAdaptType);
                EdbgOutputDebugString("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\r\n");
                EdbgOutputDebugString("-------------------------------------------------\r\n");
                EdbgOutputDebugString(" ERROR: Unsupported Ethernet adapter type (%u).\r\n", pBootArgs->ucEdbgAdapterType);
                EdbgOutputDebugString("-------------------------------------------------\r\n");
                EdbgOutputDebugString("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n");
                bFoundCard=FALSE;
                break;
            }
        };
        if (bFoundCard) {
             pBootArgs->dwEdbgBaseAddr=dwAddress;
             pBootArgs->ucEdbgIRQ=cIrq;
             pBootArgs->ucEdbgAdapterType=cAdaptType;
        }
        else 
        if (pBootArgs->dwEdbgBaseAddr && pBootArgs->ucEdbgIRQ) {
            pfnEDbgInit           = NE2000Init;
            pfnEDbgInitDMABuffer  = NULL;
            pfnEDbgGetFrame       = NE2000GetFrame;       
            pfnEDbgSendFrame      = NE2000SendFrame;      
            bFoundCard=TRUE;
            // Default to ISA or configure NE2000 Card.
        }
        else {
            EdbgOutputDebugString("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\r\n");
            EdbgOutputDebugString("-------------------------------------------------\r\n");
            EdbgOutputDebugString(" ERROR: Unsupported Ethernet adapter type (%u).\r\n", pBootArgs->ucEdbgAdapterType);
            EdbgOutputDebugString("-------------------------------------------------\r\n");
            EdbgOutputDebugString("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n");
            SpinForever();
        }
        // Initialize NIC DMA buffer, if required.
        //
        if (pfnEDbgInitDMABuffer)
        {
            if (!pfnEDbgInitDMABuffer(ETHDMA_BUFFER_BASE, ETHDMA_BUFFER_SIZE))
            {
                EdbgOutputDebugString("ERROR: Failed to initialize Ethernet controller DMA buffer.\r\n");
                return FALSE;
            }
        }
    
        // Call driver-specific initialization.
        //
        if (!pfnEDbgInit( (BYTE *) pBootArgs->dwEdbgBaseAddr, 1, MyAddr.wMAC)) {
            EdbgOutputDebugString("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\r\n");
            EdbgOutputDebugString("---------------------------------------------\r\n");
            EdbgOutputDebugString(" Failed to initialize Ethernet board!\r\n");
            EdbgOutputDebugString(" Please check that the Ethernet card is\r\n");
            EdbgOutputDebugString(" properly installed and configured.\r\n");
            EdbgOutputDebugString("---------------------------------------------\r\n");
            EdbgOutputDebugString("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n");
            return FALSE;
        }
    ...
    
  • Initialize the boot arguments, boot args, area of the memory and then populate the region with information that will be used by the OS. This shared memory buffer will be updated throughout the boot loader to carry information such as the network device used for download, including base address, interrupt, IP address, subnet mask, and MAC address, and other system or user settings.

To implement the OEMPlatformInit function

  • Edit the file Main.c by adding the code necessary to fully implement the stubbed version of the OEMPlatformInit function in Main.c.

    The following code example shows the implementation of the OEMPlatformInit function for the hardware platform used in this boot loader development example.

    BOOL OEMPlatformInit(void)
    {
        BOOL                    fRet            = FALSE;
        BOOT_ARGS              *pBootArgs;                  // OEM-defined
        ETH_HARDWARE_SETTINGS  *pEdbgSettings;              // OEM-defined
        EDBG_ADDR              *pMyAddr;
    
    
        EdbgOutputDebugString("Microsoft Windows CE Ethernet Bootloader %d.%d for Platform Example (%s %s)\n\n",
                              EBOOT_VERSION_MAJOR,EBOOT_VERSION_MINOR, __DATE__, __TIME__);
    
    
        //------------------------------------------------------------------
        // Initialize the arguments passed from boot loader to kernel.
        // At a minimum, this will include the debug ethernet settings (which 
        // are loaded from flash, specified by the user, and/or discovered at 
        // runtime).
        //
        // The boot args are part of the driver globals region of RAM.  
        // This region is reserved in the .bib file.
        //------------------------------------------------------------------
    
        pBootArgs = (BOOT_ARGS*)BOOT_ARGS_PHYSICAL_MEMORY_START;
        memset(pBootArgs, 0, sizeof(BOOT_ARGS));
    
        pBootArgs->dwSig            = BOOTARG_SIG;
        pBootArgs->dwLen            = sizeof(BOOT_ARGS);
        pBootArgs->dwEdbgDebugZone  = EdbgDebugZone;
    
    
        //------------------------------------------------------------------
        // Allow user to interrupt the loader to alter settings.
        //
        // After a few seconds WaitForKeyPress should return FALSE,
        // letting the loader continue unattended.
        //------------------------------------------------------------------
    
        if (WaitForKeyPress())
        {
            //
            // Using the debug serial functions you implemented,
            // display a configuration menu to the user.
            // Let the user toggle DHCP, set a static IP address, and so on.
            //
            LoaderMainMenu();     
        }
    
    
        //------------------------------------------------------------------
        // Initialize the ethernet controller, save configuration in 
        // boot args for kernel.
        //------------------------------------------------------------------
    
        pEdbgSettings = &pBootArgs->Edbg;
        fRet          = InitEthernet(pEdbgSettings);
    
        if (!fRet) {
            EdbgOutputDebugString("ERROR: Ethernet initialization failed\r\n");
    
            SpinForever();
    
        }
    
    
        pMyAddr = &pEdbgSettings->Adapter.Addr;
        EdbgOutputDebugString("INFO: Debug Ethernet MAC Address: %B:%B:%B:%B:%B:%B\r\n",
                              pMyAddr->wMAC[0] & 0x00FF, pMyAddr->wMAC[0] >> 8,
                              pMyAddr->wMAC[1] & 0x00FF, pMyAddr->wMAC[1] >> 8,
                              pMyAddr->wMAC[2] & 0x00FF, pMyAddr->wMAC[2] >> 8);
    
        return(TRUE);
    }
    

See Also

Eboot Code Library | How to Develop a Boot Loader

Last updated on Wednesday, April 13, 2005

© 2005 Microsoft Corporation. All rights reserved.