自己写 bootloader

本文基于:mini2440开发板

    想想 uboot 的代码量,我们说自己写一个 bootloader 是不是口出狂言了?然而并没有,bootloader 的唯一目的只有一个,那便是启动内核。内核就是一大段可执行程序,我们只要跳转到它的入口地址去执行不就OK? 所以,写一个简单的 bootloader 并不困难。

    现在来思考一下,目的是启动内核,那么内核在哪里?刚上电的时候,内核肯定是位于 nandflash 里的,我们得具备初始化 nandflash 并读取的功能。那么,我们将内核去读到 sdram 然后跳转到入口地址去执行就够了么?然而还不行,bootloader 启动内核时还需要给内核传递一些信息(tag),两个必不可少的信息是 内存标记和命令行参数。信息传递完,那么内核就一定能起得来么?未必,启动内核时,我们还会传递一个机器ID,如果Uboot传递进去的机器ID和内核支持的机器ID不匹配,那么内核也无法启动。想必,分析过 uboot 的同学对这个并不陌生。

    自己写 bootloader ,或者移植 uboot ,需要知道的一些信息

    1、内核在 nandflash 中的地址,是 uImage 还是 zImage ,我这里用的是 uImage ,在 nandflash 里的 0x60000处,uImage 是用来支持 uboot 启动的,不过我们自己写的话用 uImage 也没关系,因为 uImage 就是在 zImage 的基础上加了一个 64 字节的头部,用来告诉 uboot 内核的信息,比如版本号、加载地址、链接地址、编译时间等。uboot 会获取到这个头部,干一些事情。我们自己写的话,直接跳到 uImage 启示地址 + 64 的地方去执行就OK 。

    2、内核的链接地址:0x30008000 ,这个连接地址实际上应该说是“真正”内核的链接地址,如果是 uImage ,不应该包含它的头部。知道什么意思了吧,使用 uImage 时,我们应当将整个 uImage 拷贝到 0x30008000 - 64 的地方去,也就是 0x30007fc0 。

    3、bootloader 的连接地址:uboot的链接地址一般为 0x3ff80000 处,我们自己写的也用这个地址好了。说到这里,必须得提一下,对于2440来说,不管是 nand 启动,还是 nor 启动,刚上电的时候我们的 bootloader 并不是运行在链接地址处,那么这时候跑在非链接地址处的这些指令就得有特殊要求——位置无关码。我个人做法,在将自身代码拷贝到链接地址处之前,能用汇编写的尽量不用C写,因为用汇编我们自己可以分得清哪些是位置无关码,迫不得已的情况下用C写,写完看反汇编,看看那些跳转指令是否依赖于当前PC值。

    4、标记 tag 的地址,2440 常用的做法是放在 0x30000100 处,我们同样也放在这里。其实放那都行,地址会作为参数传递给内核的。tag的放置方法,可以参考 uboot ,必须以 ATAG_CORE 类型的开头,以 ATAG_NONE 类型的结尾。

    5、启动内核时传递给内核的参数,3个,第一个默认0,第三个是前边提到的 tag 的地址,第二个是机器ID。内核中所有支持的“机器”或者称作开发板、单板都用一个 MACHINE_START 宏来定义,这个宏的作用就是填充一个 machine_desc 类型的结构体,填充的过程中会对它的 .nr 成员赋值,这个 nr 就是所谓的机器ID。举个例子:

MACHINE_START(HALIBUT,"Halibut Board (QCT SURF7200A)")  
	.boot_params      = 0x10000100,  
	.map_io           = halibut_map_io,  
	.init_irq         = halibut_init_irq,  
	.init_machine     = halibut_init,  
	.timer            = &msm_timer,  
MACHINE_END 
struct machine_desc __mach_desc_HALIBUT{  
__used                                                            
__attribute__((__section__(".arch.info.init")))= {  
	.nr               = MACH_TYPE_HALIBUT,                
	.name             = "HalibutBoard (QCT SURF7200A)",  
	.boot_params      = 0x10000100,  
	.map_io           = halibut_map_io,  
	.init_irq         = halibut_init_irq,  
	.init_machine     = halibut_init,  
	.timer            = &msm_timer,  
}; 
    MACH_TYPE_HALIBUT 这个宏,搜遍代码也没找到,我在 linux-2.6.32.2\arch\arm\tools\mach-types 里发现了一点踪迹,应该是在这里的信息生成的宏吧。对于 MINI2440 来说,机器ID定义的是 1999 。这里边也有个 boot_params 和前边实际tag存放的地址要一致。

    6、内核刚启动时会打印一些信息,但是那时候内核自己并不会初始化串口,也为了方便自己调试,bootloader里需要初始化串口。

    熟悉以上6条,自己写一个 bootloader 就十分简单了,下边直接上代码。支持 Nor nand 启动,也可以直接跑在 sdram 里。整个程序编译完小于4K,因此自身代码的重定位比较简单。

boot.bin : boot_elf
	arm-linux-objcopy -O binary -S boot_elf boot.bin
	arm-linux-objdump -D -m arm  boot_elf > boot.dis

boot_elf : start.o init.o main.o
	arm-linux-ld -Tboot.lds -g start.o init.o main.o -o boot_elf
	
%.o:%.c
	arm-linux-gcc -g -c -o $@ $<

%.o:%.S
	arm-linux-gcc -g -c -o $@ $<

clean:
	rm -f *.o *.bin *.elf *.dis
SECTIONS {
    . = 0x33f80000;
    .text : { *(.text) }
    
    . = ALIGN(4);
    .rodata : {*(.rodata*)} 
    
    . = ALIGN(4);
    .data : { *(.data) }
    
    . = ALIGN(4);
    __bss_start = .;
    .bss : { *(.bss)  *(COMMON) }
    __bss_end = .;
}
.equ WTCON, 	0x53000000
.equ BWSCON, 	0x48000000
.equ CLKDIVN,	0x4c000014	
.equ MPLLCON,	0x4c000004

.text
.global _start
_start:

	bl close_watch_dog
	bl set_clock
	bl init_sdram
	ldr sp, =0x34000000
	bl relocate
	bl clear_bss
	ldr lr, =loop_halt          @设置返回地址
	ldr pc, =main

loop_halt:
	b loop_halt
	
close_watch_dog:
	ldr r0, =WTCON
	mov r1, #0
	str r1, [r0]
	mov pc, lr
	
set_clock:
	ldr	r0, =CLKDIVN
	mov	r1, #0x05	// FCLK:HCLK:PCLK=1:4:8, HDIVN=2,PDIVN=1
	str	r1, [r0]
	
	mrc p15, 0, r1, c1, c0, 0        /* 读出控制寄存器*/ 
    orr r1, r1, #0xc0000000          /* 设置为“asynchronous bus mode?*/
    mcr p15, 0, r1, c1, c0, 0        /* 写入控制寄存器*/
	
	ldr	r0, =MPLLCON
	ldr	r1, =((0x5c<<12)|(0x01<<4)|(0x01))	//MPLL_400MHZ  
	str	r1, [r0]
	
	/* 启动ICACHE */
	mrc p15, 0, r0, c1, c0, 0	@ read control reg
	orr r0, r0, #(1<<12)
	mcr	p15, 0, r0, c1, c0, 0   @ write it back
	
	mov pc, lr

init_sdram:
	/* 如果程序在sdram里,那么就不初始化了 */
	adr r0, _start
	ldr r1, =0x33f80000 
	cmp r0, r1
	beq 2f
	
	mov r0,#0x48000000
	adrl r1,mem_cfg_val
							@STr [r1],[r0],#4
	mov r4, #0
1:	
	ldr r3, [r1], #4
	str r3, [r0], #4
	add r4, #1
	cmp r4, #13
	bne 1b
2:	
	mov pc, lr

relocate:
	/* 如果程序在sdram里,那么就不重定位了 */
	adr r0, _start
	ldr r1, =0x33f80000 
	cmp r0, r1
	beq 5f
	
	/* 如果是 nandflash 启动 或者nor 启动,条件:整个程序小于4k*/
	mov r0, #0x0
	ldr r1, =__bss_start
	ldr r2, =0x33f80000
	sub r1, r1, r2
	add r1, r1, #4
4:	
	ldr r3, [r0] ,#4
	str r3 ,[r2] ,#4
	cmp r0, r1
	bne 4b
		
5:	
	mov pc, lr	

	
clear_bss:
	ldr	r0, =__bss_start		
	ldr	r1, =__bss_end		
	mov r2, #0x00000000		

clbss_l:
	str	r2, [r0]		
	add	r0, r0, #4
	cmp	r0, r1
	ble	clbss_l
	mov pc, lr


.align 4
mem_cfg_val:
    @ 存储控制器13个寄存器的设置值
    .long   0x22011110      @ BWSCON
    .long   0x00000700      @ BANKCON0
    .long   0x00000700      @ BANKCON1
    .long   0x00000700      @ BANKCON2
    .long   0x00000700      @ BANKCON3  
    .long   0x00000700      @ BANKCON4
    .long   0x00000700      @ BANKCON5
    .long   0x00018005      @ BANKCON6
    .long   0x00018005      @ BANKCON7
    .long   0x008C07A3      @ rEFrESH
    .long   0x000000B1      @ BANKSIZE
    .long   0x00000030      @ MrSrB6
    .long   0x00000030      @ MrSrB7
#include "s3c2440.h"

#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))

#define PCLK            50000000    // init.c中的clock_init函数设置PCLK为50MHz
#define UART_CLK        PCLK        //  UART0的时钟源设为PCLK
#define UART_BAUD_RATE  115200      // 波特率
#define UART_BRD        ((UART_CLK  / (UART_BAUD_RATE * 16)) - 1)

void write_cmd(unsigned char cmd){
	NFCMD = cmd;
}
unsigned char read_data(){
	return NFDATA;
}
void nand_chip_select(){
	
	NFCONT &= 0xfffffffd; //1111111111
}
void nand_chip_release(){
	NFCONT |= 0x02; 	//1111111111
}
void nand_busy(){	
	while(!(NFSTAT&(1<<0)));	//11111111      
}
void s3c2440_nand_reset()
{
    nand_chip_select();
    write_cmd(0xff); 
    nand_busy();
    nand_chip_release();
}
void nand_init(){
#define TACLS   1
#define TWRPH0  1
#define TWRPH1  0
	NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
	NFCONT = (1<<4)|(1<<1)|(1<<0);
	NFSTAT =0x0;
	s3c2440_nand_reset();
}
void write_addr(unsigned int addr){

	int i;
	int col, page;
	col = addr & 2047;
	page = addr / 2048;
	
	NFADDR = col & 0xff;			/* Column Address A0~A7 */
	for(i=0; i<10; i++);		
	NFADDR = (col >> 8) & 0x0f; 	/* Column Address A8~A11 */
	for(i=0; i<10; i++);
	NFADDR = page & 0xff;			/* Row Address A12~A19 */
	for(i=0; i<10; i++);
	NFADDR = (page >> 8) & 0xff;	/* Row Address A20~A27 */
	for(i=0; i<10; i++);
	NFADDR = (page >> 16) & 0x01;	/* Row Address A28 */
	for(i=0; i<10; i++);
}
void nand_read(unsigned char *buf, unsigned long start_addr, int size){//按页读取,一个起始地址对应至少2K的数捿
    int i, j;

    if ((start_addr & 2047) || (size & 2047)) {
        return ;    /* 地址或长度不对齐 */
    }

    nand_chip_select();

    for(i=start_addr; i < (start_addr + size);) {

		write_cmd(0);
		write_addr(i);
		write_cmd(0x30);		
		nand_busy();

		for(j=0; j < 2048; j++, i++) {	//按页读取

			*buf = read_data();
			buf++;
		}
    }

    nand_chip_release();
    
    return ;
}

void init_uart(){
<span style="white-space:pre">	</span>GPHCON  |= 0xa0;    // GPH2,GPH3用作TXD0,RXD0
    GPHUP   = 0x0c;     // GPH2,GPH3内部上拉	
	ULCON0  = 0x03;     // 8N1(8个数据位,无较验,1个停止位)
    UCON0   = 0x05;     // 终端或查询方式,UART时钟源为PCLK
    UFCON0  = 0x00;     // 不使用FIFO
    UMCON0  = 0x00;     // 不使用流控
    UBRDIV0 = UART_BRD; // 波特率为115200
}

void printch(unsigned char ch)
{
	while (!(UTRSTAT0 & 0x04)){
		;
	}
	UTXH0 = ch;
}

void printdec(unsigned int dec)
{
    if(dec==0)
    {
        printch( (char)('0'));
		return;
    }
    if(dec/10 != 0)printdec(dec/10);
    printch( (char)(dec%10 + '0'));
}

void    printflt(double flt)
{
    int icnt = 0;
    int tmpint = 0;
}

void    printstr(char* str)
{
    while(*str)
    {
        printch(*str++);
    }
}

#include "setup.h"

extern void nand_init();
extern void init_uart();
extern void clear_bss();
extern void printstr(char* str);
static struct tag *params;
void (*theKernel)(int zero, int arch, unsigned int params);

int strlen(const char *s)
{
	const char *sc;

	for (sc = s; *sc != '\0'; ++sc)
		/* nothing */;
	return sc - s;
}

char *strcpy(char *dest, const char *src)
{
	char *tmp = dest;

	while ((*dest++ = *src++) != '\0')
		/* nothing */;
	return tmp;
}

static void setup_start_tag (void)
{
	params = (struct tag *) 0x30000100;

	params->hdr.tag = ATAG_CORE;
	params->hdr.size = tag_size (tag_core);

	params->u.core.flags = 0;
	params->u.core.pagesize = 0;
	params->u.core.rootdev = 0;

	params = tag_next (params);
}

static void setup_memory_tags ()
{
	params->hdr.tag = ATAG_MEM;
	params->hdr.size = tag_size (tag_mem32);
	params->u.mem.start = 0x30000000;	//内存起始地址
	params->u.mem.size  = 0x4000000;	//64m
	params = tag_next (params);
}

static void setup_commandline_tag (char *commandline)
{
	char *p = commandline;

	params->hdr.tag = ATAG_CMDLINE;
	params->hdr.size =
		(sizeof (struct tag_header) + strlen (p) + 1 + 3) >> 2;

	strcpy (params->u.cmdline.cmdline, p);
	params = tag_next (params);
}

static void setup_end_tag ()
{
	params->hdr.tag = ATAG_NONE;
	params->hdr.size = 0;
}

int main(){
	init_uart();
	printstr("uart init ok \n\r");
	setup_start_tag ();
	setup_memory_tags ();
	setup_commandline_tag ("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
	setup_end_tag ();
	printstr("set up tag ok \n\r");
	nand_init();
	// 将内核从 nandflash 读出
	nand_read((unsigned char *)0x30007fc0, (unsigned long)(0x60000), 0x300000);
	printstr("image read ok \n\r");
	
	theKernel = (void (*)(int, int, unsigned int))0x30008000;
	theKernel (0, 1999, 0x30000100);
	
	printstr("error \n\r");
	return -1;
}
#ifndef     __S3C2440_H_
#define     __S3C2440_H_

/* WOTCH DOG register */
#define     WTCON           (*(volatile unsigned long *)0x53000000)
#define     WTDAT           (*(volatile unsigned long *)0x53000004)
#define     WTCNT           (*(volatile unsigned long *)0x53000008)

/* NAND Flash registers */
#define NFCONF 				(*(volatile unsigned int *)0x4E000000)
#define NFCONT 				(*(volatile unsigned int *)0x4E000004)	//bit 0     chip select  0disable 1able
#define NFCMD 				(*(volatile unsigned int *)0x4E000008)	//8bit
#define NFADDR 				(*(volatile unsigned int *)0x4E00000C)	//8bit
#define NFDATA 				(*(volatile unsigned char *)0x4E000010)	//32bit
#define NFSTAT 				(*(volatile unsigned int *)0x4E000020)	//bit 0    0 busy 1 notbusy
/* GPIO registers */
#define GPACON              (*(volatile unsigned long *)0x56000000)
#define GPADAT              (*(volatile unsigned long *)0x56000004)

#define GPBCON              (*(volatile unsigned long *)0x56000010)
#define GPBDAT              (*(volatile unsigned long *)0x56000014)
#define GPBUP               (*(volatile unsigned long *)0x56000018)

#define GPCCON              (*(volatile unsigned long *)0x56000020)
#define GPCDAT              (*(volatile unsigned long *)0x56000024)
#define GPCUP               (*(volatile unsigned long *)0x56000028)

#define GPDCON              (*(volatile unsigned long *)0x56000030)
#define GPDDAT              (*(volatile unsigned long *)0x56000034)
#define GPDUP               (*(volatile unsigned long *)0x56000038)

#define GPECON    			(*(volatile unsigned long *)0x56000040)
#define GPEDAT    		    (*(volatile unsigned long *)0x56000044)
#define GPEUP     			(*(volatile unsigned long *)0x56000048)

#define GPFCON              (*(volatile unsigned long *)0x56000050)
#define GPFDAT              (*(volatile unsigned long *)0x56000054)
#define GPFUP               (*(volatile unsigned long *)0x56000058)

#define GPGCON              (*(volatile unsigned long *)0x56000060)
#define GPGDAT              (*(volatile unsigned long *)0x56000064)
#define GPGUP               (*(volatile unsigned long *)0x56000068)

#define GPHCON              (*(volatile unsigned long *)0x56000070)
#define GPHDAT              (*(volatile unsigned long *)0x56000074)
#define GPHUP               (*(volatile unsigned long *)0x56000078)

/*UART registers*/
#define ULCON0              (*(volatile unsigned long *)0x50000000)
#define UCON0               (*(volatile unsigned long *)0x50000004)
#define UFCON0              (*(volatile unsigned long *)0x50000008)
#define UMCON0              (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0            (*(volatile unsigned long *)0x50000010)
#define UTXH0               (*(volatile unsigned char *)0x50000020)
#define URXH0               (*(volatile unsigned char *)0x50000024)
#define UBRDIV0             (*(volatile unsigned long *)0x50000028)

/*interrupt registes*/
#define SRCPND              (*(volatile unsigned long *)0x4A000000)
#define INTMOD              (*(volatile unsigned long *)0x4A000004)
#define INTMSK              (*(volatile unsigned long *)0x4A000008)
#define PRIORITY            (*(volatile unsigned long *)0x4A00000c)
#define INTPND              (*(volatile unsigned long *)0x4A000010)
#define INTOFFSET           (*(volatile unsigned long *)0x4A000014)
#define SUBSRCPND           (*(volatile unsigned long *)0x4A000018)
#define INTSUBMSK           (*(volatile unsigned long *)0x4A00001c)

/*external interrupt registers*/
#define EINTMASK            (*(volatile unsigned long *)0x560000a4)
#define EINTPEND            (*(volatile unsigned long *)0x560000a8)

/*clock registers*/
#define	LOCKTIME			(*(volatile unsigned long *)0x4c000000)
#define	MPLLCON				(*(volatile unsigned long *)0x4c000004)
#define	UPLLCON				(*(volatile unsigned long *)0x4c000008)
#define	CLKCON				(*(volatile unsigned long *)0x4c00000c)
#define	CLKSLOW				(*(volatile unsigned long *)0x4c000010)
#define	CLKDIVN				(*(volatile unsigned long *)0x4c000014)

/*PWM & Timer registers*/
#define	TCFG0				(*(volatile unsigned long *)0x51000000)
#define	TCFG1				(*(volatile unsigned long *)0x51000004)
#define	TCON				(*(volatile unsigned long *)0x51000008)
#define	TCNTB0				(*(volatile unsigned long *)0x5100000c)
#define	TCMPB0				(*(volatile unsigned long *)0x51000010)
#define	TCNTO0				(*(volatile unsigned long *)0x51000014)

/* I2C registers */
#define IICCON  			(*(volatile unsigned char *)0x54000000) // IIC control
#define IICSTAT 			(*(volatile unsigned char *)0x54000004) // IIC status
#define IICADD  			(*(volatile unsigned char *)0x54000008) // IIC address
#define IICDS   			(*(volatile unsigned char *)0x5400000c) // IIC data shift

// LCD CONTROLLER
#define LCDCON1     		(*(volatile unsigned long *)0x4d000000) //LCD control 1
#define LCDCON2     		(*(volatile unsigned long *)0x4d000004) //LCD control 2
#define LCDCON3     		(*(volatile unsigned long *)0x4d000008) //LCD control 3
#define LCDCON4     		(*(volatile unsigned long *)0x4d00000c) //LCD control 4
#define LCDCON5     		(*(volatile unsigned long *)0x4d000010) //LCD control 5
#define LCDSADDR1   		(*(volatile unsigned long *)0x4d000014) //STN/TFT Frame buffer start address 1
#define LCDSADDR2   		(*(volatile unsigned long *)0x4d000018) //STN/TFT Frame buffer start address 2
#define LCDSADDR3   		(*(volatile unsigned long *)0x4d00001c) //STN/TFT Virtual screen address set
#define REDLUT      		(*(volatile unsigned long *)0x4d000020) //STN Red lookup table
#define GREENLUT    		(*(volatile unsigned long *)0x4d000024) //STN Green lookup table 
#define BLUELUT     		(*(volatile unsigned long *)0x4d000028) //STN Blue lookup table
#define DITHMODE    		(*(volatile unsigned long *)0x4d00004c) //STN Dithering mode
#define TPAL        		(*(volatile unsigned long *)0x4d000050) //TFT Temporary palette
#define LCDINTPND   		(*(volatile unsigned long *)0x4d000054) //LCD Interrupt pending
#define LCDSRCPND   		(*(volatile unsigned long *)0x4d000058) //LCD Interrupt source
#define LCDINTMSK   		(*(volatile unsigned long *)0x4d00005c) //LCD Interrupt mask
#define LPCSEL      		(*(volatile unsigned long *)0x4d000060) //LPC3600 Control

#endif    /*#ifndef __PRINT_H_*/
/*
 *  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.
 */
#ifndef __ASMARM_SETUP_H
#define __ASMARM_SETUP_H

/*
 * 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

#define u32		unsigned long 	
#define u16 	unsigned short 	
#define u8   	unsigned char
	
/* 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(unsigned long)];
	} s;
    } u2;
    char commandline[COMMAND_LINE_SIZE];
};


/*
 * The new way of passing information: a list of tagged entries
 */

/* The list ends with an ATAG_NONE node. */
#define ATAG_NONE	0x00000000

struct tag_header {
	u32 size;
	u32 tag;
};

/* The list must start with an ATAG_CORE node */
#define ATAG_CORE	0x54410001

struct tag_core {
	u32 flags;		/* bit 0 = read-only */
	u32 pagesize;
	u32 rootdev;
};

/* it is allowed to have multiple ATAG_MEM nodes */
#define ATAG_MEM	0x54410002

struct tag_mem32 {
	u32	size;
	u32	start;	/* physical start address */
};

/* VGA text type displays */
#define ATAG_VIDEOTEXT	0x54410003

struct tag_videotext {
	u8		x;
	u8		y;
	u16		video_page;
	u8		video_mode;
	u8		video_cols;
	u16		video_ega_bx;
	u8		video_lines;
	u8		video_isvga;
	u16		video_points;
};

/* describes how the ramdisk will be used in kernel */
#define ATAG_RAMDISK	0x54410004

struct tag_ramdisk {
	u32 flags;	/* bit 0 = load, bit 1 = prompt */
	u32 size;	/* decompressed ramdisk size in _kilo_ bytes */
	u32 start;	/* starting block of floppy-based RAM disk image */
};

/* describes where the compressed ramdisk image lives (virtual address) */
/*
 * this one accidentally used virtual addresses - as such,
 * its depreciated.
 */
#define ATAG_INITRD	0x54410005

/* describes where the compressed ramdisk image lives (physical address) */
#define ATAG_INITRD2	0x54420005

struct tag_initrd {
	u32 start;	/* physical start address */
	u32 size;	/* size of compressed ramdisk image in bytes */
};

/* board serial number. "64 bits should be enough for everybody" */
#define ATAG_SERIAL	0x54410006

struct tag_serialnr {
	u32 low;
	u32 high;
};

/* board revision */
#define ATAG_REVISION	0x54410007

struct tag_revision {
	u32 rev;
};

/* initial values for vesafb-type framebuffers. see struct screen_info
 * in include/linux/tty.h
 */
#define ATAG_VIDEOLFB	0x54410008

struct tag_videolfb {
	u16		lfb_width;
	u16		lfb_height;
	u16		lfb_depth;
	u16		lfb_linelength;
	u32		lfb_base;
	u32		lfb_size;
	u8		red_size;
	u8		red_pos;
	u8		green_size;
	u8		green_pos;
	u8		blue_size;
	u8		blue_pos;
	u8		rsvd_size;
	u8		rsvd_pos;
};

/* command line: \0 terminated string */
#define ATAG_CMDLINE	0x54410009

struct tag_cmdline {
	char	cmdline[1];	/* this is the minimum size */
};

/* acorn RiscPC specific information */
#define ATAG_ACORN	0x41000101

struct tag_acorn {
	u32 memc_control_reg;
	u32 vram_pages;
	u8 sounddefault;
	u8 adfsdrives;
};

/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
#define ATAG_MEMCLK	0x41000402

struct tag_memclk {
	u32 fmemclk;
};

struct tag {
	struct tag_header hdr;
	union {
		struct tag_core		core;
		struct tag_mem32	mem;
		struct tag_videotext	videotext;
		struct tag_ramdisk	ramdisk;
		struct tag_initrd	initrd;
		struct tag_serialnr	serialnr;
		struct tag_revision	revision;
		struct tag_videolfb	videolfb;
		struct tag_cmdline	cmdline;

		/*
		 * Acorn specific
		 */
		struct tag_acorn	acorn;

		/*
		 * DC21285 specific
		 */
		struct tag_memclk	memclk;
	} u;
};

struct tagtable {
	u32 tag;
	int (*parse)(const struct tag *);
};

#define tag_next(t)	((struct tag *)((u32 *)(t) + (t)->hdr.size))
#define tag_size(type)	((sizeof(struct tag_header) + sizeof(struct type)) >> 2)

/*
 * Memory map description
 */
#define NR_BANKS 8

struct meminfo {
	int nr_banks;
	unsigned long end;
	struct {
		unsigned long start;
		unsigned long size;
		int           node;
	} bank[NR_BANKS];
};

extern struct meminfo meminfo;

#endif








 




  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值