快讯
HOME
快讯
正文内容
kernel nand分区 开发板制作开机LOGO就是这么简单
发布时间 : 2025-02-08
作者 : 小编
访问数量 : 23
扫码分享至微信

开发板制作开机LOGO就是这么简单

内核Linux -2.6.22.6

ubuntu :Ubuntu 9.10

开发板 : JZ2440(方法通用,不局限于JZ2440)

目的: JZ2440开机logo默认是一只可爱的小企鹅。我们把它替换成我们自己喜爱的图片

准备工作: 准备好BMP或者PNG 图片,若是别的格式的图片,可以使用Windows自带的画图软件打开,然后另存为BMP或者PNG格式Logo图片分辨率不小于JZ2440分辨率480*272,否则显示不了。

步骤:

1. 安装资料光盘Ubuntu 9.10没 有的图片转换工具netpbm$ sudo apt-get install netpbm 然后输入y //前提是ubuntu能上网

制作linux logo图片

2.假设图片为 jz2440.png(png格式图片) $ pngtopnm jz2440.png > jz2440.pnm

$ pnmquant 224 jz2440.pnm > logo224.pnm

$ pnmtoplainpnm logo224.pnm > logo_linux_clut224.ppm

假设图片为 jz2440.bmp(BMP格式图片)$ bmptopnm jz2440.bmp > jz2440.pnm

$ pnmquant 224 logo.pnm > logo224.pnm

$ pnmtoplainpnm logo224.pnm > logo_linux_clut224.ppm注意:转换后的文件名有规定,必须是logo_linux_clut224.ppm

3.生成的logo_linux_clut224.ppm就是我们需要的logo文件 ,把它拷贝到内核目录覆盖原来的logo文件$ cd /work/system/linux -2.6.22.6/drivers/video/logo/

$ cp /work/logo_linux_clut224.ppm . //笔者制作的logo文件在/work/目录

4.查看logo目录是否存在logo_linux_clut224.o的文件 ,如果有一定要删除!$ rm logo_linux_clut224.o

5.配置内核支持logo显示(如果内核用的是linux-2.6. 22.6_jz2440.patch补丁,默认已经支持logo显示)$ make menuconfigDevice Drivers —>Graphics support —>Console display driver support—><*>Framebuffer console supportBootup logo —><*> Standart 224-color linux logo

6.重新编译内核,烧写$make uImage把uIma ge上传到window tftp软件所在目录

进入开发板uboot,作一些必要设置, 以PING通windowset gatewayip 192.168.1.1 //设置网关set netmask 255.255.255.0 //设置子网掩码set ipaddr 192.168.1.111 //设置uboot阶段的开发板ipset serverip 192.168.1.170 //设置服务器iptftp 30000000 uImage //下载uImagenand erase kernel //擦除kernel分区nand write.jffs2 30000000 kernel //烧写uImage

因为笔者的文件系统在nfs上, 所以先设bootargsset bootargs noinitrd root=/dev/nfs nfsroot=192.168.1.199:/work/busybox-1.21.0/rootfs ip=192.168.1.100:192.168.1.199:192.168.1.255:255.255.255.0::eth0 init=/linuxrc console=ttySAC0,115200 //设置bootargssave //保存环境变量boot //启动开发板

效果:

您可能对以下内容感兴趣:

预热 | 万众期待的单片机,Linux二合一的STM32MP157开发板亮相

韦东山:嵌入式Linux学习路线图

了解更多

bootloader启动之「 lk - kernel」分析笔记

接上一篇分析: 《bootloader启动之【 Pre-loader -> Lk】》

Pre-loader 运行在ISRAM,待完成 DRAM 的初始化后,再将lk载入DRAM中,最后通过特殊sys call手段实现跳转到lk的执行入口,正式进入lk初始化阶段。

一. lk执行入口:

位于.text.boot 这个section(段),具体定义位置为:

./lk/arch/arm/system-onesegment.ld:10: .text.boot : { *(.text.boot) }./lk/arch/arm/system-twosegment.ld:10: .text.boot : { *(.text.boot) }

该段的代码执行入口是crt0.S文件,位置为:

./lk/arch/arm/crt0.S

crt0.S 中会经过一系列的初始化准备操作,最终跳转到C代码入口kmain函数开始执行,这个是 我们需要重点分析关注的,kmain的位置:

./lk/kernel/main.c

From Lk to Kernel 总时序图:

二. 源码分析:

1、crt0.S.section ".text.boot"....Lstack_setup: /* ==set up the stack for irq, fi==q, abort, undefined, system/user, and lastly supervisor mode */ mrs r0, cpsr bic r0, r0, #0x1f ldr r2, =abort_stack_top orr r1, r0, #0x12 // irq msr cpsr_c, r1 ldr r13, =irq_save_spot /* save a pointer to a temporary dumping spot used during irq delivery */ orr r1, r0, #0x11 // fiq msr cpsr_c, r1 mov sp, r2 orr r1, r0, #0x17 // abort msr cpsr_c, r1 mov sp, r2 orr r1, r0, #0x1b // undefined msr cpsr_c, r1 mov sp, r2 orr r1, r0, #0x1f // system msr cpsr_c, r1 mov sp, r2 orr r1, r0, #0x13 // supervisor msr cpsr_c, r1 mov sp, r2... bl kmain

crt0.S 小结:

这里主要干的事情就是建立fiq/irq/abort等各种模式的stack,初始化向量表,然后切换到管理模式(pre-loader运行在EL3, lk运行在EL1),最后跳转到C代码入口 kmain 执行。

2、kmain :

void kmain(void){ boot_time = get_timer(0); /* 早期初始化线程池的上下文,包括运行队列、线程链表的建立等, lk架构支持多线程,但是此阶段只有一个cpu处于online,所以也只有一条代码执行路径. */ thread_init_early(); /* 架构初始化,包括DRAM,MMU初始化使能,使能协处理器, preloader运行在ISRAM,属于物理地址,而lk运行在DRAM,可以选择开启MMU或者关闭,开启MMU可以加速lk的加载过程. */ arch_early_init(); /* 平台硬件早期初始化,包括irq、timer,wdt,uart,led,pmic,i2c,gpio等, 初始化平台硬件,建立lk基本运行环境。 */ platform_early_init(); boot_time = get_timer(0); // 这个是保留的空函数. target_early_init(); dprintf(CRITICAL, "welcome to lk\n\n"); /* 执行定义在system-onesegment.ld 描述段中的构造函数,不太清楚具体机制: __ctor_list = .; .ctors : { *(.ctors) } __ctor_end = .; */ call_constructors(); //内核堆链表上下文初始化等. heap_init(); // 线程池初始化,前提是PLATFORM_HAS_DYNAMIC_TIMER需要支持. thread_init(); // dpc系统是什么?据说是一个类似work_queue的东东,dpc的简称是什么就不清楚了. dpc_init(); // 初始化内核定时器 timer_init(); // 创建系统初始化工作线程,执行app初始化,lk把业务部分当成一个app. thread_resume(thread_create("bootstrap2", &bootstrap2, , DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); // 使能中断. exit_critical_section(); // become the idle thread thread_become_idle();}

kmain 小结:

初始化线程池,建立线程管理链表、运行队列等;

初始化各种平台硬件,包括irq、timer,wdt,uart,led,pmic,i2c,gpio等,建立lk基本运行环境;

初始化内核heap、内核timer等;

创建系统初始化主线程,进入bootstrap2执行,使能中断,当前线程进入idle;

3、bootstrap2 分析:

static int bootstrap2(void *arg){.../* 平台相关初始化,包括nand/emmc,LCM显示驱动,启动模式选择,加载logo资源, 具体代码流程如下时序图.*/ platform_init();.../* app初始化,跳转到mt_boot_init入口开始执行,对应的 ".apps" 这个section.*/ apps_init();return 0;}

platform_init 时序图:

这里的 apps_init 跳转机制还有点特别:

extern const struct app_descriptor __apps_start;extern const struct app_descriptor __apps_end;void apps_init(void){const struct app_descriptor *app;/* 这里具体干了什么?如何跳转到mt_boot_init入口?有点不知所云 依次遍历 从__apps_start 到__apps_end 又是什么东东? */for (app = &__apps_start; app != &__apps_end; app++) {if (app->init) app->init(app); }...}

这个__apps_start 跟 __apps_end哪里定义的?是怎么回事呢?这里就需要了解一点编译链接原理跟memory 布局的东东, 这个实际上是指memory中的一个只读数据段的起始&结束地址区间, 它定义在这个文件中:

./lk/arch/arm/system-onesegment.ld:47: __apps_start = .;.rodata : { ... . = ALIGN(4); __apps_start = .; KEEP (*(.apps)) __apps_end = .; . = ALIGN(4); __rodata_end = . ; }

该mem地址区间是[__apps_start, __apps_end],显然区间就是“.apps” 这个section内容了. 那么这个section是在哪里初始化的呢?继续看:

./lk/app/mt_boot/mt_boot.c:1724:APP_START(mt_boot).init = mt_boot_init, APP_END

展开APP_START:

#define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname,#define APP_END };

到这里就很明显了,编译链接系统会将mt_boot_init这个地址记录到".apps"这个section中!所以下面代码要干的事情就很清晰了,执行app->init(app)后就等价于调用了void mt_boot_init(const struct app_descriptor *app) 函数。

for (app = &__apps_start; app != &__apps_end; app++) {if (app->init) app->init(app);}

bootstrap2 函数小结:

平台相关初始化,包括nand/emmc,显现相关驱动,启动模式选择,加载logo资源 检测是否DA模式,检测分区中是否有KE信息,如果就KE信息,就从分区load 到DRAM, 点亮背光,显示logo,禁止I/D-cache和MMU,跳转到DA(??),配置二级cache的size 获取bat电压,判断是否低电量是否显示充电logo等,总之此函数干的事情比较多.时序图(platform_init)可以比较清晰直观的描述具体细节

跳转到到mt_boot_init函数,对应的 ".apps" 这个section,相关机制上面已经详细描述,不再复述。

4、mt_boot_init 分析

void mt_boot_init(const struct app_descriptor *app){unsigned usb_init = 0;unsigned sz = 0;int sec_ret = 0;char tmp[SN_BUF_LEN+1] = {0};unsigned ser_len = 0; u64 key; u32 chip_code;char serial_num[SERIALNO_LEN];/* 获取串号字符串 */ key = get_devinfo_with_index(13); key = (key << 32) | (unsigned int)get_devinfo_with_index(12);/* 芯片代码 */ chip_code = board_machtype();if (key != 0) get_serial(key, chip_code, serial_num);elsememcpy(serial_num, DEFAULT_SERIAL_NUM, SN_BUF_LEN);/* copy serial from serial_num to sn_buf */memcpy(sn_buf, serial_num, SN_BUF_LEN); dprintf(CRITICAL,"serial number %s\n",serial_num);/* 从特定分区获取产品sn号,如果获取失败就使用默认值 DEFAULT_SERIAL_NUM */#ifdef SERIAL_NUM_FROM_BARCODE ser_len = read_product_info(tmp);if (ser_len == 0) { ser_len = strlen(DEFAULT_SERIAL_NUM);strncpy(tmp, DEFAULT_SERIAL_NUM, ser_len); }memset( sn_buf, 0, sizeof(sn_buf));strncpy( sn_buf, tmp, ser_len);#endif sn_buf[SN_BUF_LEN] = '\0'; surf_udc_device.serialno = sn_buf;/* mtk平台默认不支持 fastboot */if (g_boot_mode == FASTBOOT)goto fastboot;/* secure boot相关 */#ifdef MTK_SECURITY_SW_SUPPORT#if MTK_FORCE_VERIFIED_BOOT_SIG_VFY g_boot_state = BOOT_STATE_RED;#elseif (0 != sec_boot_check(0)) { g_boot_state = BOOT_STATE_RED; }#endif#endif/* 这里干的事情就比较多了,跟进g_boot_mode选择各种启动模式,例如:normal、facotry、fastboot、recovery等,然后从ROM中的boot.img分区找到(解压)ramdisk跟zImage的地址loader到DRAM的特定地址中,kernel最终load到DRAM中的地址(DRAM_PHY_ADDR + 0x8000) == 0x00008000.read the data of boot (size = 0x811800)*/ boot_linux_from_storage();fastboot: target_fastboot_init();if (!usb_init)/*Hong-Rong: wait for porting*/ udc_init(&surf_udc_device); mt_part_dump(); sz = target_get_max_flash_size(); fastboot_init(target_get_scratch_address(), sz); udc_start();}

mt_boot_init 分析小结:

获取设备串号字符串、芯片代码、sn号等.

如果实现了secure boot则进行sec boot的check工作;

进入 boot_linux_from_storage 函数初始化,该函数很重要,干了很多事情,如下分析.

5、boot_linux_from_storage 分析:

int boot_linux_from_storage(void){int ret=0;...switch (g_boot_mode) {case NORMAL_BOOT:case META_BOOT:case ADVMETA_BOOT:case SW_REBOOT:case ALARM_BOOT:case KERNEL_POWER_OFF_CHARGING_BOOT:case LOW_POWER_OFF_CHARGING_BOOT:/* 检查boot分区的头部是否有bootopt标识,如果没有就报错 */ ret = mboot_android_load_bootimg_hdr("boot", CFG_BOOTIMG_LOAD_ADDR);if (ret < 0) { msg_header_error("Android Boot Image"); }/* 64bit & 32bit kimg地址获取不一样*/if (g_is_64bit_kernel) { kimg_load_addr = (unsigned int)target_get_scratch_address(); } else { kimg_load_addr = (g_boot_hdr!=) ? g_boot_hdr->kernel_addr : CFG_BOOTIMG_LOAD_ADDR; }/* 从EMMC的boot分区取出bootimage载入到DRAM dprintf(CRITICAL, " > from - 0x%016llx (skip boot img hdr)\n",start_addr); dprintf(CRITICAL, " > to - 0x%x (starts with kernel img hdr)\n",addr); len = dev->read(dev, start_addr, (uchar*)addr, g_bimg_sz); <<= 系统调用load到DRAM 开机log: [3380] > from - 0x0000000001d20800 (skip boot img hdr) [3380] > to - 0x80008000 (starts with kernel img hdr) */ ret = mboot_android_load_bootimg("boot", kimg_load_addr);if (ret < 0) { msg_img_error("Android Boot Image"); } dprintf(CRITICAL,"[PROFILE] ------- load boot.img takes %d ms -------- \n", (int)get_timer(time_load_bootimg));break;case RECOVERY_BOOT:...break;case FACTORY_BOOT:case ATE_FACTORY_BOOT:...break;... }/* 重定位根文件系统(ramdisk)地址 */memcpy((g_boot_hdr!=) ? (char *)g_boot_hdr->ramdisk_addr : (char *)CFG_RAMDISK_LOAD_ADDR, (char *)(g_rmem_off), g_rimg_sz); g_rmem_off = (g_boot_hdr!=) ? g_boot_hdr->ramdisk_addr : CFG_RAMDISK_LOAD_ADDR;.../* 传入cmdline,设置selinux */#if SELINUX_STATUS == 1 cmdline_append("androidboot.selinux=disabled");#elif SELINUX_STATUS == 2 cmdline_append("androidboot.selinux=permissive");#endif/* 准备启动linux kernel */ boot_linux((void *)CFG_BOOTIMG_LOAD_ADDR, (unsigned *)CFG_BOOTARGS_ADDR, (char *)cmdline_get(), board_machtype(), (void *)CFG_RAMDISK_LOAD_ADDR, g_rimg_sz);while (1) ;return 0;}

boot_linux_from_storage 小结:

跟据g_boot_mode选择各种启动模式,例如:normal、facotry、fastboot、recovery等,然后从EMMC中的boot分区找到(解压) ramdisk跟zImage的地址通过read系统调用load到DRAM址中, kernel最终load到DRAM的地址:(DRAM_PHY_ADDR + 0x8000);

重定位根文件系统地址;

跳转到 boot_linux,正式拉起kernel;

6、boot_linux 分析:

boot_linux 实际上跑的是boot_linux_fdt,这个函数有对dtb的加载做出来,期间操作相当复杂,这里只简单关注主流程。

void boot_linux(void *kernel, unsigned *tags,char *cmdline, unsigned machtype,void *ramdisk, unsigned ramdisk_size){...// 新架构都是走fdt分支.#ifdef DEVICE_TREE_SUPPORT boot_linux_fdt((void *)kernel, (unsigned *)tags, (char *)cmdline, machtype, (void *)ramdisk, ramdisk_size);while (1) ;#endif...int boot_linux_fdt(void *kernel, unsigned *tags,char *cmdline, unsigned machtype,void *ramdisk, unsigned ramdisk_size){...void (*entry)(unsigned,unsigned,unsigned*) = kernel;...// find dt from kernel imgif (fdt32_to_cpu(*(unsigned int *)dtb_addr) == FDT_MAGIC) { dtb_size = fdt32_to_cpu(*(unsigned int *)(dtb_addr+0x4)); } else { dprintf(CRITICAL,"Can't find device tree. Please check your kernel image\n");while (1) ; }...if (!has_set_p2u) {/* 控制进入kernel后uart的输出,非eng版本默认是关闭的,如果调试需要就可以改这里为 "printk.disable_uart=0" */#ifdef USER_BUILDsprintf(cmdline,"%s%s",cmdline," printk.disable_uart=1");#elsesprintf(cmdline,"%s%s",cmdline," printk.disable_uart=0 ddebug_query=\"file *mediatek* +p ; file *gpu* =_\"");#endif... }...// led,irq关闭 platform_uninit();// 关闭I/D-cache,关闭MMU,今天kernel的条件. arch_disable_cache(UCACHE); arch_disable_mmu();// sec initextern void platform_sec_post_init(void)__attribute__((weak));if (platform_sec_post_init) { platform_sec_post_init(); }// 如果是正在充电,检测到power key后执行reset.if (kernel_charging_boot() == 1) {if (pmic_detect_powerkey()) { dprintf(CRITICAL,"[%s] PowerKey Pressed in Kernel Charging Mode Before Jumping to Kernel, Reboot Os\n", __func__); mtk_arch_reset(1); } }#endif...// 输出关键信息。 dprintf(CRITICAL,"cmdline: %s\n", cmdline); dprintf(CRITICAL,"lk boot time = %d ms\n", lk_t); dprintf(CRITICAL,"lk boot mode = %d\n", g_boot_mode); dprintf(CRITICAL,"lk boot reason = %s\n", g_boot_reason[boot_reason]); dprintf(CRITICAL,"lk finished --> jump to linux kernel %s\n\n", g_is_64bit_kernel ? "64Bit" : "32Bit");// 执行系统调用,跳转到kernel,这里的entry实际上就是前面的kernel在DRAM的入口地址.if (g_is_64bit_kernel) { lk_jump64((u32)entry, (u32)tags, 0, KERNEL_64BITS); } else { dprintf(CRITICAL,"[mt_boot] boot_linux_fdt entry:0x%08x, machtype:%d\n",entry,machtype); entry(0, machtype, tags); }while (1);return 0;}

开机log打印信息:

[4260] cmdline: console=tty0 console=ttyMT0,921600n1 root=/dev/ram vmalloc=496M androidboot.hardware=mt6580 androidboot.verifiedbootstate=green bootopt=64S3,32S1,32S1 printk.disable_uart=1 bootprof.pl_t=1718 bootprof.lk_t=2178 boot_reason=0 androidboot.serialno=0123456789ABCDEF androidboot.bootreason=power_key gpt=1[4260] lk boot time = 2178 ms[4260] lk boot mode = 0[4260] lk boot reason = power_key[4260] lk finished --> jump to linux kernel 32Bit[4260] [mt_boot] boot_linux_fdt entry:0x80008000, machtype:6580

boot_linux 小结:

初始化DTB(device tree block);

准备各种cmdline参数传入kernel;

关闭I/D-cache、MMU;

打印关键信息,正式拉起kernel.

到这里,bootloader两个阶段就分析完了!

Bootloader 启动简单总结:

Pre-loader -》lk主要干的事情:

1、初始化 DRAM等必须硬件;

2、与flashtool USB握手,download 相关检测 & sec boot检测;

3、将lk载入DRAM,若实现了EL3则把atf载入内存;

4、跳转到lk,若实现了EL3,则先跳转到atf,初始化atf后再跳转回lk初始化;

lk -》 kernel 主要干的事情:

1、打开MMU,使能I/D-cache,加速lk执行,显示logo、充电相关;

2、从emmc中boot分区取出boot.img解压,将根文件系统(ramdisk)、zImage load到DRAM;

3、解析dtb,写入到DRAM指定区域;

4、关闭MMU、irq / fiq,关闭I/D-cache, 拉起 kernel;

5T技术资源大放送!包括但不限于:C/C++,Arm, Linux,Android,人工智能,单片机,树莓派,等等。在公众号内回复「peter」,即可免费获取!!

相关问答

内核 kernel 以及根文件系统rootfs是如何映射到对应的nandflash的?

n...需要修改Linux内核源码中的一个控制logbuffersize的宏:CONFIG_LOG_BUF_SHIFT,buffersize是2^shift,加大这个就可以。一...

国产芯片发展到什么水平了?

芯片制造的差距并不是单个方面,它是工艺的各个方面。许多智能手机或电脑都是中国制造,但是装有的中国“芯”却寥寥无几。以前国家对微电子的重视程度是不够的...

Android系统执行机制和碎片改变不了吗?为什么呢?

首先,我们需要知道为什么Android之前很容易卡顿。关于这个答案,一直以来都是众说纷纭,有人说Android卡是因为系统资源分配不均,有人说是因为用的越久垃圾文件...

F-ROM是什么样的存储媒介呢? - 冰湖凝心 的回答 - 懂得

FROM是FlashROM,是一种可以永久保存数据的存储体,掉电后数据不会丢失(10年以上!),FROM通常又分两种,一种是NORFROM,另一种是NANDFROM。NORFROM可以...

如何查看linux根 分区 下全部目录及文件的大小-ZOL问答

将文件系统通过tftp下载到开发板板,并写入到nandFlashtftpboot30000000fsroot.yaffs2nanderaserootnandwrite.yaffs0...

慧荣科技推出的SM3282主控怎么样?

近日召开的Computex2019大会上,慧荣科技(SiliconMotion)推出了首款适用于便携式USBSSD的单芯片主控--SM3282。该主控承诺为那些注重成本效益的移动硬盘提供...

ar7241和9344哪个好?

ar7241和9344都好,AR9344是业界顶尖的WLAN芯片厂商Atheros的新一代WLANSoC,内核为MIPS74Kc,主频高达533MHz,具有极高的集成度。适合开发无线路由器,无线A...

想配一台电脑预算在5-6k,应该如何配置?

您好!很荣幸为您解答问题!我是喜欢研究数码产品且电脑知识丰富的理工男小李,如果您喜欢我的分享,记得关注我哦!!根据您的需求,我会推荐给您这套配置,大概...固态...

酷比魔方I player什么芯片?

经过联系厂家,我们得知该芯片具有一下主要特点。ARM922TDMI微处理器内核(8KB数据缓存,8KB指令缓存);多种引导模式:NAND-Flash,UART及片外存储器CS0...AR....

混合硬盘好用吗?

感谢邀请,楼上“资深老顽童“的答案说出了重点,请参考。用过混合硬盘的,有很多觉得启动快了,打开软件也觉得快了,说明相对机械硬盘在这点上来说,还算是”...优...

 橙天娱乐  男人靠得住猪都能上树 
王经理: 180-0000-0000(微信同号)
10086@qq.com
北京海淀区西三旗街道国际大厦08A座
©2025  上海羊羽卓进出口贸易有限公司  版权所有.All Rights Reserved.  |  程序由Z-BlogPHP强力驱动
网站首页
电话咨询
微信号

QQ

在线咨询真诚为您提供专业解答服务

热线

188-0000-0000
专属服务热线

微信

二维码扫一扫微信交流
顶部