diff --git a/src/ethboot/ethboot.c b/src/ethboot/ethboot.c
--- /dev/null
+++ b/src/ethboot/ethboot.c
@@ -0,0 +1,233 @@
+/*********************************************************************************
+ * FILE PURPOSE: The Ethernet boot wrapper
+ *********************************************************************************
+ * FILE NAME: ethboot.c
+ *
+ * DESCRIPTION: This file provides the ethernet boot wrapper used by IBL modules
+ *
+ * @file ethboot.c
+ *
+ * @brief
+ * The ethernet boot wrapper
+ *
+ ***********************************************************************************/
+#include "types.h"
+#include "ibl.h"
+#include "iblloc.h"
+#include "ethboot.h"
+#include "net.h"
+#include "cpmacdrv.h"
+#include "device.h"
+#include "mdioapi.h"
+#include <string.h>
+
+
+/* Convert an IP address from unsigned char to IPN (uint32) */
+#define FORM_IPN(x) ( (x[0] << 24) | \
+ (x[1] << 16) | \
+ (x[2] << 8) | \
+ (x[3] << 0) )
+
+#define UNFORM_IPN(x,y) (x)[0] = (y) >> 24; \
+ (x)[1] = (y) >> 16; \
+ (x)[2] = (y) >> 8; \
+ (x)[3] = (y) >> 0
+
+#define MIN(a,b) ((a) < (b)) ? (a) : (b)
+
+static bool have_params;
+
+/* Receive a call back when the boot file name is known */
+void ibl_rec_params (void *params)
+{
+ NET_DRV_DEVICE *netdev = (NET_DRV_DEVICE *)params;
+
+ have_params = TRUE;
+
+ /* Copy the information to the status fields */
+ UNFORM_IPN(iblStatus.ethParams.ipAddr, netdev->ip_address);
+ UNFORM_IPN(iblStatus.ethParams.serverIp, netdev->server_ip);
+
+ memcpy (iblStatus.ethParams.hwAddress, netdev->mac_address, sizeof(iblStatus.ethParams.hwAddress));
+ strncpy (iblStatus.ethParams.fileName, netdev->file_name, sizeof(iblStatus.ethParams.fileName));
+
+}
+
+
+void iblEthBoot (Int32 eIdx)
+{
+ NET_DRV_DEVICE nDevice;
+ Uint32 nl;
+ Uint32 entry;
+ Int32 n;
+ Int32 dataSize;
+ Int32 format;
+ void (*exit)();
+ uint8 buf[16];
+ char *ext;
+
+
+
+ /* Power up the device. No action is taken if the device is already powered up */
+ if (devicePowerPeriph (TARGET_PWR_ETH(ibl.ethConfig[eIdx].port)) < 0)
+ return;
+
+ /* Do any mdio configuration */
+ if (ibl.mdioConfig.nMdioOps > 0)
+ hwMdio (ibl.mdioConfig.nMdioOps, ibl.mdioConfig.mdio,
+ ibl.mdioConfig.mdioClkDiv, ibl.mdioConfig.interDelay);
+
+
+ nDevice.port_num = ibl.ethConfig[eIdx].port;
+
+ /* Simple transation to initialize the driver */
+ memcpy (nDevice.mac_address, ibl.ethConfig[eIdx].ethInfo.hwAddress, sizeof(nDevice.mac_address));
+
+ nl = FORM_IPN(ibl.ethConfig[eIdx].ethInfo.ipAddr);
+ if (ibl.ethConfig[eIdx].doBootp == TRUE)
+ nDevice.ip_address = 0;
+ else
+ nDevice.ip_address = htonl(nl);
+
+ nl = FORM_IPN(ibl.ethConfig[eIdx].ethInfo.netmask);
+ nDevice.net_mask = htonl(nl);
+
+ nl = FORM_IPN(ibl.ethConfig[eIdx].ethInfo.serverIp);
+ nDevice.server_ip = htonl(nl);
+ nDevice.use_bootp_server_ip = ibl.ethConfig[eIdx].useBootpServerIp;
+
+ /* Note - the file name structure in nDevice is only 64 bytes, but 128 in ethInfo */
+ memcpy (nDevice.file_name, ibl.ethConfig[eIdx].ethInfo.fileName, sizeof(nDevice.file_name));
+ nDevice.use_bootp_file_name = ibl.ethConfig[eIdx].useBootpFileName;
+
+
+ nDevice.start = cpmac_drv_start;
+ nDevice.stop = cpmac_drv_stop;
+ nDevice.send = cpmac_drv_send;
+ nDevice.receive = cpmac_drv_receive;
+
+
+ /* have_params will be set to true in the tftp call back. It must be
+ * set to false before opening the module, since the call back will
+ * be from the open call if bootp is not used */
+ have_params = FALSE;
+
+ /* Open the network device */
+ if ((*net_boot_module.open) ((void *)&nDevice, ibl_rec_params) != 0)
+ return;
+
+ /* Wait for the callback with the requested filename */
+ while (have_params == FALSE) {
+
+ if ((*net_boot_module.peek) ((uint8 *)&nl, sizeof(nl)) < 0) {
+
+ (*net_boot_module.close)();
+ return;
+ }
+ }
+
+ format = ibl.ethConfig[eIdx].bootFormat;
+
+ /* If the data format was based on the name extension, determine
+ * the boot data format */
+ if (format == ibl_BOOT_FORMAT_NAME) {
+
+ ext = strrchr (iblStatus.ethParams.fileName, '.');
+
+ if (ext != NULL) {
+
+ if (!strcmp (ext, ".bis"))
+ format = ibl_BOOT_FORMAT_BIS;
+
+ else if (!strcmp (ext, ".ais"))
+ format = ibl_BOOT_FORMAT_BIS;
+
+ else if (!strcmp (ext, ".out"))
+ format = ibl_BOOT_FORMAT_COFF;
+
+ else if (!strcmp (ext, ".coff"))
+ format = ibl_BOOT_FORMAT_COFF;
+
+ else if (!strcmp (ext, ".btbl"))
+ format = ibl_BOOT_FORMAT_BTBL;
+
+ else if (!strcmp (ext, ".bin"))
+ format = ibl_BOOT_FORMAT_BBLOB;
+
+ else if (!strcmp (ext, ".blob"))
+ format = ibl_BOOT_FORMAT_BBLOB;
+
+ }
+
+ /* Name match failed it didn't change */
+ if (format == ibl_BOOT_FORMAT_NAME) {
+
+ iblStatus.nameDetectFailCnt += 1;
+
+ /* Close up the peripheral */
+ (*net_boot_module.close)();
+
+ return;
+ }
+
+ }
+
+ entry = iblBoot (&net_boot_module, format, &ibl.ethConfig[eIdx].blob);
+
+
+ /* Before closing the module read any remaining data. In the coff boot mode the boot may
+ * detect an exit before the entire file has been read. Read the rest of the file
+ * to make the server happy */
+
+ do {
+
+ dataSize = (*net_boot_module.query)(); /* Will return -1 when the data is done */
+
+ if (dataSize > 0) {
+
+ while (dataSize > 0) {
+
+ n = MIN(dataSize, sizeof(buf));
+ (*net_boot_module.read)(buf, n);
+ dataSize = dataSize - n;
+ }
+
+ /* Do not peek if the data size returned in the query was > 0 */
+ } else if (dataSize == 0) {
+
+ (*net_boot_module.peek)(buf, 1);
+ }
+
+ } while (dataSize >= 0);
+
+
+
+ /* Close up the peripheral */
+ (*net_boot_module.close)();
+
+ if (entry != 0) {
+
+ iblStatus.exitAddress = entry;
+ exit = (void (*)())entry;
+ (*exit)();
+
+ }
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+