Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.5:Update
mlxbf-bootctl
mlxbf-bootctl-1.1.6.11.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File mlxbf-bootctl-1.1.6.11.obscpio of Package mlxbf-bootctl
07070100000000000081A4000003E800000064000000015F7A2ABE00000533000000000000000000000000000000000000001F00000000mlxbf-bootctl-1.1.6.11/LICENSEBSD 2-Clause License Copyright (c) 2020, Mellanox Technologies 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 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. 07070100000001000081A4000003E800000064000000015F7A2ABE0000031C000000000000000000000000000000000000002000000000mlxbf-bootctl-1.1.6.11/MakefilePROJECT_NAME:=mlxbf-bootctl SBINDIR = /sbin # Default target. all: include $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))/package.mk # By default, use the Makefile's directory as the vpath. VPATH := $(dir $(lastword $(MAKEFILE_LIST))) CFLAGS += -O2 -g -std=gnu99 -Werror \ -Wall -Wshadow -Wuninitialized -Wstrict-overflow -Wundef \ -Wold-style-definition -Wwrite-strings LDFLAGS += -Wl,--fatal-warnings SOURCES := \ mlxbf-bootctl.c \ # Grab dependencies, if they exist. -include $(SOURCES:.c=.d) %.o: %.c $(CC) $(CFLAGS) -MD -MP -c -o $@ $< mlxbf-bootctl: $(SOURCES:.c=.o) $(CC) $(LDFLAGS) -o $@ $^ all: mlxbf-bootctl install:: mkdir -p $(DESTDIR)$(SBINDIR) cp -f mlxbf-bootctl $(DESTDIR)$(SBINDIR) clean: rm -f *.d *.o mlxbf-bootctl .PHONY: all install clean 07070100000002000081A4000003E800000064000000015F7A2ABE0000272B000000000000000000000000000000000000002100000000mlxbf-bootctl-1.1.6.11/README.mdmlxbf-bootctl ============= Background ---------- The BlueField boot flow comprises 4 main phases: - Hardware loads ARM Trusted Firmware (ATF) - ATF loads Unified Extensible Firmware Interface (UEFI); together ATF and UEFI make up the booter software - UEFI loads the operating system, such as the Linux kernel - The operating system loads applications and user data When booting from eMMC, these stages make use of two different types of storage within the eMMC part: - ATF and UEFI come from a special area known as an eMMC boot partition. Data from a boot partition is automatically streamed from the eMMC device to the eMMC controller under hardware control during the initial bootup. Each eMMC device has two boot partitions, and the partition that is used to stream the boot data is chosen by a non-volatile configuration register in the eMMC. - The operating system, applications, and user data come from the remainder of the chip, known as the user area. This area is accessed via block-size reads and writes, done by a device driver or similar software routine. In most deployments, BlueField's ARM cores are expected to obtain their software stack from an on-board Embedded Multi-Media Card (eMMC) device. Even in environments where the final OS kernel is not kept on eMMC -- for instance, systems which boot over a network -- the initial booter code will still come from eMMC. Most software stacks need to be modified or upgraded at some point in their lifetime. Doing this on a fielded BlueField system involves some risk; if there's a severe problem with the new software, system operation may be impaired to the extent that it is impossible to do further modifications to fix the problem. Ideally, one would like to be able to install a new software version on a BlueField system, try it out, and then fall back to a previous version if the new one does not work. In some environments, it's important that this fallback operation happen automatically, since there may be no physical access to the system. In others, there may be an external agent, like a service processor, which could manage the process. Solution Overview ----------------- In order to satisfy the requests listed above, we do the following: - Provide two software partitions on the eMMC, 0 and 1. At any given time, one area is designated the primary partition, and the other the backup partition. The primary partition is the one we'll boot from on the next reboot or reset. - Allow software running on the ARM cores to declare that the primary partition is now the backup partition, and vice versa. (For brevity, in the remainder of this document, we'll term this "swapping the partitions", although we're just modifying a pointer; the data on the partitions does not move.) - Allow an external agent, like a service processor, to swap the primary and backup partitions. - Allow software running on the ARM cores to reboot the system, while starting an upgrade watchdog timer. If the upgrade watchdog expires, the system will reboot, but the primary and backup partitions will first be swapped. The mlxbf-bootctl Program ------------------------- Access to all the boot partition management is via a program shipped with the BlueField software called "mlxbf-bootctl". The binary is shipped as part of our Yocto image (in /sbin) and the sources are shipped in the "src" directory in the BlueField Runtime Distribution. A simple `make` command will build the utility. The mlxbf-bootctl syntax is as follows: ``` syntax: mlxbf-bootctl [--help|-h] [--swap|-s] [--device|-d MMCFILE] [--output|-o OUTPUT] [--read|-r INPUT] [--bootstream|-b BFBFILE] [--overwrite-current] [--watchdog-swap interval | --nowatchdog-swap] --device: Use a device other than the default /dev/mmcblk0 --bootstream: Write the specified bootstream to the alternate partition of the device. This queries the base device (e.g. /dev/mmcblk0) for the alternate partition, and uses that information to open the appropriate boot partition device, e.g. /dev/mmcblk0boot0. --overwrite-current: Used with "--bootstream" to overwrite the current boot partition instead of the alternate one (not recommended) --output: Used with "--bootstream" to specify a file to write the boot partition data to (creating it if necessary), rather than using an existing master device and deriving the boot partition device. --read: Read a bootstream and convert it back to a BFBFILE specified by --bootstream. For example use "mlxbf-bootctl --read /dev/mmcblk0boot0 --bootstream current.bfb" to read the current bfb installed on boot partition zero. --watchdog-swap: Arrange to start the ARM watchdog with a countdown of the specified number of seconds until it fires; also, set the boot software so that it will swap the primary and alternate partitions at the next reset. --nowatchdog-swap: Ensure that after the next reset, no watchdog will be started, and no swapping of boot partitions will happen. ``` Updating the Boot Partition --------------------------- To update the boot partition on the ARM cores, let us assume we have a new bootstream file, e.g. "bootstream.new". We would like to install and validate this new bootstream. To just update and hope for the best, you can do: ```bash mlxbf-bootctl --bootstream bootstream.new --swap reboot ``` This will write the new bootstream to the alternate boot partition, swap alternate and primary so that the new bootstream will be used on the next reboot, then reboot to use it. (You can also use `--overwrite-current` instead of `--swap`, which will just overwrite your current boot partition, but this is not recommended as there is no easy way to recover if the new booter code does not bring the system up.) Safely Updating with a BMC -------------------------- With a BMC (board management processor) you can do better. The ARM cores simply notify the BMC prior to the reboot that an upgrade is about to happen. Software running on the BMC can then be implemented that will watch the ARM cores after reboot. If after some time the BMC has not seen the ARM cores come up properly (for whatever definition is appropriate for the application in question), it can use its USB debug connection to the ARM cores to properly reset the ARM cores, first setting a suitable mode bit that the ARM booter will respond to by switching the primary and alternate boot partitions as part of resetting into its original state. Safely Updating from the ARM Cores ---------------------------------- Without a BMC, you can use the ARM watchdog to achieve similar results. If something goes wrong on the next reboot and the system does not come up properly, it will reboot and return to the original configuration. In this case, you might run: ```bash mlxbf-bootctl --bootstream bootstream.new --swap --watchdog-swap 60 reboot ``` With these commands, you will reboot the system, and if it hangs for 60 seconds or more, the watchdog will fire and reset the chip, the booter will swap the partitions back again to the way they were before, and the system will reboot back with the original boot partition data. Similarly, if the system comes up but panics and resets, the booter will again swap the boot partition back to the way it was before. You must ensure that Linux after the reboot is configured to boot up with the `sbsa_gwdt` driver enabled. This is the SBSA (Server Base System Architecture) Generic WatchDog Timer. As soon as the driver is loaded, it will start refreshing the watchdog and preventing it from firing, which will allow your system to finish booting up safely. In the example above, we allow 60 seconds from system reset until the Linux watchdog kernel driver is loaded. At that point, your application may open /dev/watchdog explicitly, and the application would then become responsible for refreshing the watchdog frequently enough to keep the system from rebooting. For documentation on the Linux watchdog subsystem, see the Linux watchdog documentation: https://www.kernel.org/doc/Documentation/watchdog/watchdog-api.txt For example, to disable the watchdog completely, you can run: ```bash echo V > /dev/watchdog ``` You can incorporate other features of the ARM generic watchdog into your application code using the programming API as well, if you wish. Once the system has booted up, in addition to disabling or reconfiguring the watchdog itself if you wish, you should also clear the "swap on next reset" functionality from the booter by running: ```bash mlxbf-bootctl --nowatchdog-swap ``` Otherwise, next time you reset the system (via reboot, external reset, etc) it will assume a failure or watchdog reset occurred and swap the eMMC boot partition automatically. The above steps can be done manually, or can be done automatically by software running in the newly-booted system. Changing the Kernel or Userspace -------------------------------- The above solutions simply update the boot partition to hold new booter software (ATF and UEFI). If you want to also provide a new kernel image and/or new userspace, you should partition your eMMC into multiple partitions appropriately. For example, you might have a single FAT partition that UEFI can read the kernel image file from, but the new bootstream contains a UEFI bootpath pointing to an updated kernel image. Similarly, you might have two Linux partitions, and your upgrade procedure would write a new filesystem into the "idle" Linux partition, then reboot with the bootstream holding kernel boot arguments that direct it to boot from the previously idle partition. The details on how exactly to do this depend on the specifics of how and what need to be upgraded for the specific application, but in principle any component of the system can be safely upgraded using this type of approach. 07070100000003000041ED000003E800000064000000035F7A2ABE00000000000000000000000000000000000000000000001E00000000mlxbf-bootctl-1.1.6.11/debian07070100000004000081A4000003E800000064000000015F7A2ABE000000C5000000000000000000000000000000000000002800000000mlxbf-bootctl-1.1.6.11/debian/changelogmlxbf-bootctl (2.1) UNRELEASED; urgency=medium * First debian package release -- Alfonso Sanchez-Beato (email Canonical) <alfonso.sanchez-beato@canonical.com> Fri, 13 Mar 2020 09:27:39 +0100 07070100000005000081A4000003E800000064000000015F7A2ABE00000003000000000000000000000000000000000000002500000000mlxbf-bootctl-1.1.6.11/debian/compat10 07070100000006000081A4000003E800000064000000015F7A2ABE000001AC000000000000000000000000000000000000002600000000mlxbf-bootctl-1.1.6.11/debian/controlSource: mlxbf-bootctl Section: net Priority: optional Maintainer: Vladimir Sokolovsky <vlad@mellanox.com> Build-Depends: debhelper (>= 10) Standards-Version: 4.1.2 Package: mlxbf-bootctl Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Binary to manage Mellanox boot partitions Access to all the boot partition management is via a program shipped with the BlueField software called "mlxbf-bootctl". 07070100000007000081A4000003E800000064000000015F7A2ABE00000674000000000000000000000000000000000000002800000000mlxbf-bootctl-1.1.6.11/debian/copyrightFormat: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: mlxbf-bootctl Source: https://mellanox.com Files: * Copyright: 2018 Mellanox License: GPL-2 or OpenIB.org This software is available to you under a choice of one of two licenses. You may choose to be licensed under the terms of the GNU General Public License (GPL) Version 2, available from the file COPYING in the main directory of this source tree, or the OpenIB.org BSD license below: . 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. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file '/usr/share/common-licenses/GPL-2'. 07070100000008000081A4000003E800000064000000015F7A2ABE0000000A000000000000000000000000000000000000003100000000mlxbf-bootctl-1.1.6.11/debian/mlxbf-bootctl.docsREADME.md 07070100000009000081ED000003E800000064000000015F7A2ABE0000006F000000000000000000000000000000000000002400000000mlxbf-bootctl-1.1.6.11/debian/rules#!/usr/bin/make -f %: dh $@ override_dh_auto_build: dh_auto_build -- CFLAGS="$(CFLAGS) -Wno-unused-result" 0707010000000A000041ED000003E800000064000000025F7A2ABE00000000000000000000000000000000000000000000002500000000mlxbf-bootctl-1.1.6.11/debian/source0707010000000B000081A4000003E800000064000000015F7A2ABE0000000D000000000000000000000000000000000000002C00000000mlxbf-bootctl-1.1.6.11/debian/source/format3.0 (native) 0707010000000C000081A4000003E800000064000000015F7A2ABE00000D1D000000000000000000000000000000000000002700000000mlxbf-bootctl-1.1.6.11/mlxbf-bootctl.8.TH MLXBF\-BOOTCTL 8 "September 3, 2020" "version 2.1" "System Administration" .SH NAME mlxbf-bootctl \- control Mellanox BlueField boot partitions .SH SYNOPSIS .B mlxbf\-bootctl [\-h|\-\-help] [options] .SH DESCRIPTION .B mlxbf-bootctl is used to control the two boot firmware partitions present on most Mellanox BlueField devices. .SS Boot Partitions Most Bluefield devices obtain their boot firmware (ATF, UEFI, etc) from an on-board Embedded Multi-Media Card (eMMC). The eMMC has two partitions that are treated separately from the others: boot0 and boot1, one of which acts as the primary, the other acting as a backup. In addition, there is a watchdog timer present on the chip, which when activated, will automatically swap which boot partition is active if it is not deactivated in time. These two features, taken together, allow for safe BlueField firmware upgrades that may rolled back in case of failure. .B mlxbf-bootctl controls these features. If .B mlxbf-bootctl is run without options, it will print the current state of the boot partitions. .SH OPTIONS .TP .B \-\-device|\-d MMCFILE Use a device other than the default .I /dev/mmcblk0 .TP .B \-\-bootstream|\-b BFBFILE Write the specified bootstream to the alternate partition of the device. This queries the base device (e.g. .I /dev/mmcblk0 ) for the alternate partition, and uses that information to open the appropriate boot partition device, e.g. the .I /dev/mmcblk0boot0 file. BFB files that can be installed in the boot partitions are typically named "default.bfb" in BlueField software distributions. .TP .B \-\-overwrite\-current Used with "\-\-bootstream" to overwrite the current boot partition instead of the alternate one. This is not recommended as there is no easy way to recover if the new boot code does not bring the system up. .TP .B \-\-output|\-o OUTPUT Used with "\-\-bootstream" to specify a file to write the boot partition data to (creating it if necessary), rather than using an existing master device and deriving the boot partition device. .TP .B \-\-read|\-r INPUT Read a bootstream and convert it back to a BFBFILE specified by "\-\-bootstream". For example use .RS 11 .B mlxbf-bootctl \-\-read /dev/mmcblk0boot0 .sp 0 \-\-bootstream current.bfb .RE .IP to read the current bfb installed on boot partition zero. .TP .B \-\-watchdog\-swap SECONDS Arrange to start the ARM watchdog with a countdown of the specified number of seconds until it firms; also, set the boot software so that it will swap the primary and alternate partitions at the next reset. Mutually exclusive with "\-\-nowatchdog\-swap". .TP .B \-\-nowatchdog-swap Ensure that after the next reset, no watchdog will be started, and no swapping of boot partitions will happen. .TP .B \-\-swap|\-s Set the boot software so that will swap the primary and alternate partitions at the next reset. .SH EXAMPLES To update to new firmware as safely as possible: .IP .B mlxbf-bootctl \-\-bootstream new.bfb \-\-watchdog\-swap 90 .PP Once the new firmware is confirmed to be good, turn off watchdog swapping with .IP .B mlxbf-bootctl \-\-nowatchdog-swap .SH COMMON ISSUES When the watchdog timer is activated through the "\-\-watchdog\-swap" option, entering the UEFI menu for long enough will trigger a reboot and partition swap. To avoid this, run "\-\-nowatchdog\-swap" before entering the UEFI menu. 0707010000000D000081A4000003E800000064000000015F7A2ABE00005DD6000000000000000000000000000000000000002700000000mlxbf-bootctl-1.1.6.11/mlxbf-bootctl.c/* * Copyright (c) 2017-2018, Mellanox Technologies Ltd. * 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 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. */ #define _GNU_SOURCE // asprintf #include <errno.h> #include <getopt.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/fcntl.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <linux/limits.h> #include <linux/major.h> /* Boot FIFO constants */ #define BOOT_FIFO_ADDR 0x0408 #define SEGMENT_HEADER_LEN 8 #define MAX_SEG_LEN ((1 << 20) - SEGMENT_HEADER_LEN) #define SEGMENT_IS_END (1UL << 63) void die(const char* fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); putc('\n', stderr); va_end(ap); exit(1); } #ifndef OUTPUT_ONLY #include <linux/mmc/ioctl.h> /* * The Linux MMC driver doesn't export its ioctl command values, so we * copy them from include/linux/mmc/mmc.h and include/linux/mmc/core.h. */ #define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SEND_EXT_CSD 8 /* adtc R1 */ #define MMC_RSP_PRESENT (1 << 0) #define MMC_RSP_CRC (1 << 2) /* expect valid crc */ #define MMC_RSP_BUSY (1 << 3) /* card may send busy */ #define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ #define MMC_RSP_SPI_S1 (1 << 7) /* one status byte */ #define MMC_RSP_SPI_BUSY (1 << 10) /* card may send busy */ #define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) #define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY) #define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY) #define MMC_CMD_AC (0 << 5) #define MMC_CMD_ADTC (1 << 5) #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ #define EXT_CSD_CMD_SET_NORMAL (1<<0) /* EXT_CSD register offset. */ #define EXT_CSD_RST_N 162 /* R/W */ #define EXT_CSD_BOOT_BUS_WIDTH 177 /* R/W */ #define EXT_CSD_PART_CONFIG 179 /* R/W */ #define EXT_CSD_BOOT_SIZE_MULT 226 /* R/W */ /* BOOT_BUS_WIDTH register definition. */ #define EXT_CSD_BOOT_BUS_WIDTH_MASK_ALL 0x7 #define EXT_CSD_BOOT_BUS_WIDTH_MASK 0x3 #define EXT_CSD_BOOT_BUS_WIDTH_RESET_MASK 0x4 #define EXT_CSD_BOOT_BUS_WIDTH_X8 0x6 /* EXT_CSD_RST_N register definition. */ #define EXT_CSD_RST_N_MASK 0x3 #define EXT_CSD_RST_N_ENABLE 0x1 /* Program constants */ #define EMMC_MIN_BOOT_SIZE 0x20000 #define EMMC_BLOCK_SIZE 512 #define SYS_PATH1 "/sys/bus/platform/drivers/mlx-bootctl" #define SYS_PATH2 "/sys/bus/platform/devices/MLNXBF04:00" #define SECOND_RESET_ACTION_PATH "second_reset_action" #define POST_RESET_WDOG_PATH "post_reset_wdog" #define LIFECYCLE_STATE_PATH "lifecycle_state" #define SECURE_BOOT_FUSE_STATE_PATH "secure_boot_fuse_state" #define MMC_BOOT_PARTITION_MAX_SIZE (4 * 1024 * 1024) /* * BFB image header. * * This definition is extracted from file * atf/plat/mellanox/common/include/drivers/io/bluefield_boot.h */ #define BFB_IMGHDR_MAGIC 0x13026642 /* "Bf^B^S" */ typedef struct { unsigned long magic:32; unsigned long major:4; unsigned long minor:4; unsigned long reserved:4; unsigned long next_img_ver:4; unsigned long cur_img_ver:4; unsigned long hdr_len:4; unsigned long image_id:8; unsigned long image_len:32; unsigned long image_crc:32; unsigned long following_images:64; } boot_image_header_t; /* Program variables */ const char *mmc_path = "/dev/mmcblk0"; /* Run an MMC_IOC_CMD ioctl on mmc_path */ void mmc_command(struct mmc_ioc_cmd *idata) { static int mmc_fd = -1; if (mmc_fd < 0) { mmc_fd = open(mmc_path, O_RDWR); if (mmc_fd < 0) die("%s: %m", mmc_path); } if (ioctl(mmc_fd, MMC_IOC_CMD, idata) < 0) die("%s: mmc ioctl: %m", mmc_path); } uint8_t* get_ext_csd(void) { static uint8_t ext_csd[EMMC_BLOCK_SIZE] __attribute__((aligned(EMMC_BLOCK_SIZE))) = { 0 }; struct mmc_ioc_cmd idata = { .write_flag = 0, .opcode = MMC_SEND_EXT_CSD, .arg = 0, .flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC, .blksz = EMMC_BLOCK_SIZE, .blocks = 1 }; mmc_ioc_cmd_set_data(idata, ext_csd); mmc_command(&idata); return ext_csd; } /* Return the current partition (0 or 1) that we will boot from. */ int get_boot_partition(void) { uint8_t *ext_csd = get_ext_csd(); int part = ((ext_csd[EXT_CSD_PART_CONFIG] >> 3) & 0x7) - 1; /* Set part to 0 by default if it is -1 (boot disabled). */ if (part < 0 || part > 1) part = 0; return part; } /* Set which partition to boot from. */ void set_boot_partition(int part) { int value = ((part + 1) & 0x7) << 3; /* Adjust for 1-based numbering */ struct mmc_ioc_cmd idata = { .write_flag = 1, .opcode = MMC_SWITCH, .arg = ((MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_PART_CONFIG << 16) | (value << 8) | EXT_CSD_CMD_SET_NORMAL), .flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC }; mmc_command(&idata); } /* Get the boot partition size */ uint64_t get_boot_partition_size(void) { uint64_t part_size; uint8_t *ext_csd = get_ext_csd(); part_size = (ext_csd[EXT_CSD_BOOT_SIZE_MULT]) * EMMC_MIN_BOOT_SIZE; return part_size; } /* Return the current boot bus width. */ int get_boot_bus_width(void) { uint8_t *ext_csd = get_ext_csd(); return ext_csd[EXT_CSD_BOOT_BUS_WIDTH] & EXT_CSD_BOOT_BUS_WIDTH_MASK_ALL; } /* Set the boot-bus-width to 8-bit mode in ECSD. */ void set_boot_bus_width(void) { uint8_t *ext_csd = get_ext_csd(); int value = (ext_csd[EXT_CSD_BOOT_BUS_WIDTH] & ~EXT_CSD_BOOT_BUS_WIDTH_MASK_ALL) | EXT_CSD_BOOT_BUS_WIDTH_X8; struct mmc_ioc_cmd idata = { .write_flag = 1, .opcode = MMC_SWITCH, .arg = ((MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_BOOT_BUS_WIDTH << 16) | (value << 8) | EXT_CSD_CMD_SET_NORMAL), .flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC }; mmc_command(&idata); } void enable_rst_n(void) { uint8_t *ext_csd = get_ext_csd(); int value = (ext_csd[EXT_CSD_RST_N] & ~EXT_CSD_RST_N_MASK) | EXT_CSD_RST_N_ENABLE; struct mmc_ioc_cmd idata = { .write_flag = 1, .opcode = MMC_SWITCH, .arg = ((MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_RST_N << 16) | (value << 8) | EXT_CSD_CMD_SET_NORMAL), .flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC }; mmc_command(&idata); } FILE *open_sysfs(const char *name, const char *attr) { FILE *f; char path[PATH_MAX]; sprintf(path, "%s/%s", SYS_PATH1, name); f = fopen(path, attr); if (f == NULL) { sprintf(path, "%s/%s", SYS_PATH2, name); f = fopen(path, attr); } if (f == NULL) { if (errno == ENOENT) { fprintf(stderr, "cannot find required sysfs path %s\n", path); die("please load mlxbf_bootctl kernel driver"); } die("%s: %m", name); } return f; } int get_watchdog(void) { FILE *f = open_sysfs(POST_RESET_WDOG_PATH, "r"); int watchdog; if (fscanf(f, "%d", &watchdog) != 1) die("%s: failed to read integer", POST_RESET_WDOG_PATH); fclose(f); return watchdog; } void set_watchdog(int interval) { FILE *f = open_sysfs(POST_RESET_WDOG_PATH, "w"); if (fprintf(f, "%d\n", interval) < 0) die("%s: failed to set watchdog to '%d'", POST_RESET_WDOG_PATH, interval); fclose(f); } void set_second_reset_action(const char *action) { FILE *f = open_sysfs(SECOND_RESET_ACTION_PATH, "w"); if (fprintf(f, "%s\n", action) < 0) die("%s: failed to set action to '%s'", SECOND_RESET_ACTION_PATH, action); fclose(f); } // Return the (malloced) string describing the lifecycle state (w line return) char *get_lifecycle_state(void) { FILE *f = open_sysfs(LIFECYCLE_STATE_PATH, "r"); char *buf = NULL; size_t len = 0; if (getline(&buf, &len, f) == -1) die("%s: failed to get lifecycle state", LIFECYCLE_STATE_PATH); fclose(f); return buf; } // Return number of remaining free secure boot fuse versions int get_free_sbfuse_slots(void) { int free_slot = 0; FILE *f = open_sysfs(SECURE_BOOT_FUSE_STATE_PATH, "r"); char *buf = NULL, *p; size_t len = 0; while (getline(&buf, &len, f) != -1) { p = buf; while ((p = strstr(p, "Free")) != NULL) { free_slot++; p += strlen("Free"); } } free(buf); fclose(f); return free_slot; } void show_status(void) { // Display the default boot partition int part = get_boot_partition(); printf("primary: %sboot%d\n", mmc_path, part); printf("backup: %sboot%d\n", mmc_path, part ^ 1); // Display the boot bus width setting int boot_bus_width = get_boot_bus_width(); printf("boot-bus-width: x%d\n", (boot_bus_width & EXT_CSD_BOOT_BUS_WIDTH_MASK) ? (boot_bus_width & EXT_CSD_BOOT_BUS_WIDTH_MASK) * 4 : 1); printf("reset to x1 after reboot: %s\n", (boot_bus_width & EXT_CSD_BOOT_BUS_WIDTH_RESET_MASK)? "FALSE" : "TRUE"); // Display the watchdog value int watchdog = get_watchdog(); printf("watchdog-swap: "); if (watchdog == 0) printf("disabled\n"); else printf("%d\n", watchdog); // Display the secure boot fuse states char *lifecycle_state = get_lifecycle_state(); printf("lifecycle state: %s", lifecycle_state); free(lifecycle_state); printf("secure boot key free slots: %d\n", get_free_sbfuse_slots()); } #endif // OUTPUT_ONLY // Read as much as possible despite EINTR or partial reads, and die on error. ssize_t read_or_die(const char* filename, int fd, void* buf, size_t count) { ssize_t n = 0; while (count > 0) { ssize_t rc = read(fd, buf, count); if (rc < 0) { if (errno == EINTR) continue; die("%s: can't read: %m", filename); } if (rc == 0) break; n += rc; buf += rc; count -= rc; } return n; } // Write everything passed in despite EINTR or partial reads, and die on error. ssize_t write_or_die(const char* filename, int fd, const void* buf, size_t count) { ssize_t n = count; while (count > 0) { ssize_t rc = write(fd, buf, count); if (rc < 0) { if (errno == EINTR) continue; die("%s: can't write: %m", filename); } if (rc == 0) die("%s: write returned zero", filename); buf += rc; count -= rc; } return n; } /* * Generate the boot stream segment header. * * is_end: 1 if this segment is the last segment of the boot code, else 0. * channel: The channel number to write to. * address: The register address to write to. * length: The length of this segment in bytes; max is MAX_SEG_LEN. * * We ignore endian issues here since if the tool is built natively, * this is likely correct anyway, and if built cross, we don't have a * way to know the endianness of the arm cores anyway. */ uint64_t gen_seg_header(int is_end, int channel, int address, size_t length) { return (((is_end & 0x1UL) << 63) | ((channel & 0xfUL) << 45) | ((address & 0xfff8UL) << 29) | (((length + SEGMENT_HEADER_LEN) >> 3) & 0x1ffffUL)); } uint64_t get_segment_length(uint64_t segheader) { uint64_t length = (segheader & 0x1ffffUL) << 3; if (length == 0) length = MAX_SEG_LEN; else length -= SEGMENT_HEADER_LEN; return length; } bool validate_seg_header(uint64_t segheader) { return (((segheader >> 29) & 0xfff8UL) == BOOT_FIFO_ADDR); } void read_bootstream(const char *bootstream, const char *bootfile, uint64_t part_size) { // Copy the contents of the bootfile device to a bootstream printf("Copy bootstream from %s to %s\n", bootfile, bootstream); int ifd = open(bootfile, O_RDONLY); if (ifd < 0) die("%s: %m", bootfile); int ofd = open(bootstream, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (ofd < 0) die("%s: %m", bootstream); char *buf = malloc(MAX_SEG_LEN); if (buf == NULL) die("out of memory"); uint64_t header; // Read and discard the header word read_or_die(bootfile, ifd, &header, sizeof(header)); uint64_t segheader = 0, total_size = 0; while (!(segheader & SEGMENT_IS_END)) { read_or_die(bootfile, ifd, &segheader, sizeof(segheader)); if (!validate_seg_header(segheader)) die("Invalid segment header"); uint64_t seg_size = get_segment_length(segheader); read_or_die(bootfile, ifd, buf, seg_size); write_or_die(bootstream, ofd, buf, seg_size); total_size += seg_size; if (total_size > part_size) die("No valid bfb present"); } if (close(ifd) < 0) die("%s: close: %m", bootstream); if (close(ofd) < 0) die("%s: close: %m", bootfile); free(buf); } void write_bootstream(const char *bootstream, const char *bootfile, int flags) { int sysfd = -1; char *sysname; // Reset the force_ro setting if need be if (strncmp(bootfile, "/dev/", 5) == 0) { if (asprintf(&sysname, "/sys/block/%s/force_ro", &bootfile[5]) <= 0) die("unexpected failure in asprintf (%s/%d)", __FILE__, __LINE__); sysfd = open(sysname, O_RDWR | O_SYNC); if (sysfd >= 0) { char status; if (read_or_die(sysname, sysfd, &status, 1) != 1) die("%s: unexpected EOF on read", sysname); if (status == '1') { char disabled = '0'; if (lseek(sysfd, 0, SEEK_SET) != 0) die("%s: can't seek back to start: %m", sysname); write_or_die(sysname, sysfd, &disabled, 1); } else { close(sysfd); sysfd = -1; free(sysname); sysname = NULL; } } else { if (errno != ENOENT) die("%s: open: %m", sysname); printf("WARNING: No matching %s for %s\n", sysname, bootfile); free(sysname); sysname = NULL; } } // Copy the bootstream to the bootfile device int ifd = open(bootstream, O_RDONLY); if (ifd < 0) die("%s: %m", bootstream); int ofd = open(bootfile, O_WRONLY | flags, 0666); if (ofd < 0) die("%s: %m", bootfile); struct stat st; if (fstat(ifd, &st) < 0) die("%s: stat: %m", bootstream); size_t bytes_left = st.st_size; char *buf = malloc(MAX_SEG_LEN); if (buf == NULL) die("out of memory"); // Write the bootstream header word first. This has the byte to // be displayed in the rev_id register as the low 8 bits (zero for now). uint64_t header = 0; write_or_die(bootfile, ofd, &header, sizeof(header)); while (bytes_left > 0) { size_t seg_size = (bytes_left <= MAX_SEG_LEN) ? bytes_left : MAX_SEG_LEN; bytes_left -= seg_size; // Generate the segment header. size_t pad_size = seg_size % 8 ? (8 - seg_size % 8) : 0; uint64_t segheader = gen_seg_header(bytes_left == 0, 1, BOOT_FIFO_ADDR, seg_size + pad_size); write_or_die(bootfile, ofd, &segheader, sizeof(segheader)); // Copy the segment plus any padding. read_or_die(bootstream, ifd, buf, seg_size); memset(buf + seg_size, 0, pad_size); write_or_die(bootfile, ofd, buf, seg_size + pad_size); } if (close(ifd) < 0) die("%s: close: %m", bootstream); if (close(ofd) < 0) die("%s: close: %m", bootfile); free(buf); // Put back the force_ro setting if need be if (sysfd >= 0) { if (lseek(sysfd, 0, SEEK_SET) != 0) die("%s: can't seek back to start: %m", sysname); char enabled = '1'; write_or_die(sysname, sysfd, &enabled, 1); close(sysfd); free(sysname); } } #ifdef OUTPUT_ONLY int main(int argc, char **argv) { static struct option long_options[] = { { "bootstream", required_argument, NULL, 'b' }, { "output", required_argument, NULL, 'o' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; static const char short_options[] = "b:o:h"; static const char help_text[] = "syntax: mlx-bootctl [--help|-h] --bootstream|-b BFBFILE --output|-o OUTPUT"; const char *bootstream = NULL; const char *output_file = NULL; int opt; while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (opt) { case 'b': bootstream = optarg; break; case 'o': output_file = optarg; break; case 'h': default: die(help_text); break; } } if (bootstream == NULL || output_file == NULL) die("mlx-bootctl: Must specify --output and --bootstream"); write_bootstream(bootstream, output_file, O_CREAT | O_TRUNC); return 0; } #else static uint32_t crc32_update(uint32_t crc, uint8_t *p, unsigned int len) { int i; while (len--) { crc ^= *p++; for (i = 0; i < 8; i++) crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0); } return crc; } static void verify_bootstream(const char *bootfile) { int ifd, n, bytes_left, img_size; boot_image_header_t hdr; struct stat st; uint64_t data; uint32_t crc; ifd = open(bootfile, O_RDONLY); if (ifd < 0) die("%s: %m", bootfile); if (fstat(ifd, &st) < 0) die("%s: stat: %m", bootfile); bytes_left = st.st_size; if (bytes_left % sizeof(uint64_t)) die("Invalid size %d", bytes_left); if (bytes_left > MMC_BOOT_PARTITION_MAX_SIZE) die("Boot file size too big"); while (bytes_left > 0) { // Read and verify the image header. n = read_or_die(bootfile, ifd, &hdr, sizeof(hdr)); if (n != sizeof(hdr)) die("Unable to read next header, n=%d", n); n = hdr.hdr_len - sizeof(hdr) / sizeof(uint64_t); bytes_left -= hdr.hdr_len * sizeof(uint64_t); if (n < 0 || bytes_left < 0) die("Invalid header length"); // Drain the rest of header. while (n--) { if (read_or_die(bootfile, ifd, &data, sizeof(data)) != sizeof(data)) die("Not enough data for header"); } // Verify the image crc. crc = ~0; img_size = hdr.image_len; while (img_size > 0) { if (read_or_die(bootfile, ifd, &data, sizeof(data)) != sizeof(data)) die("Not enough data for image id %d, missing size %d", hdr.image_id, img_size); crc = crc32_update(crc, (uint8_t *)&data, sizeof(data)); img_size -= sizeof(data); bytes_left -= sizeof(data); } if (hdr.image_crc != ~crc) die("Invalid CRC for image_id %d", hdr.image_id); } close(ifd); } int main(int argc, char **argv) { static struct option long_options[] = { { "swap", no_argument, NULL, 's' }, { "watchdog-swap", required_argument, NULL, 'w' }, { "nowatchdog-swap", no_argument, NULL, 'n' }, { "bootstream", required_argument, NULL, 'b' }, { "overwrite-current", no_argument, NULL, 'c' }, { "device", required_argument, NULL, 'd' }, { "output", required_argument, NULL, 'o' }, { "read", required_argument, NULL, 'r' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; static const char short_options[] = "sb:d:o:r:he"; static const char help_text[] = "syntax: mlxbf-bootctl [--help|-h] [--swap|-s] [--device|-d MMCFILE]\n" " [--output|-o OUTPUT] [--read|-r INPUT]\n" " [--bootstream|-b BFBFILE] [--overwrite-current]\n" " [--watchdog-swap interval | --nowatchdog-swap]"; const char *watchdog_swap = NULL; const char *bootstream = NULL; const char *output_file = NULL; const char *input_file = NULL; bool watchdog_disable = false; bool swap = false; int which_boot = 1; // alternate boot partition by default int opt; while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (opt) { case 's': swap = true; break; case 'w': watchdog_swap = optarg; watchdog_disable = false; break; case 'n': watchdog_swap = NULL; watchdog_disable = true; break; case 'b': bootstream = optarg; break; case 'c': which_boot = 0; // overwrite current boot partition (dangerous) break; case 'd': mmc_path = optarg; break; case 'o': output_file = optarg; break; case 'r': input_file = optarg; break; case 'e': enable_rst_n(); break; case 'h': default: die(help_text); break; } } if (!bootstream && !swap && watchdog_swap == NULL && !watchdog_disable) { show_status(); return 0; } if (bootstream) { if (input_file) { uint64_t boot_part_size = get_boot_partition_size(); read_bootstream(bootstream, input_file, boot_part_size); } else if (output_file) { // Write the bootstream to the given file, creating it if needed write_bootstream(bootstream, output_file, O_CREAT | O_TRUNC); } else { verify_bootstream(bootstream); // Make sure the file will fit inside the boot partition uint64_t boot_part_size = get_boot_partition_size(); struct stat st; int error; error = stat(bootstream, &st); if (error < 0) die("%s: %m", bootstream); if (st.st_size > boot_part_size) die("Size of bootstream exceeds boot partition size"); // Get the active partition and write to the appropriate *bootN file // Must save/restore boot partition, which I/O otherwise resets to zero. int boot_part = get_boot_partition(); char *bootfile; if (asprintf(&bootfile, "%sboot%d", mmc_path, boot_part ^ which_boot) <= 0) die("unexpected failure in asprintf (%s/%d)", __FILE__, __LINE__); write_bootstream(bootstream, bootfile, O_SYNC); // The eMMC driver works in an asynchronous way, thus any commands sent // should occur after the write to the bootstream has retired. Otherwise // a blk_update_request I/O error would be raised and the success of the // command cannot be guaranteed. The check for the status of the eMMC // at user level is non-trival, thus a delay is added here instead. // @TODO: Update the delay to check for the eMMC status. sleep(1); set_boot_partition(boot_part); set_boot_bus_width(); enable_rst_n(); } } if (swap) set_boot_partition(get_boot_partition() ^ 1); if (watchdog_swap != NULL) { // Enable reset watchdog to swap eMMC on reset after watchdog interval char *end; int watchdog = strtol(watchdog_swap, &end, 0); if (end == watchdog_swap || *end != '\0') die("watchdog-swap argument ('%s') must be an integer", watchdog_swap); set_watchdog(watchdog); set_second_reset_action("swap_emmc"); enable_rst_n(); } if (watchdog_disable) { // Disable reset watchdog and don't adjust reset actions at reset time set_watchdog(0); set_second_reset_action("none"); } return 0; } #endif // OUTPUT_ONLY 0707010000000E000081A4000003E800000064000000015F7A2ABE0000074D000000000000000000000000000000000000002A00000000mlxbf-bootctl-1.1.6.11/mlxbf-bootctl.specName: mlxbf-bootctl Version: 2.1 Release: 1%{?dist} Summary: Mellanox BlueField boot partition management utility License: BSD Url: https://github.com/Mellanox/mlxbf-bootctl Source: mlxbf-bootctl-2.1.tar.gz # mlxbf-bootctl will build for most architectures, however this program is # designed only to control BlueField SoCs, which are all aarch64, so only # build for that architecture. ExclusiveArch: aarch64 BuildRequires: gcc %description mlxbf-bootctl is used to control the two boot firmware (ATF, UEFI, etc...) partitions present on most Mellanox BlueField devices. This includes switching active partitions, listing the state of boot registers, and installing new firmware. # this section is automatically generated by rpkg %prep %setup %build %{?set_build_flags} %make_build %install # Note: make install normally installs to "/sbin" %{__make} install DESTDIR=%{buildroot}%{_exec_prefix} %{__install} -d %{buildroot}%{_mandir}/man8 %{__install} -m 0644 mlxbf-bootctl.8 %{buildroot}%{_mandir}/man8 %files %{_sbindir}/mlxbf-bootctl %{_mandir}/man8/mlxbf-bootctl.8.gz %license LICENSE %doc README.md %changelog * Thu Sep 3 2020 Spencer Lingard <spencer@nvidia.com> - 2.1-1 - Bump version to sync up with others - Modify spec.rpkg to depend less on rpkg * Mon Jun 22 2020 Spencer Lingard <spencer@nvidia.com> - 1.1-6 - Add set_build_flags macro to build step - Warn user if mlxbf_bootctl kernel driver is not loaded * Wed Jun 17 2020 Spencer Lingard <spencer@nvidia.com> - 1.1-5 - Simplify release tag - Add comment explaining ExclusiveArch tag - Improve description - Remove unneeded build dependency - Move mlxbf-bootctl from /sbin to /usr/sbin - Pull in code coverage fixes * Wed Jun 10 2020 Spencer Lingard <spencer@nvidia.com> - 1.1-4 - Add man page - Add license * Tue May 12 2020 Spencer Lingard <spencer@nvidia.com> - 1.1-3 Initial packaging. 0707010000000F000081A4000003E800000064000000015F7A2ABE000007D8000000000000000000000000000000000000002F00000000mlxbf-bootctl-1.1.6.11/mlxbf-bootctl.spec.rpkgName: mlxbf-bootctl Version: 2.1 Release: 1%{?dist} Summary: Mellanox BlueField boot partition management utility License: BSD Url: https://github.com/Mellanox/mlxbf-bootctl Source: {{{ name=$(rpmspec -q --qf "%{name}-%{version}\n" mlxbf-bootctl.spec.rpkg); git_dir_pack dir_name="$name" source_name="$name".tar.gz }}} # mlxbf-bootctl will build for most architectures, however this program is # designed only to control BlueField SoCs, which are all aarch64, so only # build for that architecture. ExclusiveArch: aarch64 BuildRequires: gcc %description mlxbf-bootctl is used to control the two boot firmware (ATF, UEFI, etc...) partitions present on most Mellanox BlueField devices. This includes switching active partitions, listing the state of boot registers, and installing new firmware. # this section is automatically generated by rpkg %prep %setup %build %set_build_flags %make_build %install # Note: make install normally installs to "/sbin" %{__make} install DESTDIR=%{buildroot}%{_exec_prefix} %{__install} -d %{buildroot}%{_mandir}/man8 %{__install} -m 0644 mlxbf-bootctl.8 %{buildroot}%{_mandir}/man8 %files %{_sbindir}/mlxbf-bootctl %{_mandir}/man8/mlxbf-bootctl.8.gz %license LICENSE %doc README.md %changelog * Thu Sep 3 2020 Spencer Lingard <spencer@nvidia.com> - 2.1-1 - Bump version to sync up with others - Modify spec.rpkg to depend less on rpkg - Add makefile to build SRPMs * Mon Jun 22 2020 Spencer Lingard <spencer@nvidia.com> - 1.1-6 - Add set_build_flags macro to build step - Warn user if mlxbf_bootctl kernel driver is not loaded * Wed Jun 17 2020 Spencer Lingard <spencer@nvidia.com> - 1.1-5 - Simplify release tag - Add comment explaining ExclusiveArch tag - Improve description - Remove unneeded build dependency - Move mlxbf-bootctl from /sbin to /usr/sbin - Pull in code coverage fixes * Wed Jun 10 2020 Spencer Lingard <spencer@nvidia.com> - 1.1-4 - Add man page - Add license * Tue May 12 2020 Spencer Lingard <spencer@nvidia.com> - 1.1-3 Initial packaging. 07070100000010000081A4000003E800000064000000015F7A2ABE000005D5000000000000000000000000000000000000002200000000mlxbf-bootctl-1.1.6.11/package.mk# Include this file from the main Makefile, and define PROJECT_NAME # before the include statement. SPEC_NAME:=$(PROJECT_NAME).spec # Obtain version from RPM spec file VERSION:=$(shell grep '^Version:' $(SPEC_NAME) | cut -d' ' -f2) TAR_BASE:=$(PROJECT_NAME)-$(VERSION) TAR_NAME:=$(TAR_BASE).tar.gz GIT_FILES:=$(shell git ls-files -co --exclude-standard) git_dir_pack/$(TAR_NAME): $(GIT_FILES) rm -rf git_dir_pack mkdir -p git_dir_pack/$(TAR_BASE) rsync --relative $(GIT_FILES) git_dir_pack/$(TAR_BASE) (cd git_dir_pack; tar -zcvf ../$@ $(TAR_BASE)) .PHONY: tarball tarball: git_dir_pack/$(TAR_NAME) @echo Tarball can be found at $< .PHONY: pkgclean pkgclean: srpmclean rm -rf git_dir_pack # RPM-SPECIFIC RPMBUILD_LOC:=$(shell which rpmbuild) ifneq ($(RPMBUILD_LOC),) # Draw pkg name from spec file RPM_PROJECT_NAME:=$(shell \ rpmspec -q --qf "%{name}\n" $(SPEC_NAME) | \ head -n1) RPM_BASE:=$(shell \ rpmspec --query --qf "%{name}-%{version}-%{release}\n" $(SPEC_NAME) | \ head -n1) SRPM_NAME:=$(RPM_BASE).src.rpm srpmclean: rm -rf RPMBUILD rm -f $(RPM_PROJECT_NAME)*.src.rpm srpm: $(SRPM_NAME) RPMBUILD/SOURCES/$(TAR_NAME): git_dir_pack/$(TAR_NAME) mkdir -p RPMBUILD/SOURCES cp $< $@ $(SRPM_NAME): RPMBUILD/SOURCES/$(TAR_NAME) $(SPEC_NAME) rpmbuild -bs --define "_topdir $(shell pwd)/RPMBUILD" $(SPEC_NAME) cp RPMBUILD/SRPMS/$(SRPM_NAME) ./ else srpm: @echo "Cannot build SRPM, rpmbuild tools not installed!" exit 1 srpmclean: endif .PHONY: srpmclean srpm 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!98 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor