本文回答前文思考的问题 112.龙芯2k1000-pmon(11)- gzrom-dtb.bin 文件的组成-CSDN博客
env写的位置是ff000 后面的500字节,这个位置能否改动呢?
答案是:不可以!!! 否则需要改源码
找到源码:
Targets/LS2K-hj20004/ls2k/tgt_machdep.c
1. 函数tgt_mapenv
void tgt_mapenv(int (*func) __P((char *, char *))) //参数名注意一下,后面多次用到,就是setenv
nvram = (char *)(tgt_flashmap())->fl_map_base;
printf("nvram=%08x\n", (unsigned int)nvram); //这句被打印了
if (fl_devident(nvram, NULL) == 0 || //返回值不是0
cksum(nvram + NVRAM_OFFS, NVRAM_SIZE, 0) != 0) { //返回值为0,if条件不成立
这里我打印nvram出来了,nvram=0xbfc00000. 就是flash映射的虚拟地址
宏定义
NVRAM_OFFS 是个常量 0xff000
所以,env必须放在这个位置,不可修改为其他位置,否则 要么修改源码的偏移,要么就会读取出现问题。
NVRAM_SIZE 设置为492,实际应该是500,但是后面的字节都是0,所以不影响校验和。
2. cksum 函数 (Targets/LS2K-hj20004/ls2k/tgt_machdep.c)
看一下checksum的c语言计算,与前面的部分对应起来,是一致的。
参数s很明显应该与前文的命令一致,应该是500才对。
(这里我自己修改宏定义NVRAM_SIZE为500)
/*
* Calculate checksum. If 'set' checksum is calculated and set.
*/
static int cksum(void *p, size_t s, int set)
{
u_int16_t sum = 0;
u_int8_t *sp = p;
int sz = s / 2;
if (set) {
*sp = 0; /* Clear checksum */
*(sp + 1) = 0; /* Clear checksum */
}
while (sz--) {
sum += (*sp++) << 8;
sum += *sp++;
}
if (set) {
sum = -sum;
*(u_int8_t *) p = sum >> 8;
*((u_int8_t *) p + 1) = sum;
}
return (sum);
}
校验和通过之后才会解析,设置到环境变量,否则就无效。
nvram = (char *)(tgt_flashmap())->fl_map_base;
printf("nvram=%08x\n", (unsigned int)nvram); //这句被打印了
if (fl_devident(nvram, NULL) == 0 || //返回值不是0
cksum(nvram + NVRAM_OFFS, NVRAM_SIZE, 0) != 0) { //返回值为0,if条件不成立
printf("NVRAM is invalid!\n");
nvram_invalid = 1;
} else {
nvram += NVRAM_OFFS; //执行这个语句
ep = nvram + 2;; //为什么加2,就简单了,看makefile.inc
while (*ep != 0) { //循环解析出来
char *val = 0, *p = env;
i = 0;
while ((*p++ = *ep++) && (ep <= nvram + NVRAM_SIZE - 1)
&& i++ < 255) {
if ((*(p - 1) == '=') && (val == NULL)) {
*(p - 1) = '\0';
val = p;
}
}
if (ep <= nvram + NVRAM_SIZE - 1 && i < 255) {
(*func) (env, val);
// printf("2022-03-03 : env = %s val = %s ep = %x i = %d\n", env, val,ep,i);
} else {
nvram_invalid = 2;
// printf("2022-03-03 : nvram_invalid ep = %x i = %d\n", ep,i);
break;
}
}
}
3. 环境变量的解析
FR=1\x00al=(usb0,0)/boot/vmlinuz\x00append='console=ttyS0,115200 noinitrd root=/dev/sda2 rootfstype=ext4 rootwait rw'\x00al1=(wd0,0)/vmlinuz\x00
环境变量的解析就是找到字符‘\0’,然后分开就行
中间找到等号,把等号赋值为字符‘\0’,这样就分开了环境变量和对应的值
(*func) (env, val);
其中env就是环境变量的名字,val就是值。两个都是字符串。
4. 看一下_setenv 函数
主要作用就是把环境变量的名字和值设置到全局数组envvar中,
如果原来存在改环境变量,则修改原来对应的值,
如果不存在则新增一个环境变量。
这个数组最多能够保存64个成员,但是64并不是可以自定义的环境变量的个数!!!
static int
_setenv (name, value)
char *name, *value;
{
struct envpair *ep;
struct envpair *bp = 0;
const struct stdenv *sp;
if ((sp = getstdenv (name)) != 0) { //使用名字查询,是否在标准环境变量表中,不存在返回0
if (sp-> chgfunc && !(*sp->chgfunc) (name, value)) //如果在标准表中,看这个是否又对应的修改函数,有则调用该修改函数
return 0;
//如果标准环境变量表中存在值,且没有对应的修改函数,则看原来的值与value是不是相等,相等返回1,否则0,envinited为表示第一次初始化,否则为修改
if (sp->values && _matchval (sp, value) < 0 && envinited) {
printf ("%s: bad %s value, try [%s]\n", value, name, sp->values); //不相等则提示使用原来的默认值,而提示新的值是bad
return 0;
}
}
for (ep = envvar; ep < &envvar[NVAR]; ep++) { //在环境变量数组中找,最多64个环境变量
if (!ep->name && !bp) //数组中,环境变量名为空的,并且bp指针也是空的,就是找到一个空位了
bp = ep;
else if (ep->name && striequ (name, ep->name)) //有相同的就退出循环
break;
}
if (ep < &envvar[NVAR]) { //有相同的,是break出的循环
/* must have got a match, free old value */
if (ep->value) {
free (ep->value); ep->value = 0; //释放原来的空间
}
} else if (bp) { //没有相同的,存在有envvar数组中第一个空白的位置
/* new entry */
ep = bp;
if (!(ep->name = malloc (strlen (name) + 1))) //分配空间
return 0;
strcpy (ep->name, name); //数据拷贝到空间中
} else { //envvar数组中没有找到空白的位置,已经填满了
return 0;
}
if (value) { //value存在
if (!(ep->value = malloc (strlen (value) + 1))) { //分配空间
free (ep->name); ep->name = 0;
return 0;
}
strcpy (ep->value, value);
}
return 1;
}
4.1 有一个标准环境变量表 (env.c 中)
这个表也会解析到全局环境变量数组中。
static struct stdenv {
char *name; //环境变量的名称
char *init; //初始化的值
char *values; //所有可用的值
int (*chgfunc) __P((char *, char *)); //修改该环境变量的对应函数指针,
} stdenvtab[] = {
{"brkcmd", "l -r @cpc 1", 0},
#ifdef HAVE_QUAD
{"datasize", "-b", "-b -h -w -d"},
#else
{"datasize", "-b", "-b -h -w"},
#endif
{"dlecho", "off", "off on lfeed"},
{"dlproto", "none", "none XonXoff EtxAck"},
#ifdef INET
{"bootp", "no", "no sec pri save"},
#endif
{"hostport", "tty0", 0},
{"inalpha", "hex", "hex symbol"},
{"inbase", INBASE_DEFAULT, INBASE_STRING},
#if NCMD_MORE > 0
{"moresz", "10", 0, chg_moresz},
#endif
{"prompt", "PMON> ", 0},
{"regstyle", "sw", "hw sw"},
#ifdef HAVE_QUAD
{"regsize", "32", "32 64"},
#endif
{"rptcmd", "trace", "off on trace"},
{"trabort", "^K", 0},
{"ulcr", "cr", "cr lf crlf"},
{"uleof", "%", 0},
#ifdef PMON_DEBUGGER /* XXX: Patrik temp */
{"validpc", "_ftext etext", 0, chg_validpc},
#endif
{"heaptop", SETCLIENTPC, 0, chg_heaptop},
{"showsym", "yes", "no yes"},
{"fpfmt", "both", "both double single none"},
{"fpdis", "yes", "no yes"},
#if defined(TGT_DEFENV)
TGT_DEFENV,
#endif
{0}
};
这个数组中最多放64个环境变量。(但是注意,能够自己定义的应该小于30,原因往下看)
他们的存储方式都是存放字符串指针。
环境变量就是以数组的形式存放在这个envvar数组中。
5.还有一些默认环境变量设置(代码中标识了8个)
也就是最多能自定义的是64-8= 56个? 不,还要减掉标准的环境变量表中的。
void tgt_mapenv(int (*func) __P((char *, char *))) //参数名注意一下,后面多次用到,就是setenv
{
char *ep;
char env[512];
char *nvram;
int i;
/*
* Check integrity of the NVRAM env area. If not in order
* initialize it to empty.
*/
printf("in envinit\n");
#ifdef NVRAM_IN_FLASH //从打印的结果看,这个宏定义被定义了
nvram = (char *)(tgt_flashmap())->fl_map_base;
printf("nvram=%08x\n", (unsigned int)nvram); //这句被打印了
if (fl_devident(nvram, NULL) == 0 || //返回值不是0
cksum(nvram + NVRAM_OFFS, NVRAM_SIZE, 0) != 0) { //返回值为0,if条件不成立
#else
nvram = (char *)malloc(512);
nvram_get(nvram);
if (cksum(nvram, NVRAM_SIZE, 0) != 0) {
#endif
printf("NVRAM is invalid!\n");
nvram_invalid = 1;
} else {
#ifdef NVRAM_IN_FLASH
nvram += NVRAM_OFFS; //执行这个语句
ep = nvram + 2;; //为什么加2,就简单了,看makefile.inc
while (*ep != 0) {
char *val = 0, *p = env;
i = 0;
while ((*p++ = *ep++) && (ep <= nvram + NVRAM_SIZE - 1)
&& i++ < 255) {
if ((*(p - 1) == '=') && (val == NULL)) {
*(p - 1) = '\0';
val = p;
}
}
if (ep <= nvram + NVRAM_SIZE - 1 && i < 255) {
(*func) (env, val);
// printf("2022-03-03 : env = %s val = %s ep = %x i = %d\n", env, val,ep,i);
} else {
nvram_invalid = 2;
// printf("2022-03-03 : nvram_invalid ep = %x i = %d\n", ep,i);
break;
}
}
#endif
}
printf("NVRAM@%x\n", (u_int32_t) nvram);
#ifdef NVRAM_IN_FLASH
printf("ACTIVECOM_OFFS = %d, = 0x%x\n", ACTIVECOM_OFFS, ACTIVECOM_OFFS);
printf("MASTER_BRIDGE_OFFS = %d, = 0x%x\n", MASTER_BRIDGE_OFFS,
MASTER_BRIDGE_OFFS);
printf("before :activecom = %d. em_enable = %d\n", activecom,
em_enable);
// printf("nuram[MASTER_BRIDGE_OFFS] = %d.\n" nvram[MASTER_BRIDGE_OFFS]);
if (!nvram_invalid)
bcopy(&nvram[ACTIVECOM_OFFS], &activecom, 1);
else
activecom = 3 /*1 */ ;
sprintf(env, "0x%02x", activecom);
(*func) ("activecom", env); /*tangyt */ //1.设置环境变量activecom
if (!nvram_invalid)
bcopy(&nvram[MASTER_BRIDGE_OFFS], &em_enable, 1);
else
em_enable = 3 /*1 */ ;
sprintf(env, "0x%02x", em_enable);
(*func) ("em_enable", env); /*tangyt */ //2.设置环境变量em_enable
printf("activecom = %d. em_enable = %d.\n", activecom, em_enable);
#endif
/*
* Ethernet address for Galileo ethernet is stored in the last
* six bytes of nvram storage. Set environment to it.
*/
bcopy(&nvram[ETHER_OFFS], hwethadr, 6); //ETHER_OFFS = 494,最后6个字节可以设置mac地址,实际是0
sprintf(env, "%02x:%02x:%02x:%02x:%02x:%02x", hwethadr[0], hwethadr[1],
hwethadr[2], hwethadr[3], hwethadr[4], hwethadr[5]);
(*func) ("ethaddr", env); //3. 设置环境变量ethaddr
#ifndef NVRAM_IN_FLASH
free(nvram);
#endif
#ifdef no_thank_you
(*func) ("vxWorks", env);
#endif
sprintf(env, "%d", memorysize / (1024 * 1024));
(*func) ("memsize", env); //4. 设置环境变量memsize
sprintf(env, "%d", memorysize_high / (1024 * 1024));
(*func) ("highmemsize", env); //5.0设置环境变量highmemsize
sprintf(env, "%d", md_pipefreq);
(*func) ("cpuclock", env); //6.设置环境变量 cpuclock
sprintf(env, "%d", md_cpufreq);
(*func) ("busclock", env); //7.设置环境变量 busclock
(*func) ("systype", SYSTYPE); //8.设置环境变量 systype
}
6. 看一下实际的环境变量
能自定义的环境变量,应该是低于34个。
否则会导致一些默认的环境变量无法解析出来。
分析结束。请各位指教。
自己生成一个env呢?写到flash的oxff000的偏移地址如何?
如果只是增加环境变量,是不是就可以不用编译pmon了?