summaryrefslogtreecommitdiff
path: root/content/blog/kobo_clara-custom-distro.md
diff options
context:
space:
mode:
Diffstat (limited to 'content/blog/kobo_clara-custom-distro.md')
-rw-r--r--content/blog/kobo_clara-custom-distro.md265
1 files changed, 265 insertions, 0 deletions
diff --git a/content/blog/kobo_clara-custom-distro.md b/content/blog/kobo_clara-custom-distro.md
new file mode 100644
index 0000000..f7d40e1
--- /dev/null
+++ b/content/blog/kobo_clara-custom-distro.md
@@ -0,0 +1,265 @@
1+++
2title = "Kobo Clara HD Custom Linux Distro/RootFS"
3date = 2021-07-22
4draft = false
5+++
6
7These are just some notes I made when creating my own mini-distro after
8wanting something more custom than just using buildroot or making the
9official firmware more slim. For people other than me, I suggest
10looking through (C)LFS or running postmarketOS instead once this
11reader's pull request[1] gets integrated into upstream.
12
13Two things that'll greatly help with this is having serial terminal
14access with the four uart pins near the top right in the back of the
15reader, near the uSD card slot (I don't connect the 5V pin as my reader
16doesn't really turn on anything other than the power LED). I suggest
17maybe soldering female pin headers to there to make your life easier
18(you can later cut out a hole in the back cover or desolder the headers
19once you're done). Other than that, I suggest installing QEMU with ARM
20userspace to test programs that you have built or running them on a
21separate ARM device like a Raspberry Pi.
22
23## Prelude
24Ever since I learnt that the official firmware for the Clara was just
25using a modified Linux kernel with busybox as coreutils and many other
26libraries, I just knew that I had to minimize it. I also saw that it
27was using glibc for it's libc, which I really dislike as statically
28linking C programs against it was a pain in my experience, compared to
29something like musl and uclibc. It's also much larger than them and I
30don't use any of glibc extensions so it seemed like a waste of space to
31me.
32
33Initially when I replaced Nickel with Plato, I was able to shave about
34100 MiB after I removed /usr/local (which contains Nickel, Qt and a few
35other things), from 189 MiB to 74 MiB, but I still wanted to make it
36smaller.
37
38Using buildroot, I was able to get it under 2 MiB (!!) which was a
39little less than half the size of an uncompressed armhf Alpine Linux
40minirootfs (4.9M for 3.14). With Busybox, it was pretty much working
41out of the box, with serial terminal access! But waiting around 15
42minutes for the toolchain to build each time I wanted to change
43something in the rootfs took way too long, although it could've been
44minimized if I used ccache with a fairly large cache size. I still
45found that it compiled and installed a lot of things I wouldn't be
46using (particularly in /usr) even after disabling almost all of the
47third-party packages.
48
49I've uploaded the config file and the resulting rootfs for
50buildroot 2021.05. The root password by default is changeme.
51EDIT 2022-10-21: gone, build it yourself
52
53Of course the rootfs I got from buildroot nor me making the official
54firmware smaller is the point of this article, and the actual point is
55making one yourself! (or rather what I did to make my own)
56
57## Cross-toolchain
58For now as of July 22, 2021, I'm using my distro (Void Linux)'s
59packaged cross toolchain for armhf musl, but eventually I would be
60using my own.
61
62I'm not compiling off of the device itself as it would be somewhat slow
63for bigger programs, which is currently primarily the Linux kernel,
64U-Boot, and the toolchain itself, considering that the ereader's CPU
65(Freescale i.MX 6SLL) is a single core running up to 1 GHz. Including
66the development tools and headers would also take up more space on the
67device itself, and since the terminal can currently only be accessed
68through it's serial/uart pins, I don't think it's ideal.
69
70TODO: include steps to create own toolchain (probably based off of gcc
714.7.3 as that doesn't require c++)
72
73## Building the rootfs
74Assuming you made a new filesystem on your rootfs's partition, it'll
75likely be empty with no directories you'd expect to find on a regular
76distro. So you'll just have to make them.
77cd /path/to/rootfs
78mkdir bin dev etc proc sbin
79
80Your binaries would usually go in /bin, the uSD card, ttymxc0, and
81other devices would go in /dev, felker init's default program/script to
82execute is usually in /etc/rc, /proc is optional but I have it mounted
83to see what is currently mounted through /proc/mounts (or mount(1)
84without any arguments) as well as to see my disk usage through df(1).
85/sbin is there to place the init in as /sbin/init is the default init
86path the kernel looks at.
87
88## toybox
89Now on to the main part of the distro, the userspace. I intend to keep
90it fairly minimal so I've chosen to use toybox along with a slightly
91modified version of felker (musl dev)'s init[2], as well as dash[3] as
92the main shell since toybox doesn't include one as of 0.8.5 (though
93it'll probably be there by 1.0). I'll also be statically linking all
94the programs that'll be used so I wouldn't have to worry about shared
95libraries not being included/copied over, and also including LTO for
96slightly faster binaries. Originally, I tried going with sinit, sbase,
97and ubase but I was having trouble getting serial terminal access with
98getty to /dev/ttymxc0 (the default serial tty, at least with the
99vendor kernel). I didn't have this problem with busybox's and toybox's
100getty however. My config for toybox was also about 81K smaller than my
101trimmed sbase-box and ubase-box (352K compared to 267K+166K) where I
102removed programs that I won't use from ${BIN} in their respective
103Makefiles.
104EDIT 2022-10-21: also gone
105
106First I suggest exporting some environment variables to set the
107toolchain used as well as enabling static linking and LTO.
108
109 export CROSS_COMPILE="arm-linux-musleabihf-" # change to your cross-tc
110 export CC="${CROSS_COMPILE}gcc"
111 export LDFLAGS="--static"
112 export CFLAGS="-flto -static"
113 export ARCH=arm # for compiling the linux kernel
114
115To compile toybox, get the source from
116https://landley.net/toybox/downloads/ (or clone the upstream repo).
117Then run make menuconfig (optionally with make defconfig before it) and
118change it as you see fit. Personally, I disabled most of the programs I
119wouldn't use and kept only the ones that'll help with fixing a problem.
120Finally, make sure to run make.
121
122 make defconfig
123 make menuconfig
124 make
125
126To move it to your rootfs and set it's symlinks, you could probably run
127make install after setting PREFIX to your rootfs's /bin directory, but
128I did it manually.
129
130 # automatic (didn't test, check README)
131 make PREFIX=/path/to/rootfs/bin/ install
132
133 # (semi?) manual
134 cp toybox /path/to/rootfs/bin
135
136 # add symlinks if doing manual and you want them
137 cd /path/to/rootfs/bin
138 for prog in $(qemu-arm ./toybox); do ln -s toybox "$prog"; done
139
140## dash
141Also as of toybox 0.8.5, a shell still isn't included (probably would
142be included by 1.0 according to scripts/install.sh as well as a few
143other programs like gzip), so a separate shell would need to be built.
144Any can be used but dash would be shown as an example as I was able to
145get a static binary without too much trouble.
146
147First obtain the source[3] and cd into its
148untarred directory. Assuming your CC and CFLAGS are set, you can run
149these steps:
150
151 autoreconf -fiv
152 ./configure --host=$CROSS_COMPILE --with-libedit
153 make
154 ${CROSS_COMPILE}strip src/dash
155
156As this is going to be used as the main shell, I've decided to just
157copy it to /bin/sh in the rootfs directory, though copying it there but
158as /bin/dash and /bin/sh being symlinked to dash is also an option.
159
160 cp src/dash /path/to/rootfs/bin/sh
161 # or
162 cp src/dash /path/to/rootfs/bin
163 cd /path/to/rootfs/bin
164 ln -s dash sh
165
166## felker's init
167The init is just a single file that you can get from felker's site[2]
168or the gist on github[7]. I haven't had a good experience with the
169default startup program (/etc/rc) as a shell script with execve() run
170on it so I'd change it to execvp() and remove the third (specifies
171environment). To compile and install the init, all you need to do is
172run:
173
174 $CC $CFLAGS -o init init.c
175 cp init /path/to/rootfs/sbin
176
177Instead of /etc/rc being a shell script, you can also make a C program
178that does whatever you think is needed for a proper startup. I'll still
179use a shell script though which is linked here.
180EDIT 2022-10-21: you get the idea, it's gone.
181
182## /etc/passwd
183Copying the rootfs's contents to your device's/uSD card's root
184partition and then turning the device on should now work with a login
185prompt shown in the serial terminal. However, you probably wouldn't be
186able to login to any user. So you'll have to create a file at
187/path/to/rootfs/etc/passwd. For an empty password to root, you can use
188this, though I suggest setting a password as soon as you login:
189
190 # in rootfs's /etc/passwd
191 root::0:0:root:/root:/bin/sh
192
193With the passwd file created/updated, you should now be able to login
194to root after the rootfs is copied to your uSD card. Your rootfs so far
195should now be around 550-560K, which is much much smaller than the
196original firmware's, though it'll likely be much larger to maybe a few
197megabytes once a proper reader software is added.
198
199## Custom Linux Kernel
200WARNING: I haven't actually gotten the kernel to load in u-boot yet. It
201just hangs in the "Starting kernel ..." step and the init doesn't get
202loaded, so I'm assuming the kernel itself isn't either. If anyone out
203there has gotten a custom kernel working in the Kobo Clara HD, please
204send me an email or message on xmpp.
205
206UPDATE Jul 28, 2021: Gave up on it as I just couldn't get any kernels I
207built (both vendor and akemnade's mainline) to boot. But neither did
208postmarketOS boot beyond the initial initramfs messages without the log
209file being created. So I'll revisit this for later.
210
211EDIT 2022-10-21: I have gotten this working, but have been unable to
212get Plato build for musl, so I will have to either continue fighting
213with the crab or create my own with fbink, as that still works.
214Separate article on this later.
215
216My next big step is compiling my own kernel for the Clara HD. With the
217default configuration built for the vendor kernel, it appears to be
218about 3M, so my goal is to build a kernel that is smaller than that
219while retaining only the functionality that I need. I'm also not going
220to include networking support as that is unneeded for my purposes, but
221I suggest just keeping it if you're unsure. The wifi driver for the
222Kobo Clara HD is available as an out-of-tree driver[8].
223
224You should first obtain the kernel source, with two main options, the
225vendor kernel[9] and the mainline kernel (with akemnade's
226patches)[10]. For the latter, you need to clone the repo and switch to
227the latest kobo/drm-merged branch (kobo/merged-5.13 as of July 25,
2282021).
229
230After you've got them and assuming the CROSS_COMPILE and ARCH
231environment variables are set, you'd want to configure the kernel.
232
233I had a hard time compiling the vendor kernel with many things
234disabled, so I've kept my config somewhat similar to the default
235config. The config I used is available here (EDIT: dead).
236
237 make menuconfig
238 make zImage
239
240Assuming it compiles properly and arch/arm/boot/zImage exists, all
241that's needed to is to write it to your uSD card at the 1M offset.
242dd if=/path/to/kernel/zImage of=/path/to/uSDdev bs=512 seek=2048
243
244## Custom U-Boot
245I have not done this yet, nor really plan to, but if you do manage to
246compile the Kobo's vendored u-boot source, then all you'd have to do to
247install it is:
248
249 dd if=u-boot-file of=/dev/mmcblk0 bs=128k count=1 seek=6
250
251If I remember correctly, this command was included in an older
252firmware's startup script/rcS for updating udev, and it should still
253work.
254
255## Links
256[1]: https://gitlab.com/postmarketOS/pmaports/-/merge_requests/2334
257[2]: https://ewontfix.com/14
258[3]: https://git.kernel.org/pub/scm/utils/dash/dash.git
259[4]: https://github.com/akemnade/linux/tree/kobo/merged-5.13
260[5]: https://misc.andi.de1.cc/kobo/uboot-env.txt
261[6]: https://misc.andi.de1.cc/kobo/
262[7]: https://gist.github.com/rofl0r/6168719/raw/183525e0f0007169a49392b21ceee5b507e3aee8/init.c
263[8]: https://github.com/jwrdegoede/rtl8189ES_linux/tree/rtl8189fs
264[9]: https://github.com/kobolabs/Kobo-Reader/blob/master/hw/imx6sll-clara/kernel.tar.bz2
265[10]: https://github.com/akemnade/linux/tree/kobo/drm-merged-5.12