113.龙芯2k1000-pmon(12)- pmon源码对env的解析

2024-03-02 04:28

本文主要是介绍113.龙芯2k1000-pmon(12)- pmon源码对env的解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文回答前文思考的问题 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 ||  //返回值不是0cksum(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 ||  //返回值不是0cksum(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.incwhile (*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) { //使用名字查询,是否在标准环境变量表中,不存在返回0if (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);  //不相等则提示使用原来的默认值,而提示新的值是badreturn 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 ||  //返回值不是0cksum(nvram + NVRAM_OFFS, NVRAM_SIZE, 0) != 0) { //返回值为0,if条件不成立
#elsenvram = (char *)malloc(512);nvram_get(nvram);if (cksum(nvram, NVRAM_SIZE, 0) != 0) {
#endifprintf("NVRAM is invalid!\n");nvram_invalid = 1;} else {
#ifdef NVRAM_IN_FLASHnvram += NVRAM_OFFS;   //执行这个语句ep = nvram + 2;;    //为什么加2,就简单了,看makefile.incwhile (*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_FLASHprintf("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);elseactivecom = 3 /*1 */ ;sprintf(env, "0x%02x", activecom);      (*func) ("activecom", env);	/*tangyt */    //1.设置环境变量activecomif (!nvram_invalid)bcopy(&nvram[MASTER_BRIDGE_OFFS], &em_enable, 1);elseem_enable = 3 /*1 */ ;sprintf(env, "0x%02x", em_enable);(*func) ("em_enable", env);	/*tangyt */      //2.设置环境变量em_enableprintf("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地址,实际是0sprintf(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_FLASHfree(nvram);
#endif#ifdef no_thank_you(*func) ("vxWorks", env);
#endifsprintf(env, "%d", memorysize / (1024 * 1024));(*func) ("memsize", env);     //4. 设置环境变量memsizesprintf(env, "%d", memorysize_high / (1024 * 1024));(*func) ("highmemsize", env);   //5.0设置环境变量highmemsizesprintf(env, "%d", md_pipefreq);(*func) ("cpuclock", env);      //6.设置环境变量 cpuclocksprintf(env, "%d", md_cpufreq);(*func) ("busclock", env);      //7.设置环境变量 busclock(*func) ("systype", SYSTYPE);   //8.设置环境变量 systype  }

6.  看一下实际的环境变量

能自定义的环境变量,应该是低于34个。

否则会导致一些默认的环境变量无法解析出来。

分析结束。请各位指教。

自己生成一个env呢?写到flash的oxff000的偏移地址如何?

如果只是增加环境变量,是不是就可以不用编译pmon了?

这篇关于113.龙芯2k1000-pmon(12)- pmon源码对env的解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/764903

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

OWASP十大安全漏洞解析

OWASP(开放式Web应用程序安全项目)发布的“十大安全漏洞”列表是Web应用程序安全领域的权威指南,它总结了Web应用程序中最常见、最危险的安全隐患。以下是对OWASP十大安全漏洞的详细解析: 1. 注入漏洞(Injection) 描述:攻击者通过在应用程序的输入数据中插入恶意代码,从而控制应用程序的行为。常见的注入类型包括SQL注入、OS命令注入、LDAP注入等。 影响:可能导致数据泄

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。