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
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# _