mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-14 08:57:58 +00:00
54841ab50c
The hush shell dynamically allocates (and re-allocates) memory for the argument strings in the "char *argv[]" argument vector passed to commands. Any code that modifies these pointers will cause serious corruption of the malloc data structures and crash U-Boot, so make sure the compiler can check that no such modifications are being done by changing the code into "char * const argv[]". This modification is the result of debugging a strange crash caused after adding a new command, which used the following argument processing code which has been working perfectly fine in all Unix systems since version 6 - but not so in U-Boot: int main (int argc, char **argv) { while (--argc > 0 && **++argv == '-') { /* ====> */ while (*++*argv) { switch (**argv) { case 'd': debug++; break; ... default: usage (); } } } ... } The line marked "====>" will corrupt the malloc data structures and usually cause U-Boot to crash when the next command gets executed by the shell. With the modification, the compiler will prevent this with an error: increment of read-only location '*argv' N.B.: The code above can be trivially rewritten like this: while (--argc > 0 && **++argv == '-') { char *arg = *argv; while (*++arg) { switch (*arg) { ... Signed-off-by: Wolfgang Denk <wd@denx.de> Acked-by: Mike Frysinger <vapier@gentoo.org>
218 lines
4.3 KiB
C
218 lines
4.3 KiB
C
/*
|
|
* (C) Copyright 2005
|
|
* Ladislav Michl, 2N Telekomunikace, michl@2n.cz
|
|
*
|
|
* See file CREDITS for list of people who contributed to this
|
|
* project.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
* Some code shamelessly stolen back from Robin Getz.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <exports.h>
|
|
#include <timestamp.h>
|
|
#include <net.h>
|
|
#include "../drivers/net/smc91111.h"
|
|
|
|
static struct eth_device dev = {
|
|
.iobase = CONFIG_SMC91111_BASE
|
|
};
|
|
|
|
static u16 read_eeprom_reg(u16 reg)
|
|
{
|
|
int timeout;
|
|
|
|
SMC_SELECT_BANK(&dev, 2);
|
|
SMC_outw(&dev, reg, PTR_REG);
|
|
|
|
SMC_SELECT_BANK(&dev, 1);
|
|
SMC_outw(&dev, SMC_inw(&dev, CTL_REG) | CTL_EEPROM_SELECT |
|
|
CTL_RELOAD, CTL_REG);
|
|
|
|
timeout = 100;
|
|
|
|
while ((SMC_inw(&dev, CTL_REG) & CTL_RELOAD) && --timeout)
|
|
udelay(100);
|
|
if (timeout == 0) {
|
|
printf("Timeout reading register %02x\n", reg);
|
|
return 0;
|
|
}
|
|
|
|
return SMC_inw(&dev, GP_REG);
|
|
}
|
|
|
|
static int write_eeprom_reg(u16 value, u16 reg)
|
|
{
|
|
int timeout;
|
|
|
|
SMC_SELECT_BANK(&dev, 2);
|
|
SMC_outw(&dev, reg, PTR_REG);
|
|
|
|
SMC_SELECT_BANK(&dev, 1);
|
|
|
|
SMC_outw(&dev, value, GP_REG);
|
|
SMC_outw(&dev, SMC_inw(&dev, CTL_REG) | CTL_EEPROM_SELECT |
|
|
CTL_STORE, CTL_REG);
|
|
|
|
timeout = 100;
|
|
|
|
while ((SMC_inw(&dev, CTL_REG) & CTL_STORE) && --timeout)
|
|
udelay(100);
|
|
if (timeout == 0) {
|
|
printf("Timeout writing register %02x\n", reg);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int write_data(u16 *buf, int len)
|
|
{
|
|
u16 reg = 0x23;
|
|
|
|
while (len--)
|
|
write_eeprom_reg(*buf++, reg++);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int verify_macaddr(char *s)
|
|
{
|
|
u16 reg;
|
|
int i, err = 0;
|
|
|
|
puts("HWaddr: ");
|
|
for (i = 0; i < 3; i++) {
|
|
reg = read_eeprom_reg(0x20 + i);
|
|
printf("%02x:%02x%c", reg & 0xff, reg >> 8, i != 2 ? ':' : '\n');
|
|
if (s)
|
|
err |= reg != ((u16 *)s)[i];
|
|
}
|
|
|
|
return err ? 0 : 1;
|
|
}
|
|
|
|
static int set_mac(char *s)
|
|
{
|
|
int i;
|
|
char *e, eaddr[6];
|
|
|
|
/* turn string into mac value */
|
|
for (i = 0; i < 6; i++) {
|
|
eaddr[i] = simple_strtoul(s, &e, 16);
|
|
s = (*e) ? e+1 : e;
|
|
}
|
|
|
|
for (i = 0; i < 3; i++)
|
|
write_eeprom_reg(*(((u16 *)eaddr) + i), 0x20 + i);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_element(char *s, unsigned char *buf, int len)
|
|
{
|
|
int cnt;
|
|
char *p, num[3];
|
|
unsigned char id;
|
|
|
|
id = simple_strtoul(s, &p, 16);
|
|
if (*p++ != ':')
|
|
return -1;
|
|
cnt = 2;
|
|
num[2] = 0;
|
|
for (; *p; p += 2) {
|
|
if (p[1] == 0)
|
|
return -2;
|
|
if (cnt + 3 > len)
|
|
return -3;
|
|
num[0] = p[0];
|
|
num[1] = p[1];
|
|
buf[cnt++] = simple_strtoul(num, NULL, 16);
|
|
}
|
|
buf[0] = id;
|
|
buf[1] = cnt - 2;
|
|
|
|
return cnt;
|
|
}
|
|
|
|
int eeprom(int argc, char * const argv[])
|
|
{
|
|
int i, len, ret;
|
|
unsigned char buf[58], *p;
|
|
|
|
app_startup(argv);
|
|
i = get_version();
|
|
if (i != XF_VERSION) {
|
|
printf("Using ABI version %d, but U-Boot provides %d\n",
|
|
XF_VERSION, i);
|
|
return 1;
|
|
}
|
|
|
|
if ((SMC_inw(&dev, BANK_SELECT) & 0xFF00) != 0x3300) {
|
|
puts("SMSC91111 not found\n");
|
|
return 2;
|
|
}
|
|
|
|
/* Called without parameters - print MAC address */
|
|
if (argc < 2) {
|
|
verify_macaddr(NULL);
|
|
return 0;
|
|
}
|
|
|
|
/* Print help message */
|
|
if (argv[1][1] == 'h') {
|
|
puts("VoiceBlue EEPROM writer\n"
|
|
"Built: " U_BOOT_DATE " at " U_BOOT_TIME "\n"
|
|
"Usage:\n\t<mac_address> [<element_1>] [<...>]\n");
|
|
return 0;
|
|
}
|
|
|
|
/* Try to parse information elements */
|
|
len = sizeof(buf);
|
|
p = buf;
|
|
for (i = 2; i < argc; i++) {
|
|
ret = parse_element(argv[i], p, len);
|
|
switch (ret) {
|
|
case -1:
|
|
printf("Element %d: malformed\n", i - 1);
|
|
return 3;
|
|
case -2:
|
|
printf("Element %d: odd character count\n", i - 1);
|
|
return 3;
|
|
case -3:
|
|
puts("Out of EEPROM memory\n");
|
|
return 3;
|
|
default:
|
|
p += ret;
|
|
len -= ret;
|
|
}
|
|
}
|
|
|
|
/* First argument (MAC) is mandatory */
|
|
set_mac(argv[1]);
|
|
if (verify_macaddr(argv[1])) {
|
|
puts("*** HWaddr does not match! ***\n");
|
|
return 4;
|
|
}
|
|
|
|
while (len--)
|
|
*p++ = 0;
|
|
|
|
write_data((u16 *)buf, sizeof(buf) >> 1);
|
|
|
|
return 0;
|
|
}
|