vivi中main()的第6步就是初始化参数。 这里所谓的参数包括如下:
1. 分区表
mtd_partition_t
default_mtd_partitions[] = {
{
name: "vivi", //分区名
offset: 0, //起始位置
size: 0x00020000, //大小
flag: 0 //标志位
}, {
name: "param",
offset: 0x00020000,
size: 0x00010000,
flag: 0
}, {
name: "kernel",
offset: 0x00030000,
size: 0x000C0000,
flag: 0
}, {
name: "root",
offset: 0x00100000,
size: 0x00140000,
flag: MF_BONFS
}
};
|
2. 参数。这些参数都是非常有用的。在随后的启动过程中都要用到其中的某些量。比如boot_delay,就是vivi最后延时等待键盘输入的时间参数;media_type指的就是存储类型,这里的MT_S3C2410在预定义中为3,即NAND_FLAHS启动。
vivi_parameter_t
default_vivi_parameters[] = {
{ "mach_type", MACH_TYPE, NULL }, /* 193 */
{ "media_type", MT_S3C2410, NULL }, /* 3 */
{ "boot_mem_base", 0x30000000, NULL },
{ "baurate", UART_BAUD_RATE, NULL },
{ "xmodem_one_nak", 0, NULL },
{ "xmodem_initial_timeout", 300000, NULL },
{ "xmodem_timeout", 1000000, NULL },
{ "ymodem_initial_timeout", 1500000, NULL },
{ "boot_delay", 0x1000000, NULL }
};
|
3. linux命令。其实这个命令只是一个字符串
char linux_cmd[] = "noinitrd root=/dev/bon/2 init=/linuxrc console=ttyS0";
|
ok,看了这三个参数之后,继续来看下它们是如何被写到sdram的特定位置的。它们被写到sdram的特定位置,然后要用到这些参数时,我们再到sdram的这个特定位置去找到它。这些都是预先定好的。
/*
* 在我们的定义参数头文件里有如下的定义,可以根据它们的值将这些参数的存储位置列出来。
* +---------------+ -> 高地址
* | LINUX_CMD 16K |
* +---------------+
* | PARAMETER 16K |
* +---------------+
* | PARTITION 16K |
* +---------------+ -> VIVI_PRIV_RAM_BASE = 0x33dfc000 - 48k
*/
#define MTD_PART_SIZE SZ_16K
#define MTD_PART_OFFSET 0x00000000
#define PARAMETER_TLB_SIZE SZ_16K
#define PARAMETER_TLB_OFFSET 0x00004000
#define LINUX_CMD_SIZE SZ_16K
#define LINUX_CMD_OFFSET 0x00008000
#define VIVI_PRIV_SIZE (MTD_PART_SIZE + PARAMETER_TLB_SIZE + LINUX_CMD_SIZE) /* 16k + 16k + 16k */
|
现在从头来分析。
/*
* Step 6:
*/
init_priv_data();
putstr("Succeed priv_data initialization\r\n");
|
init_priv_data中
get_default_priv_data就是将我们程序里上面定义的那两个结构表和一个命令字符串复制到sdram指定位置去。
load_saved_priv_data会从存储设备中将参数取出然后放到sdram的指定位置,这些参数是我们设置后保存于存储设备里的。如果这一步成功,则它会覆盖掉前面
get_default_priv_data放置的默认参数。
int
init_priv_data(void)
{
int ret_def;
int ret_saved;
ret_def = get_default_priv_data();
ret_saved = load_saved_priv_data();
/* 根据函数返回标志来判断此次使用的参数是default parameters 还是 stored parameters */
if (ret_def && ret_saved) {
printk("Could not found vivi parameters.\n");
return -1;
} else if (ret_saved && !ret_def) {
printk("Could not found stored vivi parameters.\n");
printk("Use default vivi parameters.\n");
} else
printk("Found saved vivi parameters.\n");
/* 最后将上面的参数表和分区表通过串口打印出来,这样我们在minicom里面就能看到了*/
display_param_tlb();
display_mtd_partition();
return 0;
} |
可以看到,第6步做的工作还是比较简单的。复制这些参数时,注意要将它们的位置放对就行。具体来看一下:
static inline int
get_default_priv_data(void)
{
if (get_default_param_tlb()) //取参数表
return NO_DEFAULT_PARAM;
if (get_default_linux_cmd()) //取Linux命令,即上面提到的那个字符串
return NO_DEFAULT_LINUXCMD;
if (get_default_mtd_partition()) //取分区参数
return NO_DEFAULT_MTDPART;
return 0;
}
|
分别看一下上面这个函数所调用的三个子函数。最后在sdram里的实现为:
* +---------------+ -> 高地址
* | LINUX_CMD 16K |
* +---------------+
* | PARAMETER 16K |
* +---------------+
* | PARTITION 16K |
* +---------------+ -> VIVI_PRIV_RAM_BASE = 0x33dfc000 - 48k
(1)
get_default_param_tlb
static int
get_default_param_tlb(void)
{
char *src = (char *)&default_vivi_parameters; //参数数据结构的地址
char *dst = (char *)(VIVI_PRIV_RAM_BASE + PARAMETER_TLB_OFFSET); //sdram中要写入的位置
int num = default_nb_params; // default_vivi_parameters是一个数组,其每个成员都是 vivi_parameter_t 。 default_nb_params即为这个数组中的元素( vivi_parameter_t
)个数
if (src == NULL)
return -1;
*(nb_params) = num;//将元素个数保存起来,因为这个值在以后要用到。
// 确认这里的 参数结构总长度要小于16k,即我们预定的大小
if ((sizeof(vivi_parameter_t) * num) > PARAMETER_TLB_SIZE) {
printk("Error: too large partition table\n");
return -1;
}
// 这里的很多值都是预先指定好的。在预定的16k中,前16个字节拿来放置幻数。
memcpy(dst, vivi_param_magic, 8); /* V I V I P A R A */
dst += 16;
memcpy(dst, src, (sizeof(vivi_parameter_t) * num)); //然后把整个参数数据结构都复制到sdram里
return 0;
}
|
(2)
get_default_linux_cmd
static int
get_default_linux_cmd(void)
{
char *src = linux_cmd;
char *dst = (char *)(VIVI_PRIV_RAM_BASE + LINUX_CMD_OFFSET);
if (src == NULL)
return -1;
memcpy(dst, linux_cmd_magic, 8); /* V I V I C M D L */
dst += 8;
memcpy(dst, src, (strlen(src) + 1));
return 0;
}
|
(3)
get_default_mtd_partition
static int
get_default_mtd_partition(void)
{
char *src = (char *)&default_mtd_partitions;
char *dst = (char *)(VIVI_PRIV_RAM_BASE + MTD_PART_OFFSET);
int num = default_nb_part;
if (src == NULL)
return -1;
*(nb_mtd_parts) = num;
if ((sizeof(mtd_partition_t) * num + 16) > MTD_PART_SIZE) {
printk("too large mtd partition table\n");
return -1;
}
memcpy(dst, mtd_part_magic, 8); /* V I V I M T D P */
dst += 16;
memcpy(dst, src, (sizeof(mtd_partition_t)*num));
return 0;
}
|
认真分析完第一个之后,后面两个就大同小异了。注意:每一次都会在预定位置的前几个字节放置几个字节的幻数。
待这三个子函数都执行完毕,默认的参数就设置好了。此时我只是在调试vivi的代码,还没有在nandflash里存储参数,所以这时我只用了
get_default_priv_data();在执行load_saved_priv_data()时会返回错误,这样在我调试的时候,打印的是
Could not found stored vivi parameters.
Use default vivi parameters.
最后,再来看两个display。顾名思义,它们就是将这里的参数表和分区表打印出来。
void
display_mtd_partition(void)
{
mtd_partition_t *parts = mtd_parts;
int nb_parts = *(nb_mtd_parts);
printk("mtdpart info. (%d partitions)\n", nb_parts);
printk("name offset \tsize flag\n");
printk("-------------------------------------------------\n");
for (; nb_parts > 0; --nb_parts, ++parts) {
printk("%-16s: 0x%08lx\t0x%08lx %4d", parts->name, parts->offset, parts->size, parts->flag);
print_disk_size(parts->size, " ", "\n");
}
}
|
vivi_parameter_t *vivi_params = (vivi_parameter_t *)(VIVI_PRIV_RAM_BASE + PARAMETER_TLB_OFFSET + 16);
void
display_param_tlb(void)
{
vivi_parameter_t *params = vivi_params;
int i;
int num = *(nb_params);
printk("Number of parameters: %d\n", num);
printk("%-24s:\t hex\t\t integer\n", "name");
/* mach_type : 00000090 144 */
printk("----------------------------------------------------------\n");
for (i = 0; i < num; ++i) {
printk("%-24s:\t%08lx\t%13lu\n", params->name, params->value, (ulong)params->value);
++params;
}
printk("Linux command line: %s\n", linux_cmd_line); //打印Linux命令
}
|
至此,整个过程就非常明朗了。
阅读(1170) | 评论(0) | 转发(0) |