This is Unofficial EPICS BASE Doxygen Site
setBootConfigFromNVRAM.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * EPICS BASE is distributed subject to a Software License Agreement found
5 * in file LICENSE that is included with this distribution.
6 \*************************************************************************/
7 
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <arpa/inet.h>
11 #include <netinet/in.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <rtems/rtems_bsdnet.h>
15 #include <bsp.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <epicsStdlib.h>
20 #include <epicsStdio.h>
21 #include <epicsString.h>
22 #include <envDefs.h>
23 
27 
28 /*
29  * Split argument string of form nfs_server:nfs_export:<path>
30  * The nfs_export component will be used as:
31  * - the path to the directory exported from the NFS server
32  * - the local mount point
33  * - a prefix of <path>
34  * For example, the argument string:
35  * romeo:/export/users:smith/ioc/iocexample/st.cmd
36  * would:
37  * - mount /export/users from NFS server romeo on /export/users
38  * - chdir to /export/users/smith/ioc/iocexample
39  * - read commands from st.cmd
40  */
41 static void
42 splitRtemsBsdnetBootpCmdline(void)
43 {
44  char *cp1, *cp2, *cp3;
45 
46  if ((cp1 = rtems_bsdnet_bootp_cmdline) == NULL)
47  return;
48  if (((cp2 = strchr(cp1, ':')) != NULL)
49  && (((cp3 = strchr(cp2+1, ' ')) != NULL)
50  || ((cp3 = strchr(cp2+1, ':')) != NULL))) {
51  int l1 = cp2 - cp1;
52  int l2 = cp3 - cp2 - 1;
53  int l3 = strlen(cp3) - 1;
54  if (l1 && l2 && l3) {
55  *cp2++ = '\0';
56  *cp3 = '\0';
57  env_nfsServer = cp1;
59  *cp3 = '/';
60  rtems_bsdnet_bootp_cmdline = cp2;
61  }
62  }
63 }
64 
65 /*
66  * Split NFS mount information of the form nfs_server:host_path:local_path
67  */
68 static void
69 splitNfsMountPath(char *nfsString)
70 {
71  char *cp2, *cp3;
72 
73  if (nfsString == NULL)
74  return;
75  if (((cp2 = strchr(nfsString, ':')) != NULL)
76  && (((cp3 = strchr(cp2+1, ' ')) != NULL)
77  || ((cp3 = strchr(cp2+1, ':')) != NULL))) {
78  int l1 = cp2 - nfsString;
79  int l2 = cp3 - cp2 - 1;
80  int l3 = strlen(cp3) - 1;
81  if (l1 && l2 && l3) {
82  *cp2++ = '\0';
83  *cp3++ = '\0';
84  env_nfsServer = nfsString;
85  env_nfsPath = cp2;
86  env_nfsMountPoint = cp3;
87  }
88  }
89 }
90 
91 #if defined(HAVE_MOTLOAD)
92 
93 /*
94  * Motorola MOTLOAD NVRAM Access
95  */
96 static char *
97 gev(const char *parm, volatile char *nvp)
98 {
99  const char *val;
100  const char *name;
101  char *ret;
102  char c;
103 
104  for (;;) {
105  if (*nvp == '\0')
106  return NULL;
107  name = parm;
108  while ((c = *nvp++) != '\0') {
109  if ((c == '=') && (*name == '\0')) {
110  val = (char *)nvp;
111  while (*nvp++ != '\0')
112  continue;
113  ret = malloc(nvp - val);
114  if (ret == NULL)
115  return NULL;
116  strcpy(ret, val);
117  return ret;
118  }
119  if (c != *name++) {
120  while (*nvp++ != '\0')
121  continue;
122  break;
123  }
124  }
125  }
126 }
127 
128 static char *
129 motScriptParm(const char *mot_script_boot, char parm)
130 {
131  const char *cp;
132  char *ret;
133  int l;
134 
135  while (*mot_script_boot != '\0') {
136  if (isspace(*(unsigned char *)mot_script_boot)
137  && (*(mot_script_boot+1) == '-')
138  && (*(mot_script_boot+2) == parm)) {
139  mot_script_boot += 3;
140  cp = mot_script_boot;
141  while ((*mot_script_boot != '\0') &&
142  !isspace(*(unsigned char *)mot_script_boot))
143  mot_script_boot++;
144  l = mot_script_boot - cp;
145  ret = malloc(l+1);
146  if (ret == NULL)
147  return NULL;
148  strncpy(ret, cp, l);
149  *(ret+l) = '\0';
150  return ret;
151  }
152  mot_script_boot++;
153  }
154  return NULL;
155 }
156 
157 void
159 {
160  char *cp;
161  const char *mot_script_boot;
162  char *nvp;
163 
164 # if defined(BSP_NVRAM_BASE_ADDR)
165  nvp = (volatile unsigned char *)(BSP_NVRAM_BASE_ADDR+0x70f8);
166 # elif defined(BSP_I2C_VPD_EEPROM_DEV_NAME)
167  char gev_buf[3592];
168  int fd;
169  if ((fd = open(BSP_I2C_VPD_EEPROM_DEV_NAME, 0)) < 0) {
170  printf("Can't open %s: %s\n", BSP_I2C_VPD_EEPROM_DEV_NAME, strerror(errno));
171  return;
172  }
173  lseek(fd, 0x10f8, SEEK_SET);
174  if (read(fd, gev_buf, sizeof gev_buf) != sizeof gev_buf) {
175  printf("Can't read %s: %s\n", BSP_I2C_VPD_EEPROM_DEV_NAME, strerror(errno));
176  return;
177  }
178  close(fd);
179  nvp = gev_buf;
180 # else
181 # error "No way to read GEV!"
182 # endif
183 
184  if (rtems_bsdnet_config.bootp != NULL)
185  return;
186  mot_script_boot = gev("mot-script-boot", nvp);
187  if ((rtems_bsdnet_bootp_server_name = gev("mot-/dev/enet0-sipa", nvp)) == NULL)
188  rtems_bsdnet_bootp_server_name = motScriptParm(mot_script_boot, 's');
189  if ((rtems_bsdnet_config.gateway = gev("mot-/dev/enet0-gipa", nvp)) == NULL)
190  rtems_bsdnet_config.gateway = motScriptParm(mot_script_boot, 'g');
191  if ((rtems_bsdnet_config.ifconfig->ip_netmask = gev("mot-/dev/enet0-snma", nvp)) == NULL)
192  rtems_bsdnet_config.ifconfig->ip_netmask = motScriptParm(mot_script_boot, 'm');
193 
194  rtems_bsdnet_config.name_server[0] = gev("rtems-dns-server", nvp);
195  if (rtems_bsdnet_config.name_server[0] == NULL)
196  rtems_bsdnet_config.name_server[0] = rtems_bsdnet_bootp_server_name;
197  cp = gev("rtems-dns-domainname", nvp);
198  if (cp)
199  rtems_bsdnet_config.domainname = cp;
200 
201  if ((rtems_bsdnet_config.ifconfig->ip_address = gev("mot-/dev/enet0-cipa", nvp)) == NULL)
202  rtems_bsdnet_config.ifconfig->ip_address = motScriptParm(mot_script_boot, 'c');
203  rtems_bsdnet_config.hostname = gev("rtems-client-name", nvp);
204  if (rtems_bsdnet_config.hostname == NULL)
205  rtems_bsdnet_config.hostname = rtems_bsdnet_config.ifconfig->ip_address;
206 
207  if ((rtems_bsdnet_bootp_boot_file_name = gev("mot-/dev/enet0-file", nvp)) == NULL)
208  rtems_bsdnet_bootp_boot_file_name = motScriptParm(mot_script_boot, 'f');
209  rtems_bsdnet_bootp_cmdline = gev("epics-script", nvp);
210  splitRtemsBsdnetBootpCmdline();
211  splitNfsMountPath(gev("epics-nfsmount", nvp));
212  rtems_bsdnet_config.ntp_server[0] = gev("epics-ntpserver", nvp);
213  if (rtems_bsdnet_config.ntp_server[0] == NULL)
214  rtems_bsdnet_config.ntp_server[0] = rtems_bsdnet_bootp_server_name;
215  if ((cp = gev("epics-tz", nvp)) != NULL)
216  epicsEnvSet("TZ", cp);
217 }
218 
219 #elif defined(HAVE_PPCBUG)
220 /*
221  * Motorola PPCBUG NVRAM Access
222  */
223 struct ppcbug_nvram {
224  uint32_t PacketVersionIdentifier;
225  uint32_t NodeControlMemoryAddress;
226  uint32_t BootFileLoadAddress;
227  uint32_t BootFileExecutionAddress;
228  uint32_t BootFileExecutionDelay;
229  uint32_t BootFileLength;
230  uint32_t BootFileByteOffset;
231  uint32_t TraceBufferAddress;
232  uint32_t ClientIPAddress;
233  uint32_t ServerIPAddress;
234  uint32_t SubnetIPAddressMask;
235  uint32_t BroadcastIPAddressMask;
236  uint32_t GatewayIPAddress;
237  uint8_t BootpRarpRetry;
238  uint8_t TftpRarpRetry;
239  uint8_t BootpRarpControl;
240  uint8_t UpdateControl;
241  char BootFilenameString[64];
242  char ArgumentFilenameString[64];
243 };
244 
245 static char *addr(char *cbuf, uint32_t addr)
246 {
247  struct in_addr a;
248  if ((a.s_addr = addr) == 0)
249  return NULL;
250  return (char *)inet_ntop(AF_INET, &a, cbuf, INET_ADDRSTRLEN);
251 }
252 
253 void
255 {
256  static struct ppcbug_nvram nvram;
257  static char ip_address[INET_ADDRSTRLEN];
258  static char ip_netmask[INET_ADDRSTRLEN];
259  static char server[INET_ADDRSTRLEN];
260  static char gateway[INET_ADDRSTRLEN];
261 
262  if (rtems_bsdnet_config.bootp != NULL)
263  return;
264 
265  /*
266  * Get network configuation from PPCBUG.
267  * The 'correct' way to do this would be to issue a .NETCFIG PPCBUG
268  * system call. Unfortunately it is very difficult to issue such a
269  * call once RTEMS is up and running so we just copy from the 'known'
270  * location of the network configuration parameters.
271  * Care must be taken to access the NVRAM a byte at a time.
272  */
273 
274 #if defined(NVRAM_INDIRECT)
275  {
276  volatile char *addrLo = (volatile char *)0x80000074;
277  volatile char *addrHi = (volatile char *)0x80000075;
278  volatile char *data = (volatile char *)0x80000077;
279  int addr = 0x1000;
280  char *d = (char *)&nvram;
281 
282  while (d < ((char *)&nvram + sizeof nvram)) {
283  *addrLo = addr & 0xFF;
284  *addrHi = (addr >> 8) & 0xFF;
285  *d++ = *data;
286  addr++;
287  }
288  }
289 #else
290  {
291  volatile char *s = (volatile char *)0xFFE81000;
292  char *d = (char *)&nvram;
293 
294  while (d < ((char *)&nvram + sizeof nvram))
295  *d++ = *s++;
296  }
297 #endif
298  /*
299  * Assume that the boot server is also the name, log and ntp server!
300  */
301  rtems_bsdnet_config.name_server[0] =
302  rtems_bsdnet_config.ntp_server[0] =
303  rtems_bsdnet_bootp_server_name = addr(server, nvram.ServerIPAddress);
304  rtems_bsdnet_bootp_server_address.s_addr = nvram.ServerIPAddress;
305  /*
306  * Nothing better to use as host name!
307  */
308  rtems_bsdnet_config.ifconfig->ip_address =
309  rtems_bsdnet_config.hostname = addr(ip_address, nvram.ClientIPAddress);
310 
311  rtems_bsdnet_config.gateway = addr(gateway, nvram.GatewayIPAddress);
312  rtems_bsdnet_config.ifconfig->ip_netmask = addr(ip_netmask, nvram.SubnetIPAddressMask);
313 
314  rtems_bsdnet_bootp_boot_file_name = nvram.BootFilenameString;
315  rtems_bsdnet_bootp_cmdline = nvram.ArgumentFilenameString;
316  splitRtemsBsdnetBootpCmdline();
317 }
318 
319 #elif defined(__mcf528x__)
320 
321 static char *
322 env(const char *parm, const char *defaultValue)
323 {
324  const char *cp = bsp_getbenv(parm);
325 
326  if (!cp) {
327  if (!defaultValue)
328  return NULL;
329  cp = defaultValue;
330  printf ("%s environment variable missing -- using %s.\n", parm, cp);
331  }
332  return epicsStrDup(cp);
333 }
334 
335 void
337 {
338  const char *cp1;
339 
340  if (rtems_bsdnet_config.bootp != NULL)
341  return;
342  rtems_bsdnet_config.gateway = env("GATEWAY", NULL);
343  rtems_bsdnet_config.ifconfig->ip_netmask = env("NETMASK", "255.255.252.0");
344 
345  rtems_bsdnet_bootp_server_name = env("SERVER", "192.168.0.1");
346  rtems_bsdnet_config.name_server[0] = env("NAMESERVER", rtems_bsdnet_bootp_server_name);
347  rtems_bsdnet_config.ntp_server[0] = env("NTPSERVER", rtems_bsdnet_bootp_server_name);
348  cp1 = env("DOMAIN", NULL);
349  if (cp1 != NULL)
350  rtems_bsdnet_config.domainname = cp1;
351  rtems_bsdnet_config.hostname = env("HOSTNAME", "iocNobody");
352  rtems_bsdnet_config.ifconfig->ip_address = env("IPADDR0", "192.168.0.2");
353  rtems_bsdnet_bootp_boot_file_name = env("BOOTFILE", "uC5282App.boot");
354  rtems_bsdnet_bootp_cmdline = env("CMDLINE", "epics/iocBoot/iocNobody/st.cmd");
355  splitNfsMountPath(env("NFSMOUNT", NULL));
356  if ((cp1 = env("TZ", NULL)) != NULL)
357  epicsEnvSet("TZ", cp1);
358 }
359 
360 #else
361 /*
362  * Placeholder for systems without NVRAM
363  */
364 void
366 {
367  printf("SYSTEM HAS NO NON-VOLATILE RAM!\n");
368  printf("YOU MUST USE SOME OTHER METHOD TO OBTAIN NETWORK CONFIGURATION\n");
369 }
370 #endif
char * env_nfsPath
struct rtems_bsdnet_config rtems_bsdnet_config
Routines to get and set EPICS environment parameters.
#define printf
Definition: epicsStdio.h:41
#define NULL
Definition: catime.c:38
LIBCOM_API void epicsStdCall epicsEnvSet(const char *name, const char *value)
Set an environment variable&#39;s value.
Definition: osdEnv.c:35
char * env_nfsServer
char * epicsStrDup(const char *s)
Definition: epicsString.c:233
char * env_nfsMountPoint
void setBootConfigFromNVRAM(void)