每个操作系统都需要一个引导程序,如下表所示,是几种Linux支持的引导程序,目前还没有做到可以适应全部嵌入式产品的引导程序,所以只能尽量的让一个Boot Loader 代码支持多种不同的构架和操作系统,并让它有很好的可移植性。而U-boot 就是一个支持多平台多操作系统的引导程序,这也是U-boot 的优势所在,而且U-boot 的代码是开源的,对于新功能的添加也十分容易。
表3-1 Linux系统可以的BootLoader
Bootloader |
Monitor |
描述 |
X86 |
ARM |
PC |
LILO |
否 |
Linux磁盘引导程序 |
是 |
否 |
否 |
GRUB |
否 |
GNU的LILO代替程序 |
是 |
否 |
否 |
Loading |
否 |
从DOS引导Linux |
是 |
否 |
否 |
ROLO |
否 |
从ROM引导Linux而不需要BIOS |
是 |
否 |
否 |
LinuxBOIS |
否 |
完全代替BUS的Linux引导程序 |
是 |
否 |
否 |
BLOB |
是 |
LART等硬件平台的引导程序 |
是 |
否 |
否 |
U-Boot |
是 |
通用引导程序 |
是 |
是 |
是 |
RedBoot |
是 |
基于eCos的引导程序 |
是 |
是 |
是 |
本人的开发环境是window10、VMWare 12.5.2和Ubuntu 16.04,为GEC210移植uboot的具体操作如下:
(1)从三星官网下载uboot源码smdkv210.tar.bz2,在虚拟机上解压。.
(2)因为需要移植到GEC210,所以需要安装交叉编译器,下载安装包然后解压。
(3)得到了uboot的源码,进入解压后的文件根据自己的环境配置Makefile,设置好刚才解压的交叉编译器的绝对路径,将CROSS_COMPILE变量修改成自己的路径:
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
(4)修改串口设置文件和网络配置,因为开发板中用于与主机通讯的串口为UART1,修改smdkv210single.h文件:
将:
#define CONFIG_SERIAL3
#define CONFIG_DM9000_BASE (0xA8000000)
#define DM9000_DATA (CONFIG_DM9000_BASE+2)
修改为:
#define CONFIG_SERIAL1
#define CONFIG_DM9000_BASE (0x88000000)
#define DM9000_DATA (CONFIG_DM9000_BASE+8)
(5)GEC210 核心板有512MB的 DDR内存芯片,如下表所示的地址映射表S5PV210 有两个 DRAM 区域:0x20000000-0x3FFFFFFF 与0x40000000-0x7FFFFFFF,所以需要修改一下DDR参数,还是在smdkv210single.h里面进行修改:
#define MEMORY_BASE_ADDRESS1 0x40000000
#define DMC0_MEMCONTROL 0x00202400
#define DMC0_MEMCONFIG_0 0x20F00313
#define DMC0_MEMCONFIG_1 0x00F00313
#define DMC1_MEMCONTROL 0x00202400
#define DMC1_MEMCONFIG_0 0x40F00313
#define DMC1_MEMCONFIG_1 0x00F00313
#define SDRAM_BANK_SIZE 0x10000000 /* 256 MB */
//#define PHYS_SDRAM_2 (MEMORY_BASE_ADDRESS1) /* 将SDRAM_2都屏蔽掉
表3-2 地址映射表
IROM & IRAM &Reserved |
0x00000000~0x1FFFFFFF |
DRAM0 |
0x20000000~0x3FFFFFFF |
DRAM1 |
0x40000000~0x7FFFFFFF |
SROMC_BANK0 & SROMC_BANK1 |
0x80000000~0x8FFFFFFF |
SROMC_BANK2 & SROMC_BANK3 |
0x90000000~0x9FFFFFFF |
SROMC_BANK4 & SROMC_BANK5 |
0xA0000000~0xAFFFFFFF |
ONENAND/NAND |
0xB0000000~0xBFFFFFFF |
Low Power Audio SRAM |
0xC0000000~0xCFFFFFFF |
(6)修改cpu目录下的s5pc11x目录下的s5pc110目录下的cpu_init.S CPU初始化文件,将ldr r1, =0x00212400修改为 ldr r1, =DMC0_MEMCONTROL,即上面的0x00202400。
$vim cpu/s5pc11x/s5pc110/cpu_init.S
将122行:ldr r1, =0x00212400
修改为 ldr r1, =DMC0_MEMCONTROL//即上面的0x00202400
(7) 修改网卡板级初始化文件,修改board目录下的samsung目录下的smdkc110目录下的smdkc110.c文件,修改DM9000预初始化函数dm9000_pre_init:
$vim board/samsung/smdkc110/smdkc110.c
//修改DM9000预初始化函数dm9000_pre_init
static void dm9000_pre_init(void)
{
unsigned int tmp;
/* DM9000 on SROM BANK1, 16 bit */
SROM_BW_REG &= ~(0xf << 4);
SROM_BW_REG |= (0x1 << 4);
SROM_BC1_REG = ((0<<28)|(1<<24)|(5<<16)|(1<<12)|(4<<8)|(6<<4)|(0<<0));
/* Set MP01_1 as SROM_CSn[1] */
tmp = MP01CON_REG;
tmp &=~(0xf<<4);
tmp |=(2<<4);
MP01CON_REG = tmp;
}
(8)修改DDR0的基地址和配置寄存器将 DDR 的 ch0 由地址 0x20000000~0x30000000 映射到 0x30000000~0x40000000。修改include目录下的configs目录下的smdkv210single.h,将:
#define MEMORY_BASE_ADDRESS 0x20000000
#define DMC0_MEMCONFIG_0 0x20F00313
改为:
#define MEMORY_BASE_ADDRESS 0x30000000
#define DMC0_MEMCONFIG_0 0x30F00313
(9)修改虚拟地址转物理地址函数,打开board目录下的samsung目录下的smdkc110目录下的smdkc110.c文件,将:
# ifdef CONFIG_MCP_SINGLE
ulong virt_to_phy_smdkc110(ulong addr)
{
if ((0xc0000000 <= addr) && (addr < 0xd0000000))
return (addr - 0xc0000000 + 0x20000000);
else
printf("The input address don't need "\
"a virtual-to-physical translation : %08lx\n", addr);
return addr;
}
改为:
#ifdef CONFIG_MCP_SINGLE
ulong virt_to_phy_smdkc110(ulong addr)
{
if ((0xc0000000 <= addr) && (addr < 0xd0000000))
return (addr - 0xc0000000 + MEMORY_BASE_ADDRESS);
else
printf("The input address don't need "\
"a virtual-to-physical translation : %08lx\n", addr);
return addr;
}
(10)修改 MMU 转换表,打开board目录下的samsung目录下的smdkc110目录下的lowlevel_init.S文件,将:
.set __base,0x200
.rept 0xD00 - 0xC00
FL_SECTION_ENTRY __base,3,0,1,1
.set __base,__base+1
.endr
改为:
.set __base,0x300
.rept 0xD00 - 0xC00
FL_SECTION_ENTRY __base,3,0,1,1
.set __base,__base+1
.endr
(11)因为本设计的开发板没有SRAM 和电源管理芯片,所以需要屏蔽SRAM初始化代码和PMIC 代码,还是打开lowlevel_init.S文件,屏蔽掉PMIC_InitIp这一行代码,然后使用条件编译屏蔽掉下面的代码:
#if 0
ldr r0, =ELFIN_GPIO_BASE
……省略部分代码……
ldr r1, [r0]
orr r1, r1, #0x300
orr r1, r1, #0x1
str r1, [r0]
#endif
(12)屏蔽 nor flash 初始化代码,打开lib_arm目录下的board.c文件,将:
#ifndef CFG_NO_FLASH
size = flash_init ();
display_flash_config (size);
#endif
改为:
#define CFG_NO_FLASH
#ifndef CFG_NO_FLASH
size = flash_init ();
display_flash_config (size);
#endif
(13)修改 uboot 环境参数
(1 修改主机名称
$vim include/configs/smdkv210single.h
修改主机名称:
#define CFG_PROMPT "GEC210 #" /* Monitor Command Prompt */
改为:
#define CONFIG_IDENT_STRING " for GEC210V1@2014"
(2 修改默认参数配置
$vim include/configs/smdkv210single.h
修改:
#define CONFIG_ETHADDR 00:40:5c:26:0a:5a
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.1.3
#define CONFIG_SERVERIP 192.168.1.2
#define CONFIG_GATEWAYIP 192.168.1.1
(3 修改驱动参数和命令
$vim include/configs/smdkv210single.h
修改为:
#define CONFIG_BOOTARGS "root=/dev/nfs init=/linuxrc nfsroot=192.168.1.141:/home/student/workdir/rootfs ip=192.168.1.20:192.168.1.141:192.168.1.1:255.255.255.0::eth0:on console=ttySAC0,115200"
(14).编译
make smdkv210single_config
make //生成u-boot.bin
使用tftp将u-boot.bin下载到开发板,然后从0地址擦除大小为1M的内容,存放的地址是根据uboot里维护了一份分区表,内核里面维护了一份分区表,这两份分区表必须一样,本设计的分区表如下表所示。最后使用命令nand erase 0 0x100000将uboot写入nand flash中。做好以上的工作后,uboot的移植就成功完成了,当重新上电后,uboot正常启动会根据默认设置来启动内核。
内核和uboot共同维护的分区表
分区名 |
起始地址 |
结束地址 |
大小 |
Uboot |
0x000000000000 |
0x000000100000 |
0x000000100000 1MB |
Recovery |
0x000000100000 |
0x000000600000 |
0x000000500000 5MB |
Kernel |
0x000000600000 |
0x000000b00000 |
0x000000500000 5MB |
Ramdisk |
0x000000b00000 |
0x000000e00000 |
0x000000300000 3MB |
Root |
0x000000e00000 |
0x000020000000 |
0x00001F200000 498MB |