Logiciels Libres et Systèmes Embarqués


4.3. Fonctionnement Simple

4.3.1. Configuration de U-Boot

La configuration de U-Boot est stockée dans include/configs/ml300.h. Ce fichier est en fait la configuration pour la carte Xilinx ML300 (à base de Virtex-II Pro), il faut donc le réécrire pour qu'il soit compatible avec notre architecture.

Dans un premier temps, on doit définir la nature du processeur et de la carte :

#define CONFIG_405
#define CONFIG_XILINX_ML300

U-Boot peut être configuré de manière statique, c'est-à-dire avant la phase de compilation, mais aussi de manière dynamique, c'est-à-dire pendant l'exécution. Pour cela, U-Boot utilise une zone de mémoire non volatile, comme par exemple une Flash, pour stocker sa configuration ou d'autres informations. Cette zone de mémoire non-volatile est appelée environnement dans la nomenclature de U-Boot.

Pour le moment, nous allons donc tricher en utilisant de la BRAM comme mémoire non-volatile[13], pour cela il faut mettre la macro CFG_ENV_ADDR à l'adresse de base de la BRAM (0xFFFF0000). U-Boot effectuant une somme de contrôle sur son environnement avant de l'utiliser, il détectera à chaque démarrage qu'il est corrompu et utilisera donc la configuration statique. Pour réaliser cette astuce, il suffit de définir les macros suivantes :

#define CFG_NO_FLASH
#define CFG_ENV_IS_IN_NVRAM
#define CFG_ENV_SIZE            1024
#define CFG_ENV_ADDR            0xFFFF0000

Comme nous l'avons vu précédemment, U-Boot a besoin d'une zone de mémoire vive lors de l'amorce pour stocker sa pile et ses données globales, les macros suivantes permettent de définir l'espace d'adressage de cette zone :

#define CFG_INIT_RAM_ADDR	0x00000000
#define CFG_INIT_RAM_END	0x0000FFFF

Si on avait utilisé un OCM, il aurait fallu définir ici son espace d'adressage. Dans le cas où il aurait fallu utiliser le cache de données comme mémoire vive, nous aurions pris un espace d'adressage utilisé par aucun périphérique. Dans notre cas particulier, une simple zone de la SDRAM est utilisée.

Nous avons vu qu'au démarrage de U-Boot, le segment de données n'était pas accessible en écriture et que l'on utilisait ainsi une zone réservée dans le segment de pile. Le découpage de ces zones est défini par les macros suivantes :

#define CFG_GBL_DATA_SIZE	128
#define CFG_GBL_DATA_OFFSET	(CFG_INIT_RAM_END - CFG_GBL_DATA_SIZE)
#define CFG_INIT_SP_OFFSET	CFG_GBL_DATA_OFFSET

Il faut ensuite préciser à partir de quelle adresse U-Boot sera exécuté, la taille qui lui est réservée, et la taille de son tas (mémoire dynamique) :

#define CFG_MONITOR_BASE	0x00010000
#define CFG_MONITOR_LEN		(256 * 1024)
#define CFG_MALLOC_LEN		(128 * 1024)

#define CFG_SDRAM_BASE		0x00000000 // doit absolument être à 0

U-Boot possède de nombreuses commandes, nous allons donc faire en sorte de n'utiliser que celles qui correspondent à cette démonstration. Il faut donc retirer les commandes relatives à la Flash, au bus DCR, et au réseau. Pour cela, on doit définir la macro de commandes de la manière suivante :

#define CONFIG_COMMANDS	(CONFIG_CMD_DFL &  CFG_CMD_SETGETDCR & \
			 CFG_CMD_IMLS &  CFG_CMD_FLASH &       \
			 CFG_CMD_NET)

Comme on utilise les commandes de manipulation de mémoire, il faut définir la zone gérée par mtest. Cela ce fait grâce aux macros suivantes :

#define CFG_MEMTEST_START	0x00800000
#define CFG_MEMTEST_END		0x00A00000

U-Boot a besoin de connaître la taille du cache, ainsi que la taille d'une ligne de cache, même s'il ne s'en sert pas de mémoire vive. Ces valeurs sont définies par les macros suivantes :

#define CFG_DCACHE_SIZE		16384
#define CFG_CACHELINE_SIZE	32

En ce qui concerne la configuration de l'UARTLite, il faut définir son taux de transfert comme ci-dessous :

#define CFG_BAUDRATE_TABLE	{115200}
#define CONFIG_BAUDRATE		115200

Bien évidemment, U-Boot doit être configuré pour pouvoir démarrer un noyau Linux. Les macros suivantes définissent la taille et l'emplacement de la zone mémoire réservée aux arguments transmis au noyau, ainsi que l'adresse où sera chargé le noyau :

#define CFG_BARGSIZE		CFG_CBSIZE
#define CFG_BOOTMAPSZ		(8 << 20)
#define CFG_LOAD_ADDR		0x00800000

En ce qui concerne la configuration pour le chargement et le lancement du noyau Linux, il faut définir les macros suivantes. La première correspond au temps d'attente (en secondes) avant d'effectuer automatiquement les commandes de la deuxième macro. La dernière correspond aux arguments passés au noyau Linux.

#define CONFIG_BOOTDELAY   5
#define CONFIG_BOOTCOMMAND "tftp 0x800000 uImage; bootm 0x800000"
#define CONFIG_BOOTARGS    "console=ttyS0 root=/dev/ram0"

U-Boot nécessite encore quelques autres macros pour son fonctionnement :

#define CONFIG_LOADS_ECHO 1
#define CFG_LONGHELP
#define CFG_PROMPT	  "uboot# "
#define CFG_CBSIZE	  256
#define CFG_PBSIZE	  (CFG_CBSIZE+sizeof(CFG_PROMPT)+16)
#define CFG_MAXARGS	  16
#define CFG_BARGSIZE	  CFG_CBSIZE
#define CFG_EXTBDINFO
#define CFG_HZ		  1000

4.3.2. Modification des sources

Il faut ensuite copier le fichier xparameters.h (généré par EDK) contenant la configuration de cette architecture dans board/xilinx/ml300. Nous allons maintenant définir quelques macros dans ce fichier pour que U-Boot prenne en compte cette configuration. Il est à noter que cette définition dépend des noms utilisés dans l'architecture EDK :

#define XPAR_CORE_CLOCK_FREQ_HZ  XPAR_CPU_PPC405_CORE_CLOCK_FREQ_HZ
#define CONFIG_SERIAL_BASE       XPAR_RS232_BASEADDR

Il faut définir l'adresse du code de U-Boot lors du démarrage, pour cela le fichier board/xilinx/ml300/config.mk doit contenir cette unique ligne :

TEXT_BASE = 0x00010000
#TEXT_BASE doit être égale à CFG_MONITOR_BASE

Ensuite, la taille de la SDRAM doit être déclarée, en modifiant la fonction suivante dans le fichier board/xilinx/ml300/ml300.c :

  long int initdram(int board_type)
  {
-      return 128 * 1024 * 1024; // 128 Mo
+      return 32 * 1024 * 1024;  // 32 Mo

Puis il faut déclarer la fréquence d'horloge du bus PLB, en modifiant la fonction suivante dans le fichier board/xilinx/ml300/ml300.c :

  void get_sys_info(sys_info_t * sysInfo)
  {
      sysInfo->freqProcessor = XPAR_CORE_CLOCK_FREQ_HZ;

      /* only correct if the PLB and OPB run at the same frequency */
-     sysInfo->freqPLB = XPAR_UARTNS550_0_CLOCK_FREQ_HZ;
-     sysInfo->freqPCI = XPAR_UARTNS550_0_CLOCK_FREQ_HZ / 3;
+     sysInfo->freqPLB = 100000000;
+     sysInfo->freqPCI = 0;
  }

Etant donné la simplicité de cet démonstration, on doit modifier le fichier board/xilinx/ml300/Makefile pour compiler uniquement les pilotes utiles :

OBJS	= $(BOARD).o \
	  serial.o

Comme le port pour la carte ML300 ne contient pas de pilote pour l'UARTLite, il faut récupérer celui de MicroBlaze :

bash# cp drivers/serial_xuartlite.c board/xilinx/ml300/serial.c
bash# cp include/asm-microblaze/arch-microblaze/xuartlite_l.h \
         board/xilinx/ml300/

On doit alors modifier le fichier board/xilinx/ml300/serial.c de la manière suivante :

- #ifdef CONFIG_MICROBLAZE
- #include <asm/serial_xuartlite.h>
+ #ifdef CONFIG_XILINX_ML300
+ #include "xparameters.h"
+ #include "xuartlite_l.h"

Maintenant, il ne reste plus qu'à compiler U-Boot avec cette configuration :

bash# make ml300_config
bash# make CROSS_COMPILE=powerpc-405-linux-gnu-

La macro CROSS_COMPILE précise le préfixe des outils de compilation installés au chapitre 3, pour que U-Boot soit compilé avec. Pour charger l'exécutable ainsi produit, il faut utiliser l'outil "Xilinx Microprocessor Debug" (XMD). Il s'agit d'un débogueur qui se connecte au port JTAG du processeur et qui sert de moniteur au "GNU DeBugger" (GDB) [12], c'est-à-dire qu'il lui permet d'accéder au PowerPC 405. Finalement, il suffit de lancer les commandes suivantes pour tester U-Boot :

bash# xmd
XMD% ppcconnect
XMD% cd u-boot-1.1.2
XMD% dow u-boot
XMD% run

Si on connecte un terminal sur le port série, on obtient la sortie suivante :

U-Boot 1.1.2 (Jul 18 2005 - 16:08:17)

### No HW ID - assuming ML300
DRAM:  32 MB
Top of RAM usable for U-Boot at: 02000000
Reserving 333k for U-Boot at: 01fac000
Reserving 129k for malloc() at: 01f8bc00
Reserving 112 Bytes for Board Info at: 01f8bb90
Reserving 48 Bytes for Global Data at: 01f8bb60
Stack Pointer at: 01f8bb48
New Stack Pointer is: 01f8bb48
Now running in RAM - U-Boot at: 01fac000
*** Warning - bad CRC, using default environment

In:  serial
Out: serial
Err: serial
U-Boot relocated to 01fac000
uboot# _



[13] la BRAM peut être initialisée lors du démarrage du FPGA, comme une ROM en quelque sorte.