- 论坛徽章:
- 0
|
仅以此文纪念自己的程序员生涯的开端!
故事源于一个刚毕业的学生,也就是本故事的主人公作者,废话少说,开始故事:
2011年2月21号:
也就是今天我带着喜悦和莫名的伤感来到一个牛逼的公司报道,开始我正式的程序员生涯,作为一个新人来讲,那个时候我觉得刚开始肯定会有很多人指导你的工作,可是报道之后才发现一切都靠自己,没有人主动指导你什么,只有你不懂的时候自己找适合的人去问,所以基本也是很重要的,好,开始说项目吧。
需求分析:
在嵌入式linux中一般我们更新内核和rootfs的时候,都需要再UBOOT的支持下才能更新,而且要输入一大串的命令,这样比较不方便,因此我们尝试在内核运行的时候直接将内核和rootfs更新掉,(在本文中Uboot,kernel,rootfs都存放在nor flash)
本文的nor flash容量为16M,其地址
ff000000 ~ ff03ffff UBOOT
ff060000 ~ ff11ffff Kernel
ff120000 ~ ffffffff filesystem
看完需求分析,我的头脑一片空白,说实在话:因为我不知道什么叫nor flash?nand flash?当然刚开始最好的方法就是google and baidu. After google and baidu之后我大概了解nor flash是一种字符设备,按照我以前所学的知识来理解:既然作为一种设备,那么在linux下设备都可以作为文件存在,那么在Linux中写文件和都文件那岂不是很简单吗?说是迟那是快我就有了下面的想法:
1. 首先我可以把nor flash作为一个设备文件打开,通过open调用,返回一个设备文件描述符fd1
2. 将kernel文件或者filesystem文件下载到嵌入式系统中去(注意:这里的kernel文件和filesystem文件是要去更新nor flash中的文件)
3. open下载进去的kernel文件或者filesystem文件,返回一个文件描述符fd2
4. 然后通过mmap调用将fd1中要替换的区域映射到进程地址空间,mmap返回一个虚拟地址addr1
5. 将第三步open的文件fd2也通过mmap映射到进程地址空间,mmap返回一个虚拟地址add2
6. 已经知道addr1和addr2,接下来更新文件的工作就相当于字符串拷贝的工作,很简单
为了安全起见,我并没有直接按照上面的步骤来,我怕如果此方法不通,会把kernel区域破坏掉,我想先试试能不能将nor flash中的kernel区域的前16字节 都出来,开和kernel文件中的前16字节是否一致,如果一致,那至少证明这种方式可以读Nor flash的区域,那就有了我的程序员生涯的第一个程序:
1.首先通过一个宏定义nor flash中kernel的地址和大小:
#define KERNEL_START_ADDR 0xff060000
#define KERNEL_SIZE 0x000c0000 //768k
2.打开nor flash设备文件,在本系统中nor flash对应的设备文件名/dev/mem,然后将设备文件映射到进程地址空间中,返回的虚拟地址起始地址kernel_map_addr
kernel_fd = open("/dev/mem",O_RDWR|O_SYNC);
kernel_map_addr=(char*)mmap(NULL,KERNEL_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,kernel_fd,KERNEL_START_ADDR);
3.打印nor flash文件kernel区域的前16个字节,与kernel.img文件的前16个字节比较一下开是否读的对:
for(i=0;i<16;i++)
{
printf("%x",rootfs_map_addr);
printf("\n");
}
这边小小的提示一下打印的时候要用”%x”,我一开始用的是”%c”,出了很多乱码,为什么会出乱码我相信读者朋友肯定知道为什么了?如果不知道大家google一下吧!
经过上面的步骤我发现;我读出的内容和kernel.img文件的前16个字节一致 ,那证明我的程序可以读nor flash任意区域的想法是对的。下面我把代码贴出来,代码中我是分别读三个区域都进行验证的。其他区域的方法和上面提到的方法是一致的。
补充一下:如果读者对Linux中设备可以作为文件来读写的机制不了解可以去google一下,或者对mmap系统调用不是很了解的也可以去google一下,其实mmap操作我也是临时google的,才了解的
题外话:其实这天我一直搞到夜里1点多钟才休息的,刚开始程序员的生涯,就这么惨了,因为第一天我都不知道什么是交叉编译,只是以前听说过,也不知道我开发的平台是什么,就为了搞开发平台我就搞了一上午,哎,新人就是惨啊,不过第一天抗过来了,有了这么大的收获还是蛮幸福的!兄弟姐妹肯定会怀疑:心里肯定会想,作者不是写字符驱动吗?怎么现在一点也没有,在这里我做个保证,到第三天肯定会有的,我之所以这样写的原因有三个:
第一:记录一下我做一个项目从无到有的经历
第二:让大家了解做这个项目的研究的思路
第三:与大家分享我遇到问题时候解决问题的思路,我觉得第三点是最重要的
- /********************************** Include ********************************/
- #include<stdarg.h>
- #include<stdlib.h>
- #include<string.h>
- #include<stdio.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <assert.h>
- #include <time.h>
- #include <sys/ioctl.h>
- #include <sys/mman.h>
- /********************************** Define *********************************/
- #define UBOOT_START_ADDR 0xff000000
- #define UBOOT_SIZE 0x00040000 //256k
- #define KERNEL_START_ADDR 0xff060000
- #define KERNEL_SIZE 0x000c0000 //768k
- #define ROOTFS_START_ADDR 0xff120000
- #define ROOTFS_SIZE 0x00ee0000 //15232k
- /****************************** Local Variable *****************************/
- static int uboot_fd;
- static int kernel_fd;
- static int rootfs_fd;
- volatile char *uboot_map_addr;//address from using mmap()
- volatile char *kernel_map_addr;
- volatile char *rootfs_map_addr;
- /****************************** Extern Variable ****************************/
- /****************************** Local Function *****************************/
- static int openMemRW(void);
- static void closeMemRW(void);
- /********************************* Code ************************************/
- int main(int argc, char* argv[])
- {
- // if(argc<1)
- // {
- // printf("parameter error!\n");
- // return -1;
- // }
- // -----------------------------------------------------------
- // Step 1, open /dev/mem to access NOR FLASH
- // -----------------------------------------------------------
- int len,i;
-
- len=strlen(argv[1])+1;
-
- for(i=0;i<len;i++)
- printf("%c\n",argv[1][i]);
-
- if(openMemRW()<0)
- {
- printf("openMemRW fail\n");
- return -1;
- }
- closeMemRW();
- return 0;
- }
- static int openMemRW(void)
- {
- int i;
-
- //将NOR FLASH的uboot区域映射到进程空间,以便以后直接通过访问映射的进程区域来访问uboot区域
- uboot_fd = open("/dev/mem",O_RDWR|O_SYNC);
- if(uboot_fd < 0)
- {
- printf("open /dev/mem failed!\n");
- return -1;
- }
- uboot_map_addr = (char *)mmap(NULL,UBOOT_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,uboot_fd,UBOOT_START_ADDR);
- if(uboot_map_addr == NULL)
- {
- printf("openMemRW ERROR : mmap fd=%d failed!\n",uboot_fd);
- close(uboot_fd);
- return -1;
- }
- printf("uboot_map_addr=%x\n",uboot_map_addr);
-
- for(i=0;i<16;i++)
- {
- printf("%x ",uboot_map_addr[i]);
- printf("\n");
- }
- printf("__uboot_map_addr=%x\n",&uboot_map_addr[i]);
- // printf("usage:%s string\n",uboot_map_addr);
- //将NOR FLASH的kernel区域映射到进程空间,以便以后直接通过访问映射的进程区域来访问kernel区域
- kernel_fd = open("/dev/mem",O_RDWR|O_SYNC);
- if(kernel_fd < 0)
- {
- printf("open /dev/mem failed!\n");
- return -1;
- }
- kernel_map_addr = (char *)mmap(NULL,KERNEL_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,kernel_fd,KERNEL_START_ADDR);
- if(kernel_map_addr == NULL)
- {
- printf("openMemRW ERROR : mmap fd=%d failed!\n",kernel_fd);
- close(kernel_fd);
- return -1;
- }
- printf("kernel_map_addr=%x\n",kernel_map_addr);
-
- for(i=0;i<16;i++)
- {
- printf("%x",kernel_map_addr[i]);
- printf("\n");
- }
- printf("__kernel_map_addr=%x\n",&kernel_map_addr[i]);
- //printf("usage:%s string\n",kernel_map_addr);
- //将NOR FLASH的ROOTFS区域映射到进程空间,以便以后直接通过访问映射的进程区域来访问ROOTFS区域
- rootfs_fd = open("/dev/mem",O_RDWR|O_SYNC);
- if(rootfs_fd < 0)
- {
- printf("open /dev/mem failed!\n");
- return -1;
- }
- rootfs_map_addr = (char *)mmap(NULL,ROOTFS_SIZE ,PROT_READ|PROT_WRITE,MAP_SHARED,rootfs_fd,ROOTFS_START_ADDR);
- if(rootfs_map_addr == NULL)
- {
- printf("openMemRW ERROR : mmap fd=%d failed!\n",rootfs_fd);
- close(rootfs_fd);
- return -1;
- }
- printf("rootfs_map_addr=%x\n",rootfs_map_addr);
- for(i=0;i<16;i++)
- {
- printf("%x",rootfs_map_addr[i]);
- printf("\n");
- }
- printf("__rootfs_map_addr=%x\n",&rootfs_map_addr[i]);
- //printf("usage:%s string\n",rootfs_map_addr);
- return 0;
- }
- //关闭映射
- static void closeMemRW(void)
- {
-
- munmap((void*)uboot_map_addr,UBOOT_SIZE);
- close(uboot_fd);
-
- munmap((void*)kernel_map_addr,KERNEL_SIZE);
- close(kernel_fd);
-
- munmap((void*)rootfs_map_addr,ROOTFS_SIZE);
- close(rootfs_fd);
- }
复制代码 |
评分
-
查看全部评分
|