GNU/Linux su ARM
Transcript
GNU/Linux su ARM
GNU/Linux su ARM Vito De Tullio [email protected] Nicola Corriero [email protected] 12 settembre 2008 2 Copyright © 2008 Nicola Corriero, Vito De Tullio. È permesso copiare, distribuire e/o modificare questo documento seguendo i termini della “Licenza per documentazione libera GNU”, versione 1.2 o ogni versione successiva pubblicata dalla Free Software Foundation; senza sezioni non modificabili, senza testi di prima di copertina e di quarta di copertina. Una copia della licenza è inclusa nella sezione intitolata “Licenza per la documentazione libera GNU”. Indice 1 Kernel & compilatore 1.1 Kernel . . . . . . . . . . . . . . . . 1.2 Compilatore . . . . . . . . . . . . . 1.3 Configurazione dei sorgenti . . . . 1.4 Cross-compilazione . . . . . . . . 1.5 Output (Image, zImage, bzImage) . . . . . 7 7 7 8 12 13 . . . . 15 15 16 22 27 . . . . . . . . . . . 29 29 29 30 31 35 35 36 36 38 38 40 4 Debugger 4.1 A che serve . . . . . . . . . . . . . . . . . . . . . . . . . 41 41 2 Avvio 2.1 Sorgenti . . . . . 2.2 Decompressione 2.3 Boot . . . . . . . 2.4 Hello, world! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Test 3.1 Haret . . . . . . . . . . . . . . 3.1.1 Perché . . . . . . . . . 3.1.2 Come usare Haret . . 3.1.3 Codice . . . . . . . . . 3.1.4 Problemi . . . . . . . . 3.1.5 Compilazione di Haret 3.2 Qemu . . . . . . . . . . . . . 3.2.1 Come ottenerlo . . . . 3.2.2 Emulazione . . . . . . 3.2.3 Sistemi emulati . . . . 3.3 U-Boot . . . . . . . . . . . . . 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 INDICE 4.2 Quale usare . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Come usarlo . . . . . . . . . . . . . . . . . . . . . . . . 42 42 A Assembly per ARM 45 B Comandi principali gdb 47 C Licenza per la documentazione libera GNU C.1 GNU Free Documentation License . . . . . . . . . . . . 49 49 Bibliografia 61 Introduzione Questo lavoro ha la presunzione di voler ordinare le idee riguardo l’avvio di un sistema GNU/Linux su Arm dal momento che allo stato attuale delle cose non esiste una guida a proposito. Si inizia parlando della fase di compilazione e del kernel. I problemi nascono dal momento che abitualmente si lavora su piattaforma x86, mentre nel nostro caso si ha l’esigenza di compilare su una piattaforma differente. In gergo si parla di cross-compilazione. Infatti, prenderemo un compilatore tipico della piattaforma ARM e lo useremo su piattaforma x86 per generare eseguibili su ARM. Il lavoro continua presentando le componenti del kernel necessarie su ARM e parlando dei possibili output del kernel stesso. Segue una dettagliata descrizione della fase di avvio del kernel commentando direttamente il codice assembly e C eseguito sia in fase di decompressione del kernel sia in fase di avvio. Nel capitolo 3 si analizzano gli strumenti utilizzati per il testing del kernel su ARM. Qemu è un programma di emulazione molto semplice da usare e facilmente configurabile per i nostri scopi. Haret è un programma scritto in C++ per Windows Mobile®; ha l’obbiettivo di copiare in memoria il kernel, ed eventualmente INI TRD , spegnere l’hardware e avviare il kernel in memoria in maniera non invasiva per la macchina, dal momento che non fa modifiche al sistema operativo ospite. U-boot è un bootloader universale per i sistemi embedded; rappresenta però una soluzione invasiva dal momento che è necessario installarlo sulla memoria flash del dispositivo. Il capitolo 4 descrive come effettuare debugging sui dispositivi embedded. Verrà analizzato GDB (Gnu DeBugger), analizzando 5 6 INDICE come usarlo per debuggare anche il kernel. In appendice A vi è una piccola guida di assembly per ARM per facilitare la compressione del codice assembly presentato nel capitolo 2. Capitolo 1 Kernel & compilatore 1.1 Kernel È stato usata la versione 2.6.25.10 del kernel vanilla (versione di default, non patchata) reperibile presso ftp://ftp.kernel.org/ pub/linux/kernel/v2.6/linux-2.6.25.10.tar.bz2. Esistono versioni modificate da singoli per supportare questa o quell’architettura (in particolare è da notare la versione del kernel mantenuta da http://www.handhelds.org), ma non abbiamo trovato nessuna versione che già supportasse nativamente il nostro palmare (un HTC P6300) e quindi abbiamo preferito utilizzare la versione di default. 1.2 Compilatore Per compilare il kernel linux è necessario usare il gcc, a causa delle varie estensioni del compilatore utilizzate dai kernel hackers. Sulla versione da utilizzare non ci sono preferenze, ma, in genere, più nuovo è, meglio è. In effetti ci potrebbero essere problemi in caso di versioni del kernel e del compilatore particolarmente differenti tra di loro, a causa dell’uso (e spesso dell’abuso) che viene fatto delle varie estensioni non standard. Nel nostro caso sono state usate varie versioni, principalmente 4.2.3 e 3.4.1, senza riscontrare particolari problemi. 7 8 CAPITOLO 1. KERNEL & COMPILATORE 1.3 Configurazione dei sorgenti Dopo aver scaricato ed estratto il kernel, lo dobbiamo configurare per l’architettura ARM utilizzando un x86, e per questo, prima del solito make [x|menu]config, è necessario associare alla variabile ARCH il valore arm: $ wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/ linux-2.6.25.10.tar.bz2 $ tar xjf kernel-2.6.25.10.tar.bz2 $ cd kernel-2.6.25.10 $ export ARCH=arm $ make menuconfig È necessario prestare attenzione soprattutto al modello di palmare su cui vogliamo eseguire il kernel, più altre minuzie per far funzionare i vari dispositivi; in particolare • dal menù S YSTEM T YPE . A RM S YSTEM T YPE scegliamo il tipo di sistema base (nel nostro caso S AMSUNG S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443); • dal menù B OOT OPTIONS impostiamo CONSOLE = TTYAMA0 alla voce D EFAULT KERNEL COMMAND STRING (per poter avere in output i messaggi di comunicazione); • dal menù G ENERAL SETUP impostiamo 12 come valore della voce K ERNEL LOG BUFFER SIZE ; (con un buffer così piccolo i messaggi di warning/errore vengono inviati su STDOUT il prima possibile); • dal menù D EVICE D RIVERS selezioniamo MMC/SD CARD SUP PORT (per poter accedere al supporto fisico per il file system). Dopo anche altre personalizzazioni minori, si giunge al .CONFIG finale, che, nel nostro caso, è abbastanza minimale: la maggior parte dei moduli, infatti, è stata disabilitata, tranne quelli necessari a riconoscere cpu, tastiera e monitor: 1.3. CONFIGURAZIONE DEI SORGENTI 9 Listing 1.1: .config finale utilizzato (le voci commentate sono state rimosse) CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y CONFIG_GENERIC_TIME=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_MMU=y CONFIG_GENERIC_HARDIRQS=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_HARDIRQS_SW_RESEND=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_ARCH_SUPPORTS_AOUT=y CONFIG_ZONE_DMA=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="-default" CONFIG_LOCALVERSION_AUTO=y CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y CONFIG_LOG_BUF_SHIFT=12 CONFIG_NAMESPACES=y CONFIG_SYSCTL=y CONFIG_UID16=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y CONFIG_SLAB=y CONFIG_HAVE_OPROFILE=y CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y CONFIG_PROC_PAGE_MONITOR=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y CONFIG_BASE_SMALL=0 CONFIG_BLOCK=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_DEADLINE=y CONFIG_DEFAULT_DEADLINE=y CONFIG_DEFAULT_IOSCHED="deadline" CONFIG_CLASSIC_RCU=y CONFIG_ARCH_VERSATILE=y CONFIG_MACH_VERSATILE_AB=y CONFIG_CPU_32=y CONFIG_CPU_ARM926T=y CONFIG_CPU_32v5=y CONFIG_CPU_ABRT_EV5TJ=y CONFIG_CPU_CACHE_VIVT=y CONFIG_CPU_COPY_V4WB=y 10 CAPITOLO 1. KERNEL & COMPILATORE CONFIG_CPU_TLB_V4WBI=y CONFIG_CPU_CP15=y CONFIG_CPU_CP15_MMU=y CONFIG_ARM_VIC=y CONFIG_ICST307=y CONFIG_ARM_AMBA=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_HZ=100 CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_SPLIT_PTLOCK_CPUS=4096 CONFIG_ZONE_DMA_FLAG=1 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y CONFIG_ALIGNMENT_TRAP=y CONFIG_ZBOOT_ROM_TEXT=0 CONFIG_ZBOOT_ROM_BSS=0 CONFIG_CMDLINE="console=ttyAMA0" CONFIG_FPE_NWFPE=y CONFIG_BINFMT_ELF=y CONFIG_PM=y CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_INPUT=y CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_INPUT_KEYBOARD=y CONFIG_KEYBOARD_ATKBD=y CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y CONFIG_MOUSE_PS2_ALPS=y CONFIG_MOUSE_PS2_LOGIPS2PP=y CONFIG_MOUSE_PS2_SYNAPTICS=y CONFIG_MOUSE_PS2_LIFEBOOK=y CONFIG_MOUSE_PS2_TRACKPOINT=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_SERIO=y CONFIG_SERIO_SERPORT=y CONFIG_SERIO_AMBAKMI=y CONFIG_SERIO_LIBPS2=y CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_SSB_POSSIBLE=y 1.3. CONFIGURAZIONE DEI SORGENTI CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y CONFIG_FIRMWARE_EDID=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y CONFIG_FB_DEFERRED_IO=y CONFIG_FB_MODE_HELPERS=y CONFIG_FB_ARMCLCD=y CONFIG_FB_S1D13XXX=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_DISPLAY_SUPPORT=y CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y CONFIG_LOGO=y CONFIG_LOGO_LINUX_MONO=y CONFIG_LOGO_LINUX_VGA16=y CONFIG_LOGO_LINUX_CLUT224=y CONFIG_MMC=y CONFIG_MMC_DEBUG=y CONFIG_MMC_BLOCK=y CONFIG_MMC_BLOCK_BOUNCE=y CONFIG_SDIO_UART=y CONFIG_MMC_ARMMMCI=y CONFIG_RTC_LIB=y CONFIG_EXT2_FS=y CONFIG_FAT_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_PROC_FS=y CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_MSDOS_PARTITION=y CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_15=y CONFIG_NLS_UTF8=y CONFIG_ENABLE_WARN_DEPRECATED=y CONFIG_ENABLE_MUST_CHECK=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_LL=y CONFIG_BITREVERSE=y CONFIG_CRC32=y CONFIG_PLIST=y CONFIG_HAS_IOMEM=y 11 12 CAPITOLO 1. KERNEL & COMPILATORE CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y Listing 1.1: .config finale utilizzato (le voci commentate sono state rimosse) Alla fine della fase di configurazione, si dovrà iniziare a compilare i sorgenti. Poiché vogliamo generare un kernel (quindi un eseguibile) per ARM è necessario cross-compilare. 1.4 Cross-compilazione Per compilare un kernel per ARM ci sono le seguenti opzioni: 1. Avere un sistema operativo + compilatore C su architettura ARM (e parecchio tempo, data la potenza di questi dispositivi). 2. Avere un sistema operativo + compilatore C su architettura x86 + istruire il compilatore C a generare eseguibili per architettura ARM. Si è scelto di approcciarsi al problema tramite la soluzione 2. D’ora innanzi, quindi, si dirà HOST la macchina x86 su cui sono presenti compilatore e sorgenti la macchina ARM su cui si utilizzerà effettivamente il kernel compilato TARGET Ciò comporta una serie di vantaggi: • si può utilizzare come HOST un sistema linux già funzionante (nel nostro caso, sono stati utilizzati una debian Lenny e una OpenSuse 10.3); • la capacità di calcolo di una macchina TARGET è generalmente limitata, mentre le macchine HOST sono molto più potenti (minimizzando i tempi morti in attesa del termine della compilazione) 1.5. OUTPUT (IMAGE, ZIMAGE, BZIMAGE) 13 Ovviamente vi è la difficoltà di avere un compilatore C in grado di generare eseguibili per la macchina TARGET. Per fortuna questo è offerto da gcc. Per abilitare questa feature, però, è necessario impostare una opzione in fase di compilazione. Nel nostro caso si è evitato di ri-compilare il compilatore, ed è stata utilizzata una versione pre-compilata di gcc da handhelds.org http://www.handhelds.org/download/projects/toolchain/[Hic08]. Tuttavia è necessario istruire il kernel del fatto che vogliamo compilare i sorgenti (già configurati) con un compilatore diverso (ed un diverso linker, assembler, ecc). Per questo viene in aiuto la variabile d’ambiente CROSS_COMPILER, che istruisce il make su dove andare a cercare la toolchain adatta. Terminata la parte di configurazione del kernel, come già fatto nella sezione 1.3, non resta che compilare e testare. $ wget http://www.handhelds.org/download/projects/ toolchain/arm-linux-gcc-3.4.1.tar.bz2 $ su -c "tar xjf arm-linux-gcc-3.4.1.tar.bz2 -C /" [PASSWORD DI ROOT] $ export CROSS_COMPILE=/usr/local/arm/3.4.1/bin/armlinux$ make È da notare come CROSS_COMPILE indichi il prefisso comune a tutti gli eseguibili necessari (ARM - LINUX - GCC, ARM - LINUX - LD...). 1.5 Output (Image, zImage, bzImage) Terminata la fase di compilazione, verranno generati, oltre ad una serie di file temporanei / di supporto, i seguenti file. vmlinux eseguibile non compresso e non bootable del kernel. Usato soprattutto per debug, come vedremo nel capitolo 4 nella pagina 41. arch/arm/boot/Image immagine del kernel effettivamente eseguita 14 CAPITOLO 1. KERNEL & COMPILATORE Figura 1.1: Anatomia di bzImage (da en.wikipedia.org) arch/arm/boot/zImage immagine del kernel, compressa tramite gzip e preceduta da un decompressore (obsoleta) arch/arm/boot/bzImage (big zImagebig zImage) concatenatzione di bootsect.o + setup.o + misc.o + piggy.o.[Lin05, vml08] Capitolo 2 Avvio Una volta che il bootloader ha caricato il kernel in memoria e l’ha eseguito, vi è la fase di bootstrap che, nell’architettura ARM, è implementata per la maggior parte in assembly. 2.1 Sorgenti Il codice che si prende carico del boot del sistema è presente principalmente nelle directory ARCH / ARM / BOOT / COMPRESSED e ARCH / AR M / KERNEL ove sono presenti, oltre a del codice d’appoggio per comprimere e decomprimere l’eseguibile, anche una serie di file .S (scritti in assembly per ARM) tra i quali sono degni di nota i 2 file HEAD .S. ARCH / ARM / KERNEL / HEAD .S, in particolare, contiene la parte di codice che, di fatto, è il punto di partenza del kernel. In effetti questo codice, compilato, corrisponde alle prime istruzioni presenti in nel file I MAGE già descritto; Ovviamente nel caso si decida di usare i file Z I MAGE e BZ I MAGE, questo codice sarà quello invocato al termine della decompressione del kernel stesso. Ciò si evince anche dai commenti presenti nel file, come si può vedere: 59 60 61 62 /* * Kernel startup entry point. * --------------------------* 15 16 63 64 65 66 67 68 69 70 71 * * * * * * * * * CAPITOLO 2. AVVIO This is normally called from the decompressor code. The requirements are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, r1 = machine nr, r2 = atags pointer. This code is mostly position independent, so if you link the kernel at 0xc0008000, you call this at __pa(0xc0008000). See linux/arch/arm/tools/mach-types for the complete list of machine numbers for r1. In particolare, viene fatto riferimento al file ARCH / ARM / TOOLS / MACH questi altro non è che un “database” in cui si associa ad ogni modello supportato dal kernel che implementa le specifiche dell’ARM, una serie di codici univoci usati per poter generare delle guardie per implementare codice dipendente da macchina a macchina. Questo file è mantenuto dal “The ARM Linux Project”[Pro08], che assicura l’univocità degli identificatori usati per i vari palmari. In aggiunta a questo file vi è uno script awk (ARCH / ARM / TOOLS / GEN MACH - TYPES ) capace di trasformare questo file di configurazione nel file INCLUDE / ASM - ARM / MACH - TYPES . H, pieno di macro usate in fase di compilazione per abilitare o meno il codice specifico della macchina target. TYPES : 2.2 Decompressione Le prime istruzioni eseguite all’avvio di una zImage sono quelle relative alla decompressione del kernel. Il codice relativo alla decompressione è scritto in Assembly e si trova all’interno del file ARCH / ARM / BOOT / COMPRESSED / HEAD . S 109 110 111 112 113 114 115 116 117 118 119 120 121 122 .section ".start", #alloc, #execinstr /* * sort out different calling conventions */ .align start: .type start,#function .rept 8 mov r0, r0 .endr b 1f .word 0x016f2818 loader .word start address @ Magic numbers to help the @ absolute load/run zImage 2.2. DECOMPRESSIONE 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 1: .word mov mov _edata r7, r1 r8, #0 17 @ zImage end address @ save architecture ID @ save r0 #ifndef __ARM_ARCH_2__ /* * Booting from Angel - need to enter SVC mode and disable * FIQs/IRQs (numeric definitions from angel arm.h source). * We only do this if we were in user mode on entry. */ mrs r2, cpsr @ get current mode tst r2, #3 @ not user? bne not_angel mov r0, #0x17 @ angel_SWIreason_EnterSVC swi 0x123456 @ angel_SWI_ARM not_angel: mrs r2, cpsr @ turn off interrupts to orr r2, r2, #0xc0 @ prevent angel from running msr cpsr_c, r2 #else teqp pc, #0x0c000003 @ turn off interrupts #endif /* * Note that some cache flushing and other stuff may * be needed here - is there an Angel SWI call for this? */ /* * some architecture specific code can be inserted * by the linker here, but it should preserve r7 and r8. */ .text adr ldmia subs r0, LC0 r0, {r1, r2, r3, r4, r5, r6, ip, sp} r0, r0, r1 @ calculate the delta offset beq not_relocated @ if delta is zero, we’re @ running at the address we @ were linked at. /* * We’re running at a different address. * up various pointers: r5 - zImage base address * r6 - GOT start * ip - GOT end * */ add r5, r5, r0 add r6, r6, r0 add ip, ip, r0 We need to fix #ifndef CONFIG_ZBOOT_ROM /* * If we’re running fully PIC === CONFIG_ZBOOT_ROM = n, * we need to fix up pointers into the BSS region. 18 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 CAPITOLO 2. AVVIO * * * */ add add add 1: r2 - BSS start r3 - BSS end sp - stack pointer r2, r2, r0 r3, r3, r0 sp, sp, r0 /* * Relocate */ ldr r1, add r1, str r1, cmp r6, blo 1b all entries in the GOT table. [r6, #0] r1, r0 [r6], #4 ip @ relocate entries in the GOT @ table. This fixes up the @ C references. #else 1: /* * Relocate entries in the GOT table. We only relocate * the entries that are outside the (relocated) BSS region. */ ldr r1, [r6, #0] @ relocate entries in the GOT cmp r1, r2 @ entry < bss_start || cmphs r3, r1 @ _end < entry addlo r1, r1, r0 @ table. This fixes up the str r1, [r6], #4 @ C references. cmp r6, ip blo 1b #endif not_relocated: 1: mov str str str str cmp blo r0, r0, r0, r0, r0, r2, 1b #0 [r2], [r2], [r2], [r2], r3 #4 #4 #4 #4 @ clear bss /* * The C runtime environment should now be setup * sufficiently. Turn the cache on, set up some * pointers, and start decompressing. */ bl cache_on mov add r1, sp r2, sp, #0x10000 @ malloc space above stack @ 64k max /* * Check to see if we will overwrite ourselves. r4 = final kernel address * r5 = start of this image * r2 = end of malloc space (and therefore this image) * * We basically want: r4 >= r2 -> OK * r4 + image length <= r5 -> OK * 2.2. DECOMPRESSIONE 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 19 */ /* * r0 * r1-r3 * r4 * r5 * r6 * r7 * r8-r14 */ 1: = = = = = = = cmp bhs add cmp bls r4, r2 wont_overwrite r0, r4, #4096*1024 r0, r5 wont_overwrite mov mov mov bl r5, r2 r0, r5 r3, r7 decompress_kernel add bic r0, r0, #127 r0, r0, #127 @ 4MB largest kernel size @ decompress after malloc space @ align the kernel length decompressed kernel length unused kernel execution address decompressed kernel start processor ID architecture ID unused add adr ldr add ldmia stmia ldmia stmia cmp blo r1, r5, r0 r2, reloc_start r3, LC1 r3, r2, r3 r2!, {r8 - r13} r1!, {r8 - r13} r2!, {r8 - r13} r1!, {r8 - r13} r2, r3 1b bl add cache_clean_flush pc, r5, r0 @ end of decompressed kernel @ copy relocation code @ call relocation code /* * We’re not in danger of overwriting ourselves. * = kernel execution address * r4 = architecture ID * r7 */ wont_overwrite: mov r0, r4 mov r3, r7 bl decompress_kernel b call_kernel LC0: .type .word .word .word .word .word .word .word .word LC0, #object LC0 __bss_start _end _load_addr _start _got_start _got_end user_stack+4096 Do this the simple way. @ @ @ @ @ @ @ @ r1 r2 r3 r4 r5 r6 ip sp 20 294 295 CAPITOLO 2. AVVIO LC1: .word .size reloc_end - reloc_start LC0, . - LC0 Dove la funzione STAR T _ KERNEL è presente nel file BOOT / COMPRESSED / MISC . C . 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 ulg decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p, int arch_id) { output_data = (uch *)output_start; /* Points to kernel start */ free_mem_ptr = free_mem_ptr_p; free_mem_ptr_end = free_mem_ptr_end_p; __machine_arch_type = arch_id; arch_decomp_setup(); makecrc(); puts("Uncompressing Linux..."); gunzip(); puts(" done, booting the kernel.\n"); return output_ptr; } La funzione gunzip() è presente nel file 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 ARCH / ARM /- LIB / INFLATE . C /* * Do the uncompression! */ static int INIT gunzip(void) { uch flags; unsigned char magic[2]; /* magic header */ char method; ulg orig_crc = 0; /* original crc */ ulg orig_len = 0; /* original uncompressed length */ int res; magic[0] = NEXTBYTE(); magic[1] = NEXTBYTE(); method = NEXTBYTE(); if (magic[0] != 037 || ((magic[1] != 0213) && (magic[1] != 0236))) { error("bad gzip magic numbers"); return -1; } /* We only support method #8, DEFLATED */ if (method != 8) { error("internal error, invalid method"); return -1; } flags = (uch)get_byte(); 2.2. DECOMPRESSIONE 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 if ((flags & ENCRYPTED) != 0) { error("Input is encrypted"); return -1; } if ((flags & CONTINUATION) != 0) { error("Multi part input"); return -1; } if ((flags & RESERVED) != 0) { error("Input has invalid flags"); return -1; } NEXTBYTE(); /* Get timestamp */ NEXTBYTE(); NEXTBYTE(); NEXTBYTE(); (void)NEXTBYTE(); (void)NEXTBYTE(); /* Ignore extra flags for the moment */ /* Ignore OS type for the moment */ if ((flags & EXTRA_FIELD) != 0) { unsigned len = (unsigned)NEXTBYTE(); len |= ((unsigned)NEXTBYTE())<<8; while (len--) (void)NEXTBYTE(); } /* Get original file name if it was truncated */ if ((flags & ORIG_NAME) != 0) { /* Discard the old name */ while (NEXTBYTE() != 0) /* null */ ; } /* Discard file comment if any */ if ((flags & COMMENT) != 0) { while (NEXTBYTE() != 0) /* null */ ; } /* Decompress */ if ((res = inflate())) { switch (res) { case 0: break; case 1: error("invalid compressed format (err=1)"); break; case 2: error("invalid compressed format (err=2)"); break; case 3: error("out of memory"); break; case 4: error("out of input data"); break; default: error("invalid compressed format (other)"); } 21 22 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 CAPITOLO 2. AVVIO return -1; } /* Get the crc and original length */ /* crc32 (see algorithm.doc) * uncompressed input size modulo 2^32 */ orig_crc = (ulg) NEXTBYTE(); orig_crc |= (ulg) NEXTBYTE() << 8; orig_crc |= (ulg) NEXTBYTE() << 16; orig_crc |= (ulg) NEXTBYTE() << 24; orig_len orig_len orig_len orig_len = (ulg) NEXTBYTE(); |= (ulg) NEXTBYTE() << 8; |= (ulg) NEXTBYTE() << 16; |= (ulg) NEXTBYTE() << 24; /* Validate decompression */ if (orig_crc != CRC_VALUE) { error("crc error"); return -1; } if (orig_len != bytes_out) { error("length error"); return -1; } return 0; underrun: /* NEXTBYTE() goto’s here if needed */ error("out of input data"); return -1; } 2.3 Boot Tornando alla sequenza di boot, analizziamo un attimo le prime istruzioni presenti in ARCH / ARM / KERNEL / HEAD .S: 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 .section ".text.head", "ax" .type stext, %function ENTRY(stext) msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode @ and irqs disabled mrc p15, 0, r9, c0, c0 @ get processor id bl __lookup_processor_type @ r5=procinfo r9=cpuid movs r10, r5 @ invalid processor (r5=0)? beq __error_p @ yes, error ’p’ bl __lookup_machine_type @ r5=machinfo movs r8, r5 @ invalid machine (r5=0)? beq __error_a @ yes, error ’a’ bl __vet_atags bl __create_page_tables 2.3. BOOT 92 93 94 95 96 97 98 99 100 101 102 23 /* * The following calls CPU specific code in a position independent * manner. See arch/arm/mm/proc-*.S for details. r10 = base of * xxx_proc_info structure selected by __lookup_machine_type * above. On return, the CPU will be ready for the MMU to be * turned on, and r0 will hold the CPU control register value. */ ldr r13, __switch_data @ address to jump to after @ mmu has been enabled adr lr, __enable_mmu @ return (PIC) address add pc, r10, #PROCINFO_INITFUNC All’inizio degni di nota sono soprattutto i controlli effettuati dal kernel sulla possibilità di supportare processore e macchina. In caso d’errore vengono invocate delle funzioni per avvisare l’utente e terminare l’esecuzione del programma. Altrimenti vengono “salvati” nel registro 10 il processore e nel registro 8 il tipo di macchina riconosciuti. Una volta superati i controlli l’esecuzione continua con il codice specifico della cpu. Ma vengono salvate alcune funzioni da eseguire in seguito. Nelle ultime tre righe, infatti, si istruisce il programma a salvare in r13 il codice di __ SWITCH _ DATA e a salvare il LR1 il codice per abilitare l’MMU. Questi dovrà essere eseguito dopo il codice specifico della macchina: l’ultima riga, infatti, altro non fa che scrivere su PC la somma di r10 (indirizzo di memoria che contiene le informazioni sulla cpu riconosciuta) col valore di PROCINFO_INITFUNC, definito in ARCH / ARM / KERNEL / ASM - OFFSETS . C come DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush)); dove PROC _ INFO _ LIST altro non è che la struttura della variabile contenente le informazioni del processore, e __ CPU _ FLUSH è un suo campo. PROCINFO_INITFUNC, quindi, è l’offset per arrivare all’indirizzo dell’attributo __ CPU _ FLUSH partendo dall’indirizzo base della struttura. Nel nostro caso verrà eseguito il codice presente nel file ARCH / ARM / MM / PROC - ARM 926.S (cpu per la quale stiamo compilando il kernel). 471 472 473 .type __arm926_proc_info,#object __arm926_proc_info: .long 0x41069260 1 last register; all’appendice A @ ARM926EJ-S (v5TEJ) per questo e per altri comandi assembly si rimanda 24 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 CAPITOLO 2. AVVIO .long .long 0xff0ffff0 PMD_TYPE_SECT | \ PMD_SECT_BUFFERABLE | \ PMD_SECT_CACHEABLE | \ PMD_BIT4 | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ .long PMD_TYPE_SECT | \ PMD_BIT4 | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ b __arm926_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP| HWCAP_JAVA .long cpu_arm926_name .long arm926_processor_functions .long v4wbi_tlb_fns .long v4wb_user_fns .long arm926_cache_fns .size __arm926_proc_info, . - __arm926_proc_info Quindi andremo ad eseguire il codice presente nella funzione __ ARM 926_ SETUP, definita nello stesso file 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 .type __arm926_setup, __arm926_setup: mov r0, #0 mcr p15, 0, r0, c7, mcr p15, 0, r0, c7, #ifdef CONFIG_MMU mcr p15, 0, r0, c8, #endif #function c7 c10, 4 @ invalidate I,D caches on v4 @ drain write buffer on v4 c7 @ invalidate I,D TLBs on v4 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH mov r0, #4 explicitly mcr p15, 7, r0, c15, c0, 0 #endif @ disable write-back on caches adr r5, arm926_crval ldmia r5, {r5, r6} mrc p15, 0, r0, c1, c0 @ get control register v4 bic r0, r0, r5 orr r0, r0, r6 #ifdef CONFIG_CPU_CACHE_ROUND_ROBIN orr r0, r0, #0x4000 @ .1.. .... .... .... #endif mov pc, lr .size __arm926_setup, . - __arm926_setup A parte il codice specifico, è da notare come le istruzioni ter- 2.3. BOOT 25 minino impostando il program counter col valore del last register, cioè l’indirizzo di __ ENABLE _ MMU. Essa è definita in HEAD .S. 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 /* * Setup common bits before finally enabling the MMU. Essentially * this is just loading the page table pointer and domain access * registers. */ .type __enable_mmu, %function __enable_mmu: #ifdef CONFIG_ALIGNMENT_TRAP orr r0, r0, #CR_A #else bic r0, r0, #CR_A #endif #ifdef CONFIG_CPU_DCACHE_DISABLE bic r0, r0, #CR_C #endif #ifdef CONFIG_CPU_BPREDICT_DISABLE bic r0, r0, #CR_Z #endif #ifdef CONFIG_CPU_ICACHE_DISABLE bic r0, r0, #CR_I #endif mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT)) mcr p15, 0, r5, c3, c0, 0 @ load domain access register mcr p15, 0, r4, c2, c0, 0 @ load page table pointer b __turn_mmu_on L’ultima riga invoca la funzione __ TURN _ MMU _ ON, definita subito dopo. 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 /* * Enable the MMU. This completely changes the structure of the visible * memory space. You will not be able to trace execution through this. * If you have an enquiry about this, *please* check the linux-arm-kernel * mailing list archives BEFORE sending another post to the list. * * r0 = cp#15 control register * r13 = *virtual* address to jump to upon completion * * other registers depend on the function called upon completion */ .align 5 .type __turn_mmu_on, %function __turn_mmu_on: mov r0, r0 mcr p15, 0, r0, c1, c0, 0 @ write control reg mrc p15, 0, r3, c0, c0, 0 @ read id reg mov r3, r3 mov r3, r3 mov pc, r13 26 CAPITOLO 2. AVVIO Al termine della funzione, viene modificato il program counter per eseguire il contenuto di r13, contenente l’oggetto __ SWITCH _ DATA. Questo è definito nel file ARCH / ARM / KERNEL / HEAD - COMMON .S 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 .type __switch_data: .long .long .long .long .long .long .long .long .long .long __switch_data, %object __mmap_switched __data_loc @ r4 __data_start @ r5 __bss_start @ r6 _end @ r7 processor_id @ r4 __machine_arch_type @ r5 __atags_pointer @ r6 cr_alignment @ r7 init_thread_union + THREAD_START_SP @ sp /* * The following fragment of code is executed with the MMU on in MMU mode, * and uses absolute addresses; this is not position independent. * * r0 = cp#15 control register * r1 = machine ID * r2 = atags pointer * r9 = processor ID */ .type __mmap_switched, %function __mmap_switched: adr r3, __switch_data + 4 1: 1: ldmia cmp cmpne ldrne strne bne r3!, {r4, r5, r6, r7} r4, r5 r5, r6 fp, [r4], #4 fp, [r5], #4 1b mov cmp strcc bcc fp, #0 r6, r7 fp, [r6],#4 1b ldmia str str str bic stmia b r3, {r4, r5, r6, r7, sp} r9, [r4] r1, [r5] r2, [r6] r4, r0, #CR_A r7, {r0, r4} start_kernel @ Copy data segment if needed @ Clear BSS (and zero fp) @ @ @ @ @ Save processor ID Save machine type Save atags pointer Clear ’A’ bit Save control register values Il primo campo dell’oggetto __ SWITCH _ DATA è la funzione __ MMAP _ SWITCHED che, eseguita, termina invocando STAR T _ KERNEL, la funzione “ad alto livello” implementata in C nel file INIT / MAIN . C. E direi che può bastare 2.4. HELLO, WORLD! 2.4 27 Hello, world! Avendo capito dov’è il punto di avvio del kernel, e volendone modificare il comportamento all’avvio, abbiamo deciso di iniziare dal classico “Hello, world!”. In particolare, abbiamo modificato i sorgenti nei file ARCH / ARM / KERNEL / HEAD COMMON .S (in modo da invocare una funzione diversa al termine della fase di bootstrap) 61 b start_kernel_hello_os e abbiamo modificato il file funzione da invocare all’avvio) /* b INIT / MAIN . C start_kernel */ (aggiungendo la nuova 534 extern void printascii(const char*); 535 536 asmlinkage void __init start_kernel_hello_os(void) { 537 printascii("Hello, world!\n"); 538 } Il prototipo della funzione start_kernel_hello_os() è identico a quello della funzione start_kernel(), inidicando al compilatore • che essa è una funzione che non ha parametri né restituisce niente (i due void) • che la funzione non utilizzerà i registri, ma solo lo stack per i parametri (come ottimizzazione)2 • che il codice generato dovrà essere presente in una parte ben definita del binario (in questo caso nella sezione “.init.text”)3 Inoltre è stato necessario introdurre il prototipo della funzione printascii(), implementata in assembly nel file ARCH / ARM / KERNEL / DE BUG .S. 116 ENTRY(printascii) 117 addruart r3 2 3 Confronta http://kernelnewbies.org/FAQ/asmlinkage Confronta http://kernelnewbies.org/FAQ/InitExitMacros 28 118 119 1: 120 121 122 123 124 125 2: 126 127 128 129 CAPITOLO 2. AVVIO b 2f waituart r2, r3 senduart r1, r3 busyuart r2, r3 teq r1, #’\n’ moveq r1, #’\r’ beq 1b teq r0, #0 ldrneb r1, [r0], #1 teqne r1, #0 bne 1b mov pc, lr Purtroppo, l’implementazione delle macro addruart, waituart, senduart e busyuart è “implemention defined”, nel senso che ogni singola architettura dell’ARM definisce una sua versione delle quattro macro. Esse sono definite nei vari file INCLUDE / ASM - ARM / ARCH */ DEBUG - MACRO .S. Capitolo 3 Test La fase di test è consistita nel verificare il funzionamento del kernel prima sul dispositivo HTC P6300, usando una smart card come dispositivo di boot e Haret come bootloader; poi utilizzando qemu per realizzare una macchina virtuale su cui abbiamo installato il kernel che abbiamo debuggato usando gdb; infine si vedrà il comportamento del kernel usando U-boot come bootloader presente sulla memoria flash del dispositivo. 3.1 Haret Haret[ZOS08] è un boot-loader scritto in C++ per Windows Mobile® 3.1.1 Perché Esistono due modi per far partire linux su un comune palmare. • Invasivo • Non invasivo Nel modo invasivo viene modificato la memoria interna del palmare installandoci sopra un bootloader universale U-boot il quale permette di far partire kernel anche da remoto sin dall’avvio. Con questa modalità però si perde tutto il software preinstallato sulla macchina dal momento che si sovrascrive la memoria stessa. 29 30 CAPITOLO 3. TEST Nel modo non invasivo viene avviato un programma sotto Windows Mobile® per lanciare il kernel dopo aver disabilitato l’hardware in modo da non danneggiarlo. Questa è, in effetti, una modalità abbastanza utilizzata anche se vi possono essere problemi di compatibilità tra l’hardware e il bootloader. Volendo scelgliere la modalità non invasiva, ci siamo concentrati sul bootloader, Haret. Sul sito del progetto è presente anche un wiki dove è possibile trovare una lista di dispositivi testati ed in fase di testing. 3.1.2 Come usare Haret Il suo obiettivo è di preparare il dispositivo al lancio del kernel linux. Prima di tutto dobbiamo ottenerlo: sono disponibili versioni precompilate per Windows Mobile®, ma abbiamo preferito lavorare con i sorgenti prelevandoli dal server svn di sviluppo. Volendo usare i sorgenti, però, sorge il problema di compilarli da una macchina x86 con sistema operativo linux verso una macchina ARM con sistema operativo Windows Mobile®. Per quest’ultimo problema, si rimanda alla sezione 3.1.5. Nel caso si preferisca usare una versione già precompilata, basterà scaricarla e copiarla sulla miniSD con alcuni file di configurazione e il kernel stesso. $ wget http://www.handhelds.org/~koconnor/haret/haret -0.5.1.exe Il file di configurazione STAR TUP. TXT : set KERNEL "zImage-2.6.12" set MTYPE 766 set INITRD "initrd-2.6.12-hh2.gz" set CMDLINE "root=/dev/ram0 console=tty0" bootlinux indica all’eseguibile HARET. EXE come settare alcuni parametri (variabili globali all’interno del codice di haret) quali KERNEL, MTYPE, 3.1. HARET 31 INITRD, CMDLINE ed infine avvia la funzione (interna al codice di haret quindi scritta in C++) bootlinux(). 3.1.3 Codice Il codice del programma prevede parti scritte in C++ e parti scritte in Assembly. Le funzioni più interessanti sono presenti all’interno del file LINBOOT. CPP. La funzione launchKernel() ad esempio è responsabile di inibire l’hardware e lanciare il kernel 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 static void launchKernel(struct bootmem *bm) { // Prep the trampoline. uint32 physAddrTram = setupTrampoline(); if (! physAddrTram) return; // Cache an mmu pointer for the trampoline uint8 *virtAddrMmu = memPhysMap(cpuGetMMU()); Output("MMU setup: mmu=%p/%08x", virtAddrMmu, cpuGetMMU()); // Call per-arch setup. int ret = Mach->preHardwareShutdown(); if (ret) { Output(C_ERROR "Setup for machine shutdown failed"); return; } Screen("Go Go Go..."); // Disable interrupts take_control(); fb_clear(&bm->pd->fbi); fb_printf(&bm->pd->fbi, "HaRET boot\nShutting down hardware\n"); // Call per-arch boot prep function. Mach->hardwareShutdown(&bm->pd->fbi); fb_printf(&bm->pd->fbi, "Turning off MMU...\n"); // Disable MMU and launch linux. mmu_trampoline(physAddrTram, virtAddrMmu, bm->physExec, Mach->flushCache); // The above should not ever return, but we attempt recovery here. return_control(); } mentre la funzione preloader() 245 246 247 248 249 250 251 252 253 // Code to launch kernel. static void __preload preloader(struct preloadData *data) { data->fbi.fb = (uint16 *)data->physFB; data->fbi.fonts = (unsigned char *)data->physFonts; FB_PRINTF(&data->fbi, "In preloader\\n"); uint32 psr = do_cpuGetPSR(); FB_PRINTF(&data->fbi, "PSR=%%x\\n", psr); 32 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 CAPITOLO 3. TEST if ((psr & 0xc0) != 0xc0) FB_PRINTF(&data->fbi, "ERROR: IRQS not off\\n"); if (fbOverlaps(data)) { FB_PRINTF(&data->fbi, "Disabling framebuffer feedback\\n"); data->fbi.fb = 0; } // Copy tags to beginning of ram. char *destTags = (char *)data->startRam + PHYSOFFSET_TAGS; do_copy(destTags, data->tags, TAGSIZE); FB_PRINTF(&data->fbi, "Tags relocated\\n"); // Copy kernel image char *destKernel = (char *)data->startRam + PHYSOFFSET_KERNEL; int kernelCount = PAGE_ALIGN(data->kernelSize) / PAGE_SIZE; do_copyPages((char *)destKernel, data->indexPages, 0, kernelCount); FB_PRINTF(&data->fbi, "Kernel relocated\\n"); // Copy initrd (if applicable) char *destInitrd = (char *)data->startRam + PHYSOFFSET_INITRD; int initrdCount = PAGE_ALIGN(data->initrdSize) / PAGE_SIZE; do_copyPages(destInitrd, data->indexPages, kernelCount, initrdCount); FB_PRINTF(&data->fbi, "Initrd relocated\\n"); // Do CRC check (if enabled). if (data->doCRC) { FB_PRINTF(&data->fbi, "Checking tags crc..."); uint32 crc = crc32_be(0, destTags, TAGSIZE); crc = crc32_be_finish(crc, TAGSIZE); if (crc == data->tagsCRC) FB_PRINTF(&data->fbi, "okay\\n"); else FB_PRINTF(&data->fbi, "FAIL FAIL FAIL\\n"); FB_PRINTF(&data->fbi, "Checking kernel crc..."); crc = crc32_be(0, destKernel, data->kernelSize); crc = crc32_be_finish(crc, data->kernelSize); if (crc == data->kernelCRC) FB_PRINTF(&data->fbi, "okay\\n"); else FB_PRINTF(&data->fbi, "FAIL FAIL FAIL\\n"); if (data->initrdSize) { FB_PRINTF(&data->fbi, "Checking initrd crc..."); crc = crc32_be(0, destInitrd, data->initrdSize); crc = crc32_be_finish(crc, data->initrdSize); if (crc == data->initrdCRC) FB_PRINTF(&data->fbi, "okay\\n"); else FB_PRINTF(&data->fbi, "FAIL FAIL FAIL\\n"); } } FB_PRINTF(&data->fbi, "Jumping to Kernel...\\n"); // Boot typedef void (*lin_t)(uint32 zero, uint32 mach, char *tags); lin_t startfunc = (lin_t)destKernel; startfunc(0, data->machtype, destTags); } è sicuramente la più importante dal momento che nelle ultime tre righe passa il controllo al kernel terminando l’esecuzione di 3.1. HARET 33 haret stesso quindi. 315 typedef void (*lin_t)(uint32 zero, uint32 mach, char *tags); viene definita un prototipo di funzione di tipo puntatore a lin_t 316 lin_t startfunc = (lin_t)destKernel; è definita una variabile startfunc di tipo lin_t come cast della variabile destKernel, buffer di memoria contenente il kernel in ram 317 startfunc(0, data->machtype, destTags); è lanciata la funzione startfunc() con in input uno 0, il valore della variabile Mtype passata in precedenza e il valore di destTags, buffer di memoria contenenti i tags in ram. La programmazione in C++ è suddivisa in due fasi dal momento che dopo lo shutdown dell’hardware il programma accede direttamente alla memoria e non riesce a tradurre le funzioni e librerie tipiche del C++ con conseguente uso di funzion ad-hoc. Ad esempio nella funzione preloader() vi è 251 FB_PRINTF(&data->fbi, "In preloader\\n"); la quale risulta una macro definita nel codice in modo seguente 225 226 227 228 229 230 231 232 233 234 235 #define STR_IN_CODE(sec,str) ({\ const char *__str;\ asm(".section " #sec ", 1\n"\ "1: .asciz\"" str "\"\n"\ " .balign 4\n"\ " .section " #sec ", 0\n"\ " add %0, pc, #( 1b - . - 8 )\n"\ : "=r" (__str));\ __str;\ }) #define FB_PRINTF(fbi,fmt,args...) fb_printf((fbi), STR_IN_CODE (.text.preload, fmt) , ##args ) Per quanto riguarda la comunicazione verso l’utente in haret esistono due tipologie di output • file di log; • stampa a video. 34 CAPITOLO 3. TEST Per abilitare l’output su file di log è necessario creare un file vuoto all’interno della cartella dove è presente l’eseguibile HARET. EXE e rinominarlo EARLYHARETLOG . TXT. Il file di log HARETLOG . TXT verrà creato nella stessa cartella. All’interno del codice la funzione Output() è la responsabile della scrittura su file. La seconda tipologia di output si rende necessaria quando avviene lo shutdown dell’hardware dal momento che non si ha più accesso alla memoria della miniSD. All’interno del codice la funzione fb_printf() stampa a video ove previsto. Questo rappresenta la parte finale di un file di log. Nella prima parte vi è il riconoscimento della macchina da parte del sistema. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Welcome, this is HaRET pre-0.5.2-20080711_124633 running on WindowsCE v5.1 Minimal virtual address: 00010000, maximal virtual address: 7FFFFFFF Detected machine Panda/s3c2442 (Plat=’PocketPC’ OEM=’PAND100’) CPU is ARM ARM arch 4T stepping 0 running in system mode Enter ’HELP’ for a short command summary. Running WSAStartup Starting gui In initdialog Found machine Panda executing startup.txt HaRET(1)# set MTYPE 1806 HaRET(2)# set KERNEL "zImage" HaRET(3)# set CMDLINE "root=/dev/mmcblk0p2 console=tty0 mem=128M rootdelay=5" HaRET(4)# bootlinux boot KERNEL=zImage INITRD= Opening file zImage boot params: RAMADDR=30000000 RAMSIZE=08000000 MTYPE=1806 CMDLINE=’root=/dev/ mmcblk0p2 console=tty0 mem=128M rootdelay=5’ Boot FB feedback: 1 Built virtual to physical page mapping Allocated 265 pages (tags=4FB00000/36b4e000 kernel=4FB01000/36b4f000 initrd=4 FC05000/36a47000 index=4FC05000/36a47000) Built kernel tags area Built page index Video buffer at 52800000 sx=240 sy=320 mx=60 my=53 Video Phys FB=10800000 Fonts=36a45064 preload=2260@4FC08000/36a44000 sj=4FC08000 stack=4FC06000/36a46000 data=4FC07000 /36a45000 exec=36a44128 Reading 1062116 bytes... Read complete Launching to physical address 36a44010 Trampoline setup (tram=136@00024AEC/1c024aec/30882aec) MMU setup: mmu=A0250000/30550000 Go Go Go... Si noti come al terzo rigo avvisa dell’avvenuto riconoscimento della macchina e della tipologia di cpu. Poi parte nell’esecuzione del contenuto di STAR TUP. TXT come fossero comandi separati tra 3.1. HARET 35 loro (si noti il carattere # indicatore della pseudo-shell). L’ultimo comando è appunto bootlinux il quale fa partire l’esecuzione del codice visto in precedenza. Alla fine del file di log vi è la scritta “Go Go Go ...” che è l’ultimo messaggio previsto dal codice prima di spegnere l’hardware e lasciare l’esecuzione al kernel. La presenza di questo messaggio quindi implica il successo nell’esecuzione di haret. Tutti gli eventuali problemi successivi saranno dovuti al kernel non più ad haret. 3.1.4 Problemi Abbiamo constatato delle difficoltà a debuggare su un sistema embedded. Nel nostro caso avevamo problemi dal momento che ci appariva la scritta Go Go Go... ma il kernel non partiva. Eravamo quindi davanti una serie di possibili cause da dimostrare. Il primo dubbio risolto riguardava errori presenti all’interno del codice di haret. Con un attento debug tramite stringhe stampate sullo schermo ci siamo accertati che effettivamente il controllo passava al kernel (tre righe finali viste in precedenza). Il dubbio immediatamente successivo riguardava un problema di errato passaggio del file del kernel. Anche in questo caso abbiamo stampato a video e confrontato bit a bit il file del kernel con il contenuto del buffer di memoria che veniva avviato da haret. 3.1.5 Compilazione di Haret Per la compilazione di Haret è necessario usare un compilatore C++ per ARM con Windows Mobile®. Noi abbiamo usato armmingw32ce, toolset sviluppato nel progetto cegcc[ceg08], sviluppato allo scopo di compilare binari per windows CE. Dopo il dowload1 e la scompattazione si ritroveranno una serie di binari pronti all’uso con il formato arm-wince-cegcc-* o arm-wince-mingw32ce-*. 1 Non è possibile segnalare il link diretto, in quanto il progetto si appoggia a sourceforge.net, che utilizza un insieme di mirror per lo storage dei file. 36 CAPITOLO 3. TEST Se si scompattano i file nella directory radice, non sarà necessario modificare il Makefile dei sorgenti di Haret. $ su -c "tar xzf cegcc-gcc430.tar.gz -C /" [PASSWORD DI ROOT] Per ottenere l’ultima versione dei sorgenti, è necessario usare cvs: $ cvs -d :pserver:[email protected]:/cvs login CVS password: anoncvs $ cvs -d :pserver:[email protected]:/cvs co haret $ cd haret $ make al termine della compilazione, sarà stato generato il file OUT / HARET. EXE, pronto per essere usato come già detto nella sezione 3.1.2. 3.2 Qemu Qemu è un emulatore e virtualizzatore generico open source. Nello specifico è stato usato per emulare un’architettura basata su cpu ARM (Versatile AB prima, Samsung S3C2442B dopo) per semplificare le procedure di testing e debugging del kernel. 3.2.1 Come ottenerlo Qemu è libero e già installato nella maggior parte delle distribuzioni. Le versioni da noi usate sono state la 0.9.0 e la 0.9.1. Se non è già installato sarà sufficiente usare il package manager della distribuzione (YaST per OpenSuSE, Synaptic per Debian e derivate, installpkg per Slackware, eccetera); nella (improbabile) ipotesi che non sia disponibile, i sorgenti sono disponibili presso http://bellard.org/qemu/qemu-0.9.1.tar.gz. In ogni caso si avrà accesso all’applicazione tramite terminale. 3.2. QEMU Listing 3.1: Output di 37 QEMU lanciato senza parametri $ qemu QEMU PC emulator version 0.9.1, Copyright (c) 2003-2008 Fabrice Bellard usage: qemu [options] [disk_image] ’disk_image’ is a raw hard image image for IDE hard disk 0 Standard options: -M machine select emulated machine (-M ? for list) -cpu cpu select CPU (-cpu ? for list) -fda/-fdb file use ’file’ as floppy disk 0/1 image -hda/-hdb file use ’file’ as IDE hard disk 0/1 image -hdc/-hdd file use ’file’ as IDE hard disk 2/3 image -cdrom file use ’file’ as IDE cdrom image (cdrom is ide1 master) -drive [file=file][,if=type][,bus=n][,unit=m][,media=d][index=i] [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off] [,cache=on|off] use ’file’ as a drive image -mtdblock file use ’file’ as on-board Flash memory image -sd file use ’file’ as SecureDigital card image -pflash file use ’file’ as a parallel flash image -boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n) -snapshot write to temporary files instead of disk image files -no-frame open SDL window without a frame and window decorations -alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt) -no-quit disable SDL window close capability -no-fd-bootchk disable boot signature checking for floppy disks -m megs set virtual RAM size to megs MB [default=128] -smp n set the number of CPUs to ’n’ [default=1] -nographic disable graphical output and redirect serial I/Os to console -portrait rotate graphical output 90 deg left (only PXA LCD) -k language use keyboard layout (for example "fr" for French) -audio-help print list of audio drivers and their options -soundhw c1,... enable audio support and only specified sound cards (comma separated list) use -soundhw ? to get the list of supported cards use -soundhw all to enable all of them -localtime set the real time clock to local time [default=utc] -full-screen start in full screen -win2k-hack use it when installing Windows 2000 to avoid a disk full bug -usb enable the USB driver (will be the default soon) -usbdevice name add the host or guest USB device ’name’ -name string set the name of the guest Network options: -net nic[,vlan=n][,macaddr=addr][,model=type] create a new Network Interface Card and connect it to VLAN ’n’ -net user[,vlan=n][,hostname=host] connect the user mode network stack to VLAN ’n’ and send hostname ’host’ to DHCP clients -net tap[,vlan=n][,fd=h][,ifname=name][,script=file][,downscript=dfile] connect the host TAP network interface to VLAN ’n’ and use the network scripts ’file’ (default=/etc/qemu-ifup) and ’dfile’ (default=/etc/qemu-ifdown); use ’[down]script=no’ to disable script execution; use ’fd=h’ to connect to an already opened TAP interface -net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port] connect the vlan ’n’ to another VLAN using a socket connection -net socket[,vlan=n][,fd=h][,mcast=maddr:port] connect the vlan ’n’ to multicast maddr and port -net none use it alone to have zero network devices; if no -net option is provided, the default is ’-net nic -net user’ -tftp dir allow tftp access to files in dir [-net user] -bootp file advertise file in BOOTP replies -smb dir allow SMB access to files in ’dir’ [-net user] -redir [tcp|udp]:host-port:[guest-host]:guest-port redirect TCP or UDP connections from host to guest [-net user] Linux boot specific: -kernel bzImage use ’bzImage’ as kernel image -append cmdline use ’cmdline’ as kernel command line -initrd file use ’file’ as initial ram disk Debug/Expert options: -monitor dev redirect the monitor to char device ’dev’ -serial dev redirect the serial port to char device ’dev’ -parallel dev redirect the parallel port to char device ’dev’ -pidfile file Write PID to ’file’ -S freeze CPU at startup (use ’c’ to start execution) -s wait gdb connection to port -p port set gdb connection port [default=1234] -d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items) -hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS 38 CAPITOLO 3. TEST translation (t=none or lba) (usually qemu can guess them) set the directory for the BIOS, VGA BIOS and keymaps enable KQEMU full virtualization (default is user mode only) disable KQEMU kernel module usage simulate a standard VGA card with VESA Bochs Extensions (default is CL-GD5446 PCI VGA) -no-acpi disable ACPI -no-reboot exit instead of rebooting -loadvm file start right away with a saved state (loadvm in monitor) -vnc display start a VNC server on display -daemonize daemonize QEMU after initializing -option-rom rom load a file, rom, into the option ROM space -clock force the use of the given methods for timer alarm. To see what timers are available use -clock help During emulation, the following keys are useful: ctrl-alt-f toggle full screen ctrl-alt-n switch to virtual console ’n’ ctrl-alt toggle mouse and keyboard grab When using -nographic, press ’ctrl-a h’ to get some help. $ -L path -kernel-kqemu -no-kqemu -std-vga Listing 3.1: Output di QEMU lanciato senza parametri Per poter emulare anche il chip Samsung S3C2442B è stata utilizzata anche una versione di qemu custom modificata e manutenuta dagli sviluppatori del progetto openmoko[ope08]. Per migliorare le prestazioni di qemu è possibile installare anche kqemu, un modulo kernel scritto per velocizzare l’emulazione di x86 su x86 http://bellard.org/qemu/download.html 3.2.2 Emulazione Qemu fornisce alcune utility all’emulazione. Ad esempio qemu-img è un programmino per la creazione di hard disk virtuali su cui far girare o installare il sistema emulato. Per l’avvio di una emulazione è possibile specificare oltre ad un hard disk virtuale anche uno fisico presente sulla macchina. Nel nostro caso abbiamo lanciato qemu specificando come hard disk la memory card miniSD su cui avevano installato la distribuzione per Arm da testare. 3.2.3 Sistemi emulati Per avviare un sistema x86 partente da cd con un hard disk e 128 mb di ram è necessario lanciare $ qemu -cdrom image.iso -hda /dev/sda1 -m 128 -boot d dove qemu è in realtà un link a qemu-system-i386. 3.2. QEMU 39 Per emulare un sistema ARM con macchina versatileab con kernel contenuto nel file locale zImage e 128 mb di ram e avente come hard disk un’immagine virtuale locale hd0.img è necessario lanciare $ qemu-system-arm -M versatileab -kernel zImage nographic -m 126 -hda hd0.img e cosi via per tutti i sistemi attualmente emulati da qemu: $ cd /usr/bin $ ls qemu-* qemu-alpha qemu-ppc qemu-arm qemu-ppc64 qemu-armeb qemu-ppc64abi32 qemu-cris qemu-sh4 qemu-i386 qemu-sh4eb qemu-img qemu-sparc qemu-m68k qemu-sparc32plus qemu-mips qemu-sparc64 qemu-mipsel qemu-system-arm $ in particolare, ture qemu-system-cris qemu-system-i386 qemu-system-m68k qemu-system-mips qemu-system-mips64 qemu-system-mips64el qemu-system-mipsel qemu-system-ppc qemu-system-ppc64 QEMU - SYSTEM - ARM qemu-system-ppcemb qemu-system-sh4 qemu-system-sh4eb qemu-system-sparc qemu-system-x86_64 qemu-system-z80 qemu-x86_64 supporta le seguenti architet- $ qemu-system-arm -M ? Supported machines are: integratorcp ARM Integrator/CP (ARM926EJ-S) (default) versatilepb ARM Versatile/PB (ARM926EJ-S) versatileab ARM Versatile/AB (ARM926EJ-S) realview ARM RealView Emulation Baseboard (ARM926EJ-S) akita Akita PDA (PXA270) spitz Spitz PDA (PXA270) borzoi Borzoi PDA (PXA270) terrier Terrier PDA (PXA270) cheetah Palm Tungsten|E aka. Cheetah PDA (OMAP310) lm3s811evb Stellaris LM3S811EVB lm3s6965evb Stellaris LM3S6965EVB connex Gumstix Connex (PXA255) verdex Gumstix Verdex (PXA270) mainstone Mainstone II (PXA27x) e le seguenti cpu $ qemu-system-arm -cpu ? Available CPUs: arm926 arm946 arm1026 arm1136 arm11mpcore cortex-m3 40 CAPITOLO 3. TEST cortex-a8 ti925t pxa250 pxa255 pxa260 pxa261 pxa262 pxa270 pxa270-a0 pxa270-a1 pxa270-b0 pxa270-b1 pxa270-c0 pxa270-c5 any 3.3 To do U-Boot Capitolo 4 Debugger Abbiamo avuto problemi a far partire il kernel di linux sul dispositivo palmare, quindi abbiamo cercato di trovare un modo per avere feedback sull’esecuzione del codice e sugli eventuali errori riscontrati sulla piattaforma. Poiché vorremmo analizzare il comportamento di un kernel, però, non è possibile utilizzare STDOUT / STDERR come canali di comunicazione, né loggare il comportamento su file, in quanto non è ancora disponibile un’interfaccia verso queste strutture ad alto livello. Per questo motivo abbiamo considerato l’idea di usare un debugger. Per poterla applicare, però, avremmo avuto bisogno di un eseguibile per il sistema operativo Windows Mobile® che si integrasse con Haret (vedi capitolo3.1). L’alternativa scelta è stata quella di usare un emulatore per l’architettura, e di usare il classico GDB per il debug. Questa scelta ha semplificato l’analisi e il debug dell’esecuzione delle singole istruzioni del codice. 4.1 A che serve Usare un debugger col kernel è stato utile soprattutto per scoprire “qual è la prima funzione invocata” dal kernel stesso. Se è vero che su architettura x86 vi è la funzione main() in 41 42 CAPITOLO 4. DEBUGGER ARCH / X 86/ BOOT / MAIN . C che identifica la prima funzione invocata, su architettura ARM questo non succede. Al contrario, vi sono una serie di cartelle per raggruppare l’implementazione delle funzioni per piattaforma e per singolo modello, in quanto il modello di distribuzione delle specifiche di ARM è diverso dal modello di sviluppo intel[arm08]. Come si è visto nel capitolo 2, la fase iniziale del boot su ARM è implementata in assembly; vi è una parte comune (la decompressione della bzImage, il caricamento in memoria dell’immagine del kernel, alcune funzioni d’appoggio) a tutte le CPU e una parte specifica. 4.2 Quale usare Poiché vogliamo usare gdb su un HOST x86, ma con TARGET ARM, abbiamo bisogno di usare un debugger compilato per x86, che sappia tracciare le istruzioni ed estrarre i simboli da un binario (il kernel) compilato per ARM. Per questo abbiamo scaricato i sorgenti, li abbiamo estratti e compilati, facendo attenzione a impostare – TARGET = ARM - LINUX nella fase di configurazione per analizzare binari per ARM. $ $ $ $ $ wget http://ftp.gnu.org/gnu/gdb/gdb-6.8.tar.gz tar xzf gdb-6.8.tar.gz cd gdb-6.8 ./configure --target=arm-linux make && su -c "make install" Alla fine della fase di compilazione, in / USR / LOCAL / BIN (o dovunque sia stato definito il PREFIX in fase di configurazione), saranno stati generati i file ARM - LINUX - GDB (il debugger vero e proprio), ARM LINUX - GDBTUI (frontend semi-grafico) e ARM - LINUX - RUN (simulatore in grado di eseguire i programmi per ARM su x86). 4.3 Come usarlo Usare un debugger per monitorare processi utente è ragionevolmente facile. Le cose si complicano parecchio in caso si voglia de- 4.3. COME USARLO 43 Figura 4.1: Schema di funzionamento di gdb con qemu buggare il kernel stesso! Questo perché l’attività di debugging altro non è che eseguire un processo (il debugger) che, tramite chiamate di sistema (ad esempio tipo la funzione PTRACE()) analizza il comportamento di un altro processo (il programma da controllare). Tuttavia nel caso si voglia controllare il kernel, non è possibile avere accesso alle chiamate di sistema stesse (visto che riguardano il programma da controllare). Tuttavia una soluzione esiste. Lavorando con qemu è possibile impostare l’emulatore (che è un programma utente, sulla macchina host) per offrire una connessione a gdb (come se si volesse fare debugging remoto su un’altra macchina). Per fare ciò basta eseguire qemu aggiungendo le opzioni -S (per non far partire la cpu dall’inizio) e - S (per attendere una connessione dal “client” gdb). $ qemu-system-arm ... -S -s In questo modo il programma rimarrà in attesa. Da un altro terminale, quindi, sarà possibile lanciare il debugger: $ arm-linux-gdbtui vmlinux 44 CAPITOLO 4. DEBUGGER dove il parametro di gdb è proprio il file VMLINUX creato in fase di compilazione dei sorgenti. La prima cosa da fare è effettuare la connessione ad una sessione remota, usando il comando target remote :1234 che indica a gdb di collegarsi a localhost (indirizzo implicito) usando la porta 1234 (creata di default da qemu). Nell’appendice B diamo un piccolo prontuario per le operazioni più comuni di debug. Appendice A Assembly per ARM Tratto da [Uni06a] ldr (load register) carica un valore in un registro lr last register (ultimo registro). è usato come implementazione dello stack dal momento che in questo registro vengono memorizzati i riferimenti al codice a cui si vuol ritornare dopo una chiamata ad un sottoprogramma. Ad esempio vedere righe 101 e 102 di 2.3 adr aggiunge al secondo il terzo valore e lo memorizza nel primo 1b label utilizzata per ciclare verso una label (1) precedente nel codice (before) 1f label utilizzata per ciclare verso una label (1) avanti nel codice (forward) b (branch) salta alla label indicata (esempio: B STAR T _ KERNEL ) blo salta loopando alla label indicata (esempio: 45 BLO DECOMPRESS _ KERNEL ) 46 APPENDICE A. ASSEMBLY PER ARM Appendice B Comandi principali gdb Tratto da [Uni06b] h [comando] stampa informazioni, generali o sul comando specificato q esci dal debugger target connette gdb ad un processo o ad una sessione remota già in esecuzione b [nome_file:]numero_riga inserisci un breakpoint nel file e nella riga specificati b funzione inserisci un breakpoint ove la funzione è invocata d numero rimuove il breakpoing numero run [parametri] esegue il programma debuggato, eventualmente con i parametri passati. Per quanto generalmente utile, non è necessaria nel caso specifico di qemu, in quanto l’esecuzione del codice è già stata iniziata c continua l’esecuzione fino al termine o al raggiungimento di un breakpoint u [nome_file:]numero_riga continua l’esecuzione fino al raggiungimento nel file e nella riga specificati (come se ci fosse un breakpoint) 47 48 APPENDICE B. COMANDI PRINCIPALI GDB n passa all’istruzione successiva; se è l’invocazione di una subroutine viene trattata come una singola istruzione, ottenendo direttamente il risultato s passa all’istruzione successiva; se è l’invocazione di una subroutine si entra nello stack della funzione si come s, ma attraverso le istruzioni definite in assembly ni come n, ma attraverso le istruzioni definite in assembly p espressione stampa a video il valore dell’espressione (qualunque espressione valida in C, con inoltre, l’accesso ai registri tramite l’operatore $) i [sottocomando] info consente di ottenere informazioni varie sul programma, in particolare i lo informazioni sulle variabili locali i s informazioni sullo stack i r informazioni sui registri Appendice C Licenza per la documentazione libera GNU Questo documento è distribuito secondo i termini della licenza GNU Free Documentation License. Come previsto dalla licenza, ecco in allegato il testo completo (in inglese). C.1 GNU Free Documentation License Version 1.2, November 2002 Copyright © 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The purpose of this License is to make a manual, textbook, or other functional and useful document “free” in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. 49 50APPENDICE C. LICENZA PER LA DOCUMENTAZIONE LIBERA GNU This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The “Cover Texts” are certain short passages of text that are listed, as FrontCover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A “Transparent” copy of the Document means a machine-readable copy, repre- C.1. GNU FREE DOCUMENTATION LICENSE 51 sented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”. Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LATEX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machinegenerated HTML, PostScript or PDF produced by some word processors for output purposes only. The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text. A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in 52APPENDICE C. LICENZA PER LA DOCUMENTAZIONE LIBERA GNU all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computernetwork location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. C.1. GNU FREE DOCUMENTATION LICENSE 53 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: • [A.] Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. • [B.] List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. • [C.] State on the Title page the name of the publisher of the Modified Version, as the publisher. • [D.] Preserve all the copyright notices of the Document. • [E.] Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. • [F.] Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. • [G.] Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice. • [H.] Include an unaltered copy of this License. • [I.] Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. 54APPENDICE C. LICENZA PER LA DOCUMENTAZIONE LIBERA GNU • [J.] Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. • [K.] For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. • [L.] Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. • [M.] Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version. • [N.] Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section. • [O.] Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles. You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties–for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. C.1. GNU FREE DOCUMENTATION LICENSE 55 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements”. 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in 56APPENDICE C. LICENZA PER LA DOCUMENTAZIONE LIBERA GNU electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License C.1. GNU FREE DOCUMENTATION LICENSE 57 in the document and put the following copyright and license notices just after the title page: Copyright © YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”. If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with . . . Texts.” line with this: with the Invariant Sections being LIST THEIR TITLES, with the FrontCover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. 58APPENDICE C. LICENZA PER LA DOCUMENTAZIONE LIBERA GNU Elenco dei simboli big zImage vedi bzImage bootstrap Letteralmente la fascetta di cuoio cucita sul bordo posteriore degli stivali per aiutarsi a calzarli, fa riferimento alla leggenda del Barone di Münchhausen e alla sua capacità di sollevarsi in aria tirandosi per gli stivali. Indica la fase di avvio di un pc bzImage Immagine del kernel compressa ed eseguibile, ma composta da tre parti separate host In ambiente di emulazione, la macchina reale che ospita l’emulatore. In ambiente di cross-compilazione, la macchina che ospita il compilatore. Vedi: target Image Immagine del kernel effettivamente eseguita miniSD Mini Secure Digital, versione più piccola (20x21.5) delle schede di memoria SD (24x32) MMU Memory Management Unit svn SubVersioN: sistema per controllo di revisione, usato nello sviluppo di sistemi software, consente di avere e condividere la storia delle modifiche effettuate sui file del progetto target In ambiente di emulazione, la macchina virtuale generata dall’emulatore. 59 60APPENDICE C. LICENZA PER LA DOCUMENTAZIONE LIBERA GNU In ambiente di cross-compilazione, la macchina su cui verranno utilizzati i programmi compilati. Vedi: host toolchain Insieme di tutti gli strumenti (tra gli altri preprocessore, assembler, compilatore, linker...) necessari alla generazione di codice eseguibile a partire da sorgenti. vmlinux Eseguibile non compresso e non bootable del kernel. wiki categoria particolare di siti web, accomunati dalla possibilità di offrire agli utenti stesssi del sito la possibilità di modificarlo a loro piacimento, senza dover accedere direttamente ai file presenti in remoto. Windows Mobile® Microsoft® Windows Mobile®, sistema operativo concepito per palmari, telefoni cellulari e Pocket PC zImage Immagine del kernel compressa preceduta da un decompressore (obsoleta) Bibliografia [arm08] Uso di architettura arm o intel per il mobile. http://en. wikipedia.org/wiki/Controversies_regarding_ the_use_of_ARM_or_Intel_architectures_in_ mobile_computers, giugno 2008. [ceg08] cegcc. http://cegcc.sourceforge.net, agosto 2008. [Hic08] Jamey Hicks. Handhelds toolchain. http://www. handhelds.org/download/projects/toolchain/, giugno 2008. [Lin05] Bellevue Linux. vmlinuz definition. http://www.linfo. org/vmlinuz.html, marzo 2005. [ope08] Openmoko under qemu. http://wiki.openmoko.org/ wiki/Openmoko_under_QEMU, giugno 2008. [Pro08] The ARM Linux Project. mach-type. http://www.arm. linux.org.uk/developer/machines/download.php, agosto 2008. [Uni06a] University of New South Wales. Assembler intro, febbraio 2006. [Uni06b] University of New South Wales. Gdb intro, febbraio 2006. [vml08] Differenze tra vmlinu[x|z] e [[b]z]image. http://en. wikipedia.org/wiki/Vmlinux, giugno 2008. [ZOS08] Andrew Zabolotny, Kevin O’Connor, and Paul Sokolovsky. Haret. http://handhelds.org/moin/moin.cgi/HaRET, giugno 2008. 61