From 89d96c00b046bd4bf66303872644e9a589665363 Mon Sep 17 00:00:00 2001 From: Craige McWhirter Date: Wed, 20 Oct 2021 16:22:09 +1000 Subject: [PATCH] ceilidh: added odriod-hc4 support --- deployments/mio-ops.nix | 1 + hardware/odroid-hc4/default.nix | 54 + .../odroid-hc4/modules/sd-image/default.nix | 44 + .../odroid-hc4/overlays/kernel/kernel.diff | 74 ++ .../odroid-hc4/overlays/kernel/kernel.nix | 38 + .../odroid-hc4/overlays/kernel/overlay.nix | 13 + .../odroid-hc4/overlays/uboot/blx_fix.nix | 41 + .../odroid-hc4/overlays/uboot/fip_create.diff | 979 ++++++++++++++++++ .../odroid-hc4/overlays/uboot/hardkernel.nix | 50 + .../overlays/uboot/meson64-tools.nix | 15 + .../odroid-hc4/overlays/uboot/overlay.nix | 28 + hardware/odroid-hc4/overlays/uboot/pwd.diff | 13 + hardware/odroid-hc4/overlays/uboot/u-boot.nix | 98 ++ .../odroid-hc4/uboot/boot-ini-builder.nix | 15 + hardware/odroid-hc4/uboot/boot-ini-builder.sh | 189 ++++ hardware/odroid-hc4/uboot/config.ini | 101 ++ .../odroid-hc4/uboot/hardkernel-uboot.nix | 54 + hosts/ceilidh.nix | 31 + 18 files changed, 1838 insertions(+) create mode 100644 hardware/odroid-hc4/default.nix create mode 100644 hardware/odroid-hc4/modules/sd-image/default.nix create mode 100644 hardware/odroid-hc4/overlays/kernel/kernel.diff create mode 100644 hardware/odroid-hc4/overlays/kernel/kernel.nix create mode 100644 hardware/odroid-hc4/overlays/kernel/overlay.nix create mode 100644 hardware/odroid-hc4/overlays/uboot/blx_fix.nix create mode 100644 hardware/odroid-hc4/overlays/uboot/fip_create.diff create mode 100644 hardware/odroid-hc4/overlays/uboot/hardkernel.nix create mode 100644 hardware/odroid-hc4/overlays/uboot/meson64-tools.nix create mode 100644 hardware/odroid-hc4/overlays/uboot/overlay.nix create mode 100644 hardware/odroid-hc4/overlays/uboot/pwd.diff create mode 100644 hardware/odroid-hc4/overlays/uboot/u-boot.nix create mode 100644 hardware/odroid-hc4/uboot/boot-ini-builder.nix create mode 100644 hardware/odroid-hc4/uboot/boot-ini-builder.sh create mode 100755 hardware/odroid-hc4/uboot/config.ini create mode 100644 hardware/odroid-hc4/uboot/hardkernel-uboot.nix create mode 100644 hosts/ceilidh.nix diff --git a/deployments/mio-ops.nix b/deployments/mio-ops.nix index c83c353..47d8d13 100644 --- a/deployments/mio-ops.nix +++ b/deployments/mio-ops.nix @@ -16,6 +16,7 @@ }; airgead = import ../hosts/airgead.nix; + ceilidh = import ../hosts/ceilidh.nix; cuallaidh = import ../hosts/cuallaidh.nix; dhu = import ../hosts/dhu.nix; dionach = import ../hosts/dionach.nix; diff --git a/hardware/odroid-hc4/default.nix b/hardware/odroid-hc4/default.nix new file mode 100644 index 0000000..d406af2 --- /dev/null +++ b/hardware/odroid-hc4/default.nix @@ -0,0 +1,54 @@ +{ config, lib, modulesPath, pkgs, ... }: + +with lib; + +let + sources = import ../../nix/sources.nix; + unstable = import sources.nixpkgsUnstable {}; +in + +{ + imports = [ + "${modulesPath}/profiles/base.nix" + ./uboot/hardkernel-uboot.nix + ../../profiles/host_common.nix + ../../profiles/server_common.nix + ]; + + # The linux kernel used is compiled from the Hardkernel fork of + # torvalds/linux + boot = { + initrd.availableKernelModules = mkForce [ ]; + kernelPackages = pkgs.linuxPackagesFor pkgs.linux_hardkernel; + # Bootloader (use Hardkernel fork of Das U-Boot) + loader = { + grub.enable = false; + generic-extlinux-compatible.enable = false; + hardkernel-uboot.enable = true; + }; + }; + + # We do know the hardware we are planning to deploy to + hardware.enableRedistributableFirmware = mkForce false; + + nixpkgs.overlays = [ + (import ./overlays/kernel/overlay.nix) + (import ./overlays/uboot/overlay.nix) + ]; + + + # DNS + services.resolved.enable = true; + services.resolved.dnssec = "false"; + + fileSystems = { + "/boot" = { + device = "/dev/disk/by-label/FIRMWARE"; + fsType = "vfat"; + }; + "/" = { + device = "/dev/disk/by-label/NIXOS_SD"; + fsType = "ext4"; + }; + }; +} diff --git a/hardware/odroid-hc4/modules/sd-image/default.nix b/hardware/odroid-hc4/modules/sd-image/default.nix new file mode 100644 index 0000000..e415307 --- /dev/null +++ b/hardware/odroid-hc4/modules/sd-image/default.nix @@ -0,0 +1,44 @@ +{ pkgs, lib, config, modulesPath, ... }: +{ + imports = [ + "${modulesPath}/installer/sd-card/sd-image.nix" + # should we include this module or should we treat the SD + # card as the final system to run? + "${modulesPath}/profiles/installation-device.nix" + ../odroidhc4 + ]; + + security.polkit.enable = false; + + nixpkgs.overlays = [ + (final: prev: { + smartmontools = prev.smartmontools.override { enableMail = false; }; + }) + ]; + + # Remove zfs from supported filesystems as it fails when cross-compiling due + # to not being able to build kernel module + boot.supportedFilesystems = lib.mkForce [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs" ]; + + sdImage = { + compressImage = false; + # Use 512 MB for boot partition to fit multiple kernel versions + firmwareSize = 512; + # Copy u-boot bootloader to SD card + postBuildCommands = '' + dd if="${pkgs.uboot-hardkernel}" of="$img" conv=fsync,notrunc bs=512 skip=1 seek=1 + dd if="${pkgs.uboot-hardkernel}" of="$img" conv=fsync,notrunc bs=1 count=444 + ''; + # Fill the FIRMWARE partition with the u-boot files, linux kernel and initrd (ramdisk) + populateFirmwareCommands = '' + ${config.boot.loader.hardkernel-uboot.populateCmd} -c ${config.system.build.toplevel} -d ./firmware + ''; + # Fill the root partition with this nix configuration in /etc/nixos + # and create a mount point for the FIRMWARE partition at /boot + populateRootCommands = '' + mkdir -p ./files/boot ./files/etc/nixos + cp ${../../configuration.nix} ./files/etc/nixos/configuration.nix + cp -r ${../.} ./files/etc/nixos/modules + ''; + }; +} diff --git a/hardware/odroid-hc4/overlays/kernel/kernel.diff b/hardware/odroid-hc4/overlays/kernel/kernel.diff new file mode 100644 index 0000000..518e25e --- /dev/null +++ b/hardware/odroid-hc4/overlays/kernel/kernel.diff @@ -0,0 +1,74 @@ +diff --git a/Makefile b/Makefile +index bb2e9204..869ac5bb 100644 +--- a/Makefile ++++ b/Makefile +@@ -899,7 +899,7 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=strict-prototypes) + KBUILD_CFLAGS += $(call cc-option,-Werror=date-time) + + # enforce correct pointer usage +-KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types) ++KBUILD_CFLAGS += $(call cc-option,-Wno-error=incompatible-pointer-types) + + # Require designated initializers for all marked structures + KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init) +diff --git a/arch/arm64/configs/odroidg12_defconfig b/arch/arm64/configs/odroidg12_defconfig +index 8d21df65..d3eb2b6a 100644 +--- a/arch/arm64/configs/odroidg12_defconfig ++++ b/arch/arm64/configs/odroidg12_defconfig +@@ -430,7 +430,7 @@ CONFIG_ARM64_VA_BITS=39 + # CONFIG_CPU_BIG_ENDIAN is not set + CONFIG_SCHED_MC=y + # CONFIG_SCHED_SMT is not set +-CONFIG_NR_CPUS=8 ++CONFIG_NR_CPUS=4 + CONFIG_HOTPLUG_CPU=y + # CONFIG_NUMA is not set + # CONFIG_PREEMPT_NONE is not set +@@ -1841,6 +1841,8 @@ CONFIG_AMLOGIC_POWER=y + # + CONFIG_AMLOGIC_PCIE=y + # CONFIG_AMLOGIC_IRBLASTER_CORE is not set ++CONFIG_AMLOGIC_IRBLASTER_CORE=n ++CONFIG_AMLOGIC_IRBLASTER=n + CONFIG_AMLOGIC_IIO=y + + # +diff --git a/drivers/amlogic/irblaster/sysfs.c b/drivers/amlogic/irblaster/sysfs.c +index 359d439c..e0e8eb05 100644 +--- a/drivers/amlogic/irblaster/sysfs.c ++++ b/drivers/amlogic/irblaster/sysfs.c +@@ -16,6 +16,9 @@ + */ + + #include ++#include ++#include ++#include + #include + #include + #include +diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c +index 471f26a2..97bd4ef3 100644 +--- a/fs/userfaultfd.c ++++ b/fs/userfaultfd.c +@@ -496,7 +496,8 @@ static int userfaultfd_release(struct inode *inode, struct file *file) + new_flags, vma->anon_vma, + vma->vm_file, vma->vm_pgoff, + vma_policy(vma), +- NULL_VM_UFFD_CTX); ++ NULL_VM_UFFD_CTX, ++ vma_get_anon_name(vma)); + if (prev) + vma = prev; + else +@@ -555,9 +556,7 @@ static unsigned int userfaultfd_poll(struct file *file, poll_table *wait) + return POLLERR; + case UFFD_STATE_RUNNING: + /* +- * poll() never guarantees that read won't block. +- * userfaults can be waken before they're read(). +- */ ++ * poll() never guarantees that read won't block. userfaults can be waken before they're read(). */ + if (unlikely(!(file->f_flags & O_NONBLOCK))) + return POLLERR; + /* diff --git a/hardware/odroid-hc4/overlays/kernel/kernel.nix b/hardware/odroid-hc4/overlays/kernel/kernel.nix new file mode 100644 index 0000000..c8e970e --- /dev/null +++ b/hardware/odroid-hc4/overlays/kernel/kernel.nix @@ -0,0 +1,38 @@ +{ stdenv +, buildPackages +, fetchFromGitHub +, perl +, buildLinux +, libelf +, utillinux +, lib +, ... +}@args: + +buildLinux (args // rec { + version = "4.9.241-107"; + + # modDirVersion needs to be x.y.z. + modDirVersion = "4.9.241"; + + # branchVersion needs to be x.y. + extraMeta.branch = "4.9"; + + # src = ./linux; + src = fetchFromGitHub { + owner = "hardkernel"; + repo = "linux"; + rev = version; + sha256 = "1f004ahbj0x5nmr0240jdv7v6ssgbxd53ivsv7gra87hcm00hbn3"; + }; + + defconfig = "odroidg12_defconfig"; + + autoModules = false; + structuredExtraConfig = with lib.kernel; { + NR_CPUS = lib.mkForce (freeform "8"); + }; + + extraMeta.platforms = [ "aarch64-linux" ]; + +} // (args.argsOverride or { })) diff --git a/hardware/odroid-hc4/overlays/kernel/overlay.nix b/hardware/odroid-hc4/overlays/kernel/overlay.nix new file mode 100644 index 0000000..9c99392 --- /dev/null +++ b/hardware/odroid-hc4/overlays/kernel/overlay.nix @@ -0,0 +1,13 @@ +final: prev: { + linux_hardkernel = final.callPackage ./kernel.nix { + kernelPatches = [ + # The kernel fails to cross-compile due to: + # 1. warnings caused by different interpretation of function pointers + # 2. NR_CPUS causing stack overflows when allocating cpu_topology + # 3. The IRBLASTER module not registering syscalls correctly + + # The following patch makes the above warnings non-errors, decreases NR_CPUS to 4 and disables the IRBLASTER module. + ({ name = "hardkernel-patches"; patch = ./kernel.diff; }) + ]; + }; +} diff --git a/hardware/odroid-hc4/overlays/uboot/blx_fix.nix b/hardware/odroid-hc4/overlays/uboot/blx_fix.nix new file mode 100644 index 0000000..8ed40d6 --- /dev/null +++ b/hardware/odroid-hc4/overlays/uboot/blx_fix.nix @@ -0,0 +1,41 @@ +{ writeShellScript }: +writeShellScript "blx_fix" '' + #bl2 file size 41K, bl21 file size 3K (file size not equal runtime size) + #total 44K + #after encrypt process, bl2 add 4K header, cut off 4K tail + + #bl30 limit 41K + #bl301 limit 12K + #bl2 limit 41K + #bl21 limit 3K, but encrypt tool need 48K bl2.bin, so fix to 7168byte. + + #$7:name flag + if [ "$7" = "bl30" ]; then + declare blx_bin_limit=40960 + declare blx01_bin_limit=13312 + elif [ "$7" = "bl2" ]; then + declare blx_bin_limit=57344 + declare blx01_bin_limit=4096 + else + echo "blx_fix name flag not supported!" + exit 1 + fi + + # blx_size: blx.bin size, zero_size: fill with zeros + declare -i blx_size=$(du -b $1 | awk '{print int($1)}') + declare -i zero_size=$blx_bin_limit-$blx_size + dd if=/dev/zero of=$2 bs=1 count=$zero_size + cat $1 $2 >$3 + rm $2 + + declare -i blx01_size=$(du -b $4 | awk '{print int($1)}') + declare -i zero_size_01=$blx01_bin_limit-$blx01_size + dd if=/dev/zero of=$2 bs=1 count=$zero_size_01 + cat $4 $2 >$5 + + cat $3 $5 >$6 + + rm $2 + + exit 0 +'' diff --git a/hardware/odroid-hc4/overlays/uboot/fip_create.diff b/hardware/odroid-hc4/overlays/uboot/fip_create.diff new file mode 100644 index 0000000..68edd67 --- /dev/null +++ b/hardware/odroid-hc4/overlays/uboot/fip_create.diff @@ -0,0 +1,979 @@ +diff --git a/Makefile b/Makefile +index 730e8d752f..127a260ee8 100644 +--- a/Makefile ++++ b/Makefile +@@ -875,8 +875,14 @@ $(ACS_BINARY): tools prepare u-boot.bin + bl21.bin: tools prepare u-boot.bin acs.bin + $(Q)$(MAKE) -C $(srctree)/$(CPUDIR)/${SOC}/firmware/bl21 all FIRMWARE=$@ + ++.PHONY: fip_create ++fip_create: ++ $(Q)$(MAKE) -C $(srctree)/tools/fip_create/ ++ $(Q)cp $(srctree)/tools/fip_create/fip_create $(buildsrc)/fip/ ++ ++ + .PHONY : fip.bin bootimage +-fip.bin bootimage: $(ACS_BINARY) $(BL301_BINARY) ++fip.bin bootimage: $(ACS_BINARY) $(BL301_BINARY) fip_create + $(Q)$(MAKE) -C $(srctree)/fip $@ + + # +diff --git a/tools/fip_create/Makefile b/tools/fip_create/Makefile +new file mode 100644 +index 00000000000..69569a1b2f6 +--- /dev/null ++++ b/tools/fip_create/Makefile +@@ -0,0 +1,62 @@ ++# ++# Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. ++# ++# Redistribution and use in source and binary forms, with or without ++# modification, are permitted provided that the following conditions are met: ++# ++# Redistributions of source code must retain the above copyright notice, this ++# list of conditions and the following disclaimer. ++# ++# Redistributions in binary form must reproduce the above copyright notice, ++# this list of conditions and the following disclaimer in the documentation ++# and/or other materials provided with the distribution. ++# ++# Neither the name of ARM nor the names of its contributors may be used ++# to endorse or promote products derived from this software without specific ++# prior written permission. ++# ++# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++# POSSIBILITY OF SUCH DAMAGE. ++# ++ ++PROJECT = fip_create ++OBJECTS = fip_create.o ++ ++CFLAGS = -Wall -Werror -pedantic -std=c99 ++ifeq (${DEBUG},1) ++ CFLAGS += -g -O0 -DDEBUG ++else ++ CFLAGS += -O2 ++endif ++ ++# Make soft links and include from local directory otherwise wrong headers ++# could get pulled in from firmware tree. ++INCLUDE_PATHS = -I. ++ ++CC := gcc ++RM := rm -rf ++ ++.PHONY: all clean ++ ++all: ${PROJECT} ++ ++${PROJECT}: ${OBJECTS} Makefile ++ @echo " LD $@" ++ ${Q}${CC} ${OBJECTS} -o $@ ++ ++%.o: %.c %.h Makefile ++ @echo " CC $<" ++ ${Q}${CC} -c ${CFLAGS} ${INCLUDE_PATHS} $< -o $@ ++ ++clean: ++ ${Q}${RM} ${PROJECT} ++ ${Q}${RM} ${OBJECTS} +diff --git a/tools/fip_create/fip_create.c b/tools/fip_create/fip_create.c +new file mode 100644 +index 00000000000..92affb9e7a9 +--- /dev/null ++++ b/tools/fip_create/fip_create.c +@@ -0,0 +1,677 @@ ++/* ++ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following disclaimer. ++ * ++ * Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * Neither the name of ARM nor the names of its contributors may be used ++ * to endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include /* getopt_long() is a GNU extention */ ++#include ++#include ++#include ++#include ++#include ++#include "fip_create.h" ++#include "firmware_image_package.h" ++ ++/* Values returned by getopt() as part of the command line parsing */ ++#define OPT_TOC_ENTRY 0 ++#define OPT_DUMP 1 ++#define OPT_HELP 2 ++ ++file_info_t files[MAX_FILES]; ++unsigned file_info_count = 0; ++uuid_t uuid_null = {0}; ++ ++/* ++ * TODO: Add ability to specify and flag different file types. ++ * Add flags to the toc_entry? ++ * const char* format_type_str[] = { "RAW", "ELF", "PIC" }; ++ */ ++ ++/* The images used depends on the platform. */ ++static entry_lookup_list_t toc_entry_lookup_list[] = { ++ { "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2, ++ "bl2", NULL, FLAG_FILENAME }, ++ { "SCP Firmware BL3-0", UUID_SCP_FIRMWARE_BL30, ++ "bl30", NULL, FLAG_FILENAME}, ++ { "SCP Firmware BL3-0-1", UUID_SCP_FIRMWARE_BL301, ++ "bl301", NULL, FLAG_FILENAME}, ++ { "EL3 Runtime Firmware BL3-1", UUID_EL3_RUNTIME_FIRMWARE_BL31, ++ "bl31", NULL, FLAG_FILENAME}, ++ { "Secure Payload BL3-2 (Trusted OS)", UUID_SECURE_PAYLOAD_BL32, ++ "bl32", NULL, FLAG_FILENAME}, ++ { "Non-Trusted Firmware BL3-3", UUID_NON_TRUSTED_FIRMWARE_BL33, ++ "bl33", NULL, FLAG_FILENAME}, ++ { NULL, {0}, 0 } ++}; ++ ++ ++/* Return 0 for equal uuids */ ++static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2) ++{ ++ return memcmp(uuid1, uuid2, sizeof(uuid_t)); ++} ++ ++ ++static inline void copy_uuid(uuid_t *to_uuid, const uuid_t *from_uuid) ++{ ++ memcpy(to_uuid, from_uuid, sizeof(uuid_t)); ++} ++ ++ ++static void print_usage(void) ++{ ++ entry_lookup_list_t *entry = toc_entry_lookup_list; ++ ++ printf("Usage: fip_create [options] FIP_FILENAME\n\n"); ++ printf("\tThis tool is used to create a Firmware Image Package.\n\n"); ++ printf("Options:\n"); ++ printf("\t--help: Print this help message and exit\n"); ++ printf("\t--dump: Print contents of FIP\n\n"); ++ printf("\tComponents that can be added/updated:\n"); ++ for (; entry->command_line_name != NULL; entry++) { ++ printf("\t--%s%s\t\t%s", ++ entry->command_line_name, ++ (entry->flags & FLAG_FILENAME) ? " FILENAME" : "", ++ entry->name); ++ printf("\n"); ++ } ++} ++ ++ ++static entry_lookup_list_t *get_entry_lookup_from_uuid(const uuid_t *uuid) ++{ ++ unsigned int lookup_index = 0; ++ ++ while (toc_entry_lookup_list[lookup_index].command_line_name != NULL) { ++ if (compare_uuids(&toc_entry_lookup_list[lookup_index].name_uuid, ++ uuid) == 0) { ++ return &toc_entry_lookup_list[lookup_index]; ++ } ++ lookup_index++; ++ } ++ return NULL; ++} ++ ++ ++static file_info_t *find_file_info_from_uuid(const uuid_t *uuid) ++{ ++ int index; ++ ++ for (index = 0; index < file_info_count; index++) { ++ if (compare_uuids(&files[index].name_uuid, uuid) == 0) { ++ return &files[index]; ++ } ++ } ++ return NULL; ++} ++ ++ ++static int add_file_info_entry(entry_lookup_list_t *lookup_entry, char *filename) ++{ ++ file_info_t *file_info_entry; ++ int error; ++ struct stat file_status; ++ bool is_new_entry = false; ++ ++ /* Check if the file already exists in the array */ ++ file_info_entry = find_file_info_from_uuid(&lookup_entry->name_uuid); ++ if (file_info_entry == NULL) { ++ /* The file does not exist in the current list; take the next ++ * one available in the file_info list. 'file_info_count' is ++ * incremented in case of successful update at the end of the ++ * function. ++ */ ++ file_info_entry = &files[file_info_count]; ++ is_new_entry = true; ++ ++ /* Copy the uuid for the new entry */ ++ copy_uuid(&file_info_entry->name_uuid, ++ &lookup_entry->name_uuid); ++ } ++ ++ /* Get the file information for entry */ ++ error = stat(filename, &file_status); ++ if (error != 0) { ++ printf("Error: Cannot get information for file \"%s\": %s\n", ++ filename, strerror(errno)); ++ return errno; ++ } ++ file_info_entry->filename = filename; ++ file_info_entry->size = (unsigned int)file_status.st_size; ++ file_info_entry->align_size = 0x4000 * ((file_info_entry->size / 0x4000) + 1); ++ file_info_entry->entry = lookup_entry; ++ ++ /* Increment the file_info counter on success if it is new file entry */ ++ if (is_new_entry) { ++ file_info_count++; ++ ++ /* Ensure we do not overflow */ ++ if (file_info_count > MAX_FILES) { ++ printf("ERROR: Too many files in Package\n"); ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++static int write_memory_to_file(const uint8_t *start, const char *filename, ++ unsigned int size) ++{ ++ FILE *stream; ++ unsigned int bytes_written; ++ ++ /* Write the packed file out to the filesystem */ ++ stream = fopen(filename, "r+"); ++ if (stream == NULL) { ++ stream = fopen(filename, "w"); ++ if (stream == NULL) { ++ printf("Error: Cannot create output file \"%s\": %s\n", ++ filename, strerror(errno)); ++ return errno; ++ } else { ++ printf("Creating \"%s\"\n", filename); ++ } ++ } else { ++ printf("Updating \"%s\"\n", filename); ++ } ++ ++ bytes_written = fwrite(start, sizeof(uint8_t), size, stream); ++ fclose(stream); ++ ++ if (bytes_written != size) { ++ printf("Error: Incorrect write for file \"%s\": Size=%u," ++ "Written=%u bytes.\n", filename, size, bytes_written); ++ return EIO; ++ } ++ ++ return 0; ++} ++ ++ ++static int read_file_to_memory(void *memory, const file_info_t *info) ++{ ++ FILE *stream; ++ unsigned int bytes_read; ++ ++ /* If the file_info is defined by its filename we need to load it */ ++ if (info->filename) { ++ /* Read image from filesystem */ ++ stream = fopen(info->filename, "r"); ++ if (stream == NULL) { ++ printf("Error: Cannot open file \"%s\": %s\n", ++ info->filename, strerror(errno)); ++ return errno; ++ } ++ ++ bytes_read = (unsigned int)fread(memory, sizeof(uint8_t), ++ info->size, stream); ++ fclose(stream); ++ if (bytes_read != info->size) { ++ printf("Error: Incomplete read for file \"%s\":" ++ "Size=%u, Read=%u bytes.\n", info->filename, ++ info->size, bytes_read); ++ return EIO; ++ } ++ } else { ++ if (info->image_buffer == NULL) { ++ printf("ERROR: info->image_buffer = NULL\n"); ++ return EIO; ++ } ++ /* Copy the file_info buffer (extracted from the existing ++ * image package) into the new buffer. ++ */ ++ memcpy(memory, info->image_buffer, info->size); ++ } ++ ++ return 0; ++} ++ ++ ++/* Create the image package file */ ++static int pack_images(const char *fip_filename) ++{ ++ int status; ++ uint8_t *fip_base_address; ++ void *entry_address; ++ fip_toc_header_t *toc_header; ++ fip_toc_entry_t *toc_entry; ++ unsigned int entry_index; ++ unsigned int toc_size; ++ unsigned int fip_size; ++ unsigned int entry_offset_address; ++ unsigned int payload_size = 0; ++ ++ /* Validate filename */ ++ if ((fip_filename == NULL) || (strcmp(fip_filename, "") == 0)) { ++ return EINVAL; ++ } ++ ++ /* Payload size calculation */ ++ for (entry_index = 0; entry_index < file_info_count; entry_index++) { ++ payload_size += files[entry_index].align_size; ++ } ++ ++ /* Allocate memory for entire package, including the final null entry */ ++ //toc_size = (sizeof(fip_toc_header_t) + ++ //(sizeof(fip_toc_entry_t) * (file_info_count + 1))); ++ toc_size = 0x4000; ++ fip_size = toc_size + payload_size; ++ fip_base_address = malloc(fip_size); ++ if (fip_base_address == NULL) { ++ printf("Error: Can't allocate enough memory to create package." ++ "Process aborted.\n"); ++ return ENOMEM; ++ } ++ memset(fip_base_address, 0, fip_size); ++ ++ /* Create ToC Header */ ++ toc_header = (fip_toc_header_t *)fip_base_address; ++ toc_header->name = TOC_HEADER_NAME; ++ toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER; ++ toc_header->flags = 0; ++ ++ toc_entry = (fip_toc_entry_t *)(fip_base_address + ++ sizeof(fip_toc_header_t)); ++ ++ /* Calculate the starting address of the first image, right after the ++ * toc header. ++ */ ++ entry_offset_address = toc_size; ++ entry_index = 0; ++ ++ /* Create the package in memory. */ ++ for (entry_index = 0; entry_index < file_info_count; entry_index++) { ++ entry_address = (fip_base_address + entry_offset_address); ++ status = read_file_to_memory(entry_address, ++ &files[entry_index]); ++ if (status != 0) { ++ printf("Error: While reading \"%s\" from filesystem.\n", ++ files[entry_index].filename); ++ return status; ++ } ++ ++ copy_uuid(&toc_entry->uuid, &files[entry_index].name_uuid); ++ toc_entry->offset_address = entry_offset_address; ++ toc_entry->size = files[entry_index].size; ++ toc_entry->flags = 0; ++ entry_offset_address += files[entry_index].align_size; ++ toc_entry++; ++ } ++ ++ /* Add a null uuid entry to mark the end of toc entries */ ++ copy_uuid(&toc_entry->uuid, &uuid_null); ++ toc_entry->offset_address = entry_offset_address; ++ toc_entry->size = 0; ++ toc_entry->flags = 0; ++ ++ /* Save the package to file */ ++ status = write_memory_to_file(fip_base_address, fip_filename, fip_size); ++ if (status != 0) { ++ printf("Error: Failed while writing package to file \"%s\" " ++ "with status=%d.\n", fip_filename, status); ++ return status; ++ } ++ return 0; ++} ++ ++ ++static void dump_toc(void) ++{ ++ unsigned int index = 0; ++ unsigned int image_offset; ++ unsigned int image_size = 0; ++ ++ //image_offset = sizeof(fip_toc_header_t) + ++ //(sizeof(fip_toc_entry_t) * (file_info_count + 1)); ++ image_offset = 0x4000; ++ ++ printf("Firmware Image Package ToC:\n"); ++ printf("---------------------------\n"); ++ for (index = 0; index < file_info_count; index++) { ++ if (files[index].entry) { ++ printf("- %s: ", files[index].entry->name); ++ } else { ++ printf("- Unknown entry: "); ++ } ++ image_size = files[index].size; ++ ++ printf("offset=0x%X, size=0x%X\n", image_offset, image_size); ++ image_offset += files[index].align_size; ++ ++ if (files[index].filename) { ++ printf(" file: '%s'\n", files[index].filename); ++ } ++ } ++ printf("---------------------------\n"); ++} ++ ++ ++/* Read and load existing package into memory. */ ++static int parse_fip(const char *fip_filename) ++{ ++ FILE *fip; ++ char *fip_buffer; ++ char *fip_buffer_end; ++ int fip_size, read_fip_size; ++ fip_toc_header_t *toc_header; ++ fip_toc_entry_t *toc_entry; ++ bool found_last_toc_entry = false; ++ file_info_t *file_info_entry; ++ int status = -1; ++ struct stat st; ++ ++ fip = fopen(fip_filename, "r"); ++ if (fip == NULL) { ++ /* If the fip does not exist just return, it should not be ++ * considered as an error. The package will be created later ++ */ ++ status = 0; ++ goto parse_fip_return; ++ } ++ ++ if (stat(fip_filename, &st) != 0) { ++ status = errno; ++ goto parse_fip_fclose; ++ } else { ++ fip_size = (int)st.st_size; ++ } ++ ++ /* Allocate a buffer to read the package */ ++ fip_buffer = (char *)malloc(fip_size); ++ if (fip_buffer == NULL) { ++ printf("ERROR: Cannot allocate %d bytes.\n", fip_size); ++ status = errno; ++ goto parse_fip_fclose; ++ } ++ fip_buffer_end = fip_buffer + fip_size; ++ ++ /* Read the file */ ++ read_fip_size = fread(fip_buffer, sizeof(char), fip_size, fip); ++ if (read_fip_size != fip_size) { ++ printf("ERROR: Cannot read the FIP.\n"); ++ status = EIO; ++ goto parse_fip_free; ++ } ++ fclose(fip); ++ fip = NULL; ++ ++ /* The package must at least contain the ToC Header */ ++ if (fip_size < sizeof(fip_toc_header_t)) { ++ printf("ERROR: Given FIP is smaller than the ToC header.\n"); ++ status = EINVAL; ++ goto parse_fip_free; ++ } ++ /* Set the ToC Header at the base of the buffer */ ++ toc_header = (fip_toc_header_t *)fip_buffer; ++ /* The first toc entry should be just after the ToC header */ ++ toc_entry = (fip_toc_entry_t *)(toc_header + 1); ++ ++ /* While the ToC entry is contained into the buffer */ ++ int cnt = 0; ++ while (((char *)toc_entry + sizeof(fip_toc_entry_t)) < fip_buffer_end) { ++ cnt++; ++ /* Check if the ToC Entry is the last one */ ++ if (compare_uuids(&toc_entry->uuid, &uuid_null) == 0) { ++ found_last_toc_entry = true; ++ status = 0; ++ break; ++ } ++ ++ /* Add the entry into file_info */ ++ ++ /* Get the new entry in the array and clear it */ ++ file_info_entry = &files[file_info_count++]; ++ memset(file_info_entry, 0, sizeof(file_info_t)); ++ ++ /* Copy the info from the ToC entry */ ++ copy_uuid(&file_info_entry->name_uuid, &toc_entry->uuid); ++ file_info_entry->image_buffer = fip_buffer + ++ toc_entry->offset_address; ++ file_info_entry->size = toc_entry->size; ++ file_info_entry->align_size = 0x4000 * ((toc_entry->size / 0x4000) + 1); ++ ++ /* Check if there is a corresponding entry in lookup table */ ++ file_info_entry->entry = ++ get_entry_lookup_from_uuid(&toc_entry->uuid); ++ ++ /* Go to the next ToC entry */ ++ toc_entry++; ++ } ++ ++ if (!found_last_toc_entry) { ++ printf("ERROR: Given FIP does not have an end ToC entry.\n"); ++ status = EINVAL; ++ goto parse_fip_free; ++ } else { ++ /* All is well, we should not free any of the loaded images */ ++ goto parse_fip_fclose; ++ } ++ ++ parse_fip_free: ++ if (fip_buffer != NULL) { ++ free(fip_buffer); ++ fip_buffer = NULL; ++ } ++ ++ parse_fip_fclose: ++ if (fip != NULL) { ++ fclose(fip); ++ } ++ ++ parse_fip_return: ++ return status; ++} ++ ++ ++/* Parse all command-line options and return the FIP name if present. */ ++static char *get_filename(int argc, char **argv, struct option *options) ++{ ++ int c; ++ char *filename = NULL; ++ ++ /* Reset option pointer so we parse all args. starts at 1. ++ * The filename is the only argument that does not have an option flag. ++ */ ++ optind = 1; ++ while (1) { ++ c = getopt_long(argc, argv, "", options, NULL); ++ if (c == -1) ++ break; ++ ++ if (c == '?') { ++ /* Failed to parse an option. Fail. */ ++ return NULL; ++ } ++ } ++ ++ /* Only one argument left then it is the filename. ++ * We dont expect any other options ++ */ ++ if (optind + 1 == argc) ++ filename = argv[optind]; ++ ++ return filename; ++} ++ ++ ++/* Work through command-line options */ ++static int parse_cmdline(int argc, char **argv, struct option *options, ++ int *do_pack) ++{ ++ int c; ++ int status = 0; ++ int option_index = 0; ++ entry_lookup_list_t *lookup_entry; ++ int do_dump = 0; ++ ++ /* restart parse to process all options. starts at 1. */ ++ optind = 1; ++ while (1) { ++ c = getopt_long(argc, argv, "", options, &option_index); ++ if (c == -1) ++ break; ++ ++ switch (c) { ++ case OPT_TOC_ENTRY: ++ if (optarg) { ++ /* Does the option expect a filename. */ ++ lookup_entry = &toc_entry_lookup_list[option_index]; ++ if (lookup_entry->flags & FLAG_FILENAME) { ++ status = add_file_info_entry(lookup_entry, optarg); ++ if (status != 0) { ++ printf("Failed to process %s\n", ++ options[option_index].name); ++ break; ++ } else { ++ /* Update package */ ++ *do_pack = 1; ++ } ++ } ++ } ++ break; ++ ++ case OPT_DUMP: ++ do_dump = 1; ++ continue; ++ ++ case OPT_HELP: ++ print_usage(); ++ exit(0); ++ ++ default: ++ /* Unrecognised options are caught in get_filename() */ ++ break; ++ } ++ } ++ ++ ++ /* Do not dump toc if we have an error as it could hide the error */ ++ if ((status == 0) && (do_dump)) { ++ dump_toc(); ++ } ++ ++ return status; ++ ++} ++ ++int main(int argc, char **argv) ++{ ++ int i; ++ int status; ++ char *fip_filename; ++ int do_pack = 0; ++ ++ /* Clear file list table. */ ++ memset(files, 0, sizeof(files)); ++ ++ /* Initialise for getopt_long(). ++ * Use image table as defined at top of file to get options. ++ * Add 'dump' option, 'help' option and end marker. ++ */ ++ static struct option long_options[(sizeof(toc_entry_lookup_list)/ ++ sizeof(entry_lookup_list_t)) + 2]; ++ ++ for (i = 0; ++ /* -1 because we dont want to process end marker in toc table */ ++ i < sizeof(toc_entry_lookup_list)/sizeof(entry_lookup_list_t) - 1; ++ i++) { ++ long_options[i].name = toc_entry_lookup_list[i].command_line_name; ++ /* The only flag defined at the moment is for a FILENAME */ ++ long_options[i].has_arg = toc_entry_lookup_list[i].flags ? 1 : 0; ++ long_options[i].flag = 0; ++ long_options[i].val = OPT_TOC_ENTRY; ++ } ++ ++ /* Add '--dump' option */ ++ long_options[i].name = "dump"; ++ long_options[i].has_arg = 0; ++ long_options[i].flag = 0; ++ long_options[i].val = OPT_DUMP; ++ ++ /* Add '--help' option */ ++ long_options[++i].name = "help"; ++ long_options[i].has_arg = 0; ++ long_options[i].flag = 0; ++ long_options[i].val = OPT_HELP; ++ ++ /* Zero the last entry (required) */ ++ long_options[++i].name = 0; ++ long_options[i].has_arg = 0; ++ long_options[i].flag = 0; ++ long_options[i].val = 0; ++ ++#ifdef DEBUG ++ /* Print all supported options */ ++ for (i = 0; i < sizeof(long_options)/sizeof(struct option); i++) { ++ printf("long opt (%d) : name = %s\n", i, long_options[i].name); ++ } ++#endif /* DEBUG */ ++ ++ /* As the package may already exist and is to be updated we need to get ++ * the filename from the arguments and load from it. ++ * NOTE: As this is the first function to look at the program arguments ++ * it causes a failure if bad options were provided. ++ */ ++ fip_filename = get_filename(argc, argv, long_options); ++ ++ /* Try to open the file and load it into memory */ ++ if (fip_filename != NULL) { ++ status = parse_fip(fip_filename); ++ if (status != 0) { ++ return status; ++ } ++ } ++ ++ /* Work through provided program arguments and perform actions */ ++ status = parse_cmdline(argc, argv, long_options, &do_pack); ++ if (status != 0) { ++ return status; ++ }; ++ ++ if (fip_filename == NULL) { ++ printf("ERROR: Missing FIP filename\n"); ++ print_usage(); ++ return 0; ++ } ++ ++ /* Processed all command line options. Create/update the package if ++ * required. ++ */ ++ if (do_pack) { ++ status = pack_images(fip_filename); ++ if (status != 0) { ++ printf("Failed to create package (status = %d).\n", ++ status); ++ } ++ } ++ ++ return status; ++} +diff --git a/tools/fip_create/fip_create.h b/tools/fip_create/fip_create.h +new file mode 100644 +index 00000000000..81e0897f987 +--- /dev/null ++++ b/tools/fip_create/fip_create.h +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following disclaimer. ++ * ++ * Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * Neither the name of ARM nor the names of its contributors may be used ++ * to endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FIP_CREATE_H__ ++#define __FIP_CREATE_H__ ++ ++#include ++#include ++ ++#define MAX_FILES 10 ++ ++/* TODO: Update this number as required */ ++#define TOC_HEADER_SERIAL_NUMBER 0x12345678 ++ ++#define FLAG_FILENAME (1 << 0) ++ ++typedef struct entry_lookup_list { ++ const char *name; ++ uuid_t name_uuid; ++ const char *command_line_name; ++ struct file_info *info; ++ unsigned int flags; ++} entry_lookup_list_t; ++ ++typedef struct file_info { ++ uuid_t name_uuid; ++ const char *filename; ++ unsigned int size; ++ unsigned int align_size; ++ void *image_buffer; ++ entry_lookup_list_t *entry; ++} file_info_t; ++ ++#endif /* __FIP_CREATE_H__ */ +diff --git a/tools/fip_create/firmware_image_package.h b/tools/fip_create/firmware_image_package.h +new file mode 100644 +index 00000000000..0a8a67d9ac9 +--- /dev/null ++++ b/tools/fip_create/firmware_image_package.h +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following disclaimer. ++ * ++ * Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * Neither the name of ARM nor the names of its contributors may be used ++ * to endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FIRMWARE_IMAGE_PACKAGE_H__ ++#define __FIRMWARE_IMAGE_PACKAGE_H__ ++ ++#include ++#include ++ ++/* This is used as a signature to validate the blob header */ ++#define TOC_HEADER_NAME 0xAA640001 ++ ++ ++/* ToC Entry UUIDs */ ++#define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \ ++ {0x0becf95f, 0x224d, 0x4d3e, 0xa5, 0x44, {0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a} } ++#define UUID_SCP_FIRMWARE_BL30 \ ++ {0x3dfd6697, 0xbe89, 0x49e8, 0xae, 0x5d, {0x78, 0xa1, 0x40, 0x60, 0x82, 0x13} } ++#define UUID_SCP_FIRMWARE_BL301 \ ++ {0xAABBCCDD, 0xABCD, 0xEFEF, 0xAB, 0xCD, {0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD} } ++#define UUID_EL3_RUNTIME_FIRMWARE_BL31 \ ++ {0x6d08d447, 0xfe4c, 0x4698, 0x9b, 0x95, {0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x00} } ++#define UUID_SECURE_PAYLOAD_BL32 \ ++ {0x89e1d005, 0xdc53, 0x4713, 0x8d, 0x2b, {0x50, 0x0a, 0x4b, 0x7a, 0x3e, 0x38} } ++#define UUID_NON_TRUSTED_FIRMWARE_BL33 \ ++ {0xa7eed0d6, 0xeafc, 0x4bd5, 0x97, 0x82, {0x99, 0x34, 0xf2, 0x34, 0xb6, 0xe4} } ++ ++typedef struct fip_toc_header { ++ uint32_t name; ++ uint32_t serial_number; ++ uint64_t flags; ++} fip_toc_header_t; ++ ++typedef struct fip_toc_entry { ++ uuid_t uuid; ++ uint64_t offset_address; ++ uint64_t size; ++ uint64_t flags; ++} fip_toc_entry_t; ++ ++#endif /* __FIRMWARE_IMAGE_PACKAGE_H__ */ +diff --git a/tools/fip_create/uuid.h b/tools/fip_create/uuid.h +new file mode 100644 +index 00000000000..5c4767b5b55 +--- /dev/null ++++ b/tools/fip_create/uuid.h +@@ -0,0 +1,61 @@ ++/*- ++ * Copyright (c) 2002 Marcel Moolenaar ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * $FreeBSD$ ++ */ ++ ++/* ++ * Portions copyright (c) 2014, ARM Limited and Contributors. ++ * All rights reserved. ++ */ ++ ++#ifndef _SYS_UUID_H_ ++#define _SYS_UUID_H_ ++ ++#include ++ ++/* Length of a node address (an IEEE 802 address). */ ++#define _UUID_NODE_LEN 6 ++ ++/* ++ * See also: ++ * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt ++ * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm ++ * ++ * A DCE 1.1 compatible source representation of UUIDs. ++ */ ++struct uuid { ++ uint32_t time_low; ++ uint16_t time_mid; ++ uint16_t time_hi_and_version; ++ uint8_t clock_seq_hi_and_reserved; ++ uint8_t clock_seq_low; ++ uint8_t node[_UUID_NODE_LEN]; ++}; ++ ++/* XXX namespace pollution? */ ++typedef struct uuid uuid_t; ++ ++#endif /* _SYS_UUID_H_ */ diff --git a/hardware/odroid-hc4/overlays/uboot/hardkernel.nix b/hardware/odroid-hc4/overlays/uboot/hardkernel.nix new file mode 100644 index 0000000..7f2ad73 --- /dev/null +++ b/hardware/odroid-hc4/overlays/uboot/hardkernel.nix @@ -0,0 +1,50 @@ +{ gcc49Stdenv, git, bc, bison, flex, nettools, buildPackages, arm-gcc49 }: + +gcc49Stdenv.mkDerivation { + name = "hardkernel-uboot"; + src = builtins.fetchTarball { + url = "https://github.com/hardkernel/u-boot/archive/766167bbe787e494e47376b31cd017b897e9594c.tar.gz"; + sha256 = "0hj49jf9w2w55r7fjpx8asb92r85lws8mvq4mvl1v309z7k56zwv"; + }; + patches = [ ./pwd.diff ./fip_create.diff ]; + nativeBuildInputs = [ + git + gcc49Stdenv.cc + bc + bison + flex + nettools + ]; + depsBuildBuild = [ + arm-gcc49 + buildPackages.gcc49Stdenv.cc + ]; + makeFlags = [ + "CROSS_COMPILE=${gcc49Stdenv.cc.targetPrefix}" + ]; + configurePhase = '' + make odroidc4_defconfig + ''; + buildPhase = '' + make + ''; + installPhase = '' + mkdir -p $out/fip $out/bin + cp build/scp_task/bl301.bin \ + build/board/hardkernel/odroidc4/firmware/acs.bin \ + fip/g12a/bl2.bin \ + fip/g12a/bl30.bin \ + fip/g12a/bl31.img \ + fip/g12a/ddr3_1d.fw \ + fip/g12a/ddr4_1d.fw \ + fip/g12a/ddr4_2d.fw \ + fip/g12a/diag_lpddr4.fw \ + fip/g12a/lpddr3_1d.fw \ + fip/g12a/lpddr4_1d.fw \ + fip/g12a/lpddr4_2d.fw \ + fip/g12a/piei.fw \ + fip/g12a/aml_ddr.fw \ + $out/fip/ + cp fip/g12a/aml_encrypt_g12a $out/bin/ + ''; +} diff --git a/hardware/odroid-hc4/overlays/uboot/meson64-tools.nix b/hardware/odroid-hc4/overlays/uboot/meson64-tools.nix new file mode 100644 index 0000000..0fc21d1 --- /dev/null +++ b/hardware/odroid-hc4/overlays/uboot/meson64-tools.nix @@ -0,0 +1,15 @@ +{ stdenv, python2, python3 }: +stdenv.mkDerivation { + name = "meson64-tools"; + nativeBuildInputs = [ python2 python3 ]; + src = builtins.fetchTarball { + url = "https://github.com/angerman/meson64-tools/archive/a2d57d11fd8b4242b903c10dca9d25f7f99d8ff0.tar.gz"; + sha256 = "1487cr7sv34yry8f0chaj6s2g3736dzq0aqw239ahdy30yg7hb2v"; + }; + + preBuild = '' + patchShebangs . + patchShebangs ./mbedtls/scripts/generate_psa_constants.py + ''; + makeFlags = [ "PREFIX=$(out)/bin" ]; +} diff --git a/hardware/odroid-hc4/overlays/uboot/overlay.nix b/hardware/odroid-hc4/overlays/uboot/overlay.nix new file mode 100644 index 0000000..8cdcd29 --- /dev/null +++ b/hardware/odroid-hc4/overlays/uboot/overlay.nix @@ -0,0 +1,28 @@ +final: prev: +let + platform = final.lib.systems.examples.aarch64-multiplatform // { + gcc = { + arch = "armv8-a+crypto"; + }; + }; + arm64 = final.pkgsCross.aarch64-embedded; + arm = final.pkgsCross.arm-embedded; + uboot-hardkernel = arm64.callPackage ./hardkernel.nix { + arm-gcc49 = arm.buildPackages.gcc49; + }; + with-crypto = import final.path { + crossSystem = platform; + }; + meson64-tools = with-crypto.buildPackages.callPackage ./meson64-tools.nix { }; + blx_fix = arm64.buildPackages.callPackage ./blx_fix.nix { }; + uboot = arm64.callPackage ./u-boot.nix { + inherit uboot-hardkernel meson64-tools blx_fix; + }; +in +{ + uboot-hardkernel = uboot; + ubootTools-hardkernel = final.buildPackages.ubootTools; + buildPackages = prev.buildPackages // { + ubootTools-hardkernel = final.buildPackages.buildPackages.ubootTools; + }; +} diff --git a/hardware/odroid-hc4/overlays/uboot/pwd.diff b/hardware/odroid-hc4/overlays/uboot/pwd.diff new file mode 100644 index 0000000..9060801 --- /dev/null +++ b/hardware/odroid-hc4/overlays/uboot/pwd.diff @@ -0,0 +1,13 @@ +diff --git a/Makefile b/Makefile +index 730e8d752f..127a260ee8 100644 +--- a/Makefile ++++ b/Makefile +@@ -134,7 +134,7 @@ ifneq ($(KBUILD_OUTPUT),) + # check that the output directory actually exists + saved-output := $(KBUILD_OUTPUT) + KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \ +- && /bin/pwd) ++ && pwd) + $(if $(KBUILD_OUTPUT),, \ + $(error failed to create output directory "$(saved-output)")) + diff --git a/hardware/odroid-hc4/overlays/uboot/u-boot.nix b/hardware/odroid-hc4/overlays/uboot/u-boot.nix new file mode 100644 index 0000000..407fde8 --- /dev/null +++ b/hardware/odroid-hc4/overlays/uboot/u-boot.nix @@ -0,0 +1,98 @@ +{ stdenv +, git +, bc +, bison +, flex +, nettools +, openssl +, buildPackages +, uboot-hardkernel +, meson64-tools +, blx_fix +}: +let +in +stdenv.mkDerivation { + name = "uboot"; + src = builtins.fetchTarball { + url = "https://github.com/u-boot/u-boot/archive/15f7e0dc01d8a851fb1bfbf0e47eab5b67ed26b3.tar.gz"; + sha256 = "1ardkap35pi2dsajag728fnvlvpfmdrsa0igj93wbkbf2ypzzhf6"; + }; + CROSS_COMPILE = stdenv.cc.targetPrefix; + configurePhase = '' + make odroid-c4_defconfig + ''; + buildPhase = '' + make + ''; + installPhase = '' + mkdir fip + cp ${uboot-hardkernel}/fip/* fip/ + cp u-boot.bin fip/bl33.bin + ${blx_fix} \ + fip/bl30.bin \ + fip/zero_tmp \ + fip/bl30_zero.bin \ + fip/bl301.bin \ + fip/bl301_zero.bin \ + fip/bl30_new.bin \ + bl30 + + ${blx_fix} \ + fip/bl2.bin \ + fip/zero_tmp \ + fip/bl2_zero.bin \ + fip/acs.bin \ + fip/bl21_zero.bin \ + fip/bl2_new.bin \ + bl2 + + ${meson64-tools}/bin/bl30sig \ + --input fip/bl30_new.bin \ + --output fip/bl30_new.bin.g12a.enc \ + --level v3 + ${meson64-tools}/bin/bl3sig \ + --input fip/bl30_new.bin.g12a.enc \ + --output fip/bl30_new.bin.enc \ + --level v3 --type bl30 + ${meson64-tools}/bin/bl3sig \ + --input fip/bl31.img \ + --output fip/bl31.img.enc \ + --level v3 --type bl31 + ${meson64-tools}/bin/bl3sig \ + --input fip/bl33.bin --compress lz4 \ + --output fip/bl33.bin.enc \ + --level v3 --type bl33 --compress lz4 + ${meson64-tools}/bin/bl2sig \ + --input fip/bl2_new.bin \ + --output fip/bl2.n.bin.sig + ${meson64-tools}/bin/bootmk \ + --output $out \ + --bl2 fip/bl2.n.bin.sig \ + --bl30 fip/bl30_new.bin.enc \ + --bl31 fip/bl31.img.enc \ + --bl33 fip/bl33.bin.enc \ + --ddrfw1 fip/ddr4_1d.fw \ + --ddrfw2 fip/ddr4_2d.fw \ + --ddrfw3 fip/ddr3_1d.fw \ + --ddrfw4 fip/piei.fw \ + --ddrfw5 fip/lpddr4_1d.fw \ + --ddrfw6 fip/lpddr4_2d.fw \ + --ddrfw7 fip/diag_lpddr4.fw \ + --ddrfw8 fip/aml_ddr.fw \ + --ddrfw9 fip/lpddr3_1d.fw \ + --level v3 + ''; + nativeBuildInputs = [ + git + bc + bison + flex + nettools + ]; + + depsBuildBuild = [ + buildPackages.stdenv.cc + buildPackages.openssl.dev + ]; +} diff --git a/hardware/odroid-hc4/uboot/boot-ini-builder.nix b/hardware/odroid-hc4/uboot/boot-ini-builder.nix new file mode 100644 index 0000000..4d6d407 --- /dev/null +++ b/hardware/odroid-hc4/uboot/boot-ini-builder.nix @@ -0,0 +1,15 @@ +{ pkgs }: + +pkgs.substituteAll { + src = ./boot-ini-builder.sh; + isExecutable = true; + path = [ + pkgs.coreutils + pkgs.gnused + pkgs.gnugrep + pkgs.gzip + pkgs.ubootTools-hardkernel + ]; + configIni = ./config.ini; + inherit (pkgs) bash; +} diff --git a/hardware/odroid-hc4/uboot/boot-ini-builder.sh b/hardware/odroid-hc4/uboot/boot-ini-builder.sh new file mode 100644 index 0000000..66ecd16 --- /dev/null +++ b/hardware/odroid-hc4/uboot/boot-ini-builder.sh @@ -0,0 +1,189 @@ +#! @bash@/bin/sh -e + +shopt -s nullglob + +export PATH=/empty +for i in @path@; do PATH=$PATH:$i/bin; done + +usage() { + echo "usage: $0 -t -c [-d ] [-g ] [-n ]" >&2 + exit 1 +} + +timeout= # Timeout in centiseconds +default= # Default configuration +target=/boot # Target directory +numGenerations=0 # Number of other generations to include in the menu + +while getopts "t:c:d:g:n:" opt; do + case "$opt" in + t) # U-Boot interprets '0' as infinite and negative as instant boot + if [ "$OPTARG" -lt 0 ]; then + timeout=0 + elif [ "$OPTARG" = 0 ]; then + timeout=-10 + else + timeout=$((OPTARG * 10)) + fi + ;; + c) default="$OPTARG" ;; + d) target="$OPTARG" ;; + g) numGenerations="$OPTARG" ;; + n) dtbName="$OPTARG" ;; + \?) usage ;; + esac +done + +[ "$timeout" = "" -o "$default" = "" ] && usage + +mkdir -p $target/nixos + +# Convert a path to a file in the Nix store such as +# /nix/store/-/file to --. +cleanName() { + local path="$1" + echo "$path" | sed 's|^/nix/store/||' | sed 's|/|-|g' +} + +# Copy a file from the Nix store to $target/nixos. +declare -A filesCopied + +copyToKernelsDir() { + local src=$(readlink -f "$1") + local dst="$target/nixos/$(cleanName $src)" + # Don't copy the file if $dst already exists. This means that we + # have to create $dst atomically to prevent partially copied + # kernels or initrd if this script is ever interrupted. + if ! test -e $dst; then + local dstTmp=$dst.tmp.$$ + cp -r $src $dstTmp + mv $dstTmp $dst + fi + filesCopied[$dst]=1 + result=$dst +} + +copyInitrd() { + local src=$(readlink -f "$1") + local dst="$target/nixos/$(cleanName $src)" + if ! test -e $dst; then + local initrd=$dst.initrd.tmp.$$ + local dstTmp=$dst.tmp.$$ + # Unzip and convert ramdisk to uInitrd format (u-boot initrd) + gzip -d <"$path/initrd" >$initrd + mkimage -A arm64 -O linux -T ramdisk -C none -d "$initrd" "$dstTmp" >/dev/null + rm $initrd + mv $dstTmp $dst + fi + filesCopied[$dst]=1 + result=$dst +} + +# Copy its kernel, initrd and dtbs to $target/nixos, and echo out boot.ini entry +addEntry() { + local path=$(readlink -f "$1") + local tag="$2" # Generation number or 'default' + + if ! test -e $path/kernel -a -e $path/initrd; then + return + fi + + copyToKernelsDir "$path/kernel" + kernel=$result + copyInitrd "$path/initrd" + initrd=$result + dtbDir=$(readlink -m "$path/dtbs") + if [ -e "$dtbDir" ]; then + copyToKernelsDir "$dtbDir" + dtbs=$result + fi + + echo "load mmc \${devno}:1 \${k_addr} nixos/$(basename $kernel)" + echo "load mmc \${devno}:1 \${dtb_loadaddr} nixos/$(basename $dtbs)/amlogic/meson64_odroid\${variant}.dtb" + echo "fdt addr \${dtb_loadaddr}" + echo "load mmc \${devno}:1 \${initrd_loadaddr} nixos/$(basename $initrd)" + echo "setenv bootargs \"\${bootargs} \"" + echo "# Boot Args" + echo "setenv bootargs \"root=root=/dev/mmcblk\${devno}p2 rootwait rw \${condev} \${amlogic} no_console_suspend fsck.repair=yes net.ifnames=0 elevator=noop hdmimode=\${hdmimode} cvbsmode=576cvbs max_freq_a55=\${max_freq_a55} maxcpus=\${maxcpus} voutmode=\${voutmode} \${cmode} disablehpd=\${disablehpd} cvbscable=\${cvbscable} overscan=\${overscan} \${hid_quirks} monitor_onoff=\${monitor_onoff} logo=osd0,loaded \${cec_enable} sdrmode=\${sdrmode} enable_wol=\${enable_wol} systemConfig=$path init=$path/init\"" +} + +tmpFile="$target/boot.ini.tmp.$$" + +# This configuration was adapted from the Ubuntu 20.04 image provided +# on the Hardkernel Wiki. +cat >$tmpFile <>$tmpFile + +cat >>$tmpFile </boot/extlinux.conf. For instance, + U-Boot's generic distro boot support uses this file format. + See U-boot's documentation + for more information. + ''; + }; + + populateCmd = mkOption { + type = types.str; + readOnly = true; + description = '' + Contains the builder command used to populate an image, + honoring all options except the -c <path-to-default-configuration> + argument. + Useful to have for sdImage.populateRootCommands + ''; + }; + + }; + }; + + config = + let + builderArgs = "-t ${timeoutStr}" + lib.optionalString (dtCfg.name != null) " -n ${dtCfg.name}"; + in + mkIf cfg.enable { + system.build.installBootLoader = "${builder} ${builderArgs} -c"; + system.boot.loader.id = "hardkernel-uboot"; + boot.loader.hardkernel-uboot.populateCmd = "${populateBuilder} ${builderArgs}"; + }; +} diff --git a/hosts/ceilidh.nix b/hosts/ceilidh.nix new file mode 100644 index 0000000..2a4ead7 --- /dev/null +++ b/hosts/ceilidh.nix @@ -0,0 +1,31 @@ +# NixOps configuration for pĂ idh-tri + +{ config, pkgs, lib, ... }: + +{ + imports = [ + ../hardware/odroid-hc4 + ]; + + # Comment out deployment when building the SD Image. + deployment.targetHost = "10.42.0.121"; + networking.hostName = "ceilidh"; # Define your hostname. + + # Ensure the right package architecture is used + nixpkgs = { + config = { + allowUnfree = true; + allowUnsupportedSystem = true; + }; + localSystem = { + system = "aarch64-linux"; + config = "aarch64-unknown-linux-gnu"; + }; + }; + + environment.systemPackages = with pkgs; [ + gnupg # GPL OpenPGP implementation + ]; + + system.stateVersion = "21.05"; # The version of NixOS originally installed +}