WinCE6.0 BootloaderMain源码分析之OEMPlatformInit

简介:
  由于下面分析的内容与硬件平台将会有紧密的联系,但是整体的处理流程类似,所以在开始先声明一下硬件平台: 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的操作还有些没弄清楚,等以后弄明白了再写!


本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/603457,如需转载请自行联系原作者
相关文章
|
3月前
|
中间件 Linux 芯片
一张图秒懂嵌入式Linux系统的启动流程
一张图秒懂嵌入式Linux系统的启动流程
58 0
|
4月前
|
数据可视化 Linux UED
QT基础教程(GUI程序原理分析)
QT基础教程(GUI程序原理分析)
38 0
|
Linux API 开发工具
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十七)多线程编程(下)
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十七)多线程编程
281 0
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十七)多线程编程(下)
|
Linux 调度 开发工具
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十七)多线程编程(上)
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十七)多线程编程
207 0
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十七)多线程编程(上)
|
存储 API 调度
基于STM32移植UCGUI图形界面框架(3.9.0源码版本)
基于STM32移植UCGUI图形界面框架(3.9.0源码版本)
506 0
基于STM32移植UCGUI图形界面框架(3.9.0源码版本)
|
NoSQL 小程序 Linux
开源代码分析技巧之——高效Windows源码分析
引言:项目开发中,我们免不了在已有代码或版本的基础上新增代码。这个时候,如何高效的读懂别人代码逻辑,如何从几十万乃至上百万行代码中找到自己需要的逻辑显得尤为重要。
142 0
开源代码分析技巧之——高效Windows源码分析
|
XML 物联网 开发工具
(1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
原文:(1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序 版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
1229 0
|
编解码 自然语言处理 C语言
x264源代码分析-转
相关说明: 1.     使用版本:  x264-cvs-2004-05-11 2.     这次的分析基本上已经将代码中最难理解的部分做了阐释,对代码的主线也做了剖析,如果这个主线理解了,就容易设置几个区间,进行分工阅读,将各个区间击破了.
955 0