Hacking embedded Linux on the cheap
with an example system
Ed Langley
Introduction to the target system
● Mattel Juicebox
– Childrens video and MP3 player
– Only plays video from OTP ROM cartridges
● Proprietary player and format
● Low compression● No OS
– Plays MP3s from MMC socket cartridge
● Running uCLinux
Target system specification● Samsung S3C440BX micro
controller
– ARM7TDMI core
– 8KB cache/SRAM
– 2 channel UART
– 2 channel DMA
– 1 channel I2C
– 5 channel PWM
– 8 channel 10 bit ADC
– RTC with calendar
– 71 input/output pins
– LCD controller with 1 dedicated DMA channel
● 2MB SDRAM
● 8MB ROM
● Audio: Cirrus Logic CS43L43
● LCD: 2.7 inch color 240x160
● JTAG – pads on PCB left behind in production boards
● As are serial port Tx/Rx lines
Picking your own target system
● Traditional industry method:– price Vs package size Vs power consumption
– All of above Vs features:● Speed● Number of external interrupts● Supported memory range● Memory management● Number of GPIO pins● Assemblers/compilers/programming languages
supported● Operating systems supported
Picking your own target system● “On a shoestring” method
– Take what you can get
– Mass produced gadget/appliance
– Contains CPU with architecture supported by Linux
● How much work/research/porting/hacking do you want to do yourself?
– E.G. Low budget:
● PDAs MP4 video players (from China off Ebay for £20)● Older games consoles (Dreamcast, PS2, Game Cube)
– E.G. Higher budget:
● Handheld games consoles (PSP, GP2X)● Set top boxes/routers (Dreambox, Linksys routers)
Get your build environment together● Toolchain
– GCC
– Binutils (ar, as, ld, objdump, objcopy, readelf)
– Debugger● If the target system has in circuit debugging ability● GDB● Interface from GDB to target
– OpenOCD for JTAG, BDM patches for FreeScale MCUs
● Above will have “arch-binaryformat-” prefix– E.G. arm-elf-gcc, m68k-linux-objdump
Test the tool chain● If system doesn't come with Linux on it already,
best to start with some bare board code– C run time (assembly code to prepare CPU
configuration and stack to run C code, then call main())
– Linker script● Tells code what memory address it will be running from,
so function calls are compiled to JMP instructions to the correct addresses
– Makefile● Sets compile/linker commands to use the cross compiling
tool chain, passes linker script to linker
Memory management● Process memory map on typical Linux system
with an MMU:
.text
0x00000000
.data
.bss
Dynamic memory
0x40000000
Stack0xC0000000Kernel .text
Kernel .dataKernel .bss
Kernel dynamic memoryHardware access ranges
Physical memory
Page table
Linear mapping
Memory Management
● Process memory map created by default linker script, included with tool chain
● When building “Bare board” code, or an operating system kernel, need to specify custom linker script
● Script specifies where code is in output file (ELF) and what address it will be at when MMU is enabled and page tables configured
Lack of memory management● Low end micro controllers often don't have
memory management units– Less complexity in silicon
● Cheaper● Lower power consumption
● Simpler for writing bare board software from scratch
● Not so easy for running Linux– No virtual memory addresses
● Processes can't all have the same memory map● Can't “grow” process address space with sbrk()
Lack of memory management
● Solution: uCLinux– All processes loaded to different physical addresses
● New binary format (FLAT) to handle this
– Different memory allocator● No brk()/sbrk() system call● Power of 2
– No fork() system call● Can't duplicate process memory map because physical
addresses must all be different● Forces application modification to use vfork()
Benefits of no MMU● Cheaper development tool setup
– Was developing a Linux driver on a v4 Coldfire board (with MMU) at work
– Tried to debug kernel with m68k-linux-bdm-gdb
– GDB has no concept of virtual addresses● Written to debug user mode processes
– As soon as GDB tried to read a kernel variable at a virtual address – Bus error
● Wasn't translating virtual address to physical address
– Never had a problem on previous board (with no MMU) because virtual address=physical address
Benefits of no MMU● Used one of these:
Lauterbauch Trace32
● Could have used KGDB– Architecture specific code needs porting
Getting the code onto the target
● Plug and prey– Can take a few goes to get right
– Becomes tiresome trying out changes
● Program the flash/RAM in target– Requires either:
● Boot loader/monitor preprogrammed into boot ROM– Not likely on a retail product
● Debug interface hardware and connector on target– This can be very slow with cheaper debug interface– Very very slow for programming flash in target
Getting code onto the Juicebox● The S3C44B0X has JTAG interface, connector pads
are present on JB board
Joint Test Action Group overview● Serial data In, Out and Clock lines allow data bits to be
clocked in and out of the Test Access Port (TAP) on the device
● TMS controls state machine in TAP
● Devices may be chained:
Joint Test Action Group overview● Serial bits clocked in control device pins through a
path of cells known as the Boundary Scan Register:
Joint Test Action Group overview● Toggling TMS signal cycles TAP through a
state machine● This allows the device pins to be set to the data
clocked in via TDI● Or to capture the device pin state and clock it
out via TDO● Control of the pins on the device give control of
the device itself, and RAM/flash connected to the device
● So JTAG can be used to program memory in target
The JTAG Wiggler● Macraigor is a company making hardware and
software for embedded development● They created the standard “Wiggler” design for
connecting PC to target via JTAG:
The JTAG Wiggler● Everyone soon realised the Wiggler is just a
buffer chip on the end of a parallel cable● Olimex clone:
The JTAG Wiggler
● Home made version:
It doesn't work- now what?
● Systematic approach● Start at one end (I.E. Bottom of hardware/ top
of software) and work to the other● The JTAG connection to the Juicebox wouldn't
work– Started with the software
● Check permissions – retry as root● Check parport_pc kernel module not loaded, interferes
with direct port access
– Then moved down to parallel port setup in BIOS
Juicebox JTAG not working● Then checked cable wired correctly – ensure
board schematic drawn with same connector gender as actually used
● Then checked the schematic:
Juicebox JTAG not working
● Result: schematic incorrect● Amendments made to the website where I
copied it from 5 days later● Used that schematic because it was in Eagle
CAD format● Moral of the story
– The less work you do yourself, the more susceptible you are to mistakes made by others doing the work for you
Getting Linux running on a target system
● Retail gadgets– Usually some kind of kludge/hack to get own code
running
– Boot loader often runs checksum calculation over a range of the code
– Games consoles/handhelds● Generally require a massive exploit to be found before
any progress is made
Getting uCLinux running on the Juice Box
● Can run home brew code relatively easy– Can download binary to RAM/flash using Jtager
– Can download ELF using GDB+OpenOCD
● Running code from a fresh boot, not so easy– Need to steal first 512 bytes from a “Juiceware”
video cartridge and patch with some hex to add a branch instruction to the custom code
Getting uCLinux running on the Juice Box
● Not actually done this yet● Have built a “cartridge” to interface some
programmable NAND flash to the S3C44B0X:
Getting uCLinux running on the Juice Box
● Downloading even a minimal Kernel to RAM or flash over JTAG takes forever– Have built the kernel to run from RAM as configured
by Emsoft
– Will write this to flash once
● Currently crafting a boot loader to prepare the CPU, then dump the kernel from flash to RAM and run it