vivi开发笔记(十七):vivi与Linux kernel的参数传递情景分析(上)[转]
来源:互联网 发布:程序员的qq头像 编辑:程序博客网 时间:2024/04/28 08:42
原文链接:http://blog.chinaunix.net/u/21948/showart.php?id=380032
在上一部分提到过了,vivi作为bootloader,向内核传递启动参数是其本职工作之一。要把这个情景分析清楚,不仅仅需要分析vivi的参数机 制,而且要分析Linux kernel的接收机制。因为这是一个简单的通信过程,比起本科所学习的TCP/IP来简单的多,但是因为简单,所以在协议上并不规范,理解上反而不如 TCP/IP协议。下面就分为两个方面对此情景分析。
[armlinux@lqm arm]$ cat Booting
Booting ARM Linux
=================
Author: Russell King
Date : 18 May 2002
The following documentation is relevant to 2.4.18-rmk6and beyond.
In order to boot ARM Linux, you require a boot loader, which is a small
program that runs before the main kernel. The boot loader is expected
to initialise various devices, and eventually call the Linux kernel,
passing information to the kernel.
Essentially, the boot loader should provide(as a minimum) the
following:
1. Setup and initialise the RAM.
2. Initialise one serial port.
3. Detect the machine type.
4. Setup the kernel tagged list.
5. Call the kernel image.
1. Setup and initialise RAM
---------------------------
Existing boot loaders: MANDATORY
New boot loaders: MANDATORY
The boot loader is expected to find and initialise all RAM that the
kernel will use for volatile data storage in the system. It performs
this in a machine dependent manner.(It may use internal algorithms
to automatically locate and size all RAM,or it may use knowledge of
the RAM in the machine, or any other method the boot loader designer
sees fit.)
2. Initialise one serial port
-----------------------------
Existing boot loaders: OPTIONAL, RECOMMENDED
New boot loaders: OPTIONAL, RECOMMENDED
The boot loader should initialise and enable one serial port on the
target. This allows the kernel serial driver to automatically detect
which serial port it should use for the kernel console(generally
used for debugging purposes,or communication with the target.)
As an alternative, the boot loader can pass the relevant'console='
option to the kernel via the tagged lists specifing the port,and
serial format options as described in
linux/Documentation/kernel-parameters.txt.
3. Detect the machine type
--------------------------
Existing boot loaders: OPTIONAL
New boot loaders: MANDATORY
The boot loader should detect the machine type its running on by some
method. Whether this is a hard coded value or some algorithm that
looks at the connected hardware is beyond the scope of this document.
The boot loader must ultimately be able to provide a MACH_TYPE_xxx
value to the kernel. (see linux/arch/arm/tools/mach-types).
4. Setup the kernel tagged list
-------------------------------
Existing boot loaders: OPTIONAL, HIGHLY RECOMMENDED
New boot loaders: MANDATORY
The boot loader must create and initialise the kernel taggedlist.
A valid tagged list starts with ATAG_COREand ends with ATAG_NONE.
The ATAG_CORE tag may or may not be empty. An empty ATAG_CORE tag
has the size field set to '2' (0x00000002). The ATAG_NONE mustset
the size field to zero.
Any number of tags can be placed in the list. It is undefined
whether a repeated tag appends to the information carried by the
previous tag, or whether it replaces the information in its
entirety; some tags behave as the former, others the latter.
The boot loader must pass at a minimum the size and location of
the system memory,and root filesystem location. Therefore, the
minimum tagged list should look:
+-----------+
base ->| ATAG_CORE | |
+-----------+|
| ATAG_MEM | | increasing address
+-----------+|
| ATAG_NONE | |
+-----------+ v
The tagged list should be stored in system RAM.
The tagged list must be placed in a region of memory where neither
the kernel decompressor nor initrd 'bootp' program will overwrite
it. The recommended placement is in the first 16KiB of RAM.
5. Calling the kernel image
---------------------------
Existing boot loaders: MANDATORY
New boot loaders: MANDATORY
There are two options for calling the kernel zImage.If the zImage
is stored in flash, and is linked correctly to be run from flash,
then it is legal for the boot loader to call the zImage in flash
directly.
The zImage may also be placed in system RAM(at any location)and
called there. Note that the kernel uses 16K of RAM below the image
to store page tables. The recommended placement is 32KiB into RAM.
In either case, the following conditions must be met:
- CPU register settings
r0 = 0,
r1 = machine type number discovered in (3) above.
r2 = physical address of tagged list in system RAM.
- CPU mode
All forms of interrupts must be disabled (IRQsand FIQs)
The CPU must be in SVC mode. (A special exception exists for Angel)
- Caches, MMUs
The MMU must be off.
Instruction cache may be on or off.
Data cache must be off.
- The boot loader is expected to call the kernel image by jumping
directly to the first instruction of the kernel image.
/*
* linux/include/asm/setup.h
*
* Copyright (C) 1997-1999 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Structure passed to kernel to tell it about the
* hardware it's running on. See linux/Documentation/arm/Setup
* for more info.
*
* NOTE:
* This file contains two ways to pass information from the boot
* loader to the kernel. The old struct param_struct is deprecated,
* but it will be kept in the kernel for 5 years from now
* (2001). This will allow boot loaders to convert to the new struct
* tag way.
*/
media_type= get_param_value("media_type",&ret);
[armlinux@lqminclude]$ cat boot_kernel.h
#ifndef _VIVI_BOOT_KERNEL_H_
#define _VIVI_BOOT_KERNEL_H_
/*
* Media Type: A type of storage device that contains the linux kernel
*
* +----------------+-----------------------------------------+
* | Value(Integer) | Type |
* +----------------+-----------------------------------------+
* | 0 | UNKNOWN |
* | 1 | RAM |
* | 2 | NOR Flash Memory |
* | 3 | SMC (NAND Flash Memory) on the S3C2410 |
* +----------------+-----------------------------------------+
*/
enum {
MT_UNKNOWN = 0,
MT_RAM,
MT_NOR_FLASH,
MT_SMC_S3C2410
};
#endif/* _VIVI_BOOT_KERNEL_H_ */
kernel_part= get_mtd_partition("kernel");
if (kernel_part ==NULL){
printk("Can't find default 'kernel' partition\n");
return;
}
from = kernel_part->offset;
size = kernel_part->size;
boot_kernel(from, size, media_type);
boot_mem_base= get_param_value("boot_mem_base",&ret);
to= boot_mem_base + LINUX_KERNEL_OFFSET;
printk("Copy linux kernel from 0x%08lx to 0x%08lx, size = 0x%08lx ... ",
from, to, size);
ret = copy_kernel_img(to,(char*)from, size, media_type);
/*
* We place the page tables 16K below TEXTADDR. Therefore, we must make sure
* that TEXTADDR is correctly set. Currently, we expect the least significant
* "short" to be 0x8000, but we could probably relax this restriction to
* TEXTADDR > PAGE_OFFSET + 0x4000
*
* Note that swapper_pg_dir is the virtual address of the page tables, and
* pgtbl gives us a position-independent reference to these tables. We can
* do this because stext == TEXTADDR
*
* swapper_pg_dir, pgtbl and krnladr are all closely related.
*/
if(*(ulong*)(to+ 9*4)!= LINUX_ZIMAGE_MAGIC){
printk("Warning: this binary is not compressed linux kernel image\n");
printk("zImage magic = 0x%08lx\n",*(ulong*)(to+ 9*4));
} else{
printk("zImage magic = 0x%08lx\n",*(ulong*)(to+ 9*4));
}
setup_linux_param(boot_mem_base+ LINUX_PARAM_OFFSET);
staticvoid setup_linux_param(ulong param_base)
{
struct param_struct *params = (struct param_struct *)param_base;
char *linux_cmd;
//第一步:打印出param_base的基地址,这里就是0x30000100
//这里的这个位置实际上是约定的,预留了256字节
//然后初始化param_struct这个数据结构
printk("Setup linux parameters at 0x%08lx\n", param_base);
memset(params, 0,sizeof(struct param_struct));
//填写params的两个成员
//Linux kernel采用了页表方式,设置页表的大小,这里是4K
params->u1.s.page_size= LINUX_PAGE_SIZE;
params->u1.s.nr_pages= (DRAM_SIZE>> LINUX_PAGE_SHIFT);
/* set linux command line */
linux_cmd = get_linux_cmd_line();
if (linux_cmd==NULL){
printk("Wrong magic: could not found linux command line\n");
} else{
//把命令行参数复制到params的commandline成员
memcpy(params->commandline, linux_cmd,strlen(linux_cmd)+ 1);
printk("linux command line is: \"%s\"\n", linux_cmd);
}
}
/*
* Usage:
* - do not go blindly adding fields, add them at the end
* - when adding fields, don't rely on the address until
* a patch from me has been released
* - unused fields should be zero (for future expansion)
* - this structure is relatively short-lived - only
* guaranteed to contain useful data in setup_arch()
*/
#define COMMAND_LINE_SIZE 1024
/* This is the old deprecated way to pass parameters to the kernel */
struct param_struct {
union {
struct {
unsigned long page_size; /* 0 */
unsigned long nr_pages; /* 4 */
unsigned long ramdisk_size; /* 8 */
unsigned long flags; /* 12 */
#define FLAG_READONLY 1
#define FLAG_RDLOAD 4
#define FLAG_RDPROMPT 8
unsigned long rootdev; /* 16 */
unsigned long video_num_cols; /* 20 */
unsigned long video_num_rows; /* 24 */
unsigned long video_x; /* 28 */
unsigned long video_y; /* 32 */
unsigned long memc_control_reg; /* 36 */
unsigned char sounddefault; /* 40 */
unsigned char adfsdrives; /* 41 */
unsigned char bytes_per_char_h; /* 42 */
unsigned char bytes_per_char_v; /* 43 */
unsigned long pages_in_bank[4];/* 44 */
unsigned long pages_in_vram; /* 60 */
unsigned long initrd_start; /* 64 */
unsigned long initrd_size; /* 68 */
unsigned long rd_start; /* 72 */
unsigned long system_rev; /* 76 */
unsigned long system_serial_low; /* 80 */
unsigned long system_serial_high; /* 84 */
unsigned long mem_fclk_21285; /* 88 */
} s;
char unused[256];
} u1;
union {
char paths[8][128];
struct {
unsigned long magic;
char n[1024- sizeof(unsignedlong)];
} s;
} u2;
char commandline[COMMAND_LINE_SIZE];
};
page_size
This parameter must be set to the page size of the machine,and
will be checked by the kernel.
nr_pages
This is the total number of pages of memory in thesystem.If
the memory is banked, then this should contain the total number
of pages in the system.
If the system contains separate VRAM, this value should not
include this information.
commandline
Kernel command line parameters. Details can be found elsewhere.
mach_type= get_param_value("mach_type",&ret);
smdk2410 S3C2410_SMDK SMDK2410 193
call_linux(0, mach_type, to);
void call_linux(long a0,long a1,long a2)
{
cache_clean_invalidate();
tlb_invalidate();
__asm__(
"mov r0, %0\n"
"mov r1, %1\n"
"mov r2, %2\n"
"mov ip, #0\n"
"mcr p15, 0, ip, c13, c0, 0\n" /* zero PID */
"mcr p15, 0, ip, c7, c7, 0\n" /* invalidate I,D caches */
"mcr p15, 0, ip, c7, c10, 4\n" /* drain write buffer */
"mcr p15, 0, ip, c8, c7, 0\n" /* invalidate I,D TLBs */
"mrc p15, 0, ip, c1, c0, 0\n" /* get control register */
"bic ip, ip, #0x0001\n" /* disable MMU */
"mcr p15, 0, ip, c1, c0, 0\n" /* write control register */
"mov pc, r2\n"
"nop\n"
"nop\n"
: /* no outpus */
: "r" (a0),"r" (a1),"r" (a2)
);
}
原文链接:http://blog.chinaunix.net/u/21948/showart.php?id=380032
- vivi开发笔记(十七):vivi与Linux kernel的参数传递情景分析(上)[转]
- vivi开发笔记(十七):vivi与Linux kernel的参数传递情景分析(下)
- vivi与Linux kernel的参数传递情景分析(上、下)
- vivi与Linux kernel的参数传递情景分析(上)
- vivi与Linux kernel的参数传递情景分析(上)
- vivi与Linux kernel的参数传递情景分析 (转)
- vivi与Linux kernel的参数传递情景分析
- vivi与Linux kernel的参数传递情景分析(下)
- vivi开发笔记: MMU分析|ARM,vivi
- vivi开发笔记(二):软件架构分析
- vivi开发笔记(十三):clock
- vivi开发笔记(一):学习计划
- vivi开发笔记(三):Makefile详解
- Nand Flash的VIVI装载器的分析与改进 (转)
- vivi中bon与part分区的区别(转)
- VIVI讲解与分析
- vivi开发笔记
- vivi开发笔记
- Hive Python Streaming的原理及写法
- 03-2. 用天平找小球(10)
- 将HTML格式的String转化为HTMLElement的实现方法
- hdu 4925规律题
- ArmLinux BOOTLOADER全程详解[转]
- vivi开发笔记(十七):vivi与Linux kernel的参数传递情景分析(上)[转]
- Uboot-1.1.2 for PXA270源码分析-do_bootm_linux函数源码分析[转]
- linux 2.6.22.1内核在s3c2410平台的移植(完美版)
- ramdisk 和busybox在开发板上的移植[转]
- linux-2.6.14在开发板上的移植
- [转]USB驱动移植心得
- [转]一步一步解决 kernel 2.6 usb host drive
- java 多线程suspend()、resume()和wait()、notify()的区别
- 解读Object类的equals方法