Xilinx FSBL 代码简析

前言

    在分析ZYNQ7000启动流程时,发现FSBL工程在其中起到了非常重要的作用。参考了许多别人分析的过程,在这里也总结一下自己的代码分析流程。如有问题,欢迎指正。

1. 在FSBL工程中首先找到main函数,第一眼看到的就是ps7_init();从注释可以看到这里是对MIO, PLL, CLK, DDR进行初始化。

  1. int main(void)  

  2. {  

  3.     u32 BootModeRegister = 0;  

  4.     u32 HandoffAddress = 0;  

  5.     u32 Status = XST_SUCCESS;  

  6.   

  7.     /* 

  8.      * PCW initialization for MIO,PLL,CLK and DDR 

  9.      */  

  10.     Status = ps7_init();  

  11.     if (Status != FSBL_PS7_INIT_SUCCESS) {  

  12.         fsbl_printf(DEBUG_GENERAL,"PS7_INIT_FAIL : %s\r\n",  

  13.                         getPS7MessageInfo(Status));  

  14.         OutputStatus(PS7_INIT_FAIL);  

  15.         /* 

  16.          * Calling FsblHookFallback instead of Fallback 

  17.          * since, devcfg driver is not yet initialized 

  18.          */  

  19.         FsblHookFallback();  

  20.     }  

 

2. 进入到函数ps7_init();中也可以看到这里通过识别PS_VERSION对外设首先进行初始化

  1. // MIO init  

  2. ret = ps7_config (ps7_mio_init_data);    

  3. if (ret != PS7_INIT_SUCCESS) return ret;  

  4.   

  5. // PLL init  

  6. ret = ps7_config (ps7_pll_init_data);   

  7. if (ret != PS7_INIT_SUCCESS) return ret;  

  8.   

  9. // Clock init  

  10. ret = ps7_config (ps7_clock_init_data);  

  11. if (ret != PS7_INIT_SUCCESS) return ret;  

  12.   

  13. // DDR init  

  14. ret = ps7_config (ps7_ddr_init_data);  

  15. if (ret != PS7_INIT_SUCCESS) return ret;  

  16.     

  17. // Peripherals init  

  18. ret = ps7_config (ps7_peripherals_init_data);  

  19. if (ret != PS7_INIT_SUCCESS) return ret;  

  20. //xil_printf ("\n PCW Silicon Version : %d.0", pcw_ver);  

  21. return PS7_INIT_SUCCESS;  

3. 接下来在main函数中清cache关cache以及注册异常处理函数

  1. /* 

  2.  * Flush the Caches 

  3.  */  

  4. Xil_DCacheFlush();  

  5.   

  6. /* 

  7.  * Disable Data Cache 

  8.  */  

  9. Xil_DCacheDisable();  

  10.   

  11. /* 

  12.  * Register the Exception handlers 

  13.  */  

  14. RegisterHandlers();  

 

4. DDR初始化完成后,在该函数中对DDR进行基本的读写测试

  1. u32 DDRInitCheck(void)  

  2. {  

  3.     u32 ReadVal;  

  4.   

  5.     /* 

  6.      * Write and Read from the DDR location for sanity checks 

  7.      */  

  8.     Xil_Out32(DDR_START_ADDR, DDR_TEST_PATTERN);  

  9.     ReadVal = Xil_In32(DDR_START_ADDR);  

  10.     if (ReadVal != DDR_TEST_PATTERN) {  

  11.         return XST_FAILURE;  

  12.     }  

  13.   

  14.     /* 

  15.      * Write and Read from the DDR location for sanity checks 

  16.      */  

  17.     Xil_Out32(DDR_START_ADDR + DDR_TEST_OFFSET, DDR_TEST_PATTERN);  

  18.     ReadVal = Xil_In32(DDR_START_ADDR + DDR_TEST_OFFSET);  

  19.     if (ReadVal != DDR_TEST_PATTERN) {  

  20.         return XST_FAILURE;  

  21.     }  

  22.   

  23.     return XST_SUCCESS;  

  24. }  

 

5.  PCAP的初始化,这里不太清楚具体是什么设备。

  1. /* 

  2.  * PCAP initialization 

  3.  */  

  4. Status = InitPcap();  

  5. if (Status == XST_FAILURE) {  

  6.     fsbl_printf(DEBUG_GENERAL,"PCAP_INIT_FAIL \n\r");  

  7.     OutputStatus(PCAP_INIT_FAIL);  

  8.     /* 

  9.      * Calling FsblHookFallback instead of Fallback 

  10.      * since, devcfg driver is not yet initialized 

  11.      */  

  12.     FsblHookFallback();  

  13. }  

  14.   

  15. fsbl_printf(DEBUG_INFO,"Devcfg driver initialized \r\n");  

6. 从当前抓到的log版本号为:Silicon Version 3.1

  1. void GetSiliconVersion(void)  

  2. {  

  3.     /* 

  4.      * Get the silicon version 

  5.      */  

  6.     Silicon_Version = XDcfg_GetPsVersion(DcfgInstPtr);  

  7.     if(Silicon_Version == SILICON_VERSION_3_1) {  

  8.         fsbl_printf(DEBUG_GENERAL,"Silicon Version 3.1\r\n");  

  9.     } else {  

  10.         fsbl_printf(DEBUG_GENERAL,"Silicon Version %lu.0\r\n",  

  11.                 Silicon_Version + 1);  

  12.     }  

  13. }  

7. 函数MarkFSBLIn()中设置了REBOOT_STATE,从寄存器BOOT_MODE_REG(0xF8000000U + 0x25C)的低3bit获取启动模式。

  1. /* 

  2.  * Store FSBL run state in Reboot Status Register 

  3.  */  

  4. MarkFSBLIn();  

  5.   

  6. /* 

  7.  * Read bootmode register 

  8.  */  

  9. BootModeRegister = Xil_In32(BOOT_MODE_REG);  

  10. BootModeRegister &= BOOT_MODES_MASK;  

8. 基于目前调试的ZYNQ7000有以下几种启动模式,在这里我们重点关注以QSPI模式启动

  1. /* 

  2.  * Boot Modes 

  3.  */  

  4. #define JTAG_MODE           0x00000000 /**< JTAG Boot Mode */  

  5. #define QSPI_MODE           0x00000001 /**< QSPI Boot Mode */  

  6. #define NOR_FLASH_MODE      0x00000002 /**< NOR Boot Mode */  

  7. #define NAND_FLASH_MODE     0x00000004 /**< NAND Boot Mode */  

  8. #define SD_MODE             0x00000005 /**< SD Boot Mode */  

  9. #define MMC_MODE            0x00000006 /**< MMC Boot Device */  

9. 从代码中可以看出在判断启动模式为QSPI模式后,做了两件事

  1. if (BootModeRegister == QSPI_MODE) {  

  2.     fsbl_printf(DEBUG_GENERAL,"Boot mode is QSPI\n\r");  

  3.     InitQspi();  

  4.     MoveImage = QspiAccess;  

  5.     fsbl_printf(DEBUG_INFO,"QSPI Init Done \r\n");  

  6. } else  

(1)首先对QSPI进行初始化,这里我们简单的过一下QSPI初始化的代码

  1. u32 InitQspi(void)  

  2. {  

  3.     XQspiPs_Config *QspiConfig;  

  4.     int Status;  

  5.     u32 ConfigCmd;  

  6.   

  7.     QspiInstancePtr = &QspiInstance;  

  8.   

  9.     /* 

  10.      * Set up the base address for access 

  11.      */  

  12.     FlashReadBaseAddress = XPS_QSPI_LINEAR_BASEADDR;      // 表示QSPI Flash的基地址,从SDK中hdf文件中可以得到相应的硬件配置信息

  13.   

  14.     /* 

  15.      * Initialize the QSPI driver so that it's ready to use 

  16.      */  

  17.     QspiConfig = XQspiPs_LookupConfig(QSPI_DEVICE_ID);  

  18.     if (NULL == QspiConfig) {  

  19.         return XST_FAILURE;  

  20.     }  

  21.   

  22.     Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig,  

  23.                     QspiConfig->BaseAddress);  

  24.     if (Status != XST_SUCCESS) {  

  25.         return XST_FAILURE;  

  26.     }  

  27.   

  28.     /* 

  29.      * Set Manual Chip select options and drive HOLD_B pin high. 

  30.      */  

  31.     XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION |  

  32.             XQSPIPS_HOLD_B_DRIVE_OPTION);  

  33.   

  34.     /* 

  35.      * Set the prescaler for QSPI clock 

  36.      */  

  37.     XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8);  

  38.   

  39.     /* 

  40.      * Assert the FLASH chip select. 

  41.      */  

  42.     XQspiPs_SetSlaveSelect(QspiInstancePtr);  

  43.   

  44.     /* 

  45.      * Read Flash ID and extract Manufacture and Size information 

  46.      */  

  47.     Status = FlashReadID();  // 该函数非常重要,用来获取flash的制造厂商及size信息。

  48.     if (Status != XST_SUCCESS) {  

  49.         return XST_FAILURE;  

  50.     }  

从获取的log信息看当前flash信息如下:

Single Flash Information

FlashID=0x20 0xBB 0x19

MICRON 256M Bits

QSPI is in single flash connection

QSPI is in 4-bit mode

QSPI Init Done 

符合我们拿到的flash芯片手册:【N25q256.pdf】

 

做完以上这些以后,根据拿到的器件信息设置了QSPI Flash的IO模式并使能了控制器。以上完成QSPI Flash的初始化操作

 

(2)函数指针赋值,把QspiAccess赋值给MoveImage

这里我们主要关注MoveImage()函数。结合函数的注释和函数中的主要代码(即memcpy函数)该函数实现了从flash上搬移一定大小的数据到内存固定的地址上去。

  1. /******************************************************************************/  

  2. /** 

  3. * This function provides the QSPI FLASH interface for the Simplified header 

  4. * functionality. 

  5. * @param    SourceAddress is address in FLASH data space 

  6. * @param    DestinationAddress is address in DDR data space 

  7. * @param    LengthBytes is the length of the data in Bytes 

  8. * @return 

  9. *       - XST_SUCCESS if the write completes correctly 

  10. *       - XST_FAILURE if the write fails to completes correctly 

  11. * @note none. 

  12. ****************************************************************************/  

  13. u32 QspiAccess( u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes)  

  14. {  

  15.     u8  *BufferPtr;  

  16.     u32 Length = 0;  

  17.     u32 BankSel = 0;  

  18.     u32 LqspiCrReg;  

  19.     u32 Status;  

  20.     u8 BankSwitchFlag = 1;  

  21.   

  22.     /* 

  23.      * Linear access check 

  24.      */  

  25.     if (LinearBootDeviceFlag == 1) {  

  26.         /* 

  27.          * Check for non-word tail, add bytes to cover the end 

  28.          */  

  29.         if ((LengthBytes%4) != 0){  

  30.             LengthBytes += (4 - (LengthBytes & 0x00000003));  

  31.         }  

  32.   

  33.         memcpy((void*)DestinationAddress,  

  34.               (const void*)(SourceAddress + FlashReadBaseAddress),  

  35.               (size_t)LengthBytes);  

  36.     } else {  

 

10. QSPI Flash以后分别是

(1)NAND BOOT MODE

(2)NOR BOOT MODE

(3)SD BOOT MODE

// 以上几种模式的处理流程和QSPI Flash的处理流程类似,都是对设备的初始化以及函数指针的赋值

(4)JTAG  BOOT MODE

从代码中看到函数FsblHandoffJtagExit最终顺序执行到FsblHandoffExit,其中bx    lr指令就是跳转到用户代码执行。

  1. FsblHandoffJtagExit  

  2.         mcr  p15,0,r0,c7,c5,0       ;/* Invalidate Instruction cache */  

  3.         mcr  p15,0,r0,c7,c5,6       ;/* Invalidate branch predictor array */  

  4.   

  5.         dsb  

  6.         isb                         ;/* make sure it completes */  

  7.   

  8.     ldr r4, =0  

  9.         mcr  p15,0,r4,c1,c0,0       ;/* disable the ICache and MMU */  

  10.   

  11.         isb                         ;/* make sure it completes */  

  12. Loop  

  13.     wfe  

  14.     b Loop  

  15.   

  16. FsblHandoffExit  

  17.         mov  lr, r0 ;/* move the destination address into link register */  

  18.   

  19.         mcr  p15,0,r0,c7,c5,0       ;/* Invalidate Instruction cache */  

  20.         mcr  p15,0,r0,c7,c5,6       ;/* Invalidate branch predictor array */  

  21.   

  22.         dsb  

  23.         isb                         ;/* make sure it completes */  

  24.   

  25.     ldr r4, =0  

  26.         mcr  p15,0,r4,c1,c0,0       ;/* disable the ICache and MMU */  

  27.   

  28.         isb                         ;/* make sure it completes */  

  29.   

  30.   

  31.         bx      lr  ;/* force the switch, destination should have been in r0 */  

  32.   

  33. Ldone b     Ldone                   ;/* Paranoia: we should never get here */  

  34.     END  

 

11. 首先从我们打印log信息得到:Handoff Address: 0x00100000即ddr的起始地址,在hdf文件中可以查到

初步猜测里面应该完成了FPGA bit文件在PL中的加载,以及搬移裸机的软件elf文件到内存中去。

做完这些工作最终调用了FsblHandoff函数,通过该函数跳转到DDR中执行应用程序。

  1. /* 

  2.      * Load boot image 

  3.      */  

  4.     HandoffAddress = LoadBootImage();  

  5.   

  6.     fsbl_printf(DEBUG_INFO,"Handoff Address: 0x%08lx\r\n",HandoffAddress);  

  7.   

  8.     /* 

  9.      * For Performance measurement 

  10.      */  

  11. #ifdef FSBL_PERF  

  12.     XTime tEnd = 0;  

  13.     fsbl_printf(DEBUG_GENERAL,"Total Execution time is ");  

  14.     FsblMeasurePerfTime(tCur,tEnd);  

  15. #endif  

  16.   

  17.     /* 

  18.      * FSBL handoff to valid handoff address or 

  19.      * exit in JTAG 

  20.      */  

  21.     FsblHandoff(HandoffAddress);  

12. 接下来我们详细分析LoadBootImage()这个函数

因为我们的Silicon_Version不是1,所以我们执行以下代码。这段代码的作用是从multiboot寄存器中读取要执行的image的地址,其实如果就一个image的话可以不用管这个,这个算出来的imagestartaddress一定是0。

结合我们拿到的log:

Multiboot Register: 0x0000C000

Image Start Address: 0x00000000

  1. else {  

  2.         /* 

  3.          * read the multiboot register 

  4.          */  

  5.         MultiBootReg =  XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr,  

  6.                 XDCFG_MULTIBOOT_ADDR_OFFSET);  

  7.   

  8.         fsbl_printf(DEBUG_INFO,"Multiboot Register: 0x%08lx\r\n",MultiBootReg);  

  9.   

  10.         /* 

  11.          * Compute the image start address 

  12.          */  

  13.         ImageStartAddress = (MultiBootReg & PCAP_MBOOT_REG_REBOOT_OFFSET_MASK)  

  14.                                     * GOLDEN_IMAGE_OFFSET;  

  15.     }  

  16.     fsbl_printf(DEBUG_INFO,"Image Start Address: 0x%08lx\r\n",ImageStartAddress);

 

13. 这一段是读取在flash中的每个部分的头文件信息,包括大小起始地址等。也就是在生成BOOT的时候加入的几个文件,比如说先加的是FSBL,然后是BIT,最后是APP,那么这里的部分的数量就是3个。

结合log,这里跳过FSBL了,所以从Partition Number:1 开始加载bit;然后在Partition Number:2加载软件elf文件。

  1. /* 

  2.  * Get partitions header information 

  3.  */  

  4. Status = GetPartitionHeaderInfo(ImageStartAddress);  

  5. if (Status != XST_SUCCESS) {  

  6.     fsbl_printf(DEBUG_GENERAL, "Partition Header Load Failed\r\n");  

  7.     OutputStatus(GET_HEADER_INFO_FAIL);  

  8.     FsblFallback();  

  9. }  

14. 从函数Status = GetPartitionHeaderInfo(ImageStartAddress);

    ->Status = GetFsblLength(ImageBaseAddress, &FsblLength);

在该函数中调用了MoveImage函数,实际上是把BOOT.bin image的0x40地址的4字节赋值给FsblLength,从而获取到Fsbl的size大小。这里需要了解一下BOOT.bin的结构。

在boot.bin中从地址0-0x8BF可以分成17个部分,每个部分都有一定的含义 

1. 0x000  中断向量表 

2. 0x020  固定值 0xaa995566 

3. 0x024  固定值 0x584c4e58  ASCII: XLNX 

4. 0x028  如果是0xa5c3c5a3或者0x3a5c3c5a为加密的 

5. 0x02C  bootrom头版本号,不用管 

6. 0x030  从bootrom开始到app地址的总数(bytes) 

7. 0x034  从loadimage拷到OCM的长度 【上电后BootRom会主动把FSBL拷贝到OCM中执行】

8. 0x038  目的地址到哪儿拷贝FSBL 

9. 0x03C  开始执行的地址 

10. 0x040  同7 【此处代码逻辑中其实是把该字段的值赋给FSBL的size】

11. 0x044  0x01为固定值 

12. 0x048  校验和(从0x020-0x047)按32-bit word 相加取反 

13. 0x04C  bootgen相关 

14. 0x098  image头的表指针 

15. 0x09C  partition头的表指针 

16. 0x0A0  寄存器初始化的参数 

17. 0x8A0  fsbl user defined 

18. 0x8C0  fsbl开始的地方 

如果是从qspi加载的话,bootrom会把数据从qspi拷贝到OCM中,在OCM中运行,也就是0地址运行。

 

  1. u32 GetFsblLength(u32 ImageAddress, u32 *FsblLength)  

  2. {  

  3.     u32 Status;  

  4.   

  5.     Status = MoveImage(ImageAddress + IMAGE_TOT_BYTE_LEN_OFFSET,  

  6.                             (u32)FsblLength, 4);  

  7.     if (Status != XST_SUCCESS) {  

  8.         fsbl_printf(DEBUG_GENERAL,"Move Image failed reading FsblLength\r\n");  

  9.         return XST_FAILURE;  

  10.     }  

  11.   

  12.     return XST_SUCCESS;  

  13. }  

 

15. 结合14项中BOOT.bin的头信息,下面函数通过image偏移地址0x9C获取partition头的表指针。还记得13项中提供的log打印:Partition Header Offset:0x00000C80

    分析代码基于该partition header开始计算partition count,正常情况下最多遍历15个partition,我们这里实际只有3个,即FSBL, BIT, ELF。

    分析代码正常的一个partion的表头信息结构如下:

    ​    ​    ​struct HeaderArray {

    ​    ​    ​ u32 Fields[16];

    ​    ​    ​};

最后的一个partion的表头的内容应该如下:

    ​* 0x00000000

    ​* 0x00000000

    ​* ....

    ​* 0x00000000

    ​* 0x00000000

    ​* 0xFFFFFFFF

即前15个元素均为0,最后一个元素全为F,这时判断所有partition遍历完毕,得到当前的partition的个数

  1. u32 GetPartitionHeaderStartAddr(u32 ImageAddress, u32 *Offset)  

  2. {  

  3.     u32 Status;  

  4.   

  5.     Status = MoveImage(ImageAddress + IMAGE_PHDR_OFFSET, (u32)Offset, 4);  

  6.     if (Status != XST_SUCCESS) {  

  7.         fsbl_printf(DEBUG_GENERAL,"Move Image failed\r\n");  

  8.         return XST_FAILURE;  

  9.     }  

  10.   

  11.     return XST_SUCCESS;  

  12. }  

16. 首先我们这里不再解析partition 0即FSBL,直接从partition 1开始解析。在函数HeaderDump中把当前所有partition的大小即其实地址都解析出来。结合如下log我们可以看到FPGA bit和软件的elf文件的信息。

Partition Header Offset:0x00000C80

Partition Count: 3

Partition Number: 1

Header Dump

Image Word Len: 0x00427028    ​// 这里应该是bit文件的大小,单位是word。转换0x00427028 * 4 / 1024 ≈ 17009KB,查看工程符合当前bit文件的大小

Data Word Len: 0x00427028

Partition Word Len:0x00427028

Load Addr: 0x00000000

Exec Addr: 0x00000000

Partition Start: 0x000055D0

Partition Attr: 0x00000020    ​// Bitstream

Partition Checksum Offset: 0x00000000

Section Count: 0x00000001

Checksum: 0xFF385746

Bitstream

 

In FsblHookAfterBitstreamDload function 

Partition Number: 2

Header Dump

Image Word Len: 0x00004002

Data Word Len: 0x00004002

Partition Word Len:0x00004002

Load Addr: 0x00100000

Exec Addr: 0x00100000

Partition Start: 0x0042C600    ​// 0x0042C600 - 0x000055D0 = 0x427030,可以看到bit文件和软件elf基本上是连续的

Partition Attr: 0x00000010    ​// Application

Partition Checksum Offset: 0x00000000

Section Count: 0x00000001

Checksum: 0xFF9C7788

Application

 

  1. PartitionNum = 1;  

  2.   

  3. while (PartitionNum < PartitionCount) {  

  4.   

  5.     fsbl_printf(DEBUG_INFO, "Partition Number: %lu\r\n", PartitionNum);  

  6.   

  7.     HeaderPtr = &PartitionHeader[PartitionNum];  

  8.   

  9.     /* 

  10.      * Print partition header information 

  11.      */  

  12.     HeaderDump(HeaderPtr);  

 

17. 当解析当前partition属性为Bitstream时,设置如下代码中的flag

  1.         if (PartitionAttr & ATTRIBUTE_PL_IMAGE_MASK) {  

  2.             fsbl_printf(DEBUG_INFO, "Bitstream\r\n");  

  3.             PLPartitionFlag = 1;  

  4.             PSPartitionFlag = 0;  

  5.             BitstreamFlag = 1;  

  6.             if (ApplicationFlag == 1) {  

  7. #ifdef STDOUT_BASEADDRESS  

  8.                 xil_printf("\r\nFSBL Warning !!!"  

  9.                         "Bitstream not loaded into PL\r\n");  

  10.                 xil_printf("Partition order invalid\r\n");  

  11. #endif  

  12.                 break;  

  13.             }  

  14.         }  

通过函数PcapLoadPartition完成了PL的加载,这里不再做深入分析。

  1.    /* 

  2.      * Load Signed PL partition in Fabric 

  3.      */  

  4.     if (PLPartitionFlag) {  

  5.         Status = PcapLoadPartition((u32*)PartitionStartAddr,  

  6.                 (u32*)PartitionLoadAddr,  

  7.                 PartitionImageLength,  

  8.                 PartitionDataLength,  

  9.                 EncryptedPartitionFlag);  

  10.         if (Status != XST_SUCCESS) {  

  11.             fsbl_printf(DEBUG_GENERAL,"BITSTREAM_DOWNLOAD_FAIL\r\n");  

  12.             OutputStatus(BITSTREAM_DOWNLOAD_FAIL);  

  13.             FsblFallback();  

  14.         }  

  15.     }  

  16. }  

  17.   

  18.   

  19. /* 

  20.  * FSBL user hook call after bitstream download 

  21.  */  

  22. if (PLPartitionFlag) {  

  23.     Status = FsblHookAfterBitstreamDload();  

  24.     if (Status != XST_SUCCESS) {  

  25.         fsbl_printf(DEBUG_GENERAL,"FSBL_AFTER_BSTREAM_HOOK_FAIL\r\n");  

  26.         OutputStatus(FSBL_AFTER_BSTREAM_HOOK_FAIL);  

  27.         FsblFallback();  

  28.     }  

18. 根据partition属性为Application时设置如下的flag

  1. if (PartitionAttr & ATTRIBUTE_PS_IMAGE_MASK) {  

  2.  fsbl_printf(DEBUG_INFO, "Application\r\n");  

  3.  PSPartitionFlag = 1;  

  4.  PLPartitionFlag = 0;  

  5.  ApplicationFlag = 1;  

  6. }  

​    ​在这里会把elf文件搬移到DDR地址0x00100000上,而bit文件会搬移到0x00000000地址上去。

  1. /* 

  2.  * Move partitions from boot device 

  3.  */  

  4. Status = PartitionMove(ImageStartAddress, HeaderPtr);  

  5. if (Status != XST_SUCCESS) {  

  6.     fsbl_printf(DEBUG_GENERAL,"PARTITION_MOVE_FAIL\r\n");  

  7.     OutputStatus(PARTITION_MOVE_FAIL);  

  8.     FsblFallback();  

  9. }  

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章