1 /*********************************************************************************
2 * FILE PURPOSE: The Ethernet boot wrapper
3 *********************************************************************************
4 * FILE NAME: ethboot.c
5 *
6 * DESCRIPTION: This file provides the ethernet boot wrapper used by IBL modules
7 *
8 * @file ethboot.c
9 *
10 * @brief
11 * The ethernet boot wrapper
12 *
13 ***********************************************************************************/
14 #include "types.h"
15 #include "ibl.h"
16 #include "iblloc.h"
17 #include "ethboot.h"
18 #include "net.h"
19 #include "cpmacdrv.h"
20 #include "sgmii.h"
21 #include "device.h"
22 #include "mdioapi.h"
23 #include <string.h>
26 /* Convert an IP address from unsigned char to IPN (uint32) */
27 #define FORM_IPN(x) ( (x[0] << 24) | \
28 (x[1] << 16) | \
29 (x[2] << 8) | \
30 (x[3] << 0) )
32 #define UNFORM_IPN(x,y) (x)[0] = (y) >> 24; \
33 (x)[1] = (y) >> 16; \
34 (x)[2] = (y) >> 8; \
35 (x)[3] = (y) >> 0
37 #define MIN(a,b) ((a) < (b)) ? (a) : (b)
39 static bool have_params;
41 /* Receive a call back when the boot file name is known */
42 void ibl_rec_params (void *params)
43 {
44 NET_DRV_DEVICE *netdev = (NET_DRV_DEVICE *)params;
46 have_params = TRUE;
48 /* Copy the information to the status fields */
49 UNFORM_IPN(iblStatus.ethParams.ipAddr, netdev->ip_address);
50 UNFORM_IPN(iblStatus.ethParams.serverIp, netdev->server_ip);
52 memcpy (iblStatus.ethParams.hwAddress, netdev->mac_address, sizeof(iblStatus.ethParams.hwAddress));
53 strncpy (iblStatus.ethParams.fileName, netdev->file_name, sizeof(iblStatus.ethParams.fileName));
55 }
58 void iblEthBoot (Int32 eIdx)
59 {
60 NET_DRV_DEVICE nDevice;
61 Uint32 nl;
62 Uint32 entry;
63 Int32 n;
64 Int32 dataSize;
65 Int32 format;
66 void (*exit)();
67 uint8 buf[16];
68 char *ext;
72 /* Power up the device. No action is taken if the device is already powered up */
73 if (devicePowerPeriph (TARGET_PWR_ETH(ibl.ethConfig[eIdx].port)) < 0)
74 return;
76 /* Do any mdio configuration */
77 if (ibl.mdioConfig.nMdioOps > 0)
78 hwMdio (ibl.mdioConfig.nMdioOps, ibl.mdioConfig.mdio,
79 ibl.mdioConfig.mdioClkDiv, ibl.mdioConfig.interDelay);
82 /* SGMII configuration. If sgmii is not present this statement is defined
83 * to void in target.h */
84 hwSgmiiConfig (ibl.ethConfig[eIdx].port, &ibl.sgmiiConfig[eIdx]);
87 nDevice.port_num = ibl.ethConfig[eIdx].port;
89 /* Simple transation to initialize the driver */
90 memcpy (nDevice.mac_address, ibl.ethConfig[eIdx].ethInfo.hwAddress, sizeof(nDevice.mac_address));
92 nl = FORM_IPN(ibl.ethConfig[eIdx].ethInfo.ipAddr);
93 if (ibl.ethConfig[eIdx].doBootp == TRUE)
94 nDevice.ip_address = 0;
95 else
96 nDevice.ip_address = htonl(nl);
98 nl = FORM_IPN(ibl.ethConfig[eIdx].ethInfo.netmask);
99 nDevice.net_mask = htonl(nl);
101 nl = FORM_IPN(ibl.ethConfig[eIdx].ethInfo.serverIp);
102 nDevice.server_ip = htonl(nl);
103 nDevice.use_bootp_server_ip = ibl.ethConfig[eIdx].useBootpServerIp;
105 /* Note - the file name structure in nDevice is only 64 bytes, but 128 in ethInfo */
106 memcpy (nDevice.file_name, ibl.ethConfig[eIdx].ethInfo.fileName, sizeof(nDevice.file_name));
107 nDevice.use_bootp_file_name = ibl.ethConfig[eIdx].useBootpFileName;
110 nDevice.start = cpmac_drv_start;
111 nDevice.stop = cpmac_drv_stop;
112 nDevice.send = cpmac_drv_send;
113 nDevice.receive = cpmac_drv_receive;
116 /* have_params will be set to true in the tftp call back. It must be
117 * set to false before opening the module, since the call back will
118 * be from the open call if bootp is not used */
119 have_params = FALSE;
121 /* Open the network device */
122 if ((*net_boot_module.open) ((void *)&nDevice, ibl_rec_params) != 0)
123 return;
125 /* Wait for the callback with the requested filename */
126 while (have_params == FALSE) {
128 if ((*net_boot_module.peek) ((uint8 *)&nl, sizeof(nl)) < 0) {
130 (*net_boot_module.close)();
131 return;
132 }
133 }
135 format = ibl.ethConfig[eIdx].bootFormat;
137 /* If the data format was based on the name extension, determine
138 * the boot data format */
139 if (format == ibl_BOOT_FORMAT_NAME) {
141 ext = strrchr (iblStatus.ethParams.fileName, '.');
143 if (ext != NULL) {
145 if (!strcmp (ext, ".bis"))
146 format = ibl_BOOT_FORMAT_BIS;
148 else if (!strcmp (ext, ".ais"))
149 format = ibl_BOOT_FORMAT_BIS;
151 else if (!strcmp (ext, ".out"))
152 format = ibl_BOOT_FORMAT_COFF;
154 else if (!strcmp (ext, ".coff"))
155 format = ibl_BOOT_FORMAT_COFF;
157 else if (!strcmp (ext, ".btbl"))
158 format = ibl_BOOT_FORMAT_BTBL;
160 else if (!strcmp (ext, ".bin"))
161 format = ibl_BOOT_FORMAT_BBLOB;
163 else if (!strcmp (ext, ".blob"))
164 format = ibl_BOOT_FORMAT_BBLOB;
166 }
168 /* Name match failed it didn't change */
169 if (format == ibl_BOOT_FORMAT_NAME) {
171 iblStatus.nameDetectFailCnt += 1;
173 /* Close up the peripheral */
174 (*net_boot_module.close)();
176 return;
177 }
179 }
181 entry = iblBoot (&net_boot_module, format, &ibl.ethConfig[eIdx].blob);
184 /* Before closing the module read any remaining data. In the coff boot mode the boot may
185 * detect an exit before the entire file has been read. Read the rest of the file
186 * to make the server happy */
188 do {
190 dataSize = (*net_boot_module.query)(); /* Will return -1 when the data is done */
192 if (dataSize > 0) {
194 while (dataSize > 0) {
196 n = MIN(dataSize, sizeof(buf));
197 (*net_boot_module.read)(buf, n);
198 dataSize = dataSize - n;
199 }
201 /* Do not peek if the data size returned in the query was > 0 */
202 } else if (dataSize == 0) {
204 (*net_boot_module.peek)(buf, 1);
205 }
207 } while (dataSize >= 0);
211 /* Close up the peripheral */
212 (*net_boot_module.close)();
214 if (entry != 0) {
216 iblStatus.exitAddress = entry;
217 exit = (void (*)())entry;
218 (*exit)();
220 }
223 }