summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/_index.html3
-rw-r--r--content/blog/kobo_clara-custom-distro.md265
-rw-r--r--content/blog/kobo_clara-nickel.md245
-rw-r--r--content/blog/kobo_clara-plato.md129
-rw-r--r--content/blog/st-bitmap-font-fix.md37
-rw-r--r--content/blog/tmpfilehost.md73
-rw-r--r--content/blog/vfio-win10.md318
7 files changed, 1070 insertions, 0 deletions
diff --git a/content/_index.html b/content/_index.html
new file mode 100644
index 0000000..2f84b49
--- /dev/null
+++ b/content/_index.html
@@ -0,0 +1,3 @@
1---
2title: Vineet's site
3---
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
diff --git a/content/blog/kobo_clara-nickel.md b/content/blog/kobo_clara-nickel.md
new file mode 100644
index 0000000..7447283
--- /dev/null
+++ b/content/blog/kobo_clara-nickel.md
@@ -0,0 +1,245 @@
1+++
2title = 'Kobo Clara HD Notes for Nickel'
3date = 2021-01-13
4draft = false
5layout = "post"
6+++
7
8My ereader of choice is the Kobo Clara HD and I particularly like it
9because my eyes hurt less when reading for long periods of time
10compared to when I read on my phone or when I still had my iPad. It
11also had much longer battery life and only need to charge it about once
12every two weeks when I read for about 4 hours on average daily.
13
14However, the two notable things I don't like about it is it's included
15telemetry, like using Google Analytics by default and keeping a unique
16salt
17
18Spyware/Anti-Features:
19- Google Analytics (a lot of actions, if not everything, is sent to
20Google)
21- Auto-update by default
22 - I prefer being able to review what the new update provides and
23 choose not to apply it
24 - I don't like the new redesign in firmware v4.23.15505
25
26I'm also assuming your Kobo reader and it's SD card's device file would
27be would located at `/dev/sdf` and be mounted at `/mnt/kobo`.
28
29If you're going to not be using Nickel and instead be using something
30like [Plato](https://github.com/baskerville/plato), there's a newer version of this article available
31[here](./kobo-clara-plato.html), but the notes are for ~KSM~ loading Plato directly and not
32though k/fmon because I don't want to load Nickel if I'm already using
33a different reader.
34
35## Upgrade/Backup Included SD Card
36While the included 8GB microSD card is decent for storing your ebook
37library that may not have a lot of images, that would likely not be
38enough if you were aiming to read some comics on your ereader as they
39can be pretty big (quite a few of mine are over a gigabyte, with some
40over. Luckily, you can replace the microSD card with another one.
41
42Before upgrading, you should backup the SD card to into an image file
43so the filesystem would be preserved when putting the contents of the
44image on the new SD card. I'm using the command dd but there might be
45another program doing the same thing. Even if you're not going to
46upgrade, I still suggest to backup the SD card in case something goes
47wrong.
48```sh
49dd if=/dev/sdf of=kobo_sd.img conv=sync
50```
51
52After this is done, you can plug in your new SD card and reimage
53kobo_sd.img onto it. With dd, you can do something like:
54```sh
55dd if=kobo_sd.img of=/dev/sdf conv=sync
56```
57
58Checking it's partition table via lsblk or fdisk -l should show three
59partitions. If you replaced the SD card with something bigger, than you
60should resize the third partition.
61
62## Bypassing Registration On Setup
63When setting up your Kobo, you will be asked to sign into a Kobo
64account. There are other options like logging in via Google, Walmart,
65and other stores, but I don't like having to login to a device that
66would likely not be connected to the public internet. Fortunately, you
67can bypass this by choosing that you cannot connect to a Wi-Fi network
68and mount your Kobo to your computer. In, `.kobo/KoboReader.sqlite`, you
69can run:
70```sh
71echo "INSERT INTO user(UserID,UserKey) VALUES('1','');" \
72 | sqlite3 KoboReader.sqlite
73```
74
75This way you don't have to install their application just to be able to
76use your device.
77
78Note: Do not try doing this when you still have your SD card mounted
79before you setup your device. The device's screen would likely not
80update, at least on an early firmware version like v4.7.10733.
81
82## Blocking Google Analytics and other Telemetry
83Just adding 0.0.0.0 analytics.google.com to `/etc/hosts` may be enough to
84block most of the telemetry from being sent. However, you can try
85intercepting what connections your Kobo is making via mitmproxy set to
86transparent mode or using a hosts file that blocks all connections to
87Google (but not necessarily to Kobo's servers) like [Baobab's hosts file](https://codeberg.org/baobab/hosts)
88[(raw)](https://codeberg.org/baobab/hosts/raw/branch/master/hosts).
89EDIT 2022-10-21: Baobab has deleted his account from Codeberg for quite a
90while, so these two links are dead. Instead, I now recommend [Steven Black's](https://github.com/StevenBlack/hosts)
91instead [(raw)](https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts).
92
93To put the hosts file without root (which will be detailed in another
94section), you can make a directory called etc, put the hosts file in
95there, and tar it into a file called KoboRoot.tgz.
96```sh
97mkdir etc
98wget -O etc/hosts https://codeberg.org/baobab/hosts/raw/branch/master/hosts
99tar czvf KoboRoot.tgz etc
100cp KoboRoot.tgz /mnt/kobo/.kobo/
101```
102
103When you move a tar file with that name into your Kobo's .kobo folder,
104it's contents gets untarred into it's root at `/` when the device is
105turned on again, which is usually done for their updates but can be
106used for custom files like this and gaining root access.
107
108## Gaining Root Access via Telnet
109To gain root access, we first need to get the `/etc/inittab` and
110`/etc/inetd.conf` which you can get from mounting the SD card's first
111partition into your computer (the second partition seems to be like a
112backup). You should copy those two files into a folder called etc
113somewhere (probably not on the SD card).
114
115In the `etc/inittab` file, you should add these two lines:
116```
117::sysinit:/etc/custominit.sh
118::respawn:/usr/sbin/inetd -f /etc/inetd2.conf
119```
120
121You would want to rename the `etc/inetd.conf` file you copied into
122`etc/inetd2.conf` (or whatever the custom inetd.conf's filename is) and
123when editing that, you should add:
124```
12523 stream tcp nowait root /bin/busybox telnetd -i
126```
127
128However, if there is already a commented line for root telnet in the
129inetd2.conf, you should probably still add the above line and ignore
130the commented line as that may or may not work (didn't for me).
131
132To actually start inetd, you should add these lines somewhere in
133`/etc/custominit.sh`:
134```sh
135mkdir -p /dev/pts
136mount -t devpts devpts /dev/pts
137/usr/sbin/inetd /etc/inetd2.conf
138```
139
140After that, you just have to tar the `etc/` folder again and copy it to
141your Kobo's onboard/third partition's `.kobo` folder.
142```sh
143tar czvf KoboRoot.tgz etc
144cp KoboRoot.tgz /mnt/kobo/.kobo/
145```
146
147Now you could put your SD card back into your Kobo provided that they
148are already unmounted and turn your Kobo back on.
149
150After connecting to the WiFi, simplying telnetting (?) into your Kobo
151and logging in as root should give you a root shell. :D
152```sh
153telnet $KOBO_IP
154```
155
156By default, root has no password so you should change it with passwd.
157
158## Getting SSH and SFTP access via Dropbear
159I'm using Dropbear instead of OpenSSH because it's better suited for
160embedded hardware like the Kobo Clara HD. Obviously we can't copy a
161binary compiled for amd64 or whatever architecture your compiling
162computer is running so we would have to cross-compile for our ereader.
163
164Fortunately, we are not required to cross-compile `gcc`/`clang` and friends
165as we can simply download the linaro arm toolchain which has the
166binaries for gcc and others included. You could get the toolchain
167[here](https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/) and you should get the release that matches your host's
168
169architecture. After untarring the file, you should also set your PATH
170variable to the toolchain's `bin/` folder so you don't have to manually
171set the CC and CXX variables when building Dropbear.
172
173```sh
174wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
175tar xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
176export PATH=$(pwd)/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
177```
178
179Now you could get the source for Dropbear and cross-compile it. The
180source can be found on their [homepage](https://matt.ucc.asn.au/dropbear/dropbear.html) or [github](https://github.com/mkj/dropbear/releases) repo.
181```sh
182wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2020.81.tar.bz2
183tar xvf dropbear-2020.81.tar.bz2
184cd dropbear-2020.81
185./configure --enable-static --host=arm-linux-gnueabihf
186# MULTI=1 combines the binaries like busybox does and is also smaller in size
187make MULTI=1 PROGRAMS="dropbear dropbearkey"
188```
189
190Now you only need to copy the dropbearmulti binary over to your Kobo.
191What I've done is running `python3 -m http.server` and downloading the
192file onto my Kobo but you could also just copy it onto the microSD
193card.
194```sh
195wget your.computer.ip:8000/dropbearmulti
196chmod +x dropbearmulti
197mv dropbearmulti /usr/bin
198cd /usr/bin
199# below are optional but dropbear(key) would be an argument for dropbearmulti
200ln -s dropbearmulti dropbear
201ln -s dropbearmulti dropbearkey
202```
203
204Now you only need to generate the host keys. My client key is ed25519
205so I'm not going to generate the others.
206```sh
207mkdir /etc/dropbear
208dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key
209dropbear -F -r /etc/dropbear/dropbear_ed25519_key
210```
211
212Now you could `ssh` into your Kobo and login as `root`. Remember to change
213`root`'s password beforehand though if you haven't already! I suggest
214copying your public key to your Kobo via `ssh-copy-id` so you don't have
215to enter root's password all the time and so password-based logins can
216be disabled in dropbear.
217
218To start it on boot, you could add the following line to
219`/etc/inetd2.conf`:
220```
22122 stream tcp nowait root /usr/bin/dropbearmulti dropbear -i -r /etc/dropbear/dropbear_ed25519_key
222```
223
224For some reason, the symlink wasn't resolving for me inetd so I had to
225call the multi-binary directly. You could also add the command/args
226into `/etc/custominit.sh`.
227
228## FTP Access
229If you don't or can't use sftp or scp for some reason, there's always ftp :D
230There's a ftp daemon included in busybox so all we have to do is enable it
231in `/etc/inetd2.conf`:
232```
23321 stream tcp nowait root /bin/busybox ftpd -w -S /
234```
235
236This would share the entire filesystem so you may or may not want to
237restrict the shared directory to maybe just your ebook directory
238(`/mnt/onboard`) and move the files out via `telnet` or `ssh`.
239EDIT 2022-10-21: A chroot would also work.
240
241## References and Other Links
242- [Rémy's notes on hacking a Kobo Aura H2O](https://remy.grunblatt.org/kobo-aura-h2o-electronic-reader-hacking.html)
243- [Ying's notes on bypassing registration and setting up telnet, ssh, etc.](https://yingtongli.me/blog/2018/07/30/kobo-rego.html)
244- [MobileRead forum thread on disabling Google Analytics on the Kobo Touch](https://www.mobileread.com/forums/showthread.php?t=162713)
245- [MobileRead wiki on hacking the Kobo Touch](https://wiki.mobileread.com/wiki/Kobo_Touch_Hacking)
diff --git a/content/blog/kobo_clara-plato.md b/content/blog/kobo_clara-plato.md
new file mode 100644
index 0000000..b7de110
--- /dev/null
+++ b/content/blog/kobo_clara-plato.md
@@ -0,0 +1,129 @@
1+++
2title = "Kobo Clara HD Notes for Plato (and KSM)"
3date = 2021-03-27
4+++
5
6These are my notes for getting Plato on the Kobo Clara HD from scratch
7as well as some notes for getting KSM to work, but I now boot directly
8into Plato instead of through KSM.
9
10Previously, I didn't really like using KOReader because it was kind of
11slow and was written in Lua. At the time of using Plato, it seemed nice
12but it didn't cover thumbnails for books, which while it is a minor
13detail, I find books easier to be recognized with a cover thumbnail in
14addition to their title. This was added in release 0.9.10 but as an
15optional feature which I didn't somehow see until recently when I
16retried it. HOWEVER again, I didn't like using k/fmon as I had to still
17use Nickel to get back into KOReader/Plato/whatever alternate reader
18when I wanted to go away from using Nickel.
19
20<ignore>
21That was when I found out about KSM and how there was a working version
22for the Clara HD. KSM is like an alternate bootloader for the Kobo
23readers and it apparently doesn't work very well with newer models like
24the Clara HD and up, but someone got it to work with those devices.
25[KSM 09](https://www.mobileread.com/forums/showthread.php?s=c34e41df391c61810a6b06f991c29168&t=293804) is apparently not maintained anymore and I'm not sure if KSM
2610 is being developed or not since I'm pretty sure it's closed source.
27
28> Development and support for KSM stopped some time ago. Therefore, do
29> not use it!
30
31"That sign can't stop me because I can't read!" - Me imitating D.W.
32from the PBS Kids cartoon Arthur on Mar. 26, 2021 when I saw that it
33can be used on my Kobo
34
35The latest firmware version that KSM sort of supports is v4.25.15875
36but it can probably work with a newer version like v4.26+ that would
37likely only need a couple changes to /etc/init.d/rcS, if any changes
38were needed at all. I'll be using v4.26 for the rest of this
39article/guide.
40</ignore>
41
42Recently, after seeing how my Kobo boots into KSM and Nickel through
43the rcS file, I realized that I could've instead just booted directly
44into Plato, and plato.sh (the script that runs Plato) has a standalone
45option that supports just that! The KSM notes are still going to be
46here in case someone still wants to use KSM.
47
48## Installing Plato (or probably any other reader like KOReader)
49This part probably applies to any other reader other than Plato like
50KOReader but I haven't personally tested them. All you have to do is
51[get the latest release](https://github.com/baskerville/plato/releases/latest) at Plato's repo and unzip it's contents into
52a folder called plato in /path/to/kobo/mount/.adds, the latter folder
53of which should have already been created by KSM if you are using that.
54If you are using KSM, there should be a new option below "start nickel"
55called "start plato" when you have rebooted the device. Read below if
56you aren't using KSM.
57
58## Loading Plato on Boot
59Since I don't want to load Nickel only to load into another reader like
60the recommended options in Plato's forum thread (kfmon, fmon, and
61NickelMenu) suggest, I noticed that I could have booted into Plato
62directly. The only requirements for doing this having access to the
63rootfs, so either through a telnet/ssh session, or having the sd card's
64root/first partition mounted to your computer, or just ftp/rsyncing the
65files to your Kobo.
66
67First I suggest making a copy of rcS if you haven't already in case an
68update overwrites it. My copy is named custominit.sh. Next you'll want
69the Kobo's /etc/inittab to boot with custominit.sh instead of rcS:
70/etc/inittab:
71
72```
73#::sysinit:/etc/init.d/rcS
74::sysinit:/etc/custominit.sh
75```
76
77The rest of the lines don't need to change. Then you should open
78custominit.sh in your favourite editor to add the lines at the bottom
79but before hindenburg is executed:
80
81```
82cd /mnt/onboard/.adds/plato # or whereever Plato is
83PLATO_STANDALONE=1 ./plato.sh
84```
85
86You would probably also want to remove the lines where Nickel-specific
87programs/scripts are running like nickel, hindenburg, pickel, sickel,
88etc.
89
90Now on subsequent boots, Plato should automatically have been loaded.
91Boot times may also be slightly faster! :D
92
93## Installing KSM 09 (not doing anymore)
94First you would want to [download the Clara HD version of KSM 09](https://www.mobileread.com/forums/attachment.php?s=902078ac2e6fe8ff7a0947b56cbcade6&attachmentid=166556&d=1538176531) and
95[the fix for v4.25](https://www.mobileread.com/forums/attachment.php?s=902078ac2e6fe8ff7a0947b56cbcade6&attachmentid=184756&d=1610745905). Then, you would want to unzip the KoboRoot.tgz
96with separate filenames so they don't replace each other and we would
97untar those into the same directory. After that, we would cd into the
98directory and tar it's contents into a new KoboRoot.tgz and place it in
99/path/to/kobo/mount/.kobo/.
100
101An example of what I did after downloading and unzipping the files are
102below:
103
104```
105mkdir koboroot
106tar -xvf KoboRoot-main.tgz -C koboroot
107tar -xvf KoboRoot-v4.25-darkmodefix.tgz -C koboroot
108cd koboroot
109tar -czvf ../KoboRoot.tgz .
110cd ..
111rm -r koboroot
112```
113
114After your Kobo untars it and you wait a while, you should be presented
115with KSM's main screen :D ksm09's main screen running on the kobo clara
116hd
117
118## Auto-Boot into Plato instead of Nickel via KSM (not doing anymore)
119First make sure USB support is enabled in KSM and then mount your Kobo
120to your computer. Once mounted, go to
121/path/to/kobo/mount/.adds/kbmenu_user/confoptions and edit
122ksm_ini_options.txt in your favourite editor. You should see many
123options that are listed but the one that we're interested in is
124ksmAutoselectoption which may have start_nickel and start_koreader
125already and what we want to do is add ksmAutoselectoption=start_plato.
126After a quick restart to reload the options file, you should be able to
127see the new option in KSM's settings under [general] and add item if it
128wasn't already added. Now Plato should auto-boot on subsequent
129powerons.
diff --git a/content/blog/st-bitmap-font-fix.md b/content/blog/st-bitmap-font-fix.md
new file mode 100644
index 0000000..53e6740
--- /dev/null
+++ b/content/blog/st-bitmap-font-fix.md
@@ -0,0 +1,37 @@
1+++
2title = "Fixing bitmap font fallbacks in the st terminal"
3date = 2023-11-24
4draft = false
5+++
6tldr, change FC_SCALABLE in x.c from 1 to 0. (comes from the font2 patch)
7
8For some context, I have been using xterm for a long while when I'm on OpenBSD
9since it is included by default in Xenocara with Terminus as my default font,
10and the main reason why I did not use st again was that my bitmap fallback font
11for CJK was not loading. Instead, I get an ugly sans-serif scaled font that
12looked very out of place in my otherwise clean and crisp bitmap terminal.
13
14Yes, I did make sure that the font2 patch for st was applied correctly.
15
16The X11 font string for reference is Fixed:
17-misc-fixed-medium-r-normal-ja-18-120-100-100-c-180-iso10646-1
18
19It also didn't help that fontconfig was unable to find the font either no
20matter how much I looked for it with fc-list and fc-match. The weirder thing is
21that when I installed GNU Unifont to my fonts directory, fontconfig was able to
22find it and st loaded it (I put a printf in the xloadfonts() function in x.c),
23but the same old ugly scaled font was still being shown for CJK. The weirderer
24thing was that Unifont was rendering just fine when being used as the main font
25instead of in font2.
26
27I thought to myself why this was happening and wasn't able to find out, until I
28reread the font loading portion in x.c's xloadsparefonts() function that came
29part of the font2 patch.
30
31It had set the FC_SCALABLE boolean to 1 (true). That explained why the fallback
32font rendered fine as the main font and not fallback. Setting that boolean to
330 (false) fixed my fallback font not matching issue, and now I have clean and
34crisp looking text that I can read more easily.
35
36I already disliked fontconfig, freetype, xft, and friends (don't get me started
37on pango and harfbuzz), but this incident made me dislike it further.
diff --git a/content/blog/tmpfilehost.md b/content/blog/tmpfilehost.md
new file mode 100644
index 0000000..c8356d8
--- /dev/null
+++ b/content/blog/tmpfilehost.md
@@ -0,0 +1,73 @@
1+++
2title = "Creating a Temporary File Hoster"
3date = 2022-04-27
4draft = false
5+++
6For the past couple years, whenever I wanted to upload a file, I would
7curl the file to [lainsafe](https://git.qorg11.net/lainsafe.git/), [i/u.kalli.st](https://gt.kalli.st/kallist/uploader), and recently [ttm.sh](https://tildegit.org/tildeverse/ttm.sh).
8
9Since I want to selfhost, I thought i can just use either of what those
10three used. Earlier today though, I realized I could just copy the
11file(s) I want to upload via rsync/scp to a public directory that gets
12served by an httpd or gopherd.
13
14From what I understand, the previous file hosters had a program running
15that read the file that the user uploads to them, does some renaming,
16and writes that to a directory that is served. After some time, that
17file is deleted. The first part can be handled via rsync/scp like
18mentioned previously. For automatic deletion, I recently saw in find's
19man page that it can list that haven't been modified via the -mtime
20flag, so that can be used with a cron job.
21
22But while thinking of this idea, I got stumped by how to print back the
23url to this file that is uploaded since printing the filename as is
24appended to its baseurl, there could be spaces and other invalid
25unescaped characters which programs trying to download it may not like.
26
27I thought I could just create a separate program for this. However,
28doing this seemed more complicated than just copying the file to the
29server. So, with the help of awk and some StackExchanging, I've been
30able to do it.
31
32`upfile.sh`:
33```sh
34#!/bin/sh
35urlencode() {
36 awk '
37BEGIN { for (i = 1; i < 256; i++) hex[sprintf("%c", i)] = sprintf("%%%02X", i) }
38{
39 for (i = 1; i <= length($0); i++) {
40 c = substr($0, i, 1)
41 printf("%s", c ~ /^[-._~0-9a-zA-Z]$/ ? c : hex[c])
42 }
43 printf "\n"
44}
45'
46}
47
48FILE="$1"
49SERVER="REPLACEME"
50BASEURL="https://u.$SERVER"
51
52[ -z "$1" ] && exit 1
53
54scp "$FILE" "$SERVER":files/ || exit 1
55printf "%s/" "$BASEURL"
56basename "$FILE" | urlencode
57```
58
59Then to purge these files after they become too old (e.g. 3 days), you
60can put something like this in a cron job to run daily (replace file
61directory):
62
63```
640 0 * * * find /path/to/dir/ -mtime +3 -exec rm {} \;
65```
66
67You can also put this command in /etc/daily.local or /etc/cron/daily,
68or whatever file your root crontab's @daily runs (if there is one).
69
70And that's it! The only difficult part that I experienced was encoding
71the name of the file and originally did that in C. However, having a
72mixed C and shell program just for file uploading didn't sit right with
73me. It seems like whenever you're in doubt, you can rely on awk huh.
diff --git a/content/blog/vfio-win10.md b/content/blog/vfio-win10.md
new file mode 100644
index 0000000..a24b78e
--- /dev/null
+++ b/content/blog/vfio-win10.md
@@ -0,0 +1,318 @@
1+++
2title = "VFIO Install Notes"
3date = 2020-10-17
4draft = false
5+++
6You should first go look at [the Arch Wiki on it](https://wiki.archlinux.org/index.php/PCI%20passthrough%20via%20OVMF) or [Yuri Alek's guide on Single GPU passthrough](https://gitlab.com/YuriAlek/vfio) or [4chan's /g/ wiki on it](https://wiki.installgentoo.com/index.php/PCI_passthrough) as these assume prior knowledge.
7
8# Prerequisites
9## UEFI Options
10Enable VT-d and VT-x (or AMD equivalent)
11
12## Kernel Config
13Enable KVM and VFIO
14> you can set VFIO as builtin but as a module is more flexible
15Also add `"iommu=pt intel_iommu=on"` to your kernel command line (or in CONFIG\_CMDLINE)
16
17### Current Options
18```
19...
20CONFIG_IOMMU_IOVA=y
21CONFIG_IOMMU_API=y
22CONFIG_IOMMU_SUPPORT=y
23CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y
24# use the respective AMD options if using an AMD CPU
25CONFIG_INTEL_IOMMU=y
26CONFIG_INTEL_IOMMU_SVM=y
27CONFIG_INTEL_IOMMU_DEFAULT_ON=y
28CONFIG_INTEL_IOMMU_FLOPPY_WA=y
29
30CONFIG_KVM_VFIO=y
31CONFIG_VFIO_IOMMU_TYPE1=m
32CONFIG_VFIO_VIRQFD=m
33CONFIG_VFIO=m
34CONFIG_VFIO_PCI=m
35CONFIG_VFIO_PCI_VGA=y
36CONFIG_VFIO_PCI_MMAP=y
37CONFIG_VFIO_PCI_INTX=y
38CONFIG_VFIO_PCI_IGD=y
39CONFIG_VFIO_MDEV=m
40CONFIG_VFIO_MDEV_DEVICE=m
41...
42```
43
44## Packages Required
45```
46app-emulation/qemu (actual program)
47sys-firmware/edk2-ovmf (UEFI firmware for Nvidia GPU)
48media-sound/scream (audio)
49looking-glass-client (compile from source if no package, or make your own)
50```
51
52`app-emulation/libvirt` can be used as well for easier configuration and autostart
53but I have had problems with it:
54- Service not starting properly, workaround is restarting service after it starts (Gentoo)
55- Networks and domains not autostarting, workaround is starting them manually (CRUX)
56
57### Gentoo USE Flags
58```
59app-emulation/qemu gtk opengl sdl sdl-image usb # (spice, ssh, vhost-user-fs, virgl, and virtfs are optional I think)
60media-libs/libsdl2 X gles opengl # for Looking Glass
61```
62note to self (2020-10-17): check how minimal you can make qemu to run vfio
63
64# IOMMU
65Run `dmesg | grep -E 'DMAR'` and see if `DMAR: IOMMU enabled` or something similar is in output
66
67# QEMU Script
68All code blocks in this section go in the qemu script file unless specified otherwise
69
70## Environment Variables
71```sh
72IMG=/path/to/windows-image-file
73VIRTIO=/path/to/virtio-iso
74WINDOWS=/path/to/windows-install-iso
75OVMF=/usr/share/edk2-ovmf/OVMF_CODE.fd
76RAM=16G
77ULIMIT=$(ulimit -l)
78ULIMIT_TARGET=$(( $(echo $RAM | tr -d 'G')*1048576+100000 ))
79
80GPU_VIDEO=01:00.0
81GPU_AUDIO=01:00.1
82VIDEOID="10de 13c0"
83AUDIOID="10de 0fbb"
84VIDEOBUSID="0000:${GPU_VIDEO}"
85AUDIOBUSID="0000:${GPU_AUDIO}"
86```
87
88## VFIO Detaching and Attaching
89```sh
90vfio_on() {
91 # for nvidia card with proprietary drivers
92 rmmod nvidia_drm
93 rmmod nvidia_modeset
94 rmmod nvidia
95
96 # disable bumblebee service or use bbswitch to detach card if using bumblebee
97
98 modprobe vfio-pci
99
100 echo $VIDEOID > /sys/bus/pci/drivers/vfio-pci/new_id
101 echo $VIDEOBUSID > /sys/bus/pci/devices/$VIDEOBUSID/driver/unbind
102 echo $VIDEOBUSID > /sys/bus/pci/drivers/vfio-pci/bind
103 echo $VIDEOID > /sys/bus/pci/drivers/vfio-pci/remove_id
104
105 echo $AUDIOID > /sys/bus/pci/drivers/vfio-pci/new_id
106 echo $AUDIOBUSID > /sys/bus/pci/devices/$AUDIOBUSID/driver/unbind
107 echo $AUDIOBUSID > /sys/bus/pci/drivers/vfio-pci/bind
108 echo $AUDIOID > /sys/bus/pci/drivers/vfio-pci/remove_id
109
110 # add rest of gpu devices if they are in the same group (I think 4 devices in 1000 or 2000 series nvidia)
111}
112
113vfio_off() {
114 rmmod vfio_iommu_type1
115 rmmod vfio_pci
116 rmmod vfio_virqfd
117 rmmod vfio
118
119 modprobe nvidia
120}
121```
122
123## Networking
124```sh
125net_on() {
126 ip tuntap add dev tap0 mode tap group kvm
127 ip link set dev tap0 up promisc on
128 ip addr add 0.0.0.0 dev tap0
129
130 ip link add br0 type bridge
131 ip link set br0 up
132 ip link set tap0 master br0
133 echo 0 > /sys/class/net/br0/bridge/stp_state
134 ip addr add 192.168.123.1/24 dev br0
135
136 sysctl net.ipv4.conf.tap0.proxy_arp=1 > /dev/null
137 sysctl net.ipv4.conf.enp0s31f6.proxy_arp=1 > /dev/null
138 sysctl net.ipv4.ip_forward=1 > /dev/null
139
140 iptables -t nat -A POSTROUTING -o enp0s31f6 -j MASQUERADE > /dev/null
141 iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT > /dev/null
142 iptables -A FORWARD -i br0 -o enp0s31f6 -j ACCEPT > /dev/null
143}
144
145net_off() {
146 sysctl net.ipv4.conf.tap0.proxy_arp=0 > /dev/null
147 sysctl net.ipv4.conf.enp0s31f6.proxy_arp=0 > /dev/null
148 sysctl net.ipv4.ip_forward=0 > /dev/null
149
150 ip link set dev br0 down
151 ip link del br0
152
153 ip link set dev tap0 down
154 ip tuntap del mode tap name tap0
155}
156```
157
158Also add this to /etc/conf.d/net if using Gentoo ([source](https://wiki.gentoo.org/wiki/QEMU/Options#Network_bridge))
159> replace `enp0s31f6` with the host/master interface
160```sh
161...
162tuntap_tap0="tap"
163config_tap0="null"
164bridge_br0="enp0s31f6 tap0"
165
166config_br0="192.168.123.2 netmask 255.255.255.0"
167routes_br0="default via 192.168.123.1"
168bridge_forward_delay_br0=0
169bridge_hello_time_br0=10
170
171depend_br0() {
172 need net.enp0s31f6
173 need net.tap0
174}
175...
176```
177
178## Hugepages
179```sh
180hugepages_on() {
181 PAGES=$(( $(echo $RAM | tr -d 'G') * 1048576 / 2048))
182 mkdir -p /dev/hugepages
183 mount -t hugetlbfs hugetlbfs /dev/hugepages
184 echo $PAGES > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
185}
186
187hugepages_off() {
188 echo 0 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
189 umount /dev/hugepages
190}
191```
192
193## QEMU Command
194### Before installing guest OS (Windows 10 used as example)
195```sh
196ulimit -l $ULIMIT_TARGET
197
198qemu-system-x86_64 \
199 -name 'vfio-vm' \
200 -vga qxl \
201 -nodefaults -enable-kvm -machine q35 \
202 -m $RAM -mem-path /dev/hugepages \
203 -cpu host,kvm=off,svm=off,topoext,hv_relaxed,hv_spinlocks=0x1fff,hv_time,hv_vapic,hv_vendor_id=novideobad43,hv_vpindex,hv_synic,hv_stimer,hv_frequencies \
204 -smp 8,sockets=1,cores=4,threads=2 \
205 -rtc clock=host,base=localtime \
206 -boot menu=on -boot d \
207 -nic tap,ifname=tap0,script=no,downscript=0,model=virtio-net-pci \
208 -drive if=pflash,format=raw,readonly,file=$OVMF \
209 -drive file="$VIRTIO",id=cd1,media=cdrom \
210 -drive file="$WINDOWS",id=cd2,media=cdrom \
211 -device virtio-scsi-pci,id=scsi0 \
212 -device scsi-hd,bus=scsi0.0,drive=rootfs \
213 -drive file="$IMG",id=rootfs,index=0,format=qcow2,media=disk,if=none
214
215ulimit -l $ULIMIT
216```
217### After installing guest OS
218```sh
219ulimit -l $ULIMIT_TARGET
220
221qemu-system-x86_64 \
222 -name 'vfio-vm' \
223 -vga none -nographic \
224 -nodefaults -enable-kvm -machine q35 \
225 -m $RAM -mem-path /dev/hugepages \
226 -cpu host,kvm=off,svm=off,topoext,hv_relaxed,hv_spinlocks=0x1fff,hv_time,hv_vapic,hv_vendor_id=novideobad43,hv_vpindex,hv_synic,hv_stimer,hv_frequencies \
227 -smp 8,sockets=1,cores=4,threads=2 \
228 -rtc clock=host,base=localtime \
229 -boot menu=on -boot c \
230 -nic tap,ifname=tap0,script=no,downscript=0,model=virtio-net-pci \
231 -device vfio-pci,host=$GPU_VIDEO,multifunction=on,x-vga=on \
232 -device vfio-pci,host=$GPU_AUDIO \
233 -device ivshmem-plain,memdev=ivshmem,bus=pcie.0 \
234 -object memory-backend-file,id=ivshmem,share=on,mem-path=/dev/shm/looking-glass,size=32M \
235 -device virtio-keyboard-pci \
236 -device virtio-mouse-pci \
237 -object input-linux,id=kbd0,evdev=/dev/input/by-id/usb-Corsair_Corsair_K70R_Gaming_Keyboard-if02-event-kbd,grab_all=on,repeat=on \
238 -object input-linux,id=mouse0,evdev=/dev/input/by-id/usb-Logitech_Gaming_Mouse_G502_0E5F335C3236-event-mouse \
239 -object input-linux,id=mouse1,evdev=/dev/input/by-id/usb-Logitech_Gaming_Mouse_G502_0E5F335C3236-if01-event-kbd,grab_all=on,repeat=on \
240 -drive if=pflash,format=raw,readonly,file=$OVMF \
241 -drive file="$VIRTIO",id=cd1,media=cdrom \
242 -device virtio-scsi-pci,id=scsi0 \
243 -device scsi-hd,bus=scsi0.0,drive=rootfs \
244 -drive file="$IMG",id=rootfs,index=0,format=qcow2,media=disk,if=none
245
246ulimit -l $ULIMIT
247```
248
249# Extra
250## Adding USB Devices
251Get vendor and product id from `lsusb` and add them to your QEMU command arguments:
252```sh
253 -device qemu-xhci,id=xhci0 -device usb-host,bus=xhci0.0,vendorid=0x<yourvendorid>,productid=0x<yourproductid>
254```
255Example for my USB bluetooth receiver:
256```
257$ lsusb
258...
259Bus 001 Device 004: ID 0b05:17cb ASUSTek Computer, Inc. Broadcom BCM20702A0 Bluetooth
260...
261```
262My vendorid is `0x0b05` and productid is `0x17cb`, so in QEMU it would be:
263```sh
264 -device qemu-xhci,id=<usb-bus-id> -device usb-host,bus=<usb-bus-id>.0,vendorid=0x0b05,productid=0x17cb
265```
266
267## Set CPU Affinity
268While libvirt makes this more simple, it appears we need a script/function to do it in bare QEMU
269Borrowed from [here](https://null-src.com/posts/qemu-optimization/post.php#taskset)
270> note: uses bash-isms so that's why I put it in a separate file
271```bash
272#!/bin/bash
273THREAD_LIST="0,4,1,5,2,6,3,7"
274NAME="vfio-vm"
275
276sleep 20 &&
277HOST_THREAD=0
278# for each vCPU thread PID
279for PID in $(pstree -pa $(pstree -pa $(pidof qemu-system-x86_64) | grep $NAME | awk -F',' '{print $2}' | awk '{print $1}') | grep CPU | pstree -pa $(pstree -pa $(pidof qemu-system-x86_64) | grep $NAME | cut -d',' -f2 | cut -d' ' -f1) | grep CPU | sort | awk -F',' '{print $2}')
280do
281 let HOST_THREAD+=1
282 # set each vCPU thread PID to next host CPU thread in THREAD_LIST
283 echo "taskset -pc $(echo $THREAD_LIST | cut -d',' -f$HOST_THREAD) $PID" | sh
284done
285```
286
287## Additional Disk
288You can add another disk by simply copying the arguments for adding the rootfs and slightly modifying
289Example for a qcow2 image:
290```
291 -device virtio-scsi-pci,id=<scsi-id> \
292 -device scsi-hd,bus=<scsi-id>.0,drive=<drive-id> \
293 -drive file=<location>,id=<drive-id>,index=0,format=qcow2,media=disk,if=none
294```
295
296## No Drives During Installation
297Make sure virtio driver is loaded:
298- Click Load Driver
299- Choose virtio-cd disc > amd64 > w10 and press enter
300- Load Red Hat Virtio SCSI driver
301
302## Looking Glass Not Starting
303Make sure no virtual display like QXL is loaded too (`-nographic -vga none` in QEMU)
304
305## JACK Support
306To use JACK instead of Scream, you can use these QEMU arguments
307```sh
308-audiodev jack,id=snd0,in.client-name=default,out.client-name=default,in.start-server=off,out.start-server=off,in.exact-name=on,out.exact-name=on,in.connect-ports=system,out.connect-ports=system,in.frequency=48000,out.frequency=48000,timer-period=2048,out.buffer-length=5120 \
309-device ich9-intel-hda \
310-device hda-output,audiodev=snd0 \
311```
312You might need to change the timer-period and buffer-length if experiencing crackling.
313Also you might have to change the controller (ich9-intel-hda) and codec (hda-output) to something else.
314
315To list controller and codecs, run:
316```sh
317qemu-system-x86_64 -device help | grep hda
318```