diff --git a/devices/belkin-rt3200/default.nix b/devices/belkin-rt3200/default.nix new file mode 100644 index 0000000..6c07084 --- /dev/null +++ b/devices/belkin-rt3200/default.nix @@ -0,0 +1,198 @@ +{ + description = '' + Belkin RT-3200 / Linksys E8450 + ****************************** + + This device is based on a 64 bit Mediatek MT7622 ARM platform, + and is "work in progress" in Liminix. + + The factory flash image contains ECC errors that make it incompatible + with Liminix: you need to use the `OpenWrt UBI Installer `_ to rewrite the partition layout before + you can flash Liminix onto it (or even use it with "tftpboot", + if you want the wireless to work). + + - MediaTek MT7622BV (1350MHz) + - 128MB NAND flash + - 512MB RAM + - b/g/n wireless using MediaTek MT7622BV (MT7615E driver) + - a/n/ac/ax wireless using MediaTek MT7915E + ''; + + system = { + crossSystem = { + config = "aarch64-unknown-linux-musl"; + }; + }; + + module = {pkgs, config, lib, ... }: + let firmware = pkgs.stdenv.mkDerivation { + name = "wlan-firmware"; + phases = ["installPhase"]; + installPhase = '' + mkdir $out + cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out + ''; + }; + in { + imports = [ ../../modules/arch/aarch64.nix ]; + kernel = { + src = pkgs.pkgsBuildBuild.fetchurl { + name = "linux.tar.gz"; + url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz"; + hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8="; + }; + extraPatchPhase = '' + ${pkgs.openwrt.applyPatches.mediatek} + ''; + config = { + PCI = "y"; + ARCH_MEDIATEK = "y"; + # ARM_MEDIATEK_CPUFREQ = "y"; + + # needed for "Cannot find regmap for /infracfg@10000000" + MFD_SYSCON = "y"; + MTK_INFRACFG = "y"; + + MTK_PMIC_WRAP = "y"; + MTK_EFUSE="y"; + # MTK_HSDMA="y"; + MTK_SCPSYS="y"; + MTK_SCPSYS_PM_DOMAINS="y"; + # MTK_THERMAL="y"; + MTK_TIMER="y"; + + COMMON_CLK_MT7622 = "y"; + COMMON_CLK_MT7622_ETHSYS = "y"; + COMMON_CLK_MT7622_HIFSYS = "y"; + COMMON_CLK_MT7622_AUDSYS = "y"; + PM_CLK="y"; + + REGMAP_MMIO = "y"; + CLKSRC_MMIO = "y"; + REGMAP = "y"; + + MEDIATEK_GE_PHY = "y"; + # MEDIATEK_MT6577_AUXADC = "y"; + # MEDIATEK_WATCHDOG = "y"; + NET_MEDIATEK_SOC = "y"; + NET_MEDIATEK_SOC_WED = "y"; + NET_MEDIATEK_STAR_EMAC = "y"; # this enables REGMAP_MMIO + NET_VENDOR_MEDIATEK = "y"; + PCIE_MEDIATEK = "y"; + + BLOCK = "y"; # move this to base option + NETDEVICES = "y"; # and this probably also + + SPI_MASTER = "y"; + SPI = "y"; + SPI_MEM="y"; + SPI_MTK_NOR="y"; + SPI_MTK_SNFI = "y"; + + MTD = "y"; + MTD_BLOCK = "y"; + MTD_RAW_NAND = "y"; + MTD_NAND_MTK = "y"; + MTD_NAND_MTK_BMT = "y"; # Bad-block Management Table + MTD_NAND_ECC_MEDIATEK= "y"; + MTD_NAND_ECC_SW_HAMMING= "y"; + MTD_SPI_NAND= "y"; + MTD_OF_PARTS = "y"; + MTD_NAND_CORE= "y"; + MTD_SPI_NOR= "y"; + MTD_SPLIT_FIRMWARE= "y"; + MTD_SPLIT_FIT_FW= "y"; + MTD_UBI="y"; + MTD_UBI_BEB_LIMIT="20"; + MTD_UBI_BLOCK="y"; + MTD_UBI_WL_THRESHOLD="4096"; + + MMC = "y"; + MMC_BLOCK = "y"; + MMC_CQHCI = "y"; + MMC_MTK = "y"; + + # Distributed Switch Architecture is needed + # to make the ethernet ports visible + NET_DSA="y"; + NET_DSA_MT7530="y"; + NET_DSA_TAG_MTK="y"; + + PSTORE = "y"; + PSTORE_RAM = "y"; + PSTORE_CONSOLE = "y"; + PSTORE_DEFLATE_COMPRESS = "n"; + + SERIAL_8250 = "y"; + SERIAL_8250_CONSOLE = "y"; + SERIAL_8250_MT6577="y"; + # SERIAL_8250_NR_UARTS="3"; + # SERIAL_8250_RUNTIME_UARTS="3"; + SERIAL_OF_PLATFORM="y"; + }; + }; + boot = { + commandLine = [ "console=ttyS0,115200" ]; + tftp.loadAddress = "0x4007ff28"; + imageFormat = "fit"; + }; + filesystem = + let inherit (pkgs.pseudofile) dir symlink; + in + dir { + lib = dir { + firmware = dir { + mediatek = symlink firmware; + }; + }; + }; + + hardware = + let + openwrt = pkgs.openwrt; + mac80211 = pkgs.mac80211.override { + drivers = [ + "mt7615e" + "mt7915e" + ]; + klibBuild = config.system.outputs.kernel.modulesupport; + }; + in { + defaultOutput = "flashimage"; + loadAddress = "0x41080000"; + entryPoint = "0x41080000"; + rootDevice = "/dev/mtdblock0"; + dts = { + src = "${openwrt.src}/target/linux/mediatek/dts/mt7622-linksys-e8450.dts"; + includes = [ + "${openwrt.src}/target/linux/mediatek/dts" + "${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/" + ]; + }; + + flash.eraseBlockSize = "65536"; # c.f. pkgs/mips-vm/mips-vm.sh + networkInterfaces = + let + inherit (config.system.service.network) link; + inherit (config.system.service) bridge; + in rec { + wan = link.build { ifname = "wan"; }; + lan1 = link.build { ifname = "lan1"; }; + lan2 = link.build { ifname = "lan2"; }; + lan3 = link.build { ifname = "lan3"; }; + lan4 = link.build { ifname = "lan4"; }; + lan = lan3; + + wlan = link.build { + ifname = "wlan0"; + dependencies = [ mac80211 ]; + }; + wlan5 = link.build { + ifname = "wlan1"; + dependencies = [ mac80211 ]; + }; + }; + }; + + }; +} diff --git a/devices/qemu-aarch64/default.nix b/devices/qemu-aarch64/default.nix index c1144aa..6abab3d 100644 --- a/devices/qemu-aarch64/default.nix +++ b/devices/qemu-aarch64/default.nix @@ -42,6 +42,9 @@ SERIAL_AMBA_PL011_CONSOLE = "y"; }; }; + boot.commandLine = [ + "console=ttyAMA0,38400" + ]; hardware = let mac80211 = pkgs.mac80211.override { diff --git a/modules/arch/aarch64.nix b/modules/arch/aarch64.nix index 460c03e..e1e9702 100644 --- a/modules/arch/aarch64.nix +++ b/modules/arch/aarch64.nix @@ -6,14 +6,11 @@ CPU_BIG_ENDIAN= "n"; # CMDLINE_FROM_BOOTLOADER availability is conditional # on CMDLINE being set to something non-empty - CMDLINE="\"console=ttyAMA0\""; + CMDLINE="\"empty=false\""; CMDLINE_FROM_BOOTLOADER = "y"; OF = "y"; # USE_OF = "y"; }; - boot.commandLine = [ - "console=ttyAMA0,38400" - ]; }; } diff --git a/modules/base.nix b/modules/base.nix index a39c689..fb059d2 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -47,6 +47,10 @@ in { default = []; description = "Kernel command line"; }; + imageFormat = mkOption { + type = types.enum ["fit" "uimage"]; + default = "uimage"; + }; tftp = { loadAddress = mkOption { type = types.str; diff --git a/modules/outputs.nix b/modules/outputs.nix index 3232d80..ae92bbf 100644 --- a/modules/outputs.nix +++ b/modules/outputs.nix @@ -78,6 +78,7 @@ in uimage = liminix.builders.uimage { commandLine = concatStringsSep " " config.boot.commandLine; inherit (config.hardware) loadAddress entryPoint; + inherit (config.boot) imageFormat; inherit kernel; inherit dtb; }; diff --git a/modules/tftpboot.nix b/modules/tftpboot.nix index 2034aca..b011ebd 100644 --- a/modules/tftpboot.nix +++ b/modules/tftpboot.nix @@ -42,27 +42,39 @@ in { ln -s ${o.manifest} manifest ln -s ${o.kernel.headers} build ln -s ${o.uimage} uimage - ln -s ${o.boot-scr} boot.scr + ln -s ${o.boot-scr}/dtb dtb + ln -s ${o.boot-scr}/script boot.scr ''; boot-scr = let inherit (pkgs.lib.trivial) toHexString; o = config.system.outputs; + cmdline = concatStringsSep " " config.boot.commandLine; in - pkgs.buildPackages.runCommand "boot-scr" {} '' + pkgs.buildPackages.runCommand "boot-scr" { nativeBuildInputs = [ pkgs.pkgsBuildBuild.dtc ]; } '' uimageSize=$(($(stat -L -c %s ${o.uimage}) + 0x1000 &(~0xfff))) - rootfsStart=0x$(printf %x $((${cfg.loadAddress} + 0x100000 + $uimageSize))) + rootfsStart=0x$(printf %x $((${cfg.loadAddress} + 0x100000 + $uimageSize &(~0xfffff) ))) rootfsBytes=$(($(stat -L -c %s ${o.rootfs}) + 0x100000 &(~0xfffff))) + rootfsMb=$(($rootfsBytes >> 20)) rootfsBytes=$(($rootfsBytes + ${toString cfg.freeSpaceBytes} )) - cmd="mtdparts=phram0:''${rootfsMb}M(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsBytes},${config.hardware.flash.eraseBlockSize} memmap=''${rootfsBytes}\$''${rootfsStart} root=/dev/mtdblock0"; + cmd="mtdparts=phram0:''${rootfsMb}M(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsBytes},${config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0"; - cat > $out << EOF + dtbStart=$(printf %x $((${cfg.loadAddress} + $rootfsBytes + 0x100000 + $uimageSize ))) + + mkdir $out + cat ${o.dtb} > $out/dtb + fdtput -p -t s $out/dtb /reserved-memory/phram-rootfs compatible phram + fdtput -p -t lx $out/dtb /reserved-memory/phram-rootfs reg 0 $rootfsStart 0 $rootfsBytes + + dtbBytes=$(($(stat -L -c %s $out/dtb) + 0x1000 &(~0xfff))) + + cat > $out/script << EOF setenv serverip ${cfg.serverip} setenv ipaddr ${cfg.ipaddr} - setenv bootargs 'liminix $cmd' - tftp 0x$(printf %x ${cfg.loadAddress}) result/uimage ; tftp 0x$(printf %x $rootfsStart) result/rootfs - bootm 0x$(printf %x ${cfg.loadAddress}) + setenv bootargs 'liminix ${cmdline} $cmd' + tftpboot 0x$(printf %x ${cfg.loadAddress}) result/uimage ; tftpboot 0x$(printf %x $rootfsStart) result/rootfs ; tftpboot 0x$dtbStart result/dtb + bootm 0x$(printf %x ${cfg.loadAddress}) - 0x$dtbStart EOF ''; }; diff --git a/pkgs/kernel/default.nix b/pkgs/kernel/default.nix index d2fec55..b6eb19f 100644 --- a/pkgs/kernel/default.nix +++ b/pkgs/kernel/default.nix @@ -54,6 +54,7 @@ stdenv.mkDerivation rec { patches = [ ./cmdline-cookie.patch + ./phram-allow-cached-mappings.patch ]; # this is here to work around what I think is a bug in nixpkgs diff --git a/pkgs/kernel/kernel_fdt.its b/pkgs/kernel/kernel_fdt.its new file mode 100644 index 0000000..9eba3d9 --- /dev/null +++ b/pkgs/kernel/kernel_fdt.its @@ -0,0 +1,50 @@ +/dts-v1/; + +// used on aarch64 to provide a U-bootable image that combines +// kernel and fdt + +/ { + description = "Simple image with single Linux kernel and FDT blob"; + #address-cells = <1>; + + images { + kernel { + description = "Vanilla Linux kernel"; + // data = /incbin/("./vmlinux.bin.gz"); + type = "kernel"; + arch = "arm64"; + os = "linux"; + // compression = "gzip"; + // load = <00000000>; + // entry = <00000000>; + hash-1 { + algo = "crc32"; + }; + hash-2 { + algo = "sha1"; + }; + }; + fdt-1 { + description = "Flattened Device Tree blob"; + // data = /incbin/("./target.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + hash-1 { + algo = "crc32"; + }; + hash-2 { + algo = "sha1"; + }; + }; + }; + + configurations { + default = "conf-1"; + conf-1 { + description = "Boot Linux kernel with FDT blob"; + kernel = "kernel"; + fdt = "fdt-1"; + }; + }; +}; diff --git a/pkgs/kernel/phram-allow-cached-mappings.patch b/pkgs/kernel/phram-allow-cached-mappings.patch new file mode 100644 index 0000000..070502c --- /dev/null +++ b/pkgs/kernel/phram-allow-cached-mappings.patch @@ -0,0 +1,47 @@ +From bb7e7aeb3d832059e33b1e76eb85d4680f77abf2 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Fri, 3 Jun 2016 01:08:36 +0100 +Subject: [PATCH] phram: Use memremap() to allow mapping of system RAM + +Using memremap() instead of ioremap() allows mapping a disk image in +system RAM that has somehow been reserved. It should fall back +to ioremap() where necessary. + +Entirely untested, and I'm not convinced this is a good idea at all. +--- + drivers/mtd/devices/phram.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c +index 8b66e52ca3cc..0ea254e2ba51 100644 +--- a/drivers/mtd/devices/phram.c ++++ b/drivers/mtd/devices/phram.c +@@ -88,7 +88,7 @@ static void unregister_devices(void) + + list_for_each_entry_safe(this, safe, &phram_list, list) { + mtd_device_unregister(&this->mtd); +- iounmap(this->mtd.priv); ++ memunmap(this->mtd.priv); + kfree(this->mtd.name); + kfree(this); + } +@@ -104,7 +104,8 @@ static int register_device(char *name, phys_addr_t start, size_t len) + goto out0; + + ret = -EIO; +- new->mtd.priv = ioremap(start, len); ++ new->mtd.priv = memremap(start, len, ++ MEMREMAP_WB | MEMREMAP_WT | MEMREMAP_WC); + if (!new->mtd.priv) { + pr_err("ioremap failed\n"); + goto out1; +@@ -134,7 +135,7 @@ static int register_device(char *name, phys_addr_t start, size_t len) + return 0; + + out2: +- iounmap(new->mtd.priv); ++ memunmap(new->mtd.priv); + out1: + kfree(new); + out0: + diff --git a/pkgs/kernel/uimage.nix b/pkgs/kernel/uimage.nix index d0882f8..e6ac685 100644 --- a/pkgs/kernel/uimage.nix +++ b/pkgs/kernel/uimage.nix @@ -7,21 +7,27 @@ } : let objcopy = "${stdenv.cc.bintools.targetPrefix}objcopy"; + arch = stdenv.hostPlatform.linuxArch; + stripAndZip = '' + ${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin + rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin + ''; in { kernel , commandLine , entryPoint , extraName ? "" # e.g. socFamily , loadAddress +, imageFormat , dtb ? null -} : -stdenv.mkDerivation { +} : stdenv.mkDerivation { name = "kernel.image"; phases = [ "preparePhase" - (if dtb != null then "dtbPhase" else ":") - "buildPhase" - "installPhase" ]; + (if commandLine != null then assert dtb != null; "mungeDtbPhase" else ":") + (if imageFormat == "fit" then "buildPhaseFIT" else "buildPhaseUImage") + "installPhase" + ]; nativeBuildInputs = [ lzma dtc @@ -31,28 +37,38 @@ stdenv.mkDerivation { preparePhase = '' cp ${kernel} vmlinux.elf; chmod +w vmlinux.elf ''; - dtbPhase = '' + mungeDtbPhase = '' dtc -I dtb -O dts -o tmp.dts ${dtb} echo '/{ chosen { bootargs = ${builtins.toJSON commandLine}; }; };' >> tmp.dts dtc -I dts -O dtb -o tmp.dtb tmp.dts - ${objcopy} --update-section .appended_dtb=tmp.dtb vmlinux.elf || ${objcopy} --add-section .appended_dtb=${dtb} vmlinux.elf ''; - buildPhase = - let arch = - # per output of "mkimage -A list". I *think* these - # are the same as the kernel arch convention, but - # maybe that's coincidence - if stdenv.isMips - then "mips" - else if stdenv.isAarch64 - then "arm64" - else throw "unknown arch"; - in '' - ${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin - rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin - mkimage -A ${arch} -O linux -T kernel -C lzma -a ${loadAddress} -e ${entryPoint} -n '${lib.toUpper arch} Liminix Linux ${extraName}' -d vmlinux.bin.lzma kernel.uimage - ''; + buildPhaseUImage = '' + test -f tmp.dtb && ${objcopy} --update-section .appended_dtb=tmp.dtb vmlinux.elf || ${objcopy} --add-section .appended_dtb=tmp.dtb vmlinux.elf + ${stripAndZip} + mkimage -A ${arch} -O linux -T kernel -C lzma -a ${loadAddress} -e ${entryPoint} -n '${lib.toUpper arch} Liminix Linux ${extraName}' -d vmlinux.bin.lzma kernel.uimage + ''; + + buildPhaseFIT = '' + ${stripAndZip} + cat ${./kernel_fdt.its} > mkimage.its + cat << _VARS >> mkimage.its + / { + images { + kernel { + data = /incbin/("./vmlinux.bin.lzma"); + load = <${loadAddress}>; + entry = <${entryPoint}>; + compression = "lzma"; + }; + fdt-1 { data = /incbin/("./tmp.dtb"); }; + }; + }; + _VARS + mkimage -f mkimage.its kernel.uimage + mkimage -l kernel.uimage + ''; + installPhase = '' cp kernel.uimage $out '';