{ fetchurl, writeText, libguestfs-with-appliance, pkgsCross, qemu, runCommand, cpio, writeShellApplication, sshPassword, sshPort, httpPort, }: let updateName = "remarkable-production-memfault-image-3.14.1.9-rm2-public"; updateArchive = fetchurl { url = # TODO: this is not an official source. might be worth authenticating the updates "https://storage.googleapis.com/remarkable-versions/${updateName}.swu"; hash = "sha256-8zlAGdv+w2KO7BruRQLQC9ivGSHtK82e36ASIeRF3zI="; }; xochitlConfig = writeText "xochitl.conf" '' [General] DeveloperPassword=${sshPassword} wifion=false WebInterfaceEnabled=true IdleSuspendDelay=0 SuspendPowerOffDelay=0 ''; usbMacAddr = "52:54:00:12:34:56"; ifnameUdevRule = writeText "70-persistent-net.rules" '' SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", \ ATTR{address}=="${usbMacAddr}", \ ATTR{type}=="1", KERNEL=="eth*", NAME="usb0" ''; usbNetworkConfig = writeText "10-usb.network" '' [Match] Name=usb* [Network] DHCP=yes ''; xochitlService = writeText "xochitl.service" '' [Unit] Description=reMarkable main application After=home.mount network.target [Service] ExecStart=/usr/bin/xochitl --system Restart=always # required to make xochitl run Environment=LD_PRELOAD=/usr/lib/libfakefbdev.so [Install] WantedBy=multi-user.target ''; fakefbdev = pkgsCross.armv7l-hf-multiplatform.gcc11Stdenv.mkDerivation { name = "fakefbdev"; src = ./fakefbdev; installFlags = [ "DESTDIR=${placeholder "out"}" ]; }; kernel = pkgsCross.armv7l-hf-multiplatform.linux_5_4; rootfsImage = runCommand "rm-rootfs.ext4" { nativeBuildInputs = [ cpio ]; } '' cpio -i --file ${updateArchive} gzip -dc ${updateName}.ext4.gz > $out ''; diskImage = runCommand "rm-disk.qcow2" { nativeBuildInputs = [ qemu libguestfs-with-appliance ]; } '' qemu-img create -f qcow2 $out 8G guestfish --rw --blocksize=512 --add $out <<EOF run # not the original partition table of the RM2 part-init /dev/sda gpt part-add /dev/sda p 2048 2099199 part-add /dev/sda p 2099200 10487807 part-add /dev/sda p 10487808 12584959 part-add /dev/sda p 12584960 16775167 mkfs vfat /dev/sda1 upload ${rootfsImage} /dev/sda2 resize2fs /dev/sda2 # we disable the orphan_file feature to avoid the error # '/dev/vda4 has unsupported feature(s): FEATURE_C12' # when e2fsck runs at boot mkfs ext4 /dev/sda4 features:^orphan_file mount /dev/sda2 / copy-in ${kernel}/lib/modules /lib download /etc/fstab fstab ! sed -i 's/mmcblk2p/vda/' fstab upload fstab /etc/fstab upload ${ifnameUdevRule} /etc/udev/rules.d/70-persistent-net.rules upload ${usbNetworkConfig} /etc/systemd/network/10-usb.network upload ${xochitlService} /lib/systemd/system/xochitl.service # delete any systemd units that hinder or delay startup rm /lib/systemd/system/kdump.service rm /lib/systemd/system/wacom_flash.service rm /lib/systemd/system/memfaultd.service rm /lib/systemd/system/swupdate.service rm /lib/systemd/system/swupdate.socket rm /etc/systemd/system/multi-user.target.wants/busybox-ifplugd@usb1.service upload ${fakefbdev}/lib/libfakefbdev.so /usr/lib/libfakefbdev.so chmod 0755 /usr/lib/libfakefbdev.so mount /dev/sda4 /home cp-a /etc/skel /home/root mkdir-p /home/root/.local/share/remarkable/xochitl mkdir-p /home/root/.config/remarkable upload ${xochitlConfig} /home/root/.config/remarkable/xochitl.conf EOF ''; in writeShellApplication { name = "reMder-server"; runtimeInputs = [ qemu ]; text = '' rm -f ./reMder.qcow2 qemu-img create -b ${diskImage} -F qcow2 -f qcow2 ./reMder.qcow2 qemu-system-aarch64 \ -machine virt \ -enable-kvm \ -cpu host,aarch64=off \ -m 2048 \ -kernel ${kernel}/zImage \ -drive if=none,file=./reMder.qcow2,format=qcow2,id=hd \ -device virtio-blk-device,drive=hd \ -netdev user,hostfwd=tcp::${toString sshPort}-:22,hostfwd=tcp::${toString httpPort}-:80,id=net \ -device virtio-net-device,netdev=net,mac=${usbMacAddr} \ -append "console=ttyAMA0 rootfstype=ext4 root=/dev/vda2 rw rootwait init=/sbin/init" \ -serial mon:stdio \ -nographic ''; }