首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

vivi boot loader的实现

实现自己的s3c2410系统需要对bootloader修改的部分:
1. INTEL_CMD for MTD device  DONE
2. 常量FLASH_SIZE, ROM_SIZE, RAM_SIZE
3. linux_cmd[] != "noinitrd root=/dev/bon/2 init=/linuxrc console=ttyS0"; 改
mem=16M root=/dev/mtdblock2 init=/bin/init
来自89712 kernel的CONFIG_CMDLINE="mem=16M root=/dev/mtdblock2 init=/bin/init"。Arch/arm/setup.c

root =  MAJOR  MINOR MTD参数等等有关
4. Linux parameter的问题,如何传入,现有vivi用struct param_struct传入,我们应该改点什么才对;在CS89712的hermit-P2中,用的是struct tag传入,可是没打算boot;在EP7211的hermit中,打算boot,但是用的是param_struct;
Hermit-P1中用的也是tag
我们的系统在param或者tag里面传出自己flash/ram的特性 ft
 params->u1.s.rootdev = MKDEV(MTD_MAJOR, MTD_MINOR); //(31,3)

附录 一 CDB89712 linux中的有关参数
其中rootdev = (MTD_MAJOR,MTD_MINOR) = (31,3) /* i boot on /dev/mtd3 */ 
//    /dev/mtdblock3?  (31,3)
The default location for rootfs image is mtd3, put your image at the mtd3 start address (or modify the 'MTD_MINOR' variable in tags.h).
mtd3: 00400000 00020000 "cdb89712 flash free partition" ( starting at 0x400000, put your rootfs image here)

但是,干吗CONFIG_CMDLINE="mem=16M root=/dev/mtdblock2 init=/bin/init"
?? /dev/mtdblock2 (31,2)

呵呵,没法,只好自己试。
Struct mtd_partition {
 { bootloader  // /dev/mtdblock0 31 0
 },{ kernel   // /dev/mtdblock1 31 1
 },{ jffs2   // /dev/mtdblock2 31 2
 }
}

/dev/mtdblock 1 2 都试试
在2410的arch\arm\mach-s3c2410\smdk.c中

附录二  需要对kernel(zImage)和jffs2解压么?
vivi中boot_kernel可没有uncompress/decompress kernel的说

附录三 关于mtd partition在bootloader和kernel中的差别

在bootloader/ vivi中,为了方便 用户从命令行输入parameter参数,所以增加了一个param partition,;在bootloader后期,会将有关参数cp 到bootmem + LINUX_PARAM_OFFSET处。
而在kernel中,通常就用3个标准的partition:bootloader/kernel/ rootfs(e.g.jffs2)

linux kernel启动的入口处

MACHINE_START(SMDK2410, "Samsung-SMDK2410")
 //大清早刚进来,MMU还没启动呢
 BOOT_MEM(0x30000000, 0x48000000, 0xe8000000)
 //pram:0x30000000: physical start address of RAM
 //pio: 0x4800_0000 phy adrr of 8MB region containing IO for use with the debugging macros in arch/arm/kernel/debug-armv.S
 //vio: 0xe8000_0000 virtual address of the 8MB debugging region

 BOOT_PARAMS(0x30000100)
 //Physical address of struct param_struct or tag list, giving the kernel various parameters about its execution enviroment
 FIXUP(fixup_smdk)
 MAPIO(smdk_map_io)
 INITIRQ(s3c2410_init_irq)
MACHINE_END

51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)

附录 关于do_map_probe

在vivi中,没有支持jedec_probe //command_set001,所以我们自己增加了intel_flash.c etc

在kernel中,对jedec_probe的支持没有问题,command_set0001也存在,所以我们可以完全不理会下层的实现,专心将drivers/mtd/maps/cdb89712.c改造成smdk2410.c就可以了.
cdb89712.c中有关将片内SRAM和BOOT_ROM映射为MTD的部分不理会。

注意在config.in中增加相应的:CONFIG_MTD_SMDK2410


附录 param_struct 与tag_list的对比

以下代码来自testasecca的boot-patch for  89712
http://ttestasecca.free.fr/cdb89712/patch/boot_patch
cdb89712/kernel/arch/boot/compressed/misc.c

int hermit_linux_cmdfunc(int argc, char *argv[]) 
{
        struct tag *tag = (struct tag *) LINUX_PARAM_ADDRESS;

        /* zero param block */
        memzero (tag, LINUX_PARAM_SIZE);

        /* set up core tag */
        tag->hdr.tag = ATAG_CORE;
        tag->hdr.size = tag_size(tag_core);
        tag->u.core.flags = 0;
        tag->u.core.pagesize = 0x1000;
        tag->u.core.rootdev = MKDEV(MTD_MAJOR, MTD_MINOR);

        /* 16 MB of SDRAM at 0xc0000000 */
        tag = tag_next(tag);
        tag->hdr.tag = ATAG_MEM;
        tag->hdr.size = tag_size(tag_mem32);
        tag->u.mem.size = DRAM1_SIZE >> 12;
        tag->u.mem.start = DRAM1_START;

        /* an initial ramdisk image in flash at 0x00700000 */
/*      tag = tag_next(tag);
        tag->hdr.tag = ATAG_INITRD;
        tag->hdr.size = tag_size(tag_initrd);
        tag->u.initrd.start = INITRD_LOAD_ADDRESS;
        tag->u.initrd.size  = INITRD_SIZE; */
        /* the command line arguments */

/*      if (argc > 1) {
                tag = tag_next(tag);
                tag->hdr.tag = ATAG_CMDLINE;
                tag->hdr.size = (COMMAND_LINE_SIZE + 3 +
                         sizeof(struct tag_header)) >> 2;

                {
                        const unsigned char *src;
                        unsigned char *dst;
                        dst = tag->u.cmdline.cmdline;
                        memzero (dst, COMMAND_LINE_SIZE);
                        while (--argc > 0) {
                                src = *++argv;
                                hprintf ("Doing %s\n", src);
                                while (*src)
                                        *dst++ = *src++;
                                *dst++ = ' ';
                        }
                        *--dst = '\0';
                }
        }
*/


        tag = tag_next(tag);
        tag->hdr.tag = 0;
        tag->hdr.size = 0;

        /* branch to kernel image */
        __asm__ volatile (
        "       mov     r4, #0x00000000\n"      /* start of flash */
        "       add     r4, r4, #0x00020000\n"  /* kernel offset in flash*/
        "       mov     r0, #0\n"               /* kernel sanity check */
        "       mov     r1, #107\n"             /* CDB89712 arch. number */
        "       mov     r2, #0\n"
        "       mov     r3, #0\n"
//        "       mov     pc, r4"                 /* go there! */
        );

        /* never get here */
        return 0;
}

51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)

问题:
除了通过linux-parameter把kernel所在区域传入boot-kernel了之外,root.cramfs的partition分区信息怎么传入的呢?
答案
smdk.c cmd line? linux_cmd[] = "noinitrd root=/dev/bon/2 init=/linuxrc console=ttyS0"; //呵呵,考,躲这里的说
这里用的虽然是root=/dev/bon/2,但是
悖论“linux的设备都是在/dev/下,访问这些设备文件需要设备驱动程序支持,而访问设备文件才能取得设备号,才能加载驱动程序,那么第一设备驱动程序是怎么加载呢”
答案ROOT_DEV,不需要访问设备文件,直接制定设备号。
就是是直接用设备号(bon,2),它的partition信息在哪里?在bootloader中虽然用vivi> bon part 0 192k 2M做了分区,part2就是 for root的,但这些信息并不会传入kernel,除非。。??

cramfsck打开root.cramfs,看看里面的bon/2的定义,是否有init script完成分区
“Let's write root filesystem in SMC. The steps of this work are the same as those of above. But there is one caution.
vivi can't write the root image, which size is bigger than 1.2MB, on SMC. Because vivi is coded to use decided partition size of bon filesystem that is a kinds of layer for nand flash, although it controls all area of SMC. The decided size is approximately 1.2~1.3MB.
So, please use small size of root image when writing root filesystem on SMC. If you have finished this work well and rebooted target system, you can use the console of target system.”
这就是为啥 vivi首先用自己做SMC partition, writing (1) vivi (2) kernel (3)root.cramfs<1.3M
然后用Ztelent/minicom 下载root_qtopia.cramfs, 用imagewrite把image写入NAND,大约有40M
drivers/mtd/nand/bon.c
int __init part_setup(char *options)
{
    if (!options || !*options) return 0;
    PARTITION_OFFSET = simple_strtoul(options, &options, 0);
    if (*options == 'k' || *options == 'K') {
 ARTITION_OFFSET *= 1024;
    } else if (*options == 'm' || *options == 'M') {
 ARTITION_OFFSET *= 1024;
    }
    return 0;
}
__setup("nand_part_offset=", part_setup);

虽然vivi/drivers/mtd/nand/bon.c中有comand_part命令能够将在vivi命令行中输入的bon命令划分bon,但是这些partition参数可没看见被传入kernel such as param_struct/a_tag

终于搞清楚了,
在VIVI中,在bon划分partition时,在offset = mtd->size - mtd->erasesize 最后一块eraseblock中,写入了BON_MAGIC (8BYTE), PARTITION INFO
vivi/drivers/mtd/bon.c
write_partition()
 memcpy(buf, bon_part_magic, 8);
 s = (unsigned int *)(buf+8);
 *s++ = num_part;
 for (i = 0; i < num_part; i++) {
  *s++ = parts.offset;
  *s++ = parts.size;
  *s++ = parts.flag;
 }
在kernel中linux/drivers/mtd/nand/bon.c
read_partition_info()
 if (MTD_READ(mtd, offset, 512, &retlen, buf) < 0) {
     goto next_block;
 }
 if (strncmp(buf, BON_MAGIC, 8) == 0) break;
然后是:   s = (unsigned int *)(buf + 8);
   for(i=0;i < bon.num_part; i++) {
 char name[8];
// int num_block;
 bon.parts.offset = *s++;
 bon.parts.size = *s++;
 bon.parts.flag = *s++;
}

51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)


附录五 关于__setup 在内核中的作用 ,参考linux\init\main.c
以下内容来自
jeppeter (member) from http:// linuxforum.net


你的这个问题,我从google上查找到了一些资料,再结合内核源代码,就在这里把这个问题说的清楚一点.
首先,这里有一个简短的回答,
http://mail.nl.linux.org/kernelnewbies/2003-03/msg00043.html

从这上面的意思是这里会从main.c 中的checksetup函数中运行,这个函数是这样的

static int __init checksetup(char *line)
{
struct kernel_param *p;

p = &__setup_start;
do {
int n = strlen(p->str);
if (!strncmp(line,p->str,n)) {
if (p->setup_func(line+n))
return 1;
}
p++;
} while (p < &__setup_end);
return 0;
}

这里的意思是从__setup_start开始处到__setup_end处中查找一个数据结构,这个数据结构中有str与setup_func这两个数据成员变量.
只要与这里面的str与输入的参数字符串相匹配,就会调用个这个字符串后面所指的内容,
对于你这里所说的 __setup("console=",console_setup); 就是你在启动linux内核的时候如果有这么一个参数输入console=ttyS1,那内核就会
把默认的tty定位为ttyS1,这个在consol_setup函数的字符串处理中完成,因为它最后是确定prefered_console的参数.


那把这在这里实现这个的内容是这样的,

__setup() 是一个宏定义,在include/linux/init.h这个文件中.
struct kernel_param {
const char *str;
int (*setup_func)(char *);
};

extern struct kernel_param __setup_start, __setup_end;

#define __setup(str, fn) \
static char __setup_str_##fn[] __initdata = str; \
static struct kernel_param __setup_##fn __attribute__((unused)) __initsetup = { __setup_str_##fn, fn }

在这个情景中作了替换是这样的

static char __setup_str_console_setup[] = "console=";
static struct kernel_param __setup_console_setup = { __setup_str_console_setup, console_setup}

这样你还可能不是很清楚,那你就要参考arch/i386/vmlinuz.lds这个关于ld 链接器的脚本文件有这样的一段

__setup_start = .;
.setup.init : { *(.setup.init) }
__setup_end = .;


这里的意思就是__setup_start是一个节的开始,而__setup_end是一个节的结束,这个节的名称是.setup,init,
这个你可以用readelf -a这个来看一下你的vmlinux-2.4.20-8(后面的数字与你的内核版本有关)这个文件,
可以看到有一个叫.setup.init的节,__setup_start就是指这个节的开始,那这个节中有什么内容呢,其实就是一个
数据结构,一个就是str,一个就是setup_func,与我前面的说法相一致,那具体是什么呢,就是一个在.init.data节中存储的
字符串-----__initdata是一个宏,就是(__attribute__ ((__section__ (".data.init")))), 所以你可以.data.init在vmlinux-2.4.20-8中的
在文件中的偏移量与加载的的虚拟地址偏移量相减就可以得到,
举个例子,所有的这些都是用readelf 与od 命令得到的
我现在用的内核版本,它的.setup.init的节在0x26dd60的文件偏移处.
[10] .data.init PROGBITS c0368040 268040 005d18 00 WA 0 0 32
[11] .setup.init PROGBITS c036dd60 26dd60 0001b0 00 WA 0 0 4

再查找console_setup在vmlinux-2.4.20-8所被映射为内存地址,
840: c0355d40 343 FUNC LOCAL DEFAULT 9 console_setup

这就可以知道了它所在的位置,就是0xc0355d40,这就是它的虚拟映射地址

再用下面一条命令
od --address-radix=x -t x4 vmlinux-2.4.20-8 |grep -A 20 26dd60 |head -20 | grep c0355d40
可以得到
26de40 c036943b c0355d10 c0369447 c0355d40

很明显,这个函数的处理字符串在内存中的地址是0xc0369447,与前面得到的.data.init节在内存映射中的位置
0xc0368040相减就是 0x1407,与.data.init在文件中的偏移量0x268040相加就得到0x269447
这样用
od --address-radix=x -a vmlinux-2.4.20-8 |grep -A 2 269440

就可以得到下面的内容,
269440 b l i n k = nul c o n s o l e = nul
269450 r e s e r v e = nul nul nul nul nul nul nul nul
269460 ` dc4 6 @ ` dc4 6 @ c p u f r e q =

"console="这个值果真就在这里.

(注:前面od 的选项 --address-radix= 表示的是显示文件偏移量的格式,默认下是o就是八进制, -t 表示显示文件二进制的形式
默认是o6 就是八进制的6位长,而-a表示显示的是字符串格式.)
这是一点感受,与大家分享,希望大家提出宝贵意见.

51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)

谢谢,下下来 看看

下来看看!!!!!!

相當實用,謝謝![em17]
看看,老兄,辛苦了。
wo ding
thxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

好贴。

OK

下来看看多谢

多谢
kankan
not bad
返回列表