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