From 956e4399bef9786e2864ad2edf4709531957c01b Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Sun, 10 Jun 2018 03:03:24 +0000 Subject: [PATCH] WIP : boots and vibrates the device as expected --- README.md | 12 ++++ bootimg.nix | 49 ++++++++++++++++ rootfs.nix | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 bootimg.nix create mode 100644 rootfs.nix diff --git a/README.md b/README.md index 38fe6e8a..f0ab9032 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,18 @@ An overlay for building stuff. This is a work-in-progress. +WIP notes +--------- + +``` +nix-build bootimg.nix +# Maybe `nix copy ./result --to ssh://another-host` +adb wait-for-device && adb reboot bootloader +fastboot boot result # or full path +# getting adb and fastboot working is left as an exercise to the reader. +``` + + Goals ----- diff --git a/bootimg.nix b/bootimg.nix new file mode 100644 index 00000000..16df7496 --- /dev/null +++ b/bootimg.nix @@ -0,0 +1,49 @@ +{ + device_name ? "asus-z00t" +}: +with (import ./overlay); + +let + # TODO : import this from device description + linux = pkgs."linux_${device_name}"; + kernel = "${linux}/Image.gz-dtb"; + dt = "${linux}/boot/dt.img"; + cmdline = "androidboot.hardware=qcom ehci-hcd.park=3 androidboot.bootdevice=7824900.sdhci lpm_levels.sleep_disabled=1 androidboot.selinux=permissive"; + ramdisk = callPackage ./rootfs.nix { inherit device_name; }; + + base = "0x10000000"; + kernel_offset = "0x00008000"; + second_offset = "0x00f00000"; + ramdisk_offset = "0x02000000"; + tags_offset = "0x00000100"; + pagesize = "2048"; + + +in +stdenv.mkDerivation { + name = "nixos-mobile_${device_name}_boot.img"; + + src = builtins.filterSource (path: type: false) ./.; + unpackPhase = "true"; + + buildInputs = [ + mkbootimg + dtbTool + linux + ]; + + installPhase = '' + mkbootimg \ + --kernel ${kernel} \ + --dt ${dt} \ + --ramdisk ${ramdisk} \ + --cmdline "${cmdline}" \ + --base ${base } \ + --kernel_offset ${kernel_offset } \ + --second_offset ${second_offset } \ + --ramdisk_offset ${ramdisk_offset} \ + --tags_offset ${tags_offset } \ + --pagesize ${pagesize } \ + -o $out + ''; +} diff --git a/rootfs.nix b/rootfs.nix new file mode 100644 index 00000000..b9c1bd3e --- /dev/null +++ b/rootfs.nix @@ -0,0 +1,166 @@ +{ + device_name, + + stdenv, + makeInitrd, + runCommand, + writeScript, + + nukeReferences, + runCommandCC, + busybox, + glibc, + ... +}: + +# TODO : configurable through receiving device-specific informations. +let + extraUtils = runCommandCC "extra-utils" + { + buildInputs = [ nukeReferences ]; + allowedReferences = [ "out" ]; + } '' + set +o pipefail + mkdir -p $out/bin $out/lib + ln -s $out/bin $out/sbin + copy_bin_and_libs() { + [ -f "$out/bin/$(basename $1)" ] && rm "$out/bin/$(basename $1)" + cp -pd $1 $out/bin + } + # Copy Busybox + for BIN in ${busybox}/{s,}bin/*; do + copy_bin_and_libs $BIN + done + # Copy ld manually since it isn't detected correctly + cp -pv ${glibc.out}/lib/ld*.so.? $out/lib + # Copy all of the needed libraries + find $out/bin $out/lib -type f | while read BIN; do + echo "Copying libs for executable $BIN" + LDD="$(ldd $BIN)" || continue + LIBS="$(echo "$LDD" | awk '{print $3}' | sed '/^$/d')" + for LIB in $LIBS; do + TGT="$out/lib/$(basename $LIB)" + if [ ! -f "$TGT" ]; then + SRC="$(readlink -e $LIB)" + cp -pdv "$SRC" "$TGT" + fi + done + done + # Strip binaries further than normal. + chmod -R u+w $out + stripDirs "lib bin" "-s" + # Run patchelf to make the programs refer to the copied libraries. + find $out/bin $out/lib -type f | while read i; do + if ! test -L $i; then + nuke-refs -e $out $i + fi + done + find $out/bin -type f | while read i; do + if ! test -L $i; then + echo "patching $i..." + patchelf --set-interpreter $out/lib/ld*.so.? --set-rpath $out/lib $i || true + fi + done + # Make sure that the patchelf'ed binaries still work. + echo "testing patched programs..." + $out/bin/ash -c 'echo hello world' | grep "hello world" + export LD_LIBRARY_PATH=$out/lib + $out/bin/mount --help 2>&1 | grep -q "BusyBox" + ''; + + + shell = "${extraUtils}/bin/ash"; + + # TODO : make our own rootfs here! + # https://github.com/postmarketOS/pmbootstrap/blob/master/aports/main/postmarketos-mkinitfs-hook-maximum-attention/00-maximum-attention.sh + stage1 = writeScript "stage1" '' + #!${shell} + export PATH=${extraUtils}/bin/ + mkdir -p /proc /sys /dev /etc/udev /tmp /run/ /lib/ /mnt/ /var/log /etc/plymouth /bin + mount -t devtmpfs devtmpfs /dev/ + mount -t proc proc /proc + mount -t sysfs sysfs /sys + + ln -sv ${shell} /bin/sh + #ln -s ''${modules}/lib/modules /lib/modules + + + + #echo /sbin/mdev >/proc/sys/kernel/hotplug + #mdev -s + + + loop_forever() { + while true; do + sleep 1 + done + } + + BLINK_INTERVAL=2 # seconds + VIBRATION_DURATION=400 #ms + VIBRATION_INTERVAL=2 #s + + find_leds() { + find /sys -name "max_brightness" | xargs -I{} dirname {} + } + + find_vibrator() { + echo /sys/class/timed_output/vibrator + } + + # blink_leds takes a list of LEDs as parameters, + # it iterates over every LED, and changes their value, + # alternating between max_brightness and 0 every BLINK_INTERVAL + blink_leds() { + state=false # false = off, true=on + while true; do + for led in $@; do + if [ "$state" = true ]; then + cat $led/max_brightness > $led/brightness + else + echo 0 > $led/brightness + fi + echo blinking LED: $led + done + sleep ''${BLINK_INTERVAL}s + if [ "$state" = true ]; then + state=false + else + state=true + fi + done + } + + # vibrate_loop vibrates each VIBRATION_INTERVAL for VIBRATION_DURATION + # it takes a timed_device path to the vibrator as $1 + vibrate_loop() { + if [ ! -f $1/enable ]; then + return; + fi + + while true; do + echo $VIBRATION_DURATION > $1/enable + sleep ''${VIBRATION_INTERVAL}s + done + } + + blink_leds $(find_leds) & + vibrate_loop $(find_vibrator) & + + sleep 15 + ''; + ramdisk = makeInitrd { + contents = [ + { object = stage1; symlink = "/init"; } + ]; + }; +in +stdenv.mkDerivation { + name = "initrd-${device_name}"; + src = builtins.filterSource (path: type: false) ./.; + unpackPhase = "true"; + + installPhase = '' + cp ${ramdisk}/initrd $out + ''; +}