一. BootLoader简介<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
在专用的嵌入式板子运行GNU/Linux系统已经变得越来越流行。一个嵌入式Linux系统从软件的角度看通常可以分为四个层次:
1、 引导加载程序。包括固化在固件(firmware)中的boot代码(可选),和BootLoader两大部分。
2、 Linux内核。特定于嵌入式板子的定制内核以及内核的启动参数。
3、 文件系统。包括根文件系统和建立于Flash内存设备之上文件系统。通常用ramdisk来作为rootfs。
4、 用户应用程序。特定于用户的应用程序。有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面。常用的嵌入式GUI有:MicroWindows和MiniGUI懂。
引导加载程序是系统加电后运行的第一段软件代码。PC机中的引导加载程序由BIOS(其本质就是一段固件程序)和位于硬盘MBR中的OS BootLoader(比如,LILO和GRUB等)一起组成。BIOS在完成硬件检测和资源分配后,将硬盘MBR中的BootLoader读到系统的RAM中,然后将控制权交给OS BootLoader。BootLoader的主要运行任务就是将内核映象从硬盘上读到 RAM 中,然后跳转到内核的入口点去运行,也即开始启动操作系统。
而在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。比如在一个基于ARM7TDMI core的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。
简单地说,BootLoader就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。
通常,BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式世界。因此,在嵌入式世界里建立一个通用的BootLoader几乎是不可能的。尽管如此,我们仍然可以对BootLoader归纳出一些通用的概念来,以指导用户特定的BootLoader设计与实现。
二.U-BOOT介绍
uboot是一个庞大的公开源码的软件。他支持一些系列的arm体系,包含常见的外设的驱动,是一个功能强大的板极支持包。其代码可以从http://sourceforge.net/projects/u-boot下载
U-BOOT是由PPCBOOT发展起来的,是PowerPC、ARM9、Xscale、X86等系统通用的Boot方案,从官方版本<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />0.3.2开始全面支持SC系列单板机。u-boot是一个open source的bootloader,目前版本是0.4.0。u-boot是在ppcboot以及armboot的基础上发展而来,虽然宣称是0.4.0版本,却相当的成熟和稳定,已经在许多嵌入式系统开发过程中被采用。由于其开发源代码,其支持的开发板众多。唯一遗憾的是并不支持我们现在学习所用samsung 44B0X的开发板。
为什么我们需要u-boot?显然可以将ucLinux直接烧入flash,从而不需要额外的引导装载程序(bootloader)。但是从软件升级的角度以及程序修补的来说,软件的自动更新非常重要。事实上,引导装载程序(bootloader)的用途不仅如此,但仅从软件的自动更新的需要就说明我们的开发是必要的。
同时,u-boot移植的过程也是一个对嵌入式系统包括软硬件以及操作系统加深理解的一个过程。
三.disk模块分析
part.c:输出设备信息
part_amiga.c:处理amiga分区
part_dos.c:处理dos分区
part_iso.c:处理iso分区
part_mac.c:处理mac分区
Part.c文件:
void dev_print (block_dev_desc_t *dev_desc)
{ //主要用来向用户报告设备信息
……
if (dev_desc->type==DEV_TYPE_UNKNOWN) { //设备未知
puts ("not available\n");
return;
}
……
puts (" Type: ");
if (dev_desc->removable) //设备可移除
puts ("Removable ");
switch (dev_desc->type & 0x1F) { //输出设备类型
case DEV_TYPE_HARDDISK: puts ("Hard Disk");
break;
case DEV_TYPE_CDROM: puts ("CD ROM");
break;
case DEV_TYPE_OPDISK: puts ("Optical Device");
break;
case DEV_TYPE_TAPE: puts ("Tape");
break;
default: printf ("# %02X #", dev_desc->type & 0x1F);
break;
}
puts ("\n");
if ((dev_desc->lba * dev_desc->blksz)>0L) {
ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
lbaint_t lba;
lba = dev_desc->lba;
lba512 = (lba * (dev_desc->blksz/512));
mb = (10 * lba512) / 2048; /* 2048 = (1024 * 1024) / 512 MB */
/* round to 1 digit */
mb_quot = mb / 10;
mb_rem = mb - (10 * mb_quot);
gb = mb / 1024;
gb_quot = gb / 10;
gb_rem = gb - (10 * gb_quot);
……
}
else { puts (" Capacity: not available\n"); }
}
……
void init_part (block_dev_desc_t * dev_desc) //对分区iso,mac,dos,amiga进行初始化
{
#ifdef CONFIG_ISO_PARTITION //对应iso分区
……
#endif
#ifdef CONFIG_MAC_PARTITION //对应mac分区
……
#endif
#ifdef CONFIG_DOS_PARTITION //对应dos分区
……
#endif
#ifdef CONFIG_AMIGA_PARTITION //对应amiga分区
……
#endif
}
int get_partition_info (block_dev_desc_t *dev_desc, int part, disk_partition_t *info)
{ //获得不同分区的分区信息
switch (dev_desc->part_type) {
#ifdef CONFIG_MAC_PARTITION //对应mac分区,以下略
……
#endif
……
default:
break;
}
return (-1);
}
static void print_part_header (const char *type, block_dev_desc_t * dev_desc)
{ //输出设备、分区类型,如IDE, SCSI, ATAPI, USB, DOC, UNKNOWN
puts ("\nPartition Map for ");
switch (dev_desc->if_type) {
case IF_TYPE_IDE: puts ("IDE");
break;
……
default: puts ("UNKNOWN");
break;
}
printf (" device %d -- Partition Type: %s\n\n",
dev_desc->dev, type);
}
void print_part (block_dev_desc_t * dev_desc)
{ //输出分区信息
switch (dev_desc->part_type) {
#ifdef CONFIG_MAC_PARTITION
……
#endif
#ifdef CONFIG_DOS_PARTITION
……
#endif
#ifdef CONFIG_ISO_PARTITION
……
#endif
#ifdef CONFIG_AMIGA_PARTITION
……
#endif
}
puts ("## Unknown partition table\n");
}
Part_amiga文件:
static void bcpl_strcpy(char *to, char *from)
{ //将bcpl转换成c string
int len = *from++;
while (len)
{ *to++ = *from++; len--; }
*to = 0;
}
static void bstr_print(char *string)
{ //输出一个bcpl字符串。Bcpl字符串第一个byte保存了该字符串的长度
……
}
int sum_block(struct block_header *header)
{ //计算一个块的大小,块以0结束
……
for (i = 0; i < header->summed_longs; i++)
sum += *block++;
return (sum != 0);
}
static void print_disk_type(u32 disk_type)
{ //输出amigaOS 磁盘类型,一般由四个字节表示,例如DOS\0表示original file system,SFS\0表示SmartFileSystem,DOS\1表示FFS.
char buffer[6];
buffer[0] = (disk_type & 0xFF000000)>>24;
buffer[1] = (disk_type & 0x00FF0000)>>16;
buffer[2] = (disk_type & 0x0000FF00)>>8;
buffer[3] = '\\';
buffer[4] = (disk_type & 0x000000FF) + '0';
buffer[5] = 0;
printf("%s", buffer);
}
static void print_part_info(struct partition_block *p)
{ //输出给定分区块内的信息
……
bstr_print(p->drive_name);
printf("%6d\t%6d\t",
g->low_cyl * g->block_per_track * g->surfaces ,
(g->high_cyl - g->low_cyl + 1) * g->block_per_track * g->surfaces - 1);
print_disk_type(g->dos_type);
printf("\t%5d\n", g->boot_priority);
}
struct rigid_disk_block *get_rdisk(block_dev_desc_t *dev_desc)
{ //寻找Rigid Disk块。该块必须位于设备的最前面的16个块中
……
if (res == 1)
{
struct rigid_disk_block *trdb = (struct rigid_disk_block *)block_buffer;
if (trdb->id == AMIGA_ID_RDISK)
{
PRINTF("Rigid disk block suspect at %d, checking checksum\n",i);
if (sum_block((struct block_header *)block_buffer) == 0)
{
PRINTF("FOUND\n");
memcpy(&rdb, trdb, sizeof(struct rigid_disk_block));
return (struct rigid_disk_block *)&rdb;
}
}
}
}
PRINTF("Done scanning, no RDB found\n");
return NULL;
}
struct bootcode_block *get_bootcode(block_dev_desc_t *dev_desc)
{ //寻找启动代码,它必须在块设备前16个块中,或者在Ridgid块中
……
PRINTF("Scanning for BOOT from 0 to %d\n", limit);
for (i = 0; i < limit; i++)
{
ulong res = dev_desc->block_read(dev_desc->dev, i, 1, (ulong *)block_buffer);
if (res == 1)
{
struct bootcode_block *boot = (struct bootcode_block *)block_buffer;
if (boot->id == AMIGA_ID_BOOT)
{
PRINTF("BOOT block at %d, checking checksum\n", i);
if (sum_block((struct block_header *)block_buffer) == 0)
{
PRINTF("Found valid bootcode block\n");
memcpy(&bootcode, boot, sizeof(struct bootcode_block));
return &bootcode;
}
}
}
}
PRINTF("No boot code found on disk\n");
return 0;
}
int test_part_amiga(block_dev_desc_t *dev_desc)
{ //测试给定分区是否有amiga分区表/rigid块
……
PRINTF("test_part_amiga: Testing for an Amiga RDB partition\n");
rdb = get_rdisk(dev_desc);
if (rdb)
{
bootcode = get_bootcode(dev_desc);
if (bootcode)
PRINTF("test_part_amiga: bootable Amiga disk\n");
else
PRINTF("test_part_amiga: non-bootable Amiga disk\n");
return 0;
}
else
{
PRINTF("test_part_amiga: no RDB found\n");
return -1;
}
}
static struct partition_block *find_partition(block_dev_desc_t *dev_desc, int partnum)
{ //寻找指定分区号的分区
……
PRINTF("Trying to find partition block %d\n", partnum);
……
while (block != 0xFFFFFFFF)
{
ulong res = dev_desc->block_read(dev_desc->dev, block, 1,
(ulong *)block_buffer);
if (res == 1)
{
p = (struct partition_block *)block_buffer;
if (p->id == AMIGA_ID_PART)
{
PRINTF("PART block suspect at 0x%x, checking checksum\n",block);
if (sum_block((struct block_header *)p) == 0)
{
if (partnum == 0) break;
else
{
partnum--;
block = p->next;
}
}
} else block = 0xFFFFFFFF;
} else block = 0xFFFFFFFF;
}
……
return (struct partition_block *)block_buffer;
}
int get_partition_info_amiga (block_dev_desc_t *dev_desc, int part, disk_partition_t *info)
{ //获取一个分区的信息
……
if (!p) return -1;
g = (struct amiga_part_geometry *)&(p->environment);
info->start = g->low_cyl * g->block_per_track * g->surfaces;
info->size = (g->high_cyl - g->low_cyl + 1) * g->block_per_track * g->surfaces - 1;
info->blksz = rdb.block_bytes;
bcpl_strcpy(info->name, p->drive_name);
disk_type = g->dos_type;
info->type[0] = (disk_type & 0xFF000000)>>24;
info->type[1] = (disk_type & 0x00FF0000)>>16;
info->type[2] = (disk_type & 0x0000FF00)>>8;
info->type[3] = '\\';
info->type[4] = (disk_type & 0x000000FF) + '0';
info->type[5] = 0;
return 0;
}
void print_part_amiga (block_dev_desc_t *dev_desc)
{ //输出分区信息
……
PRINTF("print_part_amiga: Scanning partition list\n");
block = rdb->partition_list;
PRINTF("print_part_amiga: partition list at 0x%x\n", block);
printf("Summary: DiskBlockSize: %d\n"
" Cylinders : %d\n"
" Sectors/Track: %d\n"
" Heads : %d\n\n",
rdb->block_bytes, rdb->cylinders, rdb->sectors,
rdb->heads);
printf(" First Num. \n"
"Nr. Part. Name Block Block Type Boot Priority\n");
……
boot = get_bootcode(dev_desc);
if (boot)
{ printf("Disk is bootable\n"); }
}
文章评论(0条评论)
登录后参与讨论