最新の fsbl で Linux が起動しない理由を調べる のバックアップ差分(No.2)

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[公開メモ]]

* Petalinux 2016.4 の生成する fsbl が動作しない [#de4f661e]

[[電気回路/zynq/Petalinux のビルド#h00d6c35]] で見たとおり、
何のメッセージも出ず固まってしまいます。。。

z-turn 付属の dvd にあった mys-xc7z020-trd というサンプルプロジェクト
からビルドした fsbl ではうまく行きました。

以下、vivado 2016.4 に付属の xilinx SDK で fsbl プロジェクトを新規に作成して試してみます。

* fsbl2 プロジェクトの作成 [#uf03a5ca]

Xilinx SDK 2016.4 で Workspace に mys-xc7z020-trd.sdk を指定して開くと、
Project Explorer には

- design_1_wrapper_hw_platform_0
- fsbl
- fsbl_bsp

が表示されました。

&ref(projects.png);
&ref(projects.png,,66%);

[File]-[New]-[Project...] から [Xilinx]-[Application Project] を選び [Next]

&ref(new-project.png,,66%);

適当な名前を付けて [Next]

- OS Platform は standalone にします

&ref(new-project2.png,,66%);

Templates から [Zynq FSBL] を選択して [finish]

&ref(zynq-fsbl.png,,66%);

* コードの比較 [#w4ba4b71]

上記のようにして作った fsbl2 と、z-turn 付属の fsbl のコードを比較しました。

** Version & ChangeLog [#zb0103bc]

z-turn 付属のコードは "11.00a kv 10/08/14" ~
2016.4 で作成のコードは "16.00a gan 08/02/16" でした。

その間の ChangeLog は、

 * 12.00a ssc 12/11/14    839182 - FSBL -In the file sd.c, f_mount is called with
 *                       two arguments but f_mount is expecting the 3 arguments
 *                       from build 2015.1_1210_1, causing compilation error.
 *                        Resolution: Arguments for f_mount in InitSD() are
 *                        changed as per new signature.
 * 13.00a ssc 04/10/15    846899 - FSBL -In the file pcap.c, to clear DMA done
 *                       count, devcfg.INT_STS register is written to, which is
 *                       not correct.
 *                       Resolution: Corresponding fields in the devcfg.STATUS
 *                       register are written to, for clearing DMA done count.
 * 14.00a gan 01/13/16   869081 -(2016.1)FSBL -In qspi.c, FSBL picks the qspi
 *                        read command from LQSPI_CFG register instead of hard
 *                           coded read command (0x6B).
 * 15.00a gan 07/21/16   953654 -(2016.3)FSBL -In pcap.c/pcap.h/main.c,
 *                         Fabric Initialization sequence is modified to check
 *                         the PL power before sequence starts and checking INIT_B
 *                         reset status twice in case of failure.
 * 16.00a gan 08/02/16   Fix for CR# 955897 -(2016.3)FSBL -
 *                         In pcap.c, check pl power through MCTRL register
 *                         for 3.0 and later versions of silicon.

重要そうなところを抜き出すと、

- 13.00a : pcap.c で DMA done count をクリアする方法がおかしかったのを直した
- 15.00a : pcap.c/pcap.h/main.c にてエラーチェックを厳しくした
- 16.00a : pcap.c における PL Power チェック方法を 3.0 以上のシリコンバージョンに合わせて変更

となっています。

** 気づいたこと [#g44cec3a]

- 元々の fsbl プロジェクトは Debug モードでビルドされていた
- 全体を通じて、~
fsbl_printf(DEBUG_INFO, ... で %08x だったところが %08lx に変更されている

** 具体的な変更点 [#ie713420]

2つのプロジェクトの差分を取って比べてみます。

*** fsbl/src/main.c [#yf4185b6]

 + * 15.00a gan 07/21/16   Fix for CR# 953654 -(2016.3)FSBL -
 + * 			In pcap.c/pcap.h/main.c,
 + * 			Fabric Initialization sequence
 + * 			is modified to check the PL power
 + * 			before sequence starts and checking
 + * 			INIT_B reset status twice in case
 + * 			of failure.
   ...
   #ifdef STDOUT_BASEADDRESS
 + #ifdef XPAR_XUARTPS_0_BASEADDR
   #include "xuartps_hw.h"
 + #endif
   #endif
   ...
 
 -			FabricInit();
 + 			Status = FabricInit();
 +			if(Status != XST_SUCCESS){
 +				ClearFSBLIn();
 +				FsblHookFallback();
 +			}
   ...
 
   void OutputStatus(u32 State)
   {
   #ifdef STDOUT_BASEADDRESS
 + #ifdef XPAR_XUARTPS_0_BASEADDR
   	u32 UartReg = 0;
 + #endif
   
   	fsbl_printf(DEBUG_GENERAL,"FSBL Status = 0x%.4lx\r\n", State);
   	/*
   	 * The TX buffer needs to be flushed out
   	 * If this is not done some of the prints will not appear on the
   	 * serial output
   	 */
 + #ifdef XPAR_XUARTPS_0_BASEADDR
   	UartReg = Xil_In32(STDOUT_BASEADDRESS + XUARTPS_SR_OFFSET);
   	while ((UartReg & XUARTPS_SR_TXEMPTY) != XUARTPS_SR_TXEMPTY) {
   		UartReg = Xil_In32(STDOUT_BASEADDRESS + XUARTPS_SR_OFFSET);
   	}
 + #endif
   #endif
   }

どうやら #ifdef XPAR_XUARTPS_0_BASEADDR があちこちに追加されているのだけれど、
今の場合は fsbl_bsp\ps7_cortexa9_0\include\xparameters.h で、

 /* Canonical definitions for peripheral PS7_UART_0 */
 #define XPAR_XUARTPS_0_DEVICE_ID XPAR_PS7_UART_0_DEVICE_ID
 #define XPAR_XUARTPS_0_BASEADDR 0xE0000000
 #define XPAR_XUARTPS_0_HIGHADDR 0xE0000FFF
 #define XPAR_XUARTPS_0_UART_CLK_FREQ_HZ 100000000
 #define XPAR_XUARTPS_0_HAS_MODEM 0
 
 /* Canonical definitions for peripheral PS7_UART_1 */
 #define XPAR_XUARTPS_1_DEVICE_ID XPAR_PS7_UART_1_DEVICE_ID
 #define XPAR_XUARTPS_1_BASEADDR 0xE0001000
 #define XPAR_XUARTPS_1_HIGHADDR 0xE0001FFF
 #define XPAR_XUARTPS_1_UART_CLK_FREQ_HZ 100000000
 #define XPAR_XUARTPS_1_HAS_MODEM 0

と定義されていて、事前に main.c で読み込まれているため、問題にはならなさそう。

FabricInit() の戻り値がチェックされるようになったのだけれど、
これはすでに FsblFallback の中なので、ここに到達する時点でエラーが生じているはず。
これもあまり意味が無い。

main.c の流れを追うと、

- main() の中で、
-- ps7_init();          // PCW initialization for MIO,PLL,CLK and DDR
-- // この時点で fsbl_printf を利用可能
-- SlcrUnlock();        // Unlock SLCR for SLCR register write
-- Xil_DCacheFlush();   // Flush the Caches
-- Xil_DCacheDisable(); // Disable Data Cache
-- RegisterHandlers();  // Register the Exception handlers
-- fsbl_printf(DEBUG_GENERAL,"\n\rXilinx First Stage Boot Loader \n\r");

なので、ここまで順調に来ていれば初期メッセージが表示されるはず。

*** fsbl_bsp\ps7_cortexa9_0\include\xparameters.h [#va5b0042]

 - #define STDIN_BASEADDRESS 0xE0001000
 - #define STDOUT_BASEADDRESS 0xE0001000
 + #define STDIN_BASEADDRESS 0xE0000000
 + #define STDOUT_BASEADDRESS 0xE0000000

これ、ダメだ。

直前で見たとおり、~
0xE0001000 は XUARTPS_1 のアドレス、~
0xE0000000 は XUARTPS_0 のアドレス。

これを 0xE0001000 に書き換えて試すと、、、~
やっぱりうんともすんとも言わないか。

*** main.c の ps7_init() の直後でメッセージを表示 [#i34c57ef]

何も表示されない

*** fsbl/src/fsbl_debug.h [#l2aa1566]

 - #define	FSBL_DEBUG_INFO	1
   #define DEBUG_GENERAL	0x00000001    /* general debug  messages */
   #define DEBUG_INFO	0x00000002    /* More debug information */
   
   #if defined (FSBL_DEBUG_INFO)
   #define fsbl_dbg_current_types ((DEBUG_INFO) | (DEBUG_GENERAL))
   #elif defined (FSBL_DEBUG)
   #define fsbl_dbg_current_types (DEBUG_GENERAL)
   #else
   #define fsbl_dbg_current_types 0
   #endif
   
   #ifdef STDOUT_BASEADDRESS
   #define fsbl_printf(type,...) \
   		if (((type) & fsbl_dbg_current_types))  {xil_printf (__VA_ARGS__); }
   #else
   #define fsbl_printf(type, ...)
   #endif

さしあたってはこれが原因では無さそうだけれど、~
#define	FSBL_DEBUG_INFO	1 は復活させておく

*** ps7_init() [#a1a9eac6]

- init_data にある初期化手順を実行する形になっている
- ps7GetSiliconVersion() により初期化手順を選択する

 LANG:c
 unsigned long *ps7_mio_init_data = ps7_mio_init_data_3_0;
 unsigned long *ps7_pll_init_data = ps7_pll_init_data_3_0;
 unsigned long *ps7_clock_init_data = ps7_clock_init_data_3_0;
 unsigned long *ps7_ddr_init_data = ps7_ddr_init_data_3_0;
 unsigned long *ps7_peripherals_init_data = ps7_peripherals_init_data_3_0;
 
 int
 ps7_init() 
 {
   unsigned long si_ver = ps7GetSiliconVersion ();
   int ret;
 
   if (si_ver == PCW_SILICON_VERSION_1) {
     ps7_mio_init_data = ps7_mio_init_data_1_0;
     ps7_pll_init_data = ps7_pll_init_data_1_0;
     ps7_clock_init_data = ps7_clock_init_data_1_0;
     ps7_ddr_init_data = ps7_ddr_init_data_1_0;
     ps7_peripherals_init_data = ps7_peripherals_init_data_1_0;
   } else if (si_ver == PCW_SILICON_VERSION_2) {
     ps7_mio_init_data = ps7_mio_init_data_2_0;
     ps7_pll_init_data = ps7_pll_init_data_2_0;
     ps7_clock_init_data = ps7_clock_init_data_2_0;
     ps7_ddr_init_data = ps7_ddr_init_data_2_0;
     ps7_peripherals_init_data = ps7_peripherals_init_data_2_0;
   } else {
     ps7_mio_init_data = ps7_mio_init_data_3_0;
     ps7_pll_init_data = ps7_pll_init_data_3_0;
     ps7_clock_init_data = ps7_clock_init_data_3_0;
     ps7_ddr_init_data = ps7_ddr_init_data_3_0;
     ps7_peripherals_init_data = ps7_peripherals_init_data_3_0;
   }
 
   ret = ps7_config (ps7_mio_init_data);  
   if (ret != PS7_INIT_SUCCESS) return ret;
 
   ret = ps7_config (ps7_pll_init_data); 
   if (ret != PS7_INIT_SUCCESS) return ret;
 
   ret = ps7_config (ps7_clock_init_data);
   if (ret != PS7_INIT_SUCCESS) return ret;
 
   ret = ps7_config (ps7_ddr_init_data);
   if (ret != PS7_INIT_SUCCESS) return ret;
 
   ret = ps7_config (ps7_peripherals_init_data);
   if (ret != PS7_INIT_SUCCESS) return ret;
   return PS7_INIT_SUCCESS;
 }

シリコンバージョンはメモリの値を読むだけなので失敗しようがないし、
そもそもこのあたりのコードはうまく行く方も行かない方も共通。

 LANG:c
 unsigned long
 ps7GetSiliconVersion () {
   // Read PS version from MCTRL register [31:28]
   unsigned long mask = 0xF0000000;
   unsigned long *addr = (unsigned long*) 0XF8007080;    
   unsigned long ps_version = (*addr & mask) >> 28;
   return ps_version;
 }

 LANG:c
 int
 ps7_config(unsigned long * ps7_config_init) 
 {
     unsigned long *ptr = ps7_config_init;
 
     unsigned long  opcode;            // current instruction ..
     unsigned long  args[16];           // no opcode has so many args ...
     int  numargs;           // number of arguments of this instruction
     int  j;                 // general purpose index
 
     volatile unsigned long *addr;         // some variable to make code readable
     unsigned long  val,mask;              // some variable to make code readable
 
     int finish = -1 ;           // loop while this is negative !
     int i = 0;                  // Timeout variable
     
     while( finish < 0 ) {
         numargs = ptr[0] & 0xF;
         opcode = ptr[0] >> 4;
 
         for( j = 0 ; j < numargs ; j ++ ) 
             args[j] = ptr[j+1];
         ptr += numargs + 1;
         
         
         switch ( opcode ) {
             
         case OPCODE_EXIT:
             finish = PS7_INIT_SUCCESS;
             break;
             
         case OPCODE_CLEAR:
             addr = (unsigned long*) args[0];
             *addr = 0;
             break;
 
         case OPCODE_WRITE:
             addr = (unsigned long*) args[0];
             val = args[1];
             *addr = val;
             break;
 
         case OPCODE_MASKWRITE:
             addr = (unsigned long*) args[0];
             mask = args[1];
             val = args[2];
             *addr = ( val & mask ) | ( *addr & ~mask);
             break;
 
         case OPCODE_MASKPOLL:
             addr = (unsigned long*) args[0];
             mask = args[1];
             i = 0;
             while (!(*addr & mask)) {
                 if (i == PS7_MASK_POLL_TIME) {
                     finish = PS7_INIT_TIMEOUT;
                     break;
                 }
                 i++;
             }
             break;
         case OPCODE_MASKDELAY:
             addr = (unsigned long*) args[0];
             mask = args[1];
             int delay = get_number_of_cycles_for_delay(mask);
             perf_reset_and_start_timer(); 
             while ((*addr < delay)) {
             }
             break;
         default:
             finish = PS7_INIT_CORRUPT;
             break;
         }
     }
     return finish;
 }

#define PS7_MASK_POLL_TIME 100000000

*** fsbl_bsp\ps7_cortexa9_0\libsrc\standalone_v?_?\src\xil_printf.c [#l276479b]

最終的には outbyte を呼び出す

*** fsbl_bsp\ps7_cortexa9_0\libsrc\standalone_v?_?\src\outbyte.c [#m4edd7e6]

バージョン間で変更なし

 LANG:c
 void outbyte(char c) {
 	 XUartPs_SendByte(STDOUT_BASEADDRESS, c);
 }

*** fsbl_bsp\ps7_cortexa9_0\libsrc\uartps_v?_?\src\xuartps.c [#kcf29b72]

かなりいろいろ変更されていて厳しい、が、どうやらキャストを増やしてたりする感じ。


Counter: 13364 (from 2010/06/03), today: 6, yesterday: 0