您的位置:首页 > 大数据 > 人工智能

WinCE6.0 BootloaderMain源码分析之OEMPlatformInit

2011-07-05 21:32 417 查看
由于下面分析的内容与硬件平台将会有紧密的联系,但是整体的处理流程类似,所以在开始先声明一下硬件平台:Android6410开发板BSP、WinCE6.0。本文的内容仅是本人在学习bootloader过程中的一些记录,如果有不正确的地方,还望指正。
上传的图片被自动缩小了,想看的话直接拖到下一个标签中看吧,那样看到的是大图。
前面已经分析了BootloaderMain的全局变量重定位和调试串口初始化,接下来便是函数OEMPlatformInit,该函数主要实现目标板上设备的初始化,由OEM实现,包括初始化显示器、Flash、网卡以及BSP共享参数,如果在EBoot里面用到USB下载,则还需要进行USB的初始化。下面先给出源代码:











832行的InitializeDisplay函数用来初始化显示设备,定义在同一源文件main.c中,在这个函数中实现了开机启动界面以及启动时的进度条的显示,如果想要修改启动界面和进度条的话,可以在该函数里面找到方法。
835行的OALArgsInit函数初始化BSP参数结构体,定义在文件\WINCE600\PLATFORM\<BSP name>\SRC\COMMOM\ARG\args.c中。pBSPArgs是结构体BSP_ARGS的指针,指向内存RAM中的一块内存,用来存储一些数据信息,这些数据是在BootLoader和操作系统OAL之间的共享信息,也称为共享启动参数。
837到839行使用全局变量记录BSP的共享参数。
841行的InitializeInterrupt函数进行中断相关的初始化,包括清空中断向量表,开启IRQ中断等,其实现在\WINCE600\PLATFORM\<BSP name>\SRC\BOOTLOADER\EBOOT\usb.c文件中。
846到865行主要对NAND Flash初始化。这里用到了微软提供的一个分区模块,它是在Flash驱动支持下的用来操作存储设备的模块。首先调用BP_Init函数对NAND Flash进行分区,即调用FMD_Init来初始化Flash设备并初始化一块内存,并记录下相关的Flash信息。
868到872行的TOC_Read函数,用来从NAND Flash中读取TOC的内容,定义在文件\WINCE600\PLATFORM\<BSP name>\SRC\BOOTLOADER\EBOOT\Nand.cpp中。如果读取失败了,调用TOC_Init函数将TOC设置为默认,它的定义也在Nand.cpp中。
905到907行,调用OEMEthGetSecs函数获取当前时间,这部分为后面判断超时做准备工作。
910到913行对USB设备进行初始化,为后面通过USB进行镜像下载等准备。函数InitializeUSB在\WINCE600\PLATFORM\<BSP name>\SRC\BOOTLOADER\EBOOT\usb.c文件中。
917到961行等待用户输入,从而进入bootloader menu界面,并回显剩余的等待时间,如果超时则继续启动工作。
967到987行对用户输入的选择进行判断,如果用户按下了空格键,则进入bootloader menu主界面,通过函数MainMenu显示主界面,它定义在文件main.c源文件中,其他选项则继续后面的工作。
991到1018行记录前面用户配置的一些参数,都保存到了全局变量中。
1020到1052行表示如果用户不想要下载镜像,则从NAND Flash中启动。g_ImageType代表镜像的类别,包括stepldr.bin、eboot.bin和nk.bin,如果是要启动nk.bin,则从Flash中读出OSImage,实现函数为ReadOSImageFromBootMedia。
1055到1062行表示如果用户想要下载镜像,而且不希望通过USB下载,那么初始化以太网设备,从以太网进行下载。当然本开发板是采用USB下载镜像的,所以g_bUSBDownload的值为TRUE。InitEthDevice函数定义在文件\WINCE600\PLATFORM\<BSP name>\SRC\BOOTLOADER\EBOOT中。

一、那么按着流程图的顺序,先来解析一下InitializeDisplay函数,调用InitializeDisplay主要用来初始化显示设备,也是这里对开机的启动界面进行的设置。先把源码粘出来。

static void InitializeDisplay(void)
{
tDevInfo RGBDevInfo;

volatile S3C6410_GPIO_REG *pGPIOReg = (S3C6410_GPIO_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_GPIO, FALSE);
volatile S3C6410_DISPLAY_REG *pDispReg = (S3C6410_DISPLAY_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_DISPLAY, FALSE);
volatile S3C6410_SPI_REG *pSPIReg = (S3C6410_SPI_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_SPI0, FALSE);
volatile S3C6410_MSMIF_REG *pMSMIFReg = (S3C6410_MSMIF_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_MSMIF_SFR, FALSE);

volatile S3C6410_SYSCON_REG *pSysConReg = (S3C6410_SYSCON_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_SYSCON, FALSE);

EdbgOutputDebugString("[Eboot] ++InitializeDisplay()\r\n");

// Initialize Display Power Gating
if(!(pSysConReg->BLK_PWR_STAT & (1<<4))) {
pSysConReg->NORMAL_CFG |= (1<<14);
while(!(pSysConReg->BLK_PWR_STAT & (1<<4)));
}
//denis_wei add to turn on the backlight 2009-09-28
pGPIOReg->GPFCON &= ~(0x03<<28); // Set GPF14 to OUTPUT mode.
pGPIOReg->GPFCON |= (0x1 << 28);
pGPIOReg->GPFDAT |= (1<<14);
//add end 2009-09-28

// Initialize Virtual Address
LDI_initialize_register_address((void *)pSPIReg, (void *)pDispReg, (void *)pGPIOReg);
Disp_initialize_register_address((void *)pDispReg, (void *)pMSMIFReg, (void *)pGPIOReg);
//gao0131
// Set LCD Module Type
#if (SMDK6410_LCD_MODULE == LCD_MODULE_UT_LCD35A)
LDI_set_LCD_module_type(LDI_LCD35A_RGB);
#elif (SMDK6410_LCD_MODULE == LCD_MODULE_UT_LCD43D)
LDI_set_LCD_module_type(LDI_LCD43D_RGB);
#elif (SMDK6410_LCD_MODULE == LCD_MODULE_UT_LCD7B)
LDI_set_LCD_module_type(LDI_LCD7B_RGB);
#elif (SMDK6410_LCD_MODULE == LCD_MODULE_UT_LCD102A)
LDI_set_LCD_module_type(LDI_LCD102A_RGB);
#elif (SMDK6410_LCD_MODULE == LCD_MODULE_UT_LCD102B)
LDI_set_LCD_module_type(LDI_LCD102B_RGB);
#elif (SMDK6410_LCD_MODULE == LCD_MODULE_UT_LCD104C)
LDI_set_LCD_module_type(LDI_LCD104C_RGB);
#elif (SMDK6410_LCD_MODULE == LCD_MODULE_VGA6448)
LDI_set_LCD_module_type(LDI_VGA6448_RGB);
#elif (SMDK6410_LCD_MODULE == LCD_MODULE_VGA8060)
LDI_set_LCD_module_type(LDI_VGA8060_RGB);
#else
EdbgOutputDebugString("[Eboot:ERR] InitializeDisplay() : Unknown Module Type [%d]\r\n", SMDK6410_LCD_MODULE);
#endif

// Get RGB Interface Information from LDI Library
LDI_fill_output_device_information(&RGBDevInfo);

// Setup Output Device Information
Disp_set_output_device_information(&RGBDevInfo);

// Initialize Display Controller
Disp_initialize_output_interface(DISP_VIDOUT_RGBIF);

#if (LCD_BPP == 16)
Disp_set_window_mode(DISP_WIN1_DMA, DISP_16BPP_565, LCD_WIDTH, LCD_HEIGHT, 0, 0);
#elif (LCD_BPP == 32) // XRGB format (RGB888)
Disp_set_window_mode(DISP_WIN1_DMA, DISP_24BPP_888, LCD_WIDTH, LCD_HEIGHT, 0, 0);
#else
EdbgOutputDebugString("[Eboot:ERR] InitializeDisplay() : Unknown Color Depth %d bpp\r\n", LCD_BPP);
#endif

Disp_set_framebuffer(DISP_WIN1, EBOOT_FRAMEBUFFER_PA_START);
Disp_window_onfoff(DISP_WIN1, DISP_WINDOW_ON);

// Initialize LCD Module
LDI_initialize_LCD_module();

// Video Output Enable
Disp_envid_onoff(DISP_ENVID_ON);

// Fill Framebuffer
#if(SMDK6410_LCD_MODULE == LCD_MODULE_UT_LCD35A)
memcpy((void *)EBOOT_FRAMEBUFFER_UA_START, (void *)InitialImage_rgb16_320x240, 320*240*2);
#elif (LCD_BPP == 16)
{
int i;
unsigned short *pFB;
pFB = (unsigned short *)EBOOT_FRAMEBUFFER_UA_START;

for (i=0; i<LCD_WIDTH*LCD_HEIGHT; i++)
*pFB++ = 0x0000;//0x001F; // Blue

DisprogressBar();

}
#elif (LCD_BPP == 32)
{
int i;
unsigned int *pFB;
pFB = (unsigned int *)EBOOT_FRAMEBUFFER_UA_START;

for (i=0; i<LCD_WIDTH*LCD_HEIGHT; i++)
*pFB++ = 0x000000FF; // Blue
}
#endif

// TODO:
// Backlight Power On
//Set PWM GPIO to control Back-light Regulator Shotdown Pin (GPF[15])

// fusq 20090618 : disable buzzer when boot
// pGPIOReg->GPFDAT |= (1<<15);
// pGPIOReg->GPFCON = (pGPIOReg->GPFCON & ~(3<<30)) | (1<<30); // set GPF[15] as Output

// Display control by GPE0
pGPIOReg->GPEPUD &= ~(0x3); // Pull-Up/Down Disable
pGPIOReg->GPECON &= ~(0xf); // GPE0 -> Output
pGPIOReg->GPECON |= 0x1;
pGPIOReg->GPEDAT &= ~(0x1);

pGPIOReg->GPEDAT |= 0x1;

EdbgOutputDebugString("[Eboot] --InitializeDisplay()\r\n");
}
开始先声明了一个tDevInfo的结构体变量,tDevInfo的定义在文件S3c6410_display_con.h中,主要定义了一些属性变量,如下:

typedef struct _tDevInfo
{
DISP_VIDOUT_MODE VideoOutMode;
DISP_RGBIFOUT_MODE RGBOutMode;
unsigned int uiWidth;
unsigned int uiHeight;
unsigned int VBPD_Value;
unsigned int VFPD_Value;
unsigned int VSPW_Value;
unsigned int HBPD_Value;
unsigned int HFPD_Value;
unsigned int HSPW_Value;
unsigned int VCLK_Polarity;
unsigned int HSYNC_Polarity;
unsigned int VSYNC_Polarity;
unsigned int VDEN_Polarity;
unsigned int PNR_Mode;
unsigned int VCLK_Source;
unsigned int Frame_Rate;
unsigned int VCLK_Direction;
//unsigned int VCLK_Value;
} tDevInfo;
1718到1723行定义一些关于寄存器的变量,以便对相关寄存器进行设置。
1728到1731行主要是对电源模块的设置,BLK_PWR_STAT是块电源的状态寄存器,第4位为1表示块F电源准备就绪,而NORMAL_CFG用来激活块F电源。
1733到1735行设置GPF14为输出模式,而且输出高电平,这样是为了打开背景光,这个设置于硬件连接有关,要看背景光开启脚连接到了CPU的哪个IO口上。
1740和1741两行的功能类型,LDI_initialize_register_address函数定义在文件S3c6410_ldi.c中,Disp_initialize_register_address函数定义在文件S3c6410_display_con.c中。这两个函数主要是用全局变量记录下这几个寄存器的相关设置。
1744到1762行是用来判断LCD模块的类型的,也就是3.5寸还是4.3寸等。
1765行的LDI_fill_output_device_information函数在,根据前面选择的LCD模块类型,填充结构体RGBDevInfo的内容。
1767行的Disp_set_output_device_information函数在文件S3c6410_display_con.h中,将结构体RGBDevInfo的内容设置记录到全局变量g_DevInfoRGB中。
1771行的Disp_initialize_output_interface函数在文件S3c6410_display_con.h中,按视频或图像输出模式为DISP_VIDOUT_RGBIF对IO端口和视频控制寄存器以及视频时序控制寄存器进行设置。
1773到1779行的Disp_set_window_mode函数在文件S3c6410_display_con.h中,对相应窗口格式进行初始化。
1781行的Disp_set_framebuffer函数在文件S3c6410_display_con.h中,主要对源图像缓冲区地址进行设置。
1782行的Disp_window_onfoff函数在文件S3c6410_display_con.h中,用于使能相应窗口的视频输出和VIDEO控制信号。
1785行的LDI_initialize_LCD_module函数在文件S3c6410_ldi.c中,用来初始化LCD。
1788行的Disp_envid_onoff函数在文件S3c6410_display_con.h中,使能视频输出。
1791到1851行用来填充源图像缓冲区的内容。其中DisprogressBar函数在文件main.c中,用来显示处理的进度条。
1863到1868行通过对端口GPE0的输出来控制显示器。

二、OALArgsInit函数
该函数用来设置一个数据结构,该数据结构承载了BootLoader和操作系统之间的共享信息,比如IP地址、子网掩码以及用户在Bootloader的选项菜单中作出的选择,这些从BootLoader共享给操作系统使用的数据也称为启动参数。其实这些启动参数用BootLoader共享给操作系统的OAL模块的,所以共享哪些参数都是由OEM用户自己开发的,内容也不是通用的。
下面是该函数的实现内容:

VOID OALArgsInit(BSP_ARGS* pArgs)
{
int i;
OALMSG(OAL_FUNC, (TEXT("+OALArgsInit()\r\n")));

// Check the BSP Args area
//
if ((pArgs->header.signature == OAL_ARGS_SIGNATURE)
|| (pArgs->header.oalVersion == OAL_ARGS_VERSION)
|| (pArgs->header.bspVersion == BSP_ARGS_VERSION))
{
OALMSG(OAL_INFO, (TEXT("Arguments area has some values. Do not Initialize\r\n")));
OALMSG(OAL_VERBOSE, (TEXT("pArgs :0x%x\r\n"), pArgs));
for(i=0;i<sizeof(BSP_ARGS); i++)
{
OALMSG(OAL_VERBOSE, (TEXT("0x%02x "),*((UINT8*)pArgs+i)));
}
}
else
{
volatile S3C6410_SYSCON_REG *pSysConReg;
DWORD count, code, j;
UCHAR d;

pSysConReg = (S3C6410_SYSCON_REG *)OALPAtoUA(S3C6410_BASE_REG_PA_SYSCON);

memset(pArgs, 0x0, sizeof(BSP_ARGS));

// Setup header
pArgs->header.signature = OAL_ARGS_SIGNATURE;
pArgs->header.oalVersion = OAL_ARGS_VERSION;
pArgs->header.bspVersion = BSP_ARGS_VERSION;

//Set-up device ID for SMDK6410
count = sizeof(BSP_DEVICE_PREFIX) - 1; // BSP_DEVICE_PREFIX = "SMDK6410" defined in bsp_cfg.h

if (count > sizeof(pArgs->deviceId)/2) count = sizeof(pArgs->deviceId)/2;
memcpy(pArgs->deviceId, BSP_DEVICE_PREFIX, count);

code = pSysConReg->SYS_ID;
OALMSG(TRUE, (TEXT("SocID:0x%x\n"),code, sizeof(pArgs->deviceId)));

// Convert it to hex number
// 36410101 -> extract 6410101, means 6410 EVT1
for (j = 28; j >= 0 && count < sizeof(pArgs->deviceId); j -= 4)
{
d = (UCHAR)((code >> j) & 0xF);
pArgs->deviceId[count++] = ((d < 10) ? ('0' + d) : ('A' + d - 10));
}

// End string will be "SMDK6410641010x"
while (count < sizeof(pArgs->deviceId)) pArgs->deviceId[count++] = '\0';

count = 0;
// Set-up dummy uuid for SMDK6410.
// Actually, S3C6410 does not provide UUID for each chip
// So on S3C6410 EVT1, uuid will be 3641010136410101
for(j=60; j> 0 && count < sizeof(pArgs->uuid); j -=4)
{
d = (UCHAR)(((code >> (j%32))) & 0xF);
pArgs->uuid[count++] = d < 10 ? '0' + d : 'A' + d - 10;
}
// Can Add code for cleanboot, hiveclean, formatpartion
OALMSG(TRUE, (TEXT("Arguments area is initialized\r\n")));
}

OALMSG(TRUE, (TEXT("-OALArgsInit()\r\n")));

return;
}

首先看输入参数pBSPArgs是一个宏,定义在文件\WINCE600\PLATFORM\<BSP name>\SRC\BOOTLOADER\EBOOT\loader.h中,如下
#define pBSPArgs ((BSP_ARGS *)IMAGE_SHARE_ARGS_UA_START)
该宏代表的是一个内存地址,实际上一块RAM内存空间的指针,所指向的内存就是用来专门存储共享启动参数的。
在文件\WINCE600\PLATFORM\<BSP name>\SRC\INC\Bsp_args.h中给出了结构体BSP_ARGS的定义,如下:

typedef struct
{
OAL_ARGS_HEADER header;
UINT8 deviceId[16]; // Device identification
OAL_KITL_ARGS kitl;
UINT8 uuid[16];
BOOL bUpdateMode; // TRUE = Enter update mode on reboot.
BOOL bHiveCleanFlag; // TRUE = Clean hive at boot
BOOL bCleanBootFlag; // TRUE = Clear RAM, user objectstore at boot
BOOL bFormatPartFlag; // TRUE = Format partion when mounted at boot
DWORD nfsblk; // for NAND Lock Tight
HANDLE g_SDCardDetectEvent; //For USB MSF , check SD Card insert & remove.
DWORD g_SDCardState; //For USB MSF , check SD Card insert & remove.
} BSP_ARGS;
header成员是启动参数的头信息,定义在文件\WINCE600\PLATFORM\COMMON\SRC\INC\oal_args.h中,由于指示pBSPArgs内存区域是否包含有效的共享数据、版本及如何使用其中的信息。
OALArgsInit函数开始先判断共享的启动参数是否有效,即如果版本号发生变化意味着启动参数的结构体定义发生了变化,需要重新填充启动参数的内容。
deviceId成员和kitl成员用于BootLoader向OAL传递用户对KITL的选项设置参数。deviceID是16字节的设备名字字符串,标识用于做KITL传输功能的端口外设。kitl成员用于存放KITL端口外设在目标系统的硬件位置和软件配置信息。OALArgsInit函数的54到71行用于设置deviceID成员的值。
uuid成员是16字节的CPU芯片的虚拟ID字符串。OALArgsInit函数的73到84行就是用来填充uuid字符串的。

该函数是eboot里面最为复杂的函数,里面有一些关于nand的操作还有些没弄清楚,等以后弄明白了再写!本文出自 “飞雪待剑” 博客,请务必保留此出处http://jazka.blog.51cto.com/809003/603457
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: