Group: Hardware/Computers/e-readers/Kobo/Aura H2O Edition 2

From LibrePlanet
< Group:Hardware‎ | Computers‎ | e-readers‎ | Kobo
Revision as of 13:37, 9 February 2019 by GNUtoo (talk | contribs)
Jump to: navigation, search

Issues

WiFi

Priority investigations

TODO

  • u-boot source code: Read it to see if it loads any firmware
  • u-boot: dump boot pins values and document booting
  • u-boot: compile and run the source code, and document recovery
  • Linux source code: Look at the dts and drivers again to spot if something was missed
  • Hardware: describe the hardware better and look again if there is anything doggy (unlikely to be missed with the software review though)

Common firmwares

Since Linux and u-boot sources are available, the most interesting information (for RYF certification) to look for is if some peripherals require a non-free firmware.

The most common places where firmwares can be used or required are:

  • WiFi/Bluetooth: The WiFi chip has a firmware
  • The touchscreen driver: At least one of the touchscreens should be ok

nxtfw

TODO: There is also a ntxfw partition => find what it is

The device seem to operate properly with that partition being blanked. Some drivers however complain about some backlight level tables that are missing:

[_fl_lm3630a_percentage-1162] Front light table not exist !!

Firmwares

WiFi firmware

The WiFi driver rely on binary firmwares for the WiFi part.

The firmwares are provided as binary (in arrays format) in the hal/phydm/rtl8188f/halhwimg8188f_fw.c source code file, however this file is provided under the GPLv2. So it may be possible to convert the firmware binary in source code.

TODO:

  • Investigate if the WiFi chip also has other functions (Bluetooth, FM Radio, etc)
  • Investigate if the firmware source code can easily be reconstructed
  • Investigate if the chip can work without the firmware

WiFi firmware informations found inside the driver

  • The firmware binary is really uploaded to the device chip, see
hal/phydm/phydm_hwconfig.c:2730:			READ_FIRMWARE_MP(8188F, _FW_NIC);
hal/phydm/phydm_hwconfig.c:2764:			READ_FIRMWARE_MP(8188F,_FW_NIC);

How to extract the firmware

There are generic tools to create a binary out of hex arrays, but it took me less time to write a specific program than to find such tool. I vaguely remember that one of theses tools was mentioned on a blog post on the sigrok blog, it was about something like reconstructing an I2S stream with 'unix way' tools.

firmware_extraction_utility.c

usage:

$ gcc firmware_extraction_utility.c
$ ./a.out > 8188F_FW_NIC.bin

Then not all the firmware seem to be code. If we look at it with hexdump:

$ hexdump -C 8188F_FW_NIC.bin
00000000  f1 88 10 00 01 00 0e 00  03 25 14 55 62 52 02 00  |.........%.UbR..|
00000010  af 2f 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |./..............|
00000020  02 86 a9 02 c7 d7 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 02 c0 2d 00 00  00 00 00 00 00 00 00 00  |.....-..........|
00000040  00 00 00 02 c8 29 00 00  00 00 00 00 00 00 00 00  |.....)..........|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000060  00 00 00 02 c7 d8 00 00  00 00 00 02 c2 f0 00 00  |................|
00000070  00 00 00 02 c8 28 00 00  00 00 00 00 00 00 00 00  |.....(..........|
00000080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000000a0  02 87 b7 02 88 d5 02 80  86 02 80 89 02 a5 11 02  |................|
[...]
we can see a '*'. This indicates that there is some blank space between '00000080' and '000000a0'
This can be an easy way to identify sections in the firmware binary.

I then found a section that looks like 8051, which I extracted like that:

$ dd if=8188F_FW_NIC.bin of=code.bin skip=2 bs=512
$ r2 -a 8051 ./code.bin # r2 comes from radare2, which is an interactive disassembler.

Then we can start using radare2:

[0x00000000]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze value pointers (aav)
[x] Value from 0x00000000 to 0x00004e82 (aav)
[x] 0x00000000-0x00004e82 in 0x0-0x4e82 (aav)
[x] 0x00000000-0x00004e82 in 0x10000000-0x10000100 (aav)
[x] 0x00000000-0x00004e82 in 0x10000180-0x10000200 (aav)
[x] 0x00000000-0x00004e82 in 0x20000000-0x20010000 (aav)
[x] Value from 0x10000000 to 0x10000100 (aav)
[x] 0x10000000-0x10000100 in 0x0-0x4e82 (aav)
[x] 0x10000000-0x10000100 in 0x10000000-0x10000100 (aav)
[x] 0x10000000-0x10000100 in 0x10000180-0x10000200 (aav)
[x] 0x10000000-0x10000100 in 0x20000000-0x20010000 (aav)
[x] Value from 0x10000180 to 0x10000200 (aav)
[x] 0x10000180-0x10000200 in 0x0-0x4e82 (aav)
[x] 0x10000180-0x10000200 in 0x10000000-0x10000100 (aav)
[x] 0x10000180-0x10000200 in 0x10000180-0x10000200 (aav)
[x] 0x10000180-0x10000200 in 0x20000000-0x20010000 (aav)
[x] Value from 0x20000000 to 0x20010000 (aav)
[x] 0x20000000-0x20010000 in 0x0-0x4e82 (aav)
[x] 0x20000000-0x20010000 in 0x10000000-0x10000100 (aav)
[x] 0x20000000-0x20010000 in 0x10000180-0x10000200 (aav)
[x] 0x20000000-0x20010000 in 0x20000000-0x20010000 (aav)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[x] Type matching analysis for all functions (afta)
[x] Emulate code to find computed references (aae)
[x] Analyze consecutive function (aat)
[0x00000000]> pd
            ;-- r1:
            ;-- r2:
            ;-- r3:
            ;-- r4:
            ;-- r5:
            ;-- r6:
            ;-- r7:
            ;-- a:
            ;-- b:
            ;-- dpl:
            ;-- dph:
            ;-- psw:
            ;-- sp:
            ;-- r0:
/ (fcn) fcn.r0 18
|   fcn.r0 ();
|           0x00000000      00             nop
|           0x00000001      00             nop
|           ; CODE XREF from fcn.000002f6 (+0x9)
|           0x00000002      00             nop
|           0x00000003      00             nop
|           0x00000004      00             nop
|           0x00000005      00             nop
|           0x00000006      00             nop
|           0x00000007      00             nop
|           0x00000008      00             nop
|           0x00000009      00             nop
|           0x0000000a      00             nop
|           0x0000000b      00             nop
|           0x0000000c      00             nop
|           0x0000000d      00             nop
|           0x0000000e      00             nop
|           0x0000000f      00             nop
|           0x00000010      00             nop
\           0x00000011      00             nop
            ; CALL XREF from fcn.00000418 (0x429)
            ; CALL XREF from fcn.00000474 (0x482)
            0x00000012      00             nop
            ; CALL XREF from fcn.000004b4 (0x4bf)
            0x00000013      00             nop
            0x00000014      00             nop
            0x00000015      00             nop
            0x00000016      00             nop
            0x00000017      00             nop
            0x00000018      00             nop
            ; CODE XREF from fcn.00000528 (+0x54)
            0x00000019      00             nop
            0x0000001a      00             nop
            0x0000001b      00             nop
            0x0000001c      00             nop
            0x0000001d      00             nop
            0x0000001e      00             nop
            0x0000001f      00             nop
/ (fcn) fcn.00000020 4
|   fcn.00000020 ();
|           ; CODE XREF from fcn.00000020 (+0x30)
\       .-> 0x00000020      c2af           clr ie.7                    ; [0x100001a8:1]=0
|      |:   ; CODE XREF from fcn.00000020 (0x22)
|      `=-> 0x00000022      80fe           sjmp 0x0022
        :   0x00000024      32             reti
        :   0x00000025      128404         lcall 0x8404
        :   0x00000028      85d00b         mov 0x0b, psw               ; [0x100001d0:1]=0
        :   0x0000002b      75d008         mov psw, #0x08              ; [0x100001d0:1]=0
        :   0x0000002e      aae0           mov r2, acc                 ; [0x100001e0:1]=0
        :   0x00000030      c28c           clr tcon.4                  ; [0x10000188:1]=0
        :   0x00000032      e58a           mov a, tl0                  ; [0x1000018a:1]=0
        :   0x00000034      2467           add a, #0x67                ; 'g'
        :   0x00000036      f58a           mov tl0, a                  ; [0x1000018a:1]=0
        :   0x00000038      e58c           mov a, th0                  ; [0x1000018c:1]=0
        :   0x0000003a      3479           addc a, #0x79               ; 'y'
        :   0x0000003c      f58c           mov th0, a                  ; [0x1000018c:1]=0
        :   0x0000003e      d28c           setb tcon.4                 ; [0x10000188:1]=0
        :   0x00000040      ec             mov a, r4
        :   0x00000041      2487           add a, #0x87
        :   0x00000043      f8             mov r0, a
        :   0x00000044      e6             mov a, @r0
       ,==< 0x00000045      bc0202         cjne r4, #0x02, 0x004a
       |:   0x00000048      74ff           mov a, #0xff
       |:   ; CODE XREF from fcn.00000020 (+0x25)
       `--> 0x0000004a      c3             clr c
        :   0x0000004b      9581           subb a, sp                  ; [0x10000181:1]=0
       ,==< 0x0000004d      b44000         cjne a, #0x40, 0x0050       ; '@'
       ||   ; CODE XREF from fcn.00000020 (+0x2d)
       ``=< 0x00000050      40ce           jc 0x0020                   ; fcn.00000020
            0x00000052      7903           mov r1, #0x03
            0x00000054      7880           mov r0, #0x80
            ; CODE XREF from fcn.00000020 (+0x47)
            0x00000056      16             dec @r0
            0x00000057      e6             mov a, @r0
            0x00000058      08             inc r0
        ,=< 0x00000059      700b           jnz 0x0066
        |   0x0000005b      c2af           clr ie.7                    ; [0x100001a8:1]=0
[0x00000000]> 
  • You can then jump to functions with s <address>
  • You can continue listing code with s<address><enter> <enter>

Information on the WiFi firmware

WiFi Firmware ISA
  • Everything tend to indicate that the firmware uses the 8051 instruction set:
    • The firmware loading driver has way(s) to reset the 8051
    • The firmware loading code in the driver has several other mention to a 8051 processor
    • The firmware looks consistent, ex: jump to self
  `=-> 0x00000022      80fe           sjmp 0x0022
Reverse engineering
  • The driver has many comments about the firmware and processor that runs the firmware. That can help a lot.
  • At the time of writing, Retdec README doesn't support the 8051 architecture yet:
Supported architectures (32b only): Intel x86, ARM, MIPS, PIC32, and PowerPC.
  • Radare2 seem to work on the firmware and has some good auto-analyze functions
  • The firmware is small:
 $ du -hs 8188F_FW_NIC.bin 
 24K	8188F_FW_NIC.bin
firmware format:
  • it probably has a header and some calibration data at the begining
 => check the struct format

Touchscreen

cyttsp5

This should work without firmware.

Details:

  • This driver can use the cyttsp5_fw.bin firmware
    • The firmware seem optional at least in certain cases
    • A firmware file cannot be found on the filesystem
    • The support for loading the firmware is builtin the module but that could be because the vendor code has some issue without that code (like won't compile or similar)
    • The touchscreen works in Parabola (with ntxfw partition blanked): tested with evtest /dev/input/event1

TODO:

  • Find if u-boot contains code to update that firmware

External interfaces

USB

Several interfaces are exposed through USB:

  • It's possible to make the device switch to fastboot during boot
  • If the device is not registered, you can switch to mass-storage by selecting "no wifi" during the device boot.

Power button

Touchscreen

Internal interfaces

Serial/UART

As it can be seen on one of the PCB pictures, near the battery, there is some holes with some markings: V, TX, RX, and a ground sign. It seems that more recent manufacturing batch lacks such markings.

V
  • At 3.3v when the device is powered on
  • At 0v when the device is off
  • You should not connect the serial port adapter to it
TX
  • Serial port TX
  • Connect to the RX of your USB<->Serial port adapter
RX
  • Serial port RX
  • Connect to the TX of your USB<->Serial port adapter
GND Ground

The holes pitch are 2.54mm (0.1 inch), so it's compatible with most common pin-headers found in electronic shops like this one. The best is to use headers that are bent, this way:

  • You could even be able to put back the cover if the pin headers height is small enough
  • You can still easily use the e-book reader with the screen towards you while still having the serial port adapter plugged in.

Soldering on theses holes is tricky as there is some transparent plastic coating on all the PCB, including the internal connectors and the components. Under that there is the classic PCB coating (which is green here).

So I used some "grain 400" sand paper to remove the plastic and green coating on the serial port pin holes.

If you're not careful enough this will also expose the ground plane, making it harder to solder without any shorts.

For the ground connector, if you remove too much coating, it will make soldering harder as the big ground plane will dissipate your soldering iron heat, preventing you from melting the tin.

Also beware that the '3v3' pin is shorted to GND when the device is off (and is at 3.3V when the device is on). So even if it seems shorted to GND, it might not be.

You also need to choose how to solder the header:

  • If the header pin goes on the battery side, then there won't be any risk of shorting the pins and if you manage to find a header that is the right size, it will stay better in place as the cable you will plug in can be exactly the size of the hole between the header and the battery. However you won't be able to close the cover anymore.
  • If the header pin goes on the opposite side of the battery, then you will be able to close the cover, but you will need to make sure that the header, the cable (and possibly the serial adapter stay in a position where they cannot cause short circuit by having their metallic part touch some of the conductive part on the e-reader PCB.

I used the following equipment to do it:

  • Lead free solder
  • TS100 Soldering iron with the free software firmware at 450 Degrees
  • A tip that is chisel-like but only one one side
  • Tivoly "Métal Peint", grain 240 "sand paper"
Voltage 3.3v
Baudrate 115200
Settings 8N1 (the default almost everywhere)

To get a shell you can login through the serial port with the user 'root':

(none) login: root
[root@(none) ~]# 

However once logged the console will probably freeze at some point. This is because the device has aggressive power management which makes the device goes into suspend.

To wake up the device, touching the screen is enough, however touching the screen all the time is not very convenient for development.

It seems to be an userspace application that makes the device goes into suspend. So we will overwrite /sys/power/state with a file that does nothing. We have ram filesystem mounted in /tmp, so we will use that to be saver (as it will not make permanent modifications):

[root@(none) ~]# mount
[...]
none on /tmp type tmpfs (rw,relatime,size=16384k)
[...]

We can overwrite /sys/power/state like that:

[root@(none) ~]# touch /tmp/state
[root@(none) ~]# mount -o bind /tmp/state /sys/power/state

This effectively prevent the device from going into suspend.

main storage

Partitions

With fdisk or by looking in /proc/partition we can see 3 partitions:

partition size function source
mmcblk0p1 256M rootfs cat /proc/cmdline: root=/dev/mmcblk0p1
mmcblk0p2 256M Backup rootfs ? after mounting it, there are some similar files. Strangely there are no kernel modules in this one.
mmcblk0p3 6.8G user data mount: /dev/mmcblk0p3 on /mnt/onboard type vfat

However if we look at update scripts or fastboot we have more partitions:

name start size (from fastboot) function source
mbr 0 1 The MBR
  • The partition is called mbr and it's at the beginning.
sn 1 1 The device serial number
  • The partition content viewed with hexdump
bootloader 2 1022 The bootloader (u-boot code)
  • The name of the partition
  • bootloader partitions are typically at the beginning
hwcfg 1024 2
  • Probably some hardware configuration
  • Also contains the string "HW CONFIG v2.8.A"
  • The partition content viewed with hexdump
ntxfw 1030 255 Unknown, looks like some firmware
  • doesn't look promising: has 'fw' in its name
  • contains several zones
  • is big enough to be a firmware (128k)
waveform 14336 20480 The waveform for the e-ink display
  • The name of the partition
  • Some e-paper displays needs some 'waveform' data to work
  • Contains some huge patterns of zero ones two that are contiguous
logo 34816 4096 empty
  • partition content viewed with hexdump
bootenv 1536 510 Probably u-boot environment
  • The name of the partition
  • The fact that u-boot typically stores its environment in a separate partition
  • The partition content contains the boot environment strings
kernel 2048 12284 The linux kernel in zImage format
  • The partition content
dtb 1286 250 The device tree binary
  • The partition content
rootfs 49152 524289 The two rootfs concatenated
  • The name of the partition
  • The location and size of the partition
  • The fact that it's recognized as ext4
vfat 1097730 14139389
  • Probably user data
  • this partition is vfat and can be mounted
  • this partition is made available if you choose to use your computer to setup the device
  • The partition name and content
  • The usage of the e-book reader
recoveryfs 573441 524289
  • A recovery partition?
  • The name of the partition
  • Contains a Linux kernel and initramfs

Exporting the internal eMMC as a block device

After getting a shell in u-boot we can look at the list of eMMC/SD cards:

eBR-1A # mmc list
FSL_SDHC: 0 (eMMC)
FSL_SDHC: 1

The second mmc listed above doesn't seem to exist:

eBR-1A # mmc dev 1
Card did not respond to voltage select!

This is probably because the u-boot code is based on the code for a Freescale developement/evaluation board and since device manufacturers need to ship products fast they probably didn't bother removing the code for that non-existing hardware.

There is a command called 'ums' in u-boot that can export the e-MMC card through USB and make it appear as a mass storage device (like an USB key or an USB hard disk) to the computer it's connected to.

To use it you need to first connect an usb cable between your computer and the e-book reader and then type 'ums 0 mmc 0' in u-boot like that:

eBR-1A # ums 0 mmc 0
UMS: LUN 0, dev 0, hwpart 0, sector 0xe90000

You can then see it on your laptop:

$ lsblk 
[...]
sdb                         8:16   1   7.3G  0 disk  
├─sdb1                      8:17   1   256M  0 part  
├─sdb2                      8:18   1   256M  0 part  
└─sdb3                      8:19   1   6.8G  0 part

You can then use GNU ddrescue to backup the eMMC device:

ddrescue /dev/sdb kobo_emmc.img

Extracting the hidden partitions

Since the fastboot provides us the offset and that dd default is to operate on 512b at a time we can simply run the following commands:

dd if=kobo_emmc.img of=mbr.img count=1
dd if=kobo_emmc.img of=sn.img skip=1 count=1
dd if=kobo_emmc.img of=bootloader.img skip=2 count=1022
dd if=kobo_emmc.img of=hwcfg.img skip=1024 count=2
dd if=kobo_emmc.img of=ntxfw.img skip=1030 count=255
dd if=kobo_emmc.img of=waveform.img skip=14336 count=20480
dd if=kobo_emmc.img of=logo.img skip=34816 count=4096
dd if=kobo_emmc.img of=bootenv.img skip=1536 count=510
dd if=kobo_emmc.img of=kernel.img skip=2048 count=12284
dd if=kobo_emmc.img of=dtb.img skip=1286 count=250
dd if=kobo_emmc.img of=rootfs.img skip=49152 count=524289
dd if=kobo_emmc.img of=vfat.img skip=1097730 count=14139389
dd if=kobo_emmc.img of=recoveryfs.img skip=573441 count=524289

Fastboot

There is a fastboot command in u-boot. If you want to enable it from the u-boot shell you can do it like that:

# fastboot 0
ptn 0 name='mbr' start=0 len=1
ptn 1 name='sn' start=1 len=1
ptn 2 name='bootloader' start=2 len=1022
ptn 3 name='hwcfg' start=1024 len=2
ptn 4 name='ntxfw' start=1030 len=255
ptn 5 name='waveform' start=14336 len=20480
ptn 6 name='logo' start=34816 len=4096
ptn 7 name='bootenv' start=1536 len=510
ptn 8 name='kernel' start=2048 len=12284
ptn 9 name='dtb' start=1286 len=250
ptn 10 name='rootfs' start=49152 len=524289
ptn 11 name='vfat' start=1097730 len=14139389
ptn 12 name='recoveryfs' start=573441 len=524289

Here we have access to a lot more partition than with the block device export over USB.

fastboot lsusb

Here's how it looks like on lsusb

$ lsusb
Bus 001 Device 008: ID 18d1:0d02 Google Inc. Celkon A88

Triggering fastboot without access to the serial port

First run the fastboot command you want to run. You need to do that first because with this method, fastboot will be available for a very short ammount of time (about 5 seconds).

For instance if you want to boot an image named 'boot.img' you can run the follwing command:

$ fastboot boot ./boot.img

First make sure that the device is powered off. With the stock OS, it will either display 'Powered off' in the language it's configured in, or an image on how to plug the device if it never has been powered on.

Once the device is off press the power button. The device will then lit the top-right blue light. At this point press the power button again, and the device will go in fastboot mode for a very short amount of time (about 5 seconds).

PCB

Here are the chips on the top of the PCB. Caevats:

  • you need a big screen to view properly the markings as it will line-break with smaller screens
  • The markings might contain errors as they are tiny and some letter/number could be mixed up
  • I didn't disassemble it enough to see the bottom because the connectors seemed really fragile (they even had glue inside them) so if I do, I fear that I won't be able to put everything back in place. There might be some more chips on the bottom.
Usage Location Package Markings Driver(s) Documentation
512M RAM 168-Ball PoP-FBGA
NANYA 1718
NT6TL 128M 32BQ-G0
7201166 AEP 3TW
?
? ?
SEC 737
BO41
KLM8616EME
H56P4788D
?
System on a chip (IMX6SLL) ? (BGA)
MCIMX6V7DVN10AB
XAA 1739
TAIW HMAAXK
Lots of drivers
WiFi chip (and potentially other features) ?
REALTEK
8189PTY
H857492
GH438
The 8188f chip in the RTL8189FS out of tree driver
? ?
RICOH AC5T619
1137
7409N1
Power management integrated circuit (and potentially other features) ?
TPS
65185
T1 7AI
CS6S G4
?
On the display flex cable ?
TT21000
-48L0I
1725 B03
PRD627959
PHI   □ C
041
?

Pictures

Some pictures of the top PCB taken with a camera:

Software

Kobo u-boot version

U-boot is a free software bootloader. The source code is provided by kobo.

It is based on one of the branches/commits of the freescale fork of u-boot for their I.MX System on a chip.

u-boot serial console

To get a shell in u-boot you will need to setup a serial cable, and press a key in the serial console during boot:

U-Boot 2016.03-00031-gcd5f70c (Aug 31 2017 - 13:17:25 +0800)

CPU:   Freescale i.MX6SLL rev1.1 996 MHz (running at 792 MHz)
CPU:   Commercial temperature grade (0C to 95C) at 43C
Reset cause: WDOG
Board: MX6SLL LPDDR2 NTX
I2C:   ready
DRAM:  512 MiB
__get_sd_number(),cfg23=0,cfg24=0 
MMC:   board_mmc_init() : isd=0 
board_mmc_init() : wifi=2 
FSL_SDHC: 0, FSL_SDHC: 1
In:    serial
Out:   serial
Err:   serial
ntx_hw_early_init() 0
ram p=80000000,size=536870912
switch to partitions #0, OK
mmc0(part 0) is current device
mmc read 0x9ffffe00 0x3ff 0x1

MMC read: dev # 0, block # 1023, count 1 ... 1 blocks read: OK
mmc read 0x9ffffe00 0x400 0x1

MMC read: dev # 0, block # 1024, count 1 ... 1 blocks read: OK
ntx_hw_late_init()
mmc read 0x9ffffc00 0x1 0x1

MMC read: dev # 0, block # 1, count 1 ... 1 blocks read: OK
NTXSN not avalible !
ntx_gpio_get_value(402) : error parameter ! null ptr !
ntx_config_fastboot_layout():10 binaries partition added
ntx_config_fastboot_layout():3 mbr partition added
check_and_clean: reg 0, flag_set 0
Fastboot: Normal
Net:   CPU Net Initialization Failed
No ethernet found.
Hit any key to stop autoboot:  0 
eBR-1A #

u-boot environment

Here's the u-boot environment:

eBR-1A # printenv
baudrate=115200
bootcmd=mmc dev ${mmcdev};if run loadimage; then run mmcboot; fi; 
bootcmd_mfg=run mfgtool_args;bootz ${loadaddr} ${initrd_addr} ${fdt_addr};
bootdelay=1
bootscript=echo Running bootscript from mmc ...; source
console=ttymxc0
epdc_waveform=epdc_splash.bin
fastboot_dev=mmc0
fdt_addr=0x83000000
fdt_file=undefined
fdt_high=0xffffffff
image=zImage
initrd_addr=0x83800000
initrd_high=0xffffffff
ip_dyn=yes
loadaddr=0x80800000
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
loadfdt=load_ntxdtb
loadimage=load_ntxkernel
mfgtool_args=setenv bootargs console=${console},${baudrate} rdinit=/linuxrc g_mass_storage.stall=0 g_mass_storage.removable=1 g_mass_storage.file=/fat g_mass_storage.ro=1 g_mass_storage.idVendor=0x066F g_mass_storage.idProduct=0x37FF g_mass_storage.iSerialNumber="" 
mmcargs=setenv bootargs console=${console},${baudrate} rootwait rw no_console_suspend 
mmcautodetect=no
mmcboot=echo Booting from mmc ...; run mmcargs; if run loadfdt; then bootz ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi;
mmcdev=0
mmcpart=1
script=boot.scr
stderr=serial
stdin=serial
stdout=serial

Environment size: 1203/8188 bytes

u-boot booting process

Here the u-boot boot process in uncomon and relies on custom commands like load_ntxkernel to load and execute the Linux kernel and associated data like the dtb:

bootcmd=mmc dev ${mmcdev};if run loadimage; then run mmcboot; fi; 
loadimage=load_ntxkernel

Adding extra kernel commandline arguments

You can do that in u-boot by overriding mmcargs

setenv mmcargs setenv bootargs <your extra arguments> console=\${console},\${baudrate} rootwait rw no_console_suspend

Stock OS analysis

  • The default OS forces the user to register or use some network services like Kobo, google, facebook, etc, however we can get a shell through the serial port.

Source code

  • Some Heavily modified Linux 4.1.15 source code is provided by Kobo for this device. It is most probably based on an unknown branch in Freescale's fork of Linux for I.MX system on a chip.
  • The WiFi driver source code is also provided by Kobo for this device.
  • Some less interesting userspace source code is probably also provided at the same location.

Linux 4.1.15 sources

New sources for Linux seem to have been pushed the 30 April:

  • They don't contain all the build scripts that the 3.0.35 did
  • They use the devicetre
  • They were compiled with gcc 5.3.0
  • Parabola's community/arm-none-eabi-gcc isn't able to compile it, however pcr/crosstool-ng can be installed and used to create an arm baremetal 5.4.0 gcc which is able to compile it.
How to build
Getting the kernel configuration and device tree source file name

To build it for the device we need:

  • A configuration file, hopefully in my case it can be exrtacted from the device by running the following on the device:
# zcat /proc/config.gz
  • To identify which device tree source file was used if we want to avoid reusing the one that is in the eMMC

We can start by looking the machine name:

# grep . /sys/firmware/devicetree/base/*
[...]
/sys/firmware/devicetree/base/compatible:fsl,imx6sll-lpddr3-arm2
/sys/firmware/devicetree/base/compatible:fsl,imx6sll
/sys/firmware/devicetree/base/model:Freescale i.MX6SLL NTX Board

And grepping in the source to see the matching files:

$ grep "Freescale i.MX6SLL NTX Board" -r arch/arm/boot/dts/*
arch/arm/boot/dts/imx6sll-e60k02.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-e60ql2.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-e60qm2.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-e60qp2.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-e70q02.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-lpddr2-ntx.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-t05r02.dts:	model = "Freescale i.MX6SLL NTX Board";

Then on my board I've the 'cyttsp5' touchscreen controller:

# cd /sys/bus/i2c/devices
# grep . 0-*/name 1-*/name 2-*/name
0-0036/name:lm3630a_bl
1-0024/name:cyttsp5_i2c_adapter
1-0068/name:tps6518x
2-0032/name:ricoh619

Now only two files are remainign:

$ grep "cyttsp5_i2c_adapter" $(grep "Freescale i.MX6SLL NTX Board" -r arch/arm/boot/dts/* | sed 's#:.*##')
arch/arm/boot/dts/imx6sll-e60k02.dts:		compatible = "cy,cyttsp5_i2c_adapter";
arch/arm/boot/dts/imx6sll-e60k02.dts:		cy,adapter_id = "cyttsp5_i2c_adapter";
arch/arm/boot/dts/imx6sll-e60qm2.dts:		compatible = "cy,cyttsp5_i2c_adapter";
arch/arm/boot/dts/imx6sll-e60qm2.dts:		cy,adapter_id = "cyttsp5_i2c_adapter";

It is possible to visualize the difference between both files in a very convenient way like this:

$ meld arch/arm/boot/dts/imx6sll-e60k02.dts arch/arm/boot/dts/imx6sll-e60qm2.dts

It shows quite some difference in the way the system on a chip pins are configured.

For instance for arch/arm/boot/dts/imx6sll-e60qm2.dts we have:

pinctrl_elan_ts_gpio_sleep: elan_ts_gpio_grp_sleep {
	fsl,pins = <
		MX6SLL_PAD_SD1_DATA3__GPIO5_IO06		0x10059 /* TP_INT */
		MX6SLL_PAD_SD1_DATA2__GPIO5_IO13		0x10059 /* TP_RST */
	>;
};

and for arch/arm/boot/dts/imx6sll-e60k02.dts we have:

pinctrl_elan_ts_gpio: elan_ts_gpio_grp {
	fsl,pins = <
		MX6SLL_PAD_GPIO4_IO24__GPIO4_IO24		0x17059 /* TP_INT */
		MX6SLL_PAD_GPIO4_IO18__GPIO4_IO18		0x10059 /* TP_RST */
		MX6SLL_PAD_GPIO4_IO17__GPIO4_IO17		0x10059 /* TP_SWDIO */
	>;
};

Fortunately the Linux kernel exports that information at runtime, and we can access it like that:

# mount -t debugfs none /sys/kernel/debug/
# cd /sys/kernel/debug/pinctrl

After grepping we can see the following line in pinctrl-handles:

type: MUX_GROUP controller 20e0000.iomuxc group: elan_ts_gpio_grp (34) function: imx6sll-lpddr3-arm2
type: CONFIGS_PIN controller 20e0000.iomuxc pin MX6SLL_PAD_GPIO4_IO24 (147) 00017059                
type: CONFIGS_PIN controller 20e0000.iomuxc pin MX6SLL_PAD_GPIO4_IO18 (146) 00010059                
type: CONFIGS_PIN controller 20e0000.iomuxc pin MX6SLL_PAD_GPIO4_IO17 (149) 00010059                

Note that to open pinctrl-handles with a text editor on the device you need to copy it somewhere first, like in /tmp/

In my case the device tree file that works for my hardware is the arch/arm/boot/dts/imx6sll-e60qm2.dts

kernel logs

runtime informations

Here's the kernel version of the device I got:

# uname -r
4.1.15-00104-gcd6a6a6

The boot kernel parameters are available in /proc/cmdline:

console=ttymxc0,115200 rootwait rw no_console_suspend hwcfg_p=0x9ffffe00 hwcfg_sz=110 waveform_p=0x9fdc8a00 waveform_sz=2323160 ntxfw_p=0x9fdc6400 ntxfw_sz=9474 mem=509M boot_port=0 rootfstype=ext4 root=/dev/mmcblk0p1 quiet
  • The kernel configuration is available at /proc/config.gz
  • The device uses a devicertee that is passed by the bootloader:
# grep . /sys/firmware/devicetree/base/*
[...]
/sys/firmware/devicetree/base/compatible:fsl,imx6sll-lpddr3-arm2
/sys/firmware/devicetree/base/compatible:fsl,imx6sll
/sys/firmware/devicetree/base/model:Freescale i.MX6SLL NTX Board

Running Parabola

The rootfs partitions are too small to install Parabola (They are 256M each), thankfully we have a big partition (6.8G) that is formatted as FAT. But we cannot easily use this as the bootloader boot command uses "root=/dev/mmcblk0p1" and we don't want to require users to use the serial console as it would require soldering.

A way to deal with that would be to set the fat partition as mmcblk0p1. This is possible since we can force the device to go in fastboot mode and overwrite the MBR that way.

Changing partition order

First dump the MBR in mbr1.img as described in this page.

Then change the partitions orders.

sfdisk -d mbr.img > mbr.txt

The following will be in mbr.txt:

mbr1.img1 : start=       49152, size=      524289, type=83
mbr1.img2 : start=      573441, size=      524289, type=83
mbr1.img3 : start=     1097730, size=    14139389, type=b

You can change it to:

mbr.img2 : start=       49152, size=      524289, type=83
mbr.img3 : start=      573441, size=      524289, type=83
mbr.img1 : start=     1097730, size=    14139389, type=b

Then we recreate a new mbr:

qemu-img create -f raw tmp.img 8G
sfdisk -f tmp.img < mbr.txt
dd if=tmp.img of=mbr2.img count=1
rm tmp.img

We can then flash that:

fastboot flash mbr mbr2.img

TODO:

  • Find if it's still possible to trigger the mount of the partition from the stock OS (which doesn't require a serial port)

Serial console with OpenRC

Then you can install OpenRC as systemd won't work with the default kernel unless you recompile it (systemd requires cgroups)

To get a serial console follow this guide https://wiki.gentoo.org/wiki/OpenRC#openrc-init and also add ttymxc0 to /etc/securetty

You also need to create a file at /etc/conf.d/agetty.ttymxc0 with this content:

# make agetty quiet
#quiet="yes"

# Set the baud rate of the terminal line
baud="115200"

# set the terminal type
term_type="linux"

# extra options to pass to agetty for this port
agetty_options=""

else the console will use 38400 bauds while it is at 115200 during the boot.

Stock kernel and modules modules

To use the stock kernel and modules seamlessly do:

mkdir -p /lib/modules/4.1.15-00104-gcd6a6a6/kernel/drivers/

If the stock rootfs is mounted on /mnt you can just copy them that way:

cp -r /mnt/drivers/mx6sll-ntx/usb/ /lib/modules/4.1.15-00104-gcd6a6a6/kernel/drivers/
cp -r /mnt/drivers/mx6sll-ntx/wifi/ /lib/modules/4.1.15-00104-gcd6a6a6/kernel/drivers/
touch /lib/modules/4.1.15-00104-gcd6a6a6/modules.order
touch /lib/modules/4.1.15-00104-gcd6a6a6/modules.builtin
depmod -a

Then you can use them as usual, for instance to get usbnet you could do:

modprobe g_ether


Making the display work

TODO: The display was only validated with 1fps with Xorg -retro. The image quality wasn't extensively checked (Xorg -retro is not suited for that).

To enable the display

  • Build the patched vendor kernel
  • Enable CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE=y in the device vendor kernel
  • Once the device booted under Parabola, run the following program:
/*
 * Copyright (C) 2019 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stropts.h>
#include <stdint.h>
#include <asm/ioctls.h>

#define AUTO_UPDATE_MODE_AUTOMATIC_MODE		1
#define MXCFB_SET_AUTO_UPDATE_MODE		_IOW('F', 0x2D, uint32_t)

static int set_auto_update(int fd)
{
	int ret;
	int mode = AUTO_UPDATE_MODE_AUTOMATIC_MODE;

	ret = ioctl(fd, MXCFB_SET_AUTO_UPDATE_MODE, &mode);
	if (ret < 0) {
		int err = errno;
		printf("ioctl error: %s\n", strerror(err));
	}
}

int main()
{
	int fd = open("/dev/fb0", 0);
	if (fd < 0) {
		int err = errno;
		printf("open error: %s\n", strerror(err));
	}
	set_auto_update(fd);

	return 0;
}
  • Run Xorg -retro
  • Touch the screen, the cursor will move (not at the location of the touch though)

Manufacturer informations

Other informations