diff options
Diffstat (limited to 'content')
| -rw-r--r-- | content/_index.html | 3 | ||||
| -rw-r--r-- | content/blog/kobo_clara-custom-distro.md | 265 | ||||
| -rw-r--r-- | content/blog/kobo_clara-nickel.md | 245 | ||||
| -rw-r--r-- | content/blog/kobo_clara-plato.md | 129 | ||||
| -rw-r--r-- | content/blog/st-bitmap-font-fix.md | 37 | ||||
| -rw-r--r-- | content/blog/tmpfilehost.md | 73 | ||||
| -rw-r--r-- | content/blog/vfio-win10.md | 318 |
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 | --- | ||
| 2 | title: 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 | +++ | ||
| 2 | title = "Kobo Clara HD Custom Linux Distro/RootFS" | ||
| 3 | date = 2021-07-22 | ||
| 4 | draft = false | ||
| 5 | +++ | ||
| 6 | |||
| 7 | These are just some notes I made when creating my own mini-distro after | ||
| 8 | wanting something more custom than just using buildroot or making the | ||
| 9 | official firmware more slim. For people other than me, I suggest | ||
| 10 | looking through (C)LFS or running postmarketOS instead once this | ||
| 11 | reader's pull request[1] gets integrated into upstream. | ||
| 12 | |||
| 13 | Two things that'll greatly help with this is having serial terminal | ||
| 14 | access with the four uart pins near the top right in the back of the | ||
| 15 | reader, near the uSD card slot (I don't connect the 5V pin as my reader | ||
| 16 | doesn't really turn on anything other than the power LED). I suggest | ||
| 17 | maybe 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 | ||
| 19 | once you're done). Other than that, I suggest installing QEMU with ARM | ||
| 20 | userspace to test programs that you have built or running them on a | ||
| 21 | separate ARM device like a Raspberry Pi. | ||
| 22 | |||
| 23 | ## Prelude | ||
| 24 | Ever since I learnt that the official firmware for the Clara was just | ||
| 25 | using a modified Linux kernel with busybox as coreutils and many other | ||
| 26 | libraries, I just knew that I had to minimize it. I also saw that it | ||
| 27 | was using glibc for it's libc, which I really dislike as statically | ||
| 28 | linking C programs against it was a pain in my experience, compared to | ||
| 29 | something like musl and uclibc. It's also much larger than them and I | ||
| 30 | don't use any of glibc extensions so it seemed like a waste of space to | ||
| 31 | me. | ||
| 32 | |||
| 33 | Initially when I replaced Nickel with Plato, I was able to shave about | ||
| 34 | 100 MiB after I removed /usr/local (which contains Nickel, Qt and a few | ||
| 35 | other things), from 189 MiB to 74 MiB, but I still wanted to make it | ||
| 36 | smaller. | ||
| 37 | |||
| 38 | Using buildroot, I was able to get it under 2 MiB (!!) which was a | ||
| 39 | little less than half the size of an uncompressed armhf Alpine Linux | ||
| 40 | minirootfs (4.9M for 3.14). With Busybox, it was pretty much working | ||
| 41 | out of the box, with serial terminal access! But waiting around 15 | ||
| 42 | minutes for the toolchain to build each time I wanted to change | ||
| 43 | something in the rootfs took way too long, although it could've been | ||
| 44 | minimized if I used ccache with a fairly large cache size. I still | ||
| 45 | found that it compiled and installed a lot of things I wouldn't be | ||
| 46 | using (particularly in /usr) even after disabling almost all of the | ||
| 47 | third-party packages. | ||
| 48 | |||
| 49 | I've uploaded the config file and the resulting rootfs for | ||
| 50 | buildroot 2021.05. The root password by default is changeme. | ||
| 51 | EDIT 2022-10-21: gone, build it yourself | ||
| 52 | |||
| 53 | Of course the rootfs I got from buildroot nor me making the official | ||
| 54 | firmware smaller is the point of this article, and the actual point is | ||
| 55 | making one yourself! (or rather what I did to make my own) | ||
| 56 | |||
| 57 | ## Cross-toolchain | ||
| 58 | For now as of July 22, 2021, I'm using my distro (Void Linux)'s | ||
| 59 | packaged cross toolchain for armhf musl, but eventually I would be | ||
| 60 | using my own. | ||
| 61 | |||
| 62 | I'm not compiling off of the device itself as it would be somewhat slow | ||
| 63 | for bigger programs, which is currently primarily the Linux kernel, | ||
| 64 | U-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 | ||
| 66 | the development tools and headers would also take up more space on the | ||
| 67 | device itself, and since the terminal can currently only be accessed | ||
| 68 | through it's serial/uart pins, I don't think it's ideal. | ||
| 69 | |||
| 70 | TODO: include steps to create own toolchain (probably based off of gcc | ||
| 71 | 4.7.3 as that doesn't require c++) | ||
| 72 | |||
| 73 | ## Building the rootfs | ||
| 74 | Assuming you made a new filesystem on your rootfs's partition, it'll | ||
| 75 | likely be empty with no directories you'd expect to find on a regular | ||
| 76 | distro. So you'll just have to make them. | ||
| 77 | cd /path/to/rootfs | ||
| 78 | mkdir bin dev etc proc sbin | ||
| 79 | |||
| 80 | Your binaries would usually go in /bin, the uSD card, ttymxc0, and | ||
| 81 | other devices would go in /dev, felker init's default program/script to | ||
| 82 | execute is usually in /etc/rc, /proc is optional but I have it mounted | ||
| 83 | to see what is currently mounted through /proc/mounts (or mount(1) | ||
| 84 | without 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 | ||
| 86 | path the kernel looks at. | ||
| 87 | |||
| 88 | ## toybox | ||
| 89 | Now on to the main part of the distro, the userspace. I intend to keep | ||
| 90 | it fairly minimal so I've chosen to use toybox along with a slightly | ||
| 91 | modified version of felker (musl dev)'s init[2], as well as dash[3] as | ||
| 92 | the main shell since toybox doesn't include one as of 0.8.5 (though | ||
| 93 | it'll probably be there by 1.0). I'll also be statically linking all | ||
| 94 | the programs that'll be used so I wouldn't have to worry about shared | ||
| 95 | libraries not being included/copied over, and also including LTO for | ||
| 96 | slightly faster binaries. Originally, I tried going with sinit, sbase, | ||
| 97 | and ubase but I was having trouble getting serial terminal access with | ||
| 98 | getty to /dev/ttymxc0 (the default serial tty, at least with the | ||
| 99 | vendor kernel). I didn't have this problem with busybox's and toybox's | ||
| 100 | getty however. My config for toybox was also about 81K smaller than my | ||
| 101 | trimmed sbase-box and ubase-box (352K compared to 267K+166K) where I | ||
| 102 | removed programs that I won't use from ${BIN} in their respective | ||
| 103 | Makefiles. | ||
| 104 | EDIT 2022-10-21: also gone | ||
| 105 | |||
| 106 | First I suggest exporting some environment variables to set the | ||
| 107 | toolchain 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 | |||
| 115 | To compile toybox, get the source from | ||
| 116 | https://landley.net/toybox/downloads/ (or clone the upstream repo). | ||
| 117 | Then run make menuconfig (optionally with make defconfig before it) and | ||
| 118 | change it as you see fit. Personally, I disabled most of the programs I | ||
| 119 | wouldn't use and kept only the ones that'll help with fixing a problem. | ||
| 120 | Finally, make sure to run make. | ||
| 121 | |||
| 122 | make defconfig | ||
| 123 | make menuconfig | ||
| 124 | make | ||
| 125 | |||
| 126 | To move it to your rootfs and set it's symlinks, you could probably run | ||
| 127 | make install after setting PREFIX to your rootfs's /bin directory, but | ||
| 128 | I 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 | ||
| 141 | Also as of toybox 0.8.5, a shell still isn't included (probably would | ||
| 142 | be included by 1.0 according to scripts/install.sh as well as a few | ||
| 143 | other programs like gzip), so a separate shell would need to be built. | ||
| 144 | Any can be used but dash would be shown as an example as I was able to | ||
| 145 | get a static binary without too much trouble. | ||
| 146 | |||
| 147 | First obtain the source[3] and cd into its | ||
| 148 | untarred directory. Assuming your CC and CFLAGS are set, you can run | ||
| 149 | these steps: | ||
| 150 | |||
| 151 | autoreconf -fiv | ||
| 152 | ./configure --host=$CROSS_COMPILE --with-libedit | ||
| 153 | make | ||
| 154 | ${CROSS_COMPILE}strip src/dash | ||
| 155 | |||
| 156 | As this is going to be used as the main shell, I've decided to just | ||
| 157 | copy it to /bin/sh in the rootfs directory, though copying it there but | ||
| 158 | as /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 | ||
| 167 | The init is just a single file that you can get from felker's site[2] | ||
| 168 | or the gist on github[7]. I haven't had a good experience with the | ||
| 169 | default startup program (/etc/rc) as a shell script with execve() run | ||
| 170 | on it so I'd change it to execvp() and remove the third (specifies | ||
| 171 | environment). To compile and install the init, all you need to do is | ||
| 172 | run: | ||
| 173 | |||
| 174 | $CC $CFLAGS -o init init.c | ||
| 175 | cp init /path/to/rootfs/sbin | ||
| 176 | |||
| 177 | Instead of /etc/rc being a shell script, you can also make a C program | ||
| 178 | that does whatever you think is needed for a proper startup. I'll still | ||
| 179 | use a shell script though which is linked here. | ||
| 180 | EDIT 2022-10-21: you get the idea, it's gone. | ||
| 181 | |||
| 182 | ## /etc/passwd | ||
| 183 | Copying the rootfs's contents to your device's/uSD card's root | ||
| 184 | partition and then turning the device on should now work with a login | ||
| 185 | prompt shown in the serial terminal. However, you probably wouldn't be | ||
| 186 | able 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 | ||
| 188 | this, 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 | |||
| 193 | With the passwd file created/updated, you should now be able to login | ||
| 194 | to root after the rootfs is copied to your uSD card. Your rootfs so far | ||
| 195 | should now be around 550-560K, which is much much smaller than the | ||
| 196 | original firmware's, though it'll likely be much larger to maybe a few | ||
| 197 | megabytes once a proper reader software is added. | ||
| 198 | |||
| 199 | ## Custom Linux Kernel | ||
| 200 | WARNING: I haven't actually gotten the kernel to load in u-boot yet. It | ||
| 201 | just hangs in the "Starting kernel ..." step and the init doesn't get | ||
| 202 | loaded, so I'm assuming the kernel itself isn't either. If anyone out | ||
| 203 | there has gotten a custom kernel working in the Kobo Clara HD, please | ||
| 204 | send me an email or message on xmpp. | ||
| 205 | |||
| 206 | UPDATE Jul 28, 2021: Gave up on it as I just couldn't get any kernels I | ||
| 207 | built (both vendor and akemnade's mainline) to boot. But neither did | ||
| 208 | postmarketOS boot beyond the initial initramfs messages without the log | ||
| 209 | file being created. So I'll revisit this for later. | ||
| 210 | |||
| 211 | EDIT 2022-10-21: I have gotten this working, but have been unable to | ||
| 212 | get Plato build for musl, so I will have to either continue fighting | ||
| 213 | with the crab or create my own with fbink, as that still works. | ||
| 214 | Separate article on this later. | ||
| 215 | |||
| 216 | My next big step is compiling my own kernel for the Clara HD. With the | ||
| 217 | default configuration built for the vendor kernel, it appears to be | ||
| 218 | about 3M, so my goal is to build a kernel that is smaller than that | ||
| 219 | while retaining only the functionality that I need. I'm also not going | ||
| 220 | to include networking support as that is unneeded for my purposes, but | ||
| 221 | I suggest just keeping it if you're unsure. The wifi driver for the | ||
| 222 | Kobo Clara HD is available as an out-of-tree driver[8]. | ||
| 223 | |||
| 224 | You should first obtain the kernel source, with two main options, the | ||
| 225 | vendor kernel[9] and the mainline kernel (with akemnade's | ||
| 226 | patches)[10]. For the latter, you need to clone the repo and switch to | ||
| 227 | the latest kobo/drm-merged branch (kobo/merged-5.13 as of July 25, | ||
| 228 | 2021). | ||
| 229 | |||
| 230 | After you've got them and assuming the CROSS_COMPILE and ARCH | ||
| 231 | environment variables are set, you'd want to configure the kernel. | ||
| 232 | |||
| 233 | I had a hard time compiling the vendor kernel with many things | ||
| 234 | disabled, so I've kept my config somewhat similar to the default | ||
| 235 | config. The config I used is available here (EDIT: dead). | ||
| 236 | |||
| 237 | make menuconfig | ||
| 238 | make zImage | ||
| 239 | |||
| 240 | Assuming it compiles properly and arch/arm/boot/zImage exists, all | ||
| 241 | that's needed to is to write it to your uSD card at the 1M offset. | ||
| 242 | dd if=/path/to/kernel/zImage of=/path/to/uSDdev bs=512 seek=2048 | ||
| 243 | |||
| 244 | ## Custom U-Boot | ||
| 245 | I have not done this yet, nor really plan to, but if you do manage to | ||
| 246 | compile the Kobo's vendored u-boot source, then all you'd have to do to | ||
| 247 | install it is: | ||
| 248 | |||
| 249 | dd if=u-boot-file of=/dev/mmcblk0 bs=128k count=1 seek=6 | ||
| 250 | |||
| 251 | If I remember correctly, this command was included in an older | ||
| 252 | firmware's startup script/rcS for updating udev, and it should still | ||
| 253 | work. | ||
| 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 | +++ | ||
| 2 | title = 'Kobo Clara HD Notes for Nickel' | ||
| 3 | date = 2021-01-13 | ||
| 4 | draft = false | ||
| 5 | layout = "post" | ||
| 6 | +++ | ||
| 7 | |||
| 8 | My ereader of choice is the Kobo Clara HD and I particularly like it | ||
| 9 | because my eyes hurt less when reading for long periods of time | ||
| 10 | compared to when I read on my phone or when I still had my iPad. It | ||
| 11 | also had much longer battery life and only need to charge it about once | ||
| 12 | every two weeks when I read for about 4 hours on average daily. | ||
| 13 | |||
| 14 | However, the two notable things I don't like about it is it's included | ||
| 15 | telemetry, like using Google Analytics by default and keeping a unique | ||
| 16 | salt | ||
| 17 | |||
| 18 | Spyware/Anti-Features: | ||
| 19 | - Google Analytics (a lot of actions, if not everything, is sent to | ||
| 20 | Google) | ||
| 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 | |||
| 26 | I'm also assuming your Kobo reader and it's SD card's device file would | ||
| 27 | be would located at `/dev/sdf` and be mounted at `/mnt/kobo`. | ||
| 28 | |||
| 29 | If you're going to not be using Nickel and instead be using something | ||
| 30 | like [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 | ||
| 32 | though k/fmon because I don't want to load Nickel if I'm already using | ||
| 33 | a different reader. | ||
| 34 | |||
| 35 | ## Upgrade/Backup Included SD Card | ||
| 36 | While the included 8GB microSD card is decent for storing your ebook | ||
| 37 | library that may not have a lot of images, that would likely not be | ||
| 38 | enough if you were aiming to read some comics on your ereader as they | ||
| 39 | can be pretty big (quite a few of mine are over a gigabyte, with some | ||
| 40 | over. Luckily, you can replace the microSD card with another one. | ||
| 41 | |||
| 42 | Before upgrading, you should backup the SD card to into an image file | ||
| 43 | so the filesystem would be preserved when putting the contents of the | ||
| 44 | image on the new SD card. I'm using the command dd but there might be | ||
| 45 | another program doing the same thing. Even if you're not going to | ||
| 46 | upgrade, I still suggest to backup the SD card in case something goes | ||
| 47 | wrong. | ||
| 48 | ```sh | ||
| 49 | dd if=/dev/sdf of=kobo_sd.img conv=sync | ||
| 50 | ``` | ||
| 51 | |||
| 52 | After this is done, you can plug in your new SD card and reimage | ||
| 53 | kobo_sd.img onto it. With dd, you can do something like: | ||
| 54 | ```sh | ||
| 55 | dd if=kobo_sd.img of=/dev/sdf conv=sync | ||
| 56 | ``` | ||
| 57 | |||
| 58 | Checking it's partition table via lsblk or fdisk -l should show three | ||
| 59 | partitions. If you replaced the SD card with something bigger, than you | ||
| 60 | should resize the third partition. | ||
| 61 | |||
| 62 | ## Bypassing Registration On Setup | ||
| 63 | When setting up your Kobo, you will be asked to sign into a Kobo | ||
| 64 | account. There are other options like logging in via Google, Walmart, | ||
| 65 | and other stores, but I don't like having to login to a device that | ||
| 66 | would likely not be connected to the public internet. Fortunately, you | ||
| 67 | can bypass this by choosing that you cannot connect to a Wi-Fi network | ||
| 68 | and mount your Kobo to your computer. In, `.kobo/KoboReader.sqlite`, you | ||
| 69 | can run: | ||
| 70 | ```sh | ||
| 71 | echo "INSERT INTO user(UserID,UserKey) VALUES('1','');" \ | ||
| 72 | | sqlite3 KoboReader.sqlite | ||
| 73 | ``` | ||
| 74 | |||
| 75 | This way you don't have to install their application just to be able to | ||
| 76 | use your device. | ||
| 77 | |||
| 78 | Note: Do not try doing this when you still have your SD card mounted | ||
| 79 | before you setup your device. The device's screen would likely not | ||
| 80 | update, at least on an early firmware version like v4.7.10733. | ||
| 81 | |||
| 82 | ## Blocking Google Analytics and other Telemetry | ||
| 83 | Just adding 0.0.0.0 analytics.google.com to `/etc/hosts` may be enough to | ||
| 84 | block most of the telemetry from being sent. However, you can try | ||
| 85 | intercepting what connections your Kobo is making via mitmproxy set to | ||
| 86 | transparent mode or using a hosts file that blocks all connections to | ||
| 87 | Google (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). | ||
| 89 | EDIT 2022-10-21: Baobab has deleted his account from Codeberg for quite a | ||
| 90 | while, so these two links are dead. Instead, I now recommend [Steven Black's](https://github.com/StevenBlack/hosts) | ||
| 91 | instead [(raw)](https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts). | ||
| 92 | |||
| 93 | To put the hosts file without root (which will be detailed in another | ||
| 94 | section), you can make a directory called etc, put the hosts file in | ||
| 95 | there, and tar it into a file called KoboRoot.tgz. | ||
| 96 | ```sh | ||
| 97 | mkdir etc | ||
| 98 | wget -O etc/hosts https://codeberg.org/baobab/hosts/raw/branch/master/hosts | ||
| 99 | tar czvf KoboRoot.tgz etc | ||
| 100 | cp KoboRoot.tgz /mnt/kobo/.kobo/ | ||
| 101 | ``` | ||
| 102 | |||
| 103 | When you move a tar file with that name into your Kobo's .kobo folder, | ||
| 104 | it's contents gets untarred into it's root at `/` when the device is | ||
| 105 | turned on again, which is usually done for their updates but can be | ||
| 106 | used for custom files like this and gaining root access. | ||
| 107 | |||
| 108 | ## Gaining Root Access via Telnet | ||
| 109 | To 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 | ||
| 111 | partition into your computer (the second partition seems to be like a | ||
| 112 | backup). You should copy those two files into a folder called etc | ||
| 113 | somewhere (probably not on the SD card). | ||
| 114 | |||
| 115 | In 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 | |||
| 121 | You 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 | ||
| 123 | when editing that, you should add: | ||
| 124 | ``` | ||
| 125 | 23 stream tcp nowait root /bin/busybox telnetd -i | ||
| 126 | ``` | ||
| 127 | |||
| 128 | However, if there is already a commented line for root telnet in the | ||
| 129 | inetd2.conf, you should probably still add the above line and ignore | ||
| 130 | the commented line as that may or may not work (didn't for me). | ||
| 131 | |||
| 132 | To actually start inetd, you should add these lines somewhere in | ||
| 133 | `/etc/custominit.sh`: | ||
| 134 | ```sh | ||
| 135 | mkdir -p /dev/pts | ||
| 136 | mount -t devpts devpts /dev/pts | ||
| 137 | /usr/sbin/inetd /etc/inetd2.conf | ||
| 138 | ``` | ||
| 139 | |||
| 140 | After that, you just have to tar the `etc/` folder again and copy it to | ||
| 141 | your Kobo's onboard/third partition's `.kobo` folder. | ||
| 142 | ```sh | ||
| 143 | tar czvf KoboRoot.tgz etc | ||
| 144 | cp KoboRoot.tgz /mnt/kobo/.kobo/ | ||
| 145 | ``` | ||
| 146 | |||
| 147 | Now you could put your SD card back into your Kobo provided that they | ||
| 148 | are already unmounted and turn your Kobo back on. | ||
| 149 | |||
| 150 | After connecting to the WiFi, simplying telnetting (?) into your Kobo | ||
| 151 | and logging in as root should give you a root shell. :D | ||
| 152 | ```sh | ||
| 153 | telnet $KOBO_IP | ||
| 154 | ``` | ||
| 155 | |||
| 156 | By default, root has no password so you should change it with passwd. | ||
| 157 | |||
| 158 | ## Getting SSH and SFTP access via Dropbear | ||
| 159 | I'm using Dropbear instead of OpenSSH because it's better suited for | ||
| 160 | embedded hardware like the Kobo Clara HD. Obviously we can't copy a | ||
| 161 | binary compiled for amd64 or whatever architecture your compiling | ||
| 162 | computer is running so we would have to cross-compile for our ereader. | ||
| 163 | |||
| 164 | Fortunately, we are not required to cross-compile `gcc`/`clang` and friends | ||
| 165 | as we can simply download the linaro arm toolchain which has the | ||
| 166 | binaries 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 | |||
| 169 | architecture. After untarring the file, you should also set your PATH | ||
| 170 | variable to the toolchain's `bin/` folder so you don't have to manually | ||
| 171 | set the CC and CXX variables when building Dropbear. | ||
| 172 | |||
| 173 | ```sh | ||
| 174 | wget 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 | ||
| 175 | tar xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz | ||
| 176 | export PATH=$(pwd)/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH | ||
| 177 | ``` | ||
| 178 | |||
| 179 | Now you could get the source for Dropbear and cross-compile it. The | ||
| 180 | source 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 | ||
| 182 | wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2020.81.tar.bz2 | ||
| 183 | tar xvf dropbear-2020.81.tar.bz2 | ||
| 184 | cd 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 | ||
| 187 | make MULTI=1 PROGRAMS="dropbear dropbearkey" | ||
| 188 | ``` | ||
| 189 | |||
| 190 | Now you only need to copy the dropbearmulti binary over to your Kobo. | ||
| 191 | What I've done is running `python3 -m http.server` and downloading the | ||
| 192 | file onto my Kobo but you could also just copy it onto the microSD | ||
| 193 | card. | ||
| 194 | ```sh | ||
| 195 | wget your.computer.ip:8000/dropbearmulti | ||
| 196 | chmod +x dropbearmulti | ||
| 197 | mv dropbearmulti /usr/bin | ||
| 198 | cd /usr/bin | ||
| 199 | # below are optional but dropbear(key) would be an argument for dropbearmulti | ||
| 200 | ln -s dropbearmulti dropbear | ||
| 201 | ln -s dropbearmulti dropbearkey | ||
| 202 | ``` | ||
| 203 | |||
| 204 | Now you only need to generate the host keys. My client key is ed25519 | ||
| 205 | so I'm not going to generate the others. | ||
| 206 | ```sh | ||
| 207 | mkdir /etc/dropbear | ||
| 208 | dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key | ||
| 209 | dropbear -F -r /etc/dropbear/dropbear_ed25519_key | ||
| 210 | ``` | ||
| 211 | |||
| 212 | Now 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 | ||
| 214 | copying your public key to your Kobo via `ssh-copy-id` so you don't have | ||
| 215 | to enter root's password all the time and so password-based logins can | ||
| 216 | be disabled in dropbear. | ||
| 217 | |||
| 218 | To start it on boot, you could add the following line to | ||
| 219 | `/etc/inetd2.conf`: | ||
| 220 | ``` | ||
| 221 | 22 stream tcp nowait root /usr/bin/dropbearmulti dropbear -i -r /etc/dropbear/dropbear_ed25519_key | ||
| 222 | ``` | ||
| 223 | |||
| 224 | For some reason, the symlink wasn't resolving for me inetd so I had to | ||
| 225 | call the multi-binary directly. You could also add the command/args | ||
| 226 | into `/etc/custominit.sh`. | ||
| 227 | |||
| 228 | ## FTP Access | ||
| 229 | If you don't or can't use sftp or scp for some reason, there's always ftp :D | ||
| 230 | There's a ftp daemon included in busybox so all we have to do is enable it | ||
| 231 | in `/etc/inetd2.conf`: | ||
| 232 | ``` | ||
| 233 | 21 stream tcp nowait root /bin/busybox ftpd -w -S / | ||
| 234 | ``` | ||
| 235 | |||
| 236 | This would share the entire filesystem so you may or may not want to | ||
| 237 | restrict the shared directory to maybe just your ebook directory | ||
| 238 | (`/mnt/onboard`) and move the files out via `telnet` or `ssh`. | ||
| 239 | EDIT 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 | +++ | ||
| 2 | title = "Kobo Clara HD Notes for Plato (and KSM)" | ||
| 3 | date = 2021-03-27 | ||
| 4 | +++ | ||
| 5 | |||
| 6 | These are my notes for getting Plato on the Kobo Clara HD from scratch | ||
| 7 | as well as some notes for getting KSM to work, but I now boot directly | ||
| 8 | into Plato instead of through KSM. | ||
| 9 | |||
| 10 | Previously, I didn't really like using KOReader because it was kind of | ||
| 11 | slow and was written in Lua. At the time of using Plato, it seemed nice | ||
| 12 | but it didn't cover thumbnails for books, which while it is a minor | ||
| 13 | detail, I find books easier to be recognized with a cover thumbnail in | ||
| 14 | addition to their title. This was added in release 0.9.10 but as an | ||
| 15 | optional feature which I didn't somehow see until recently when I | ||
| 16 | retried it. HOWEVER again, I didn't like using k/fmon as I had to still | ||
| 17 | use Nickel to get back into KOReader/Plato/whatever alternate reader | ||
| 18 | when I wanted to go away from using Nickel. | ||
| 19 | |||
| 20 | <ignore> | ||
| 21 | That was when I found out about KSM and how there was a working version | ||
| 22 | for the Clara HD. KSM is like an alternate bootloader for the Kobo | ||
| 23 | readers and it apparently doesn't work very well with newer models like | ||
| 24 | the 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 | ||
| 26 | 10 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. | ||
| 32 | from the PBS Kids cartoon Arthur on Mar. 26, 2021 when I saw that it | ||
| 33 | can be used on my Kobo | ||
| 34 | |||
| 35 | The latest firmware version that KSM sort of supports is v4.25.15875 | ||
| 36 | but it can probably work with a newer version like v4.26+ that would | ||
| 37 | likely only need a couple changes to /etc/init.d/rcS, if any changes | ||
| 38 | were needed at all. I'll be using v4.26 for the rest of this | ||
| 39 | article/guide. | ||
| 40 | </ignore> | ||
| 41 | |||
| 42 | Recently, after seeing how my Kobo boots into KSM and Nickel through | ||
| 43 | the rcS file, I realized that I could've instead just booted directly | ||
| 44 | into Plato, and plato.sh (the script that runs Plato) has a standalone | ||
| 45 | option that supports just that! The KSM notes are still going to be | ||
| 46 | here in case someone still wants to use KSM. | ||
| 47 | |||
| 48 | ## Installing Plato (or probably any other reader like KOReader) | ||
| 49 | This part probably applies to any other reader other than Plato like | ||
| 50 | KOReader 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 | ||
| 52 | a folder called plato in /path/to/kobo/mount/.adds, the latter folder | ||
| 53 | of which should have already been created by KSM if you are using that. | ||
| 54 | If you are using KSM, there should be a new option below "start nickel" | ||
| 55 | called "start plato" when you have rebooted the device. Read below if | ||
| 56 | you aren't using KSM. | ||
| 57 | |||
| 58 | ## Loading Plato on Boot | ||
| 59 | Since I don't want to load Nickel only to load into another reader like | ||
| 60 | the recommended options in Plato's forum thread (kfmon, fmon, and | ||
| 61 | NickelMenu) suggest, I noticed that I could have booted into Plato | ||
| 62 | directly. The only requirements for doing this having access to the | ||
| 63 | rootfs, so either through a telnet/ssh session, or having the sd card's | ||
| 64 | root/first partition mounted to your computer, or just ftp/rsyncing the | ||
| 65 | files to your Kobo. | ||
| 66 | |||
| 67 | First I suggest making a copy of rcS if you haven't already in case an | ||
| 68 | update overwrites it. My copy is named custominit.sh. Next you'll want | ||
| 69 | the 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 | |||
| 77 | The rest of the lines don't need to change. Then you should open | ||
| 78 | custominit.sh in your favourite editor to add the lines at the bottom | ||
| 79 | but before hindenburg is executed: | ||
| 80 | |||
| 81 | ``` | ||
| 82 | cd /mnt/onboard/.adds/plato # or whereever Plato is | ||
| 83 | PLATO_STANDALONE=1 ./plato.sh | ||
| 84 | ``` | ||
| 85 | |||
| 86 | You would probably also want to remove the lines where Nickel-specific | ||
| 87 | programs/scripts are running like nickel, hindenburg, pickel, sickel, | ||
| 88 | etc. | ||
| 89 | |||
| 90 | Now on subsequent boots, Plato should automatically have been loaded. | ||
| 91 | Boot times may also be slightly faster! :D | ||
| 92 | |||
| 93 | ## Installing KSM 09 (not doing anymore) | ||
| 94 | First 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 | ||
| 96 | with separate filenames so they don't replace each other and we would | ||
| 97 | untar those into the same directory. After that, we would cd into the | ||
| 98 | directory and tar it's contents into a new KoboRoot.tgz and place it in | ||
| 99 | /path/to/kobo/mount/.kobo/. | ||
| 100 | |||
| 101 | An example of what I did after downloading and unzipping the files are | ||
| 102 | below: | ||
| 103 | |||
| 104 | ``` | ||
| 105 | mkdir koboroot | ||
| 106 | tar -xvf KoboRoot-main.tgz -C koboroot | ||
| 107 | tar -xvf KoboRoot-v4.25-darkmodefix.tgz -C koboroot | ||
| 108 | cd koboroot | ||
| 109 | tar -czvf ../KoboRoot.tgz . | ||
| 110 | cd .. | ||
| 111 | rm -r koboroot | ||
| 112 | ``` | ||
| 113 | |||
| 114 | After your Kobo untars it and you wait a while, you should be presented | ||
| 115 | with KSM's main screen :D ksm09's main screen running on the kobo clara | ||
| 116 | hd | ||
| 117 | |||
| 118 | ## Auto-Boot into Plato instead of Nickel via KSM (not doing anymore) | ||
| 119 | First make sure USB support is enabled in KSM and then mount your Kobo | ||
| 120 | to your computer. Once mounted, go to | ||
| 121 | /path/to/kobo/mount/.adds/kbmenu_user/confoptions and edit | ||
| 122 | ksm_ini_options.txt in your favourite editor. You should see many | ||
| 123 | options that are listed but the one that we're interested in is | ||
| 124 | ksmAutoselectoption which may have start_nickel and start_koreader | ||
| 125 | already and what we want to do is add ksmAutoselectoption=start_plato. | ||
| 126 | After a quick restart to reload the options file, you should be able to | ||
| 127 | see the new option in KSM's settings under [general] and add item if it | ||
| 128 | wasn't already added. Now Plato should auto-boot on subsequent | ||
| 129 | powerons. | ||
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 | +++ | ||
| 2 | title = "Fixing bitmap font fallbacks in the st terminal" | ||
| 3 | date = 2023-11-24 | ||
| 4 | draft = false | ||
| 5 | +++ | ||
| 6 | tldr, change FC_SCALABLE in x.c from 1 to 0. (comes from the font2 patch) | ||
| 7 | |||
| 8 | For some context, I have been using xterm for a long while when I'm on OpenBSD | ||
| 9 | since it is included by default in Xenocara with Terminus as my default font, | ||
| 10 | and the main reason why I did not use st again was that my bitmap fallback font | ||
| 11 | for CJK was not loading. Instead, I get an ugly sans-serif scaled font that | ||
| 12 | looked very out of place in my otherwise clean and crisp bitmap terminal. | ||
| 13 | |||
| 14 | Yes, I did make sure that the font2 patch for st was applied correctly. | ||
| 15 | |||
| 16 | The X11 font string for reference is Fixed: | ||
| 17 | -misc-fixed-medium-r-normal-ja-18-120-100-100-c-180-iso10646-1 | ||
| 18 | |||
| 19 | It also didn't help that fontconfig was unable to find the font either no | ||
| 20 | matter how much I looked for it with fc-list and fc-match. The weirder thing is | ||
| 21 | that when I installed GNU Unifont to my fonts directory, fontconfig was able to | ||
| 22 | find it and st loaded it (I put a printf in the xloadfonts() function in x.c), | ||
| 23 | but the same old ugly scaled font was still being shown for CJK. The weirderer | ||
| 24 | thing was that Unifont was rendering just fine when being used as the main font | ||
| 25 | instead of in font2. | ||
| 26 | |||
| 27 | I thought to myself why this was happening and wasn't able to find out, until I | ||
| 28 | reread the font loading portion in x.c's xloadsparefonts() function that came | ||
| 29 | part of the font2 patch. | ||
| 30 | |||
| 31 | It had set the FC_SCALABLE boolean to 1 (true). That explained why the fallback | ||
| 32 | font rendered fine as the main font and not fallback. Setting that boolean to | ||
| 33 | 0 (false) fixed my fallback font not matching issue, and now I have clean and | ||
| 34 | crisp looking text that I can read more easily. | ||
| 35 | |||
| 36 | I already disliked fontconfig, freetype, xft, and friends (don't get me started | ||
| 37 | on 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 | +++ | ||
| 2 | title = "Creating a Temporary File Hoster" | ||
| 3 | date = 2022-04-27 | ||
| 4 | draft = false | ||
| 5 | +++ | ||
| 6 | For the past couple years, whenever I wanted to upload a file, I would | ||
| 7 | curl 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 | |||
| 9 | Since I want to selfhost, I thought i can just use either of what those | ||
| 10 | three used. Earlier today though, I realized I could just copy the | ||
| 11 | file(s) I want to upload via rsync/scp to a public directory that gets | ||
| 12 | served by an httpd or gopherd. | ||
| 13 | |||
| 14 | From what I understand, the previous file hosters had a program running | ||
| 15 | that read the file that the user uploads to them, does some renaming, | ||
| 16 | and writes that to a directory that is served. After some time, that | ||
| 17 | file is deleted. The first part can be handled via rsync/scp like | ||
| 18 | mentioned previously. For automatic deletion, I recently saw in find's | ||
| 19 | man page that it can list that haven't been modified via the -mtime | ||
| 20 | flag, so that can be used with a cron job. | ||
| 21 | |||
| 22 | But while thinking of this idea, I got stumped by how to print back the | ||
| 23 | url to this file that is uploaded since printing the filename as is | ||
| 24 | appended to its baseurl, there could be spaces and other invalid | ||
| 25 | unescaped characters which programs trying to download it may not like. | ||
| 26 | |||
| 27 | I thought I could just create a separate program for this. However, | ||
| 28 | doing this seemed more complicated than just copying the file to the | ||
| 29 | server. So, with the help of awk and some StackExchanging, I've been | ||
| 30 | able to do it. | ||
| 31 | |||
| 32 | `upfile.sh`: | ||
| 33 | ```sh | ||
| 34 | #!/bin/sh | ||
| 35 | urlencode() { | ||
| 36 | awk ' | ||
| 37 | BEGIN { 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 | |||
| 48 | FILE="$1" | ||
| 49 | SERVER="REPLACEME" | ||
| 50 | BASEURL="https://u.$SERVER" | ||
| 51 | |||
| 52 | [ -z "$1" ] && exit 1 | ||
| 53 | |||
| 54 | scp "$FILE" "$SERVER":files/ || exit 1 | ||
| 55 | printf "%s/" "$BASEURL" | ||
| 56 | basename "$FILE" | urlencode | ||
| 57 | ``` | ||
| 58 | |||
| 59 | Then to purge these files after they become too old (e.g. 3 days), you | ||
| 60 | can put something like this in a cron job to run daily (replace file | ||
| 61 | directory): | ||
| 62 | |||
| 63 | ``` | ||
| 64 | 0 0 * * * find /path/to/dir/ -mtime +3 -exec rm {} \; | ||
| 65 | ``` | ||
| 66 | |||
| 67 | You can also put this command in /etc/daily.local or /etc/cron/daily, | ||
| 68 | or whatever file your root crontab's @daily runs (if there is one). | ||
| 69 | |||
| 70 | And that's it! The only difficult part that I experienced was encoding | ||
| 71 | the name of the file and originally did that in C. However, having a | ||
| 72 | mixed C and shell program just for file uploading didn't sit right with | ||
| 73 | me. 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 | +++ | ||
| 2 | title = "VFIO Install Notes" | ||
| 3 | date = 2020-10-17 | ||
| 4 | draft = false | ||
| 5 | +++ | ||
| 6 | You 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 | ||
| 10 | Enable VT-d and VT-x (or AMD equivalent) | ||
| 11 | |||
| 12 | ## Kernel Config | ||
| 13 | Enable KVM and VFIO | ||
| 14 | > you can set VFIO as builtin but as a module is more flexible | ||
| 15 | Also add `"iommu=pt intel_iommu=on"` to your kernel command line (or in CONFIG\_CMDLINE) | ||
| 16 | |||
| 17 | ### Current Options | ||
| 18 | ``` | ||
| 19 | ... | ||
| 20 | CONFIG_IOMMU_IOVA=y | ||
| 21 | CONFIG_IOMMU_API=y | ||
| 22 | CONFIG_IOMMU_SUPPORT=y | ||
| 23 | CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y | ||
| 24 | # use the respective AMD options if using an AMD CPU | ||
| 25 | CONFIG_INTEL_IOMMU=y | ||
| 26 | CONFIG_INTEL_IOMMU_SVM=y | ||
| 27 | CONFIG_INTEL_IOMMU_DEFAULT_ON=y | ||
| 28 | CONFIG_INTEL_IOMMU_FLOPPY_WA=y | ||
| 29 | |||
| 30 | CONFIG_KVM_VFIO=y | ||
| 31 | CONFIG_VFIO_IOMMU_TYPE1=m | ||
| 32 | CONFIG_VFIO_VIRQFD=m | ||
| 33 | CONFIG_VFIO=m | ||
| 34 | CONFIG_VFIO_PCI=m | ||
| 35 | CONFIG_VFIO_PCI_VGA=y | ||
| 36 | CONFIG_VFIO_PCI_MMAP=y | ||
| 37 | CONFIG_VFIO_PCI_INTX=y | ||
| 38 | CONFIG_VFIO_PCI_IGD=y | ||
| 39 | CONFIG_VFIO_MDEV=m | ||
| 40 | CONFIG_VFIO_MDEV_DEVICE=m | ||
| 41 | ... | ||
| 42 | ``` | ||
| 43 | |||
| 44 | ## Packages Required | ||
| 45 | ``` | ||
| 46 | app-emulation/qemu (actual program) | ||
| 47 | sys-firmware/edk2-ovmf (UEFI firmware for Nvidia GPU) | ||
| 48 | media-sound/scream (audio) | ||
| 49 | looking-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 | ||
| 53 | but 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 | ``` | ||
| 59 | app-emulation/qemu gtk opengl sdl sdl-image usb # (spice, ssh, vhost-user-fs, virgl, and virtfs are optional I think) | ||
| 60 | media-libs/libsdl2 X gles opengl # for Looking Glass | ||
| 61 | ``` | ||
| 62 | note to self (2020-10-17): check how minimal you can make qemu to run vfio | ||
| 63 | |||
| 64 | # IOMMU | ||
| 65 | Run `dmesg | grep -E 'DMAR'` and see if `DMAR: IOMMU enabled` or something similar is in output | ||
| 66 | |||
| 67 | # QEMU Script | ||
| 68 | All code blocks in this section go in the qemu script file unless specified otherwise | ||
| 69 | |||
| 70 | ## Environment Variables | ||
| 71 | ```sh | ||
| 72 | IMG=/path/to/windows-image-file | ||
| 73 | VIRTIO=/path/to/virtio-iso | ||
| 74 | WINDOWS=/path/to/windows-install-iso | ||
| 75 | OVMF=/usr/share/edk2-ovmf/OVMF_CODE.fd | ||
| 76 | RAM=16G | ||
| 77 | ULIMIT=$(ulimit -l) | ||
| 78 | ULIMIT_TARGET=$(( $(echo $RAM | tr -d 'G')*1048576+100000 )) | ||
| 79 | |||
| 80 | GPU_VIDEO=01:00.0 | ||
| 81 | GPU_AUDIO=01:00.1 | ||
| 82 | VIDEOID="10de 13c0" | ||
| 83 | AUDIOID="10de 0fbb" | ||
| 84 | VIDEOBUSID="0000:${GPU_VIDEO}" | ||
| 85 | AUDIOBUSID="0000:${GPU_AUDIO}" | ||
| 86 | ``` | ||
| 87 | |||
| 88 | ## VFIO Detaching and Attaching | ||
| 89 | ```sh | ||
| 90 | vfio_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 | |||
| 113 | vfio_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 | ||
| 125 | net_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 | |||
| 145 | net_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 | |||
| 158 | Also 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 | ... | ||
| 162 | tuntap_tap0="tap" | ||
| 163 | config_tap0="null" | ||
| 164 | bridge_br0="enp0s31f6 tap0" | ||
| 165 | |||
| 166 | config_br0="192.168.123.2 netmask 255.255.255.0" | ||
| 167 | routes_br0="default via 192.168.123.1" | ||
| 168 | bridge_forward_delay_br0=0 | ||
| 169 | bridge_hello_time_br0=10 | ||
| 170 | |||
| 171 | depend_br0() { | ||
| 172 | need net.enp0s31f6 | ||
| 173 | need net.tap0 | ||
| 174 | } | ||
| 175 | ... | ||
| 176 | ``` | ||
| 177 | |||
| 178 | ## Hugepages | ||
| 179 | ```sh | ||
| 180 | hugepages_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 | |||
| 187 | hugepages_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 | ||
| 196 | ulimit -l $ULIMIT_TARGET | ||
| 197 | |||
| 198 | qemu-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 | |||
| 215 | ulimit -l $ULIMIT | ||
| 216 | ``` | ||
| 217 | ### After installing guest OS | ||
| 218 | ```sh | ||
| 219 | ulimit -l $ULIMIT_TARGET | ||
| 220 | |||
| 221 | qemu-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 | |||
| 246 | ulimit -l $ULIMIT | ||
| 247 | ``` | ||
| 248 | |||
| 249 | # Extra | ||
| 250 | ## Adding USB Devices | ||
| 251 | Get 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 | ``` | ||
| 255 | Example for my USB bluetooth receiver: | ||
| 256 | ``` | ||
| 257 | $ lsusb | ||
| 258 | ... | ||
| 259 | Bus 001 Device 004: ID 0b05:17cb ASUSTek Computer, Inc. Broadcom BCM20702A0 Bluetooth | ||
| 260 | ... | ||
| 261 | ``` | ||
| 262 | My 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 | ||
| 268 | While libvirt makes this more simple, it appears we need a script/function to do it in bare QEMU | ||
| 269 | Borrowed 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 | ||
| 273 | THREAD_LIST="0,4,1,5,2,6,3,7" | ||
| 274 | NAME="vfio-vm" | ||
| 275 | |||
| 276 | sleep 20 && | ||
| 277 | HOST_THREAD=0 | ||
| 278 | # for each vCPU thread PID | ||
| 279 | for 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}') | ||
| 280 | do | ||
| 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 | ||
| 284 | done | ||
| 285 | ``` | ||
| 286 | |||
| 287 | ## Additional Disk | ||
| 288 | You can add another disk by simply copying the arguments for adding the rootfs and slightly modifying | ||
| 289 | Example 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 | ||
| 297 | Make 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 | ||
| 303 | Make sure no virtual display like QXL is loaded too (`-nographic -vga none` in QEMU) | ||
| 304 | |||
| 305 | ## JACK Support | ||
| 306 | To 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 | ``` | ||
| 312 | You might need to change the timer-period and buffer-length if experiencing crackling. | ||
| 313 | Also you might have to change the controller (ich9-intel-hda) and codec (hda-output) to something else. | ||
| 314 | |||
| 315 | To list controller and codecs, run: | ||
| 316 | ```sh | ||
| 317 | qemu-system-x86_64 -device help | grep hda | ||
| 318 | ``` | ||
