bootload启动流程(四)--Eboot每个函数的详细说明

4OEMPreDownload ()

       这个函数也是boot里面实现的功能相对少点,但是也不能忽略,很多人在移植boot的时候实际就在这里容易出问题,关键是要搞清除你的一些flag参数。他的工作主要处理下载前的一些准备工作,我们首先看一下原型,然后对其进行分析:

DWORD OEMPreDownload()

{

    char szDeviceName[EDBG_MAX_DEV_NAMELEN];

    BOOL fGotJumpImg = FALSE;

    DWORD DHCPLeaseTime = 0, *pDHCPLeaseTime = &DHCPLeaseTime;

    EdbgOutputDebugString ( "/r/the address of DHCPLeaseTime is %x /r/n",&DHCPLeaseTime);

    // If user wants to jump to existing image with no KD - skip download...

    if ( !g_bDownloadImage && !g_bWaitForConnect)

    {

        return(BL_JUMP);

    }//如果不需要下载,则可以直接进行启动系统了

    if ( !g_bDownloadImage && g_bWaitForConnect )

        fGotJumpImg = TRUE;

 

 

//                 EdbgOutputDebugString ( "/r/fgojumpimg is %d /r/n",fGotJumpImg);

    // Create device name based on MAC address.

    memset(szDeviceName, 0, EDBG_MAX_DEV_NAMELEN);

    CreateDeviceName(&g_pBootCfg->EdbgAddr, szDeviceName);

    EdbgOutputDebugString("Using device name: '%s'/n", szDeviceName);

    // initialize TFTP transport

    if ( !(g_pBootCfg->ConfigFlags & CONFIG_FLAGS_DHCP) ) {

        pDHCPLeaseTime = NULL;  // the pDHCPLeaseTime parameter is overloaded.

                                // NULL indicates static IP

        pDriverGlobals->eth.EdbgFlags = EDBG_FLAGS_STATIC_IP;

    }

#ifndef SIMULATOR

         if ( g_bUSBDownload == FALSE )

         {

if (g_bDownloadImage &&

                            !EbootInitEtherTransport (&g_pBootCfg->EdbgAddr, &g_pBootCfg->SubnetMask, &fGotJumpImg, pDHCPLeaseTime,

EBOOT_VERSION_MAJOR, EBOOT_VERSION_MINOR, PLATFORM_STRING, szDeviceName, EDBG_CPUID, 0)) {

                            return BL_ERROR;

                   }

         }

#endif

//    SMCSetOptions(OPT_BROADCAST_FILTERING);

    // update DHCP lease time

    pDriverGlobals->eth.DHCPLeaseTime = DHCPLeaseTime;

         if ( g_bUSBDownload == TRUE )

             EdbgOutputDebugString("Please send the Image through USB/r/n");

    return fGotJumpImg? BL_JUMP : BL_DOWNLOAD;

}

这个函数实际只是在下载前打印了一些下载信息,比较简单,在这里主要确认是USB下载还是网线下载,或者直接从磁盘启动。

5DownloadImage()

重头戏来了,这个函数在Bootload里面应该算是最重要的,如果是移植别人的boot首先得看懂这个函数,如果是自己编写,首先得完成这里的OEM相关的东西。下面首先看一下原型,然后我们自己分析:

#define BL_HDRSIG_SIZE           7

static BOOL DownloadImage (LPDWORD pdwImageStart, LPDWORD pdwImageLength, LPDWORD pdwLaunchAddr)

{

    BYTE hdr[BL_HDRSIG_SIZE];

    DWORD dwRecLen, dwRecChk, dwRecAddr;

    BOOL fIsFlash;

    LPBYTE lpDest;

    int nPkgNum = 0;

         BYTE nNumRegions = 1;

         DWORD dwImageStart, dwImageLength;

         *pdwImageStart = *pdwImageLength = *pdwLaunchAddr = 0;

         //初始化所需下载参数

         EdbgOutputDebugString ("/r/nBegin to read magic number_1/r/n");

         do

         {

                   EdbgOutputDebugString ("/r/nBegin to read magic number_2/r/n");

                   // read the 7 byte "magic number"

                   if (!OEMReadData (BL_HDRSIG_SIZE, hdr)) {

                            EdbgOutputDebugString ("/r/nUnable to read image signature./r/n");

                            HALT (BLERR_MAGIC);

                            return FALSE;

                   }//读取BIN文件的标记

                   // check for multi-bin information packet.

                   if (!memcmp (hdr, "X000FF/x0A", BL_HDRSIG_SIZE)) {

                            // determine number of BIN files to be downloaded.

                            if (!OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecChk)) {

                                     EdbgOutputDebugString("/r/nUnable to read BIN region checksum./r/n");

                                     HALT (BLERR_MAGIC);

                                     return FALSE;

                            }

                            // read BIN region descriptions (start address and length).

                            if (!OEMReadData (sizeof (DWORD), (LPBYTE) &g_MultiBINInfo.dwNumRegions)

                                || !OEMReadData ((g_MultiBINInfo.dwNumRegions * sizeof(RegionInfo)), (LPBYTE) &g_MultiBINInfo.Region[0])) {

                                     EdbgOutputDebugString("/r/nUnable to read BIN region descriptors./r/n");

                                     HALT (BLERR_MAGIC);

                                     return FALSE;

                            }

                            // verify the packet checksum.

                            if (!VerifyChecksum((g_MultiBINInfo.dwNumRegions * sizeof(RegionInfo)), (LPBYTE) &g_MultiBINInfo.Region, dwRecChk)) {

                                     EdbgOutputDebugString ("/r/nBIN region descriptor packet failed checksum./r/n");

                                     HALT (BLERR_CHECKSUM);

                                     return FALSE;

                            }

                            // provide the region information to the OEM.

                            if (g_pOEMMultiBINNotify) {

                                     g_pOEMMultiBINNotify((const PMultiBINInfo)&g_MultiBINInfo);

                            }

                            // look for next download...

                            nNumRegions = (BYTE)(g_MultiBINInfo.dwNumRegions + 1);                  // +1 to account for this packet.

                            continue;

                   }

                   else {

                            // make sure it is a standard BIN file.

                            if (memcmp (hdr, "B000FF/x0A", BL_HDRSIG_SIZE)) {

                                     EdbgOutputDebugString ("/r/nThis is not a .BIN file %x %x %x %x %x %x %x/r/n",

                                               hdr[0], hdr[1], hdr[2], hdr[3], hdr[4], hdr[5], hdr[6]);

                                     HALT (BLERR_MAGIC);

                                     return FALSE;

                            }//确认为BIN文件

                   }

                   // read image start/length

                   if (!OEMReadData (sizeof (DWORD), (LPBYTE) &dwImageStart)

                            || !OEMReadData (sizeof (DWORD), (LPBYTE) &dwImageLength)) {

                            EdbgOutputDebugString ("Unable to read image start/length/r/n");

                            HALT (BLERR_MAGIC);

                            return FALSE;

                   }//读取镜像文件的运行地址和长度

                   // if this is a single-bin download, record the bin file information and notify the OEM.

                   if (!g_MultiBINInfo.dwNumRegions) {

                            g_MultiBINInfo.dwNumRegions             = 1;

                            g_MultiBINInfo.Region[0].dwRegionStart  = dwImageStart;

                            g_MultiBINInfo.Region[0].dwRegionLength = dwImageLength;

                            // provide the region information to the OEM.

                            if (g_pOEMMultiBINNotify) {

                                     g_pOEMMultiBINNotify((const PMultiBINInfo)&g_MultiBINInfo);

                            }//可选模块,与用户交互使用

                   }

                   // give the OEM a chance to verify memory

                   if (g_pOEMVerifyMemory && !g_pOEMVerifyMemory (dwImageStart, dwImageLength)) {

                            EdbgOutputDebugString ("!OEMVERIFYMEMORY: Invalid image/r/n");

                            HALT (BLERR_OEMVERIFY);

                            return FALSE;

                   }//确认下载类型

                   // check for flash image. Start erasing if it is.

                   if ((fIsFlash = OEMIsFlashAddr (dwImageStart))

                            && !OEMStartEraseFlash (dwImageStart, dwImageLength)) {

                            EdbgOutputDebugString ("Invalid Flash Address/Length/r/n");

                            HALT (BLERR_FLASHADDR);

                            return FALSE;

                   }//这断代码可选用在一些用户想要实现的东西上

                   // read records (start with address, length, and checksum)

                   while (OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecAddr)

                            && OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecLen)

                            && OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecChk)) {

//开始读取record

                            RETAILMSG(1, (_T("DownloadImage RecAddr: 0x%x/r/n"), dwRecAddr));

                            RETAILMSG(1, (_T("DownloadImage RecLen:  0x%x/r/n"), dwRecLen));

                            RETAILMSG(1, (_T("DownloadImage RecChk:  0x%x/r/n"), dwRecChk));

                            // check for last record

                            if (!dwRecAddr && !dwRecChk) {

                                     // if this is the kernel region, update launch address

                                     if (IsKernelRegion(dwImageStart, dwImageLength)) {

                                               *pdwImageStart  = dwImageStart;

                                               *pdwImageLength = dwImageLength;

                                               *pdwLaunchAddr  = dwRecLen;

//检测是不是最后一条record,如果是将跳转地址赋给launch

                             RETAILMSG(1, (_T("dwImageStart : 0x%x/r/n"), dwImageStart));

                             RETAILMSG(1, (_T("dwImageLength: 0x%x/r/n"), dwImageLength));

                             RETAILMSG(1, (_T("LaunchAddr   : 0x%x/r/n"), dwRecLen));

                                     }

                                     // write to flash if it's flash image

                                     if (fIsFlash) {

                                               // finish the flash erase

                                               if (!OEMFinishEraseFlash ()) {

                                                        HALT (BLERR_FLASH_ERASE);

                                                        return FALSE;

                                               }

                                               // Before writing the image to flash, optionally check the image signature.

                                               if (g_pOEMCheckSignature)

{

if (!g_pOEMCheckSignature(dwImageStart, g_dwROMOffset, *pdwLaunchAddr, TRUE))

                   HALT(BLERR_WHQL_SIGNATURE);

                                               }

                                     }

                                     // On to the next (possible) BIN file...

                                     break;

                            }

                            // map the record address (FLASH data is cached, for example)

                            lpDest = OEMMapMemAddr (dwImageStart, dwRecAddr);

//获得目标地址

                            // read data block

                            if (!OEMReadData (dwRecLen, lpDest)) {

         EdbgOutputDebugString ("****** Data record %d corrupted, ABORT!!! ******/r/n", nPkgNum);

                                     HALT (BLERR_CORRUPTED_DATA);

                                     return FALSE;

                            }//读取该记录的数据

                            if (!VerifyChecksum (dwRecLen, lpDest, dwRecChk)) {

EdbgOutputDebugString ("****** Checksum failure on record %d, ABORT!!! ******/r/n", nPkgNum);

                                     HALT (BLERR_CHECKSUM);

                                     return FALSE;

                            }//CRC和效验

// Look for ROMHDR to compute ROM offset.  NOTE: romimage guarantees that the record containing

// the TOC signature and pointer will always come before the record that contains the ROMHDR contents.

if (dwRecLen == sizeof(ROMHDR) && (*(LPDWORD) OEMMapMemAddr(dwImageStart, dwImageStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE))//检测TOC记录

                            {

DWORD dwTempOffset = (dwRecAddr - *(LPDWORD)OEMMapMemAddr(dwImageStart, dwImageStart + ROM_SIGNATURE_OFFSET + sizeof(ULONG)));

//找到TOC并且标记出偏移

                                     ROMHDR *pROMHdr = (ROMHDR *)lpDest;

                                     // Check to make sure this record really contains the ROMHDR.

                                     if ((pROMHdr->physfirst == (dwImageStart - dwTempOffset)) &&

                                               (pROMHdr->physlast  == (dwImageStart - dwTempOffset + dwImageLength)) &&

                                               (DWORD)(HIWORD(pROMHdr->dllfirst << 16) <= pROMHdr->dlllast) &&

                                               (DWORD)(LOWORD(pROMHdr->dllfirst << 16) <= pROMHdr->dlllast))

                                     {

                                               g_dwROMOffset = dwTempOffset;

                                               EdbgOutputDebugString("rom_offset=0x%x./r/n", g_dwROMOffset);

                                     }

                            }//这块代码实际是验证TOC的一些信息

                            // verify partial checksum

                            OEMShowProgress (nPkgNum ++);

                            if (fIsFlash) {

                                     OEMContinueEraseFlash ();

                            }

                   }

         }//下载完成

         while (--nNumRegions);

         if (fIsFlash) {

                   nNumRegions = (BYTE)g_MultiBINInfo.dwNumRegions;

                   while (nNumRegions--) {

                            if (!OEMWriteFlash (g_MultiBINInfo.Region[nNumRegions].dwRegionStart, g_MultiBINInfo.Region[nNumRegions].dwRegionLength)) {

                                     HALT (BLERR_FLASH_WRITE);

                                     return FALSE;

                            }

                   }

         }

    return TRUE;

}

这个函数整体实际也不是很难理解,但是用户可以在里面加入一些自己需要的模块就会使得其变得复杂,还有一个就是里面那个OEMReadData()函数是需要用户自己完成的,这个与你自己的下载硬件以及媒介有关系,在我的BOOT里面我选用的是USB下载方法,下面就将自己的这块代码贴出来与大家共享(我也是在前人的基础上自己修改的)。

BOOL OEMReadData (DWORD cbData, LPBYTE pbData)

{

         if ( g_bUSBDownload == FALSE )

         {

                   return EbootEtherReadData(cbData, pbData);

         }

         else

         {

                   return UbootReadData(cbData, pbData);

         }

}

从代码中可以看出实际调用了一个模块,而我选用的是USB,所以看下面的原型:

BOOL UbootReadData(DWORD cbData, LPBYTE pbData)

{

         volatile USBD_GLOBALS *usbdShMem = (USBD_GLOBALS *)(DRIVER_GLOBALS_PHYSICAL_MEMORY_START);

         volatile INTreg *s2440INT = (INTreg *)INT_BASE;

         volatile DMAreg *v_pDMAregs = (DMAreg *)DMA_BASE;

         unsigned int temp;

         int i;

         //初始化USB的一些寄存器地址

 

                  

Loop:

         if ( downPtIndex > readPtIndex + cbData )

         {      

                   memcpy(pbData, readPtIndex, cbData);

                   readPtIndex += cbData;

         //下载先于读取的时候开始读取数据

         }

         else if (downPtIndex == DMABUFFER)

         {

                   while (downPtIndex == DMABUFFER) {};   // first 64 bytes, get interrupt mode.

//64字节用中断读取,详细看后面的中断处理

                   if ( readPtIndex == DMABUFFER )

                   {

                            readPtIndex +=  8;

                            memcpy(pbData, readPtIndex, cbData);

                            readPtIndex += cbData;

                            //读取下载中缓存中的数据,这里首先第一组数据必须小于64字节

                   }

                   s2440INT->rSRCPND  = BIT_USBD;

                   if (s2440INT->rINTPND & BIT_USBD) s2440INT->rINTPND = BIT_USBD;

                   s2440INT->rINTMSK |= BIT_USBD;            // USB Interrupt disable.

                   //USB中断关掉

                   // read data with DMA operation.

                   s2440INT->rSRCPND  = BIT_DMA2;

                   if (s2440INT->rINTPND & BIT_DMA2) s2440INT->rINTPND = BIT_DMA2;

                   s2440INT->rINTMSK &= ~BIT_DMA2;                // DMA Interrupt enable.

              //启动DMA中断

                   pUSBCtrlAddr->INDEX.index=3;

                   CLR_EP3_OUT_PKT_READY();

                   ConfigEp3DmaMode(downPtIndex,0x80000);

             //配置DMA模式

                   v_pDMAregs->rDIDST2=(downPtIndex+0x80000);        //for 1st autoreload.

                   v_pDMAregs->rDIDSTC2=(1<<2)|(0<<1)|(0<<0);

                   v_pDMAregs->rDCON2=v_pDMAregs->rDCON2&~(0xfffff)|(0x80000);

                   //第一次DMA重载

                   while(rEP3_DMA_TTC<0xfffff)

                   {

                            pUSBCtrlAddr->EP3DTL.ep3_ttl_l = 0xff;

                            pUSBCtrlAddr->EP3DTM.ep3_ttl_m = 0xff;

                            pUSBCtrlAddr->EP3DTH.ep3_ttl_h = 0x0f;

                   }

         }

         else

         {

                   temp = rEP3_DMA_TTC;

                   for (i = 0; i < 60000; i++ )

                   {

                   }

                   if ( temp == rEP3_DMA_TTC )

                   {

                            downPtIndex += ((unsigned int)0xfffff - (unsigned int)rEP3_DMA_TTC);

                   }

                   goto Loop;

         }

                   return TRUE;

}

#pragma optimize ("",on)

这断代码整体是很简单,但是也存在几个问题大家需要注意一下。代码首先用中断读取数据,详细过程看下面函数:

void Ep3Handler(void)

{

    int fifoCnt;

         volatile INTreg *s2440INT = (INTreg *)INT_BASE;

    pUSBCtrlAddr->INDEX.index=3;

    if(pUSBCtrlAddr->OCSR1.out_pkt_rdy)//中断标记

    {

                   fifoCnt=pUSBCtrlAddr->OFCR1.out_cnt_low;//读取计数值

                   downPt = (LPBYTE)(downPtIndex);//一定要转换

                   RdPktEp3((U8 *)downPt,fifoCnt);

                   downPtIndex += 64;

                   s2440INT->rINTMSK |= BIT_USBD;            // USB Interrupt disable.

                   return;

    }

    //I think that EPO_SENT_STALL will not be set to 1.

    if(pUSBCtrlAddr->OCSR1.sent_stall)

    {

               CLR_EP3_SENT_STALL();

                return;

    }

}

后面配置DMA并且开启DMA中断,当第一次DMA读取数据完成以后(即CURR_TC == 0),进去DMA中断再次配置相关设置。这个过程比较简单,但是细心的读者会发现这段代码在一些很细致的地方写的很精致,如在配置完DMA读取的时候,代码中多写了一次装载信息v_pDMAregs->rDIDST2=(downPtIndex+0x80000);        //for 1st autoreload.。这样会使得DMACPU同时工作将目标地址提前写进去。然后等第一次DMA结束后中断设置和DMA加载同时进行提高运行效率。

      在实际中这里的代码有很多很值得研究的地方,比如细心的读者就会发现这里的DMAMEMSET函数用的都是物理地址,而有些地方用的却是虚拟地址。这样写是为了代码的可扩展性。但是为什么是正确的呢?这里我就先不说明了,可给你更多自己思考的空间。如果有读者要进行探讨我可以email给他答案,实际只要细心这个问题很简单,顺便提一句,实际这些代码都是经过多次改写和慎密优化过的。所以代码只有精简实现功能强大才能优秀。

6OEMLaunch()

下面我们来研究一下这里最后一个也很关键的函数,这个函数实现了内核的开始运行以及烧写到FLASH的过程。先来看原型:

void OEMLaunch(DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr, const ROMHDR *pRomHdr)

{

    EDBG_OS_CONFIG_DATA *pCfgData;

    EDBG_ADDR EshellHostAddr = {0,0,0};

    EdbgOutputDebugString("::OEMLaunch, ImageStart:0x%x, ImageLength:0x%x, LaunchAddr:0x%x/r/n",

        dwImageStart, dwImageLength, dwLaunchAddr);

    // If the user requested an image be stored on media, do so now.  For multiple RAM BIN files, we need to map

    // its RAM address to a flash address - the image base address offset in RAM is maintained in flash.

 

    // Remember kernel launch address or recall stored address if this download didn't provide one

    // (i.e., we didn't download the kernel region).

    EdbgOutputDebugString ( "/r/nto_g_pBootCfg->ConfigFlags =%x/r/n",g_pBootCfg->ConfigFlags);

    if (g_bDownloadImage && (g_pBootCfg->ConfigFlags & TARGET_TYPE_NAND))

    {

         if (dwImageStart && dwImageLength)//需要写入FLASH的标记,如果设置为0就不用烧写FLASH

                  {

                            g_pTOC->id[g_dwTocEntry].dwLoadAddress = dwImageStart;

                            g_pTOC->id[g_dwTocEntry].dwTtlSectors = FILE_TO_SECTOR_SIZE(dwImageLength);

                  }//在这里更新TOC(BLOCK),以便在镜像从FLASH启动的时候调用

         EdbgOutputDebugString ( "/r/ng_ImageType_to =%x/r/n",g_ImageType);

        switch ( g_ImageType ) {

            case IMAGE_TYPE_LOADER:

                EdbgOutputDebugString("OEMLaunch: IMAGE_TYPE_LOADER/r/n");

                if ( !WriteRamImageToBootMedia(g_dwTocEntry) ) {

                    RETAILMSG(1, (TEXT("OEMLaunch ERROR: Failed to write image to boot media./r/n")));

                    SPIN_FOREVER;

                }

                break;

            case IMAGE_TYPE_RAMIMAGE:

                EdbgOutputDebugString("OEMLaunch: IMAGE_TYPE_RAMIMAGE/r/n");

                if ( !WriteRamImageToBootMedia(g_dwTocEntry) ) {

                    RETAILMSG(1, (TEXT("OEMLaunch ERROR: Failed to write image to boot media./r/n")));

                    SPIN_FOREVER;

                }

                break;

            case (IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS|IMAGE_TYPE_MXIP):

            case (IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS):

                EdbgOutputDebugString("OEMLaunch: (%s|IMAGE_TYPE_BINFS)/r/n",

 (g_ImageType & IMAGE_TYPE_MXIP) ? "IMAGE_TYPE_MXIP" : "IMAGE_TYPE_RAMIMAGE");

if ( !WriteRegionsToBootMedia(dwImageStart, dwImageLength, dwLaunchAddr) ) {

//调用函数将下载镜像写入flash,注意这里写入的nb0,而不是bin文件

EdbgOutputDebugString("WARNING: OEMLaunch: Failed to store BinFS regions to boot media./r/n");

                    SPIN_FOREVER;

                }

                break;

            default:

EdbgOutputDebugString("OEMLaunch ERROR: unknown image type: 0x%x /r/n",

                    g_pTOC->id[g_dwTocEntry].dwImageType);

                SPIN_FOREVER;

        }

    }

         // Remember kernel launch address or recall stored address if this download didn't provide one (i.e., we didn't download the kernel region).

         if (dwLaunchAddr && (g_pTOC->id[g_dwTocEntry].dwJumpAddress != dwLaunchAddr))

         {

                  g_pTOC->id[g_dwTocEntry].dwJumpAddress = dwLaunchAddr;

                  if ( !TOC_Write() ) {

            EdbgOutputDebugString("*** OEMLaunch ERROR: TOC_Write failed! Next boot may not load from disk *** /r/n");

                  }

        TOC_Print();

         }//如果TOC的内核运行地址和下载的不一致,更新运行地址

         else

         {

                  dwLaunchAddr= g_pTOC->id[g_dwTocEntry].dwJumpAddress;

EdbgOutputDebugString("INFO: using TOC[%d] dwJumpAddress: 0x%x/r/n", g_dwTocEntry, dwLaunchAddr);

         }

    //  Our Launch function takes Physical address, so we need to convert it

    //  to physical address

   dwLaunchAddr = ToPhysicalAddr(dwLaunchAddr);//下面的启动函数只认识物理地址,所以转换地址

    EdbgOutputDebugString("/r/n::: Physical Launch Address: 0x%Xh/r/n",dwLaunchAddr);

    Launch(dwLaunchAddr);

//启动内核

    // never returned

    SPIN_FOREVER;

}

从上面的注释你不难发现这个函数其实功能也相当单一,首先检测是不是需要将内核写入磁盘,如果需要先更新TOC,然后写入磁盘,最后开始运行内核。

在这里首先接受两个简单函数,一个地址转换,另一个跳转。这两个函数虽然简单,但是在整个ARM编程中很具有代表性,所以在这里需要提一下:

DWORD  ToPhysicalAddr(DWORD add)

{

            padd = add - vir_start + phy_start;

return padd;

}//这里代码不是这样的,我是为了清晰将关键的部分提取出来了,其实也简单。ARM中无论汇编还是C其实现的思想就是这样,是没法变的。

下面是Launch()原型:

    TEXTAREA

    LEAF_ENTRY Launch

    ldr r2, = PhysicalStart

    ldr     r3, = (VIR_RAM_START - PHY_RAM_START)

    sub     r2, r2, r3//计算PhysicalStart的物理地址

    mov     r1, #0x0070             ; Disable MMU

    mcr     p15, 0, r1, c1, c0, 0

    nop//MMU并且进入PhysicalStart

    mov     pc, r2                  ; Jump to PStart

    nop

    ; MMU & caches now disabled.

PhysicalStart

    mov     r2, #0

    mcr     p15, 0, r2, c8, c7, 0   ; Flush the TLB

    mov     pc, r0          ; Jump to program we are launching.

//启动内核,注意这里MMU启动与否都没有关系,因为内核还需要初始化一次内核

    mov pc, lr

    END

 

接下来我们讨论最后一个棘手的问题就是WriteRegionsToBootMedia()函数,写入内核到FLASHBINFS分区。这个函数比较繁琐,所以将它的说明放在了附录中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值