diff --git a/cmd/installer/pkg/install/install.go b/cmd/installer/pkg/install/install.go index 1d87a2452..e6f8cb6ff 100644 --- a/cmd/installer/pkg/install/install.go +++ b/cmd/installer/pkg/install/install.go @@ -285,7 +285,13 @@ func (i *Installer) Install(ctx context.Context, mode Mode) (err error) { i.options.Printf("installing U-Boot for %q", b.Name()) - if err = b.Install(i.options.Disk); err != nil { + if err = b.Install(runtime.BoardInstallOptions{ + InstallDisk: i.options.Disk, + UBootPath: i.options.BootAssets.UBootPath, + DTBPath: i.options.BootAssets.DTBPath, + RPiFirmwarePath: i.options.BootAssets.RPiFirmwarePath, + Printf: i.options.Printf, + }); err != nil { return err } } diff --git a/internal/app/machined/pkg/runtime/board.go b/internal/app/machined/pkg/runtime/board.go index 55c7ea76b..b40c82e4a 100644 --- a/internal/app/machined/pkg/runtime/board.go +++ b/internal/app/machined/pkg/runtime/board.go @@ -12,10 +12,19 @@ type PartitionOptions struct { PartitionsOffset uint64 } +// BoardInstallOptions are the board specific options for installation of various boot assets. +type BoardInstallOptions struct { + InstallDisk string + DTBPath string + UBootPath string + RPiFirmwarePath string + Printf func(string, ...any) +} + // Board defines the requirements for a SBC. type Board interface { Name() string - Install(string) error + Install(options BoardInstallOptions) error KernelArgs() procfs.Parameters PartitionOptions() *PartitionOptions } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/bananapi_m64/bananapi_m64.go b/internal/app/machined/pkg/runtime/v1alpha1/board/bananapi_m64/bananapi_m64.go index 32d5fe982..a10f5260b 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/bananapi_m64/bananapi_m64.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/bananapi_m64/bananapi_m64.go @@ -6,8 +6,6 @@ package bananapim64 import ( - "fmt" - "log" "os" "path/filepath" @@ -20,9 +18,9 @@ import ( ) var ( - bin = fmt.Sprintf("/usr/install/arm64/u-boot/%s/u-boot-sunxi-with-spl.bin", constants.BoardBananaPiM64) + bin = constants.BoardBananaPiM64 + "/u-boot-sunxi-with-spl.bin" off int64 = 1024 * 8 - dtb = "/dtb/allwinner/sun50i-a64-bananapi-m64.dtb" + dtb = "allwinner/sun50i-a64-bananapi-m64.dtb" ) // BananaPiM64 represents the Banana Pi M64. @@ -39,10 +37,10 @@ func (b *BananaPiM64) Name() string { } // Install implements the runtime.Board. -func (b *BananaPiM64) Install(disk string) (err error) { +func (b *BananaPiM64) Install(options runtime.BoardInstallOptions) (err error) { var f *os.File - if f, err = os.OpenFile(disk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { + if f, err = os.OpenFile(options.InstallDisk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { return err } //nolint:errcheck @@ -50,12 +48,12 @@ func (b *BananaPiM64) Install(disk string) (err error) { var uboot []byte - uboot, err = os.ReadFile(bin) + uboot, err = os.ReadFile(filepath.Join(options.UBootPath, bin)) if err != nil { return err } - log.Printf("writing %s at offset %d", bin, off) + options.Printf("writing %s at offset %d", bin, off) var n int @@ -64,7 +62,7 @@ func (b *BananaPiM64) Install(disk string) (err error) { return err } - log.Printf("wrote %d bytes", n) + options.Printf("wrote %d bytes", n) // NB: In the case that the block device is a loopback device, we sync here // to esure that the file is written before the loopback device is @@ -74,8 +72,8 @@ func (b *BananaPiM64) Install(disk string) (err error) { return err } - src := "/usr/install/arm64" + dtb - dst := "/boot/EFI" + dtb + src := filepath.Join(options.DTBPath, dtb) + dst := filepath.Join("/boot/EFI/dtb", dtb) err = os.MkdirAll(filepath.Dir(dst), 0o600) if err != nil { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/jetson_nano/jetson_nano.go b/internal/app/machined/pkg/runtime/v1alpha1/board/jetson_nano/jetson_nano.go index ef3a2853a..2b3585a60 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/jetson_nano/jetson_nano.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/jetson_nano/jetson_nano.go @@ -21,7 +21,7 @@ import ( // - https://github.com/u-boot/u-boot/blob/v2021.10/configs/p3450-0000_defconfig#L8 // - https://github.com/u-boot/u-boot/blob/v2021.10/include/configs/tegra-common.h#L53 // - https://github.com/u-boot/u-boot/blob/v2021.10/include/configs/tegra210-common.h#L49 -var dtb = "/dtb/nvidia/tegra210-p3450-0000.dtb" +var dtb = "nvidia/tegra210-p3450-0000.dtb" // JetsonNano represents the JetsonNano board // @@ -35,10 +35,10 @@ func (b *JetsonNano) Name() string { } // Install implements the runtime.Board. -func (b JetsonNano) Install(disk string) (err error) { +func (b JetsonNano) Install(options runtime.BoardInstallOptions) (err error) { var f *os.File - if f, err = os.OpenFile(disk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { + if f, err = os.OpenFile(options.InstallDisk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { return err } //nolint:errcheck @@ -52,8 +52,8 @@ func (b JetsonNano) Install(disk string) (err error) { return err } - src := "/usr/install/arm64" + dtb - dst := "/boot/EFI" + dtb + src := filepath.Join(options.DTBPath, dtb) + dst := filepath.Join("/boot/EFI/dtb", dtb) err = os.MkdirAll(filepath.Dir(dst), 0o600) if err != nil { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/libretech_all_h3_cc_h5/libretech_all_h3_cc_h5.go b/internal/app/machined/pkg/runtime/v1alpha1/board/libretech_all_h3_cc_h5/libretech_all_h3_cc_h5.go index 910cccbd5..70c1ab225 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/libretech_all_h3_cc_h5/libretech_all_h3_cc_h5.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/libretech_all_h3_cc_h5/libretech_all_h3_cc_h5.go @@ -6,8 +6,6 @@ package libretechallh3cch5 import ( - "fmt" - "log" "os" "path/filepath" @@ -20,9 +18,9 @@ import ( ) var ( - bin = fmt.Sprintf("/usr/install/arm64/u-boot/%s/u-boot-sunxi-with-spl.bin", constants.BoardLibretechAllH3CCH5) + bin = constants.BoardLibretechAllH3CCH5 + "/u-boot-sunxi-with-spl.bin" off int64 = 1024 * 8 - dtb = "/dtb/allwinner/sun50i-h5-libretech-all-h3-cc.dtb" + dtb = "allwinner/sun50i-h5-libretech-all-h3-cc.dtb" ) // LibretechAllH3CCH5 represents the Libre Computer ALL-H3-CC (Tritium). @@ -36,10 +34,10 @@ func (l *LibretechAllH3CCH5) Name() string { } // Install implements the runtime.Board. -func (l *LibretechAllH3CCH5) Install(disk string) (err error) { +func (l *LibretechAllH3CCH5) Install(options runtime.BoardInstallOptions) (err error) { var f *os.File - if f, err = os.OpenFile(disk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { + if f, err = os.OpenFile(options.InstallDisk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { return err } //nolint:errcheck @@ -47,12 +45,12 @@ func (l *LibretechAllH3CCH5) Install(disk string) (err error) { var uboot []byte - uboot, err = os.ReadFile(bin) + uboot, err = os.ReadFile(filepath.Join(options.UBootPath, bin)) if err != nil { return err } - log.Printf("writing %s at offset %d", bin, off) + options.Printf("writing %s at offset %d", bin, off) var n int @@ -61,7 +59,7 @@ func (l *LibretechAllH3CCH5) Install(disk string) (err error) { return err } - log.Printf("wrote %d bytes", n) + options.Printf("wrote %d bytes", n) // NB: In the case that the block device is a loopback device, we sync here // to esure that the file is written before the loopback device is @@ -71,8 +69,8 @@ func (l *LibretechAllH3CCH5) Install(disk string) (err error) { return err } - src := "/usr/install/arm64" + dtb - dst := "/boot/EFI" + dtb + src := filepath.Join(options.DTBPath, dtb) + dst := filepath.Join("/boot/EFI/dtb", dtb) err = os.MkdirAll(filepath.Dir(dst), 0o600) if err != nil { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/nanopi_r4s/nanopi_r4s.go b/internal/app/machined/pkg/runtime/v1alpha1/board/nanopi_r4s/nanopi_r4s.go index b46d6788e..54d40c612 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/nanopi_r4s/nanopi_r4s.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/nanopi_r4s/nanopi_r4s.go @@ -6,8 +6,6 @@ package nanopir4s import ( - "fmt" - "log" "os" "path/filepath" @@ -20,9 +18,9 @@ import ( ) var ( - bin = fmt.Sprintf("/usr/install/arm64/u-boot/%s/u-boot-rockchip.bin", constants.BoardNanoPiR4S) + bin = constants.BoardNanoPiR4S + "u-boot-rockchip.bin" off int64 = 512 * 64 - dtb = "/dtb/rockchip/rk3399-nanopi-r4s.dtb" + dtb = "rockchip/rk3399-nanopi-r4s.dtb" ) // NanoPiR4S represents the Friendlyelec Nano Pi R4S board. @@ -36,27 +34,27 @@ func (n *NanoPiR4S) Name() string { } // Install implements the runtime.Board. -func (n *NanoPiR4S) Install(disk string) (err error) { - file, err := os.OpenFile(disk, os.O_RDWR|unix.O_CLOEXEC, 0o666) +func (n *NanoPiR4S) Install(options runtime.BoardInstallOptions) (err error) { + file, err := os.OpenFile(options.InstallDisk, os.O_RDWR|unix.O_CLOEXEC, 0o666) if err != nil { return err } defer file.Close() //nolint:errcheck - uboot, err := os.ReadFile(bin) + uboot, err := os.ReadFile(filepath.Join(options.UBootPath, bin)) if err != nil { return err } - log.Printf("writing %s at offset %d", bin, off) + options.Printf("writing %s at offset %d", bin, off) amount, err := file.WriteAt(uboot, off) if err != nil { return err } - log.Printf("wrote %d bytes", amount) + options.Printf("wrote %d bytes", amount) // NB: In the case that the block device is a loopback device, we sync here // to esure that the file is written before the loopback device is @@ -65,8 +63,8 @@ func (n *NanoPiR4S) Install(disk string) (err error) { return err } - src := "/usr/install/arm64" + dtb - dst := "/boot/EFI" + dtb + src := filepath.Join(options.DTBPath, dtb) + dst := filepath.Join("/boot/EFI/dtb", dtb) if err := os.MkdirAll(filepath.Dir(dst), 0o600); err != nil { return err diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/pine64/pine64.go b/internal/app/machined/pkg/runtime/v1alpha1/board/pine64/pine64.go index 26d395ba1..4f680a9b3 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/pine64/pine64.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/pine64/pine64.go @@ -6,8 +6,6 @@ package pine64 import ( - "fmt" - "log" "os" "path/filepath" @@ -20,9 +18,9 @@ import ( ) var ( - bin = fmt.Sprintf("usr/install/arm64/u-boot/%s/u-boot-sunxi-with-spl.bin", constants.BoardPine64) + bin = constants.BoardPine64 + "/u-boot-sunxi-with-spl.bin" off int64 = 1024 * 8 - dtb = "/dtb/allwinner/sun50i-a64-pine64-plus.dtb" + dtb = "allwinner/sun50i-a64-pine64-plus.dtb" ) // Pine64 represents the Pine64 board @@ -37,10 +35,10 @@ func (b *Pine64) Name() string { } // Install implements the runtime.Board. -func (b Pine64) Install(disk string) (err error) { +func (b Pine64) Install(options runtime.BoardInstallOptions) (err error) { var f *os.File - if f, err = os.OpenFile(disk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { + if f, err = os.OpenFile(options.InstallDisk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { return err } //nolint:errcheck @@ -48,12 +46,12 @@ func (b Pine64) Install(disk string) (err error) { var uboot []byte - uboot, err = os.ReadFile(bin) + uboot, err = os.ReadFile(filepath.Join(options.UBootPath, bin)) if err != nil { return err } - log.Printf("writing %s at offset %d", bin, off) + options.Printf("writing %s at offset %d", bin, off) var n int @@ -62,7 +60,7 @@ func (b Pine64) Install(disk string) (err error) { return err } - log.Printf("wrote %d bytes", n) + options.Printf("wrote %d bytes", n) // NB: In the case that the block device is a loopback device, we sync here // to esure that the file is written before the loopback device is @@ -72,8 +70,8 @@ func (b Pine64) Install(disk string) (err error) { return err } - src := "/usr/install/arm64" + dtb - dst := "/boot/EFI" + dtb + src := filepath.Join(options.DTBPath, dtb) + dst := filepath.Join("/boot/EFI/dtb", dtb) err = os.MkdirAll(filepath.Dir(dst), 0o600) if err != nil { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/rock64/rock64.go b/internal/app/machined/pkg/runtime/v1alpha1/board/rock64/rock64.go index 57ce8626a..578f05277 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/rock64/rock64.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/rock64/rock64.go @@ -6,8 +6,6 @@ package rock64 import ( - "fmt" - "log" "os" "path/filepath" @@ -20,9 +18,9 @@ import ( ) var ( - bin = fmt.Sprintf("/usr/install/arm64/u-boot/%s/u-boot-rockchip.bin", constants.BoardRock64) + bin = constants.BoardRock64 + "/u-boot-rockchip.bin" off int64 = 512 * 64 - dtb = "/dtb/rockchip/rk3328-rock64.dtb" + dtb = "rockchip/rk3328-rock64.dtb" ) // Rock64 represents the Pine64 Rock64 board. @@ -36,10 +34,10 @@ func (r *Rock64) Name() string { } // Install implements the runtime.Board. -func (r *Rock64) Install(disk string) (err error) { +func (r *Rock64) Install(options runtime.BoardInstallOptions) (err error) { var f *os.File - if f, err = os.OpenFile(disk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { + if f, err = os.OpenFile(options.InstallDisk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { return err } //nolint:errcheck @@ -47,12 +45,12 @@ func (r *Rock64) Install(disk string) (err error) { var uboot []byte - uboot, err = os.ReadFile(bin) + uboot, err = os.ReadFile(filepath.Join(options.UBootPath, bin)) if err != nil { return err } - log.Printf("writing %s at offset %d", bin, off) + options.Printf("writing %s at offset %d", bin, off) var n int @@ -61,7 +59,7 @@ func (r *Rock64) Install(disk string) (err error) { return err } - log.Printf("wrote %d bytes", n) + options.Printf("wrote %d bytes", n) // NB: In the case that the block device is a loopback device, we sync here // to esure that the file is written before the loopback device is @@ -71,8 +69,8 @@ func (r *Rock64) Install(disk string) (err error) { return err } - src := "/usr/install/arm64" + dtb - dst := "/boot/EFI" + dtb + src := filepath.Join(options.DTBPath, dtb) + dst := filepath.Join("/boot/EFI/dtb", dtb) err = os.MkdirAll(filepath.Dir(dst), 0o600) if err != nil { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/rockpi4/rockpi4.go b/internal/app/machined/pkg/runtime/v1alpha1/board/rockpi4/rockpi4.go index 224060303..47e374c2c 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/rockpi4/rockpi4.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/rockpi4/rockpi4.go @@ -6,8 +6,6 @@ package rockpi4 import ( - "fmt" - "log" "os" "path/filepath" @@ -20,11 +18,11 @@ import ( ) var ( - bin = fmt.Sprintf("/usr/install/arm64/u-boot/%s/u-boot-rockchip.bin", constants.BoardRockpi4) + bin = constants.BoardRockpi4 + "/u-boot-rockchip.bin" off int64 = 512 * 64 // https://github.com/u-boot/u-boot/blob/4de720e98d552dfda9278516bf788c4a73b3e56f/configs/rock-pi-4-rk3399_defconfig#L7= // 4a and 4b uses the same overlay. - dtb = "/dtb/rockchip/rk3399-rock-pi-4b.dtb" + dtb = "rockchip/rk3399-rock-pi-4b.dtb" ) // Rockpi4 represents the Radxa rock pi board. @@ -38,21 +36,21 @@ func (r *Rockpi4) Name() string { } // Install implements the runtime.Board. -func (r *Rockpi4) Install(disk string) (err error) { +func (r *Rockpi4) Install(options runtime.BoardInstallOptions) (err error) { var f *os.File - if f, err = os.OpenFile(disk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { + if f, err = os.OpenFile(options.InstallDisk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { return err } defer f.Close() //nolint:errcheck - uboot, err := os.ReadFile(bin) + uboot, err := os.ReadFile(filepath.Join(options.UBootPath, bin)) if err != nil { return err } - log.Printf("writing %s at offset %d", bin, off) + options.Printf("writing %s at offset %d", bin, off) var n int @@ -61,7 +59,7 @@ func (r *Rockpi4) Install(disk string) (err error) { return err } - log.Printf("wrote %d bytes", n) + options.Printf("wrote %d bytes", n) // NB: In the case that the block device is a loopback device, we sync here // to esure that the file is written before the loopback device is @@ -71,8 +69,8 @@ func (r *Rockpi4) Install(disk string) (err error) { return err } - src := "/usr/install/arm64" + dtb - dst := "/boot/EFI" + dtb + src := filepath.Join(options.DTBPath, dtb) + dst := filepath.Join("/boot/EFI/dtb", dtb) err = os.MkdirAll(filepath.Dir(dst), 0o600) if err != nil { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/rockpi4c/rockpi4c.go b/internal/app/machined/pkg/runtime/v1alpha1/board/rockpi4c/rockpi4c.go index 1a1361620..7ade79e6f 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/rockpi4c/rockpi4c.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/rockpi4c/rockpi4c.go @@ -6,8 +6,6 @@ package rockpi4c import ( - "fmt" - "log" "os" "path/filepath" @@ -20,10 +18,10 @@ import ( ) var ( - bin = fmt.Sprintf("/usr/install/arm64/u-boot/%s/u-boot-rockchip.bin", constants.BoardRockpi4) + bin = constants.BoardRockpi4 + "/u-boot-rockchip.bin" off int64 = 512 * 64 // https://github.com/u-boot/u-boot/blob/4de720e98d552dfda9278516bf788c4a73b3e56f/configs/rock-pi-4c-rk3399_defconfig#L7= - dtb = "/dtb/rockchip/rk3399-rock-pi-4c.dtb" + dtb = "rockchip/rk3399-rock-pi-4c.dtb" ) // Rockpi4c represents the Radxa rock pi board. @@ -37,21 +35,21 @@ func (r *Rockpi4c) Name() string { } // Install implements the runtime.Board. -func (r *Rockpi4c) Install(disk string) (err error) { +func (r *Rockpi4c) Install(options runtime.BoardInstallOptions) (err error) { var f *os.File - if f, err = os.OpenFile(disk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { + if f, err = os.OpenFile(options.InstallDisk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { return err } defer f.Close() //nolint:errcheck - uboot, err := os.ReadFile(bin) + uboot, err := os.ReadFile(filepath.Join(options.UBootPath, bin)) if err != nil { return err } - log.Printf("writing %s at offset %d", bin, off) + options.Printf("writing %s at offset %d", bin, off) var n int @@ -60,7 +58,7 @@ func (r *Rockpi4c) Install(disk string) (err error) { return err } - log.Printf("wrote %d bytes", n) + options.Printf("wrote %d bytes", n) // NB: In the case that the block device is a loopback device, we sync here // to esure that the file is written before the loopback device is @@ -70,8 +68,8 @@ func (r *Rockpi4c) Install(disk string) (err error) { return err } - src := "/usr/install/arm64" + dtb - dst := "/boot/EFI" + dtb + src := filepath.Join(options.DTBPath, dtb) + dst := filepath.Join("/boot/EFI/dtb", dtb) err = os.MkdirAll(filepath.Dir(dst), 0o600) if err != nil { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/rpi_generic/rpi_generic.go b/internal/app/machined/pkg/runtime/v1alpha1/board/rpi_generic/rpi_generic.go index 107bd624b..4fba67364 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/rpi_generic/rpi_generic.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/rpi_generic/rpi_generic.go @@ -8,6 +8,7 @@ package rpigeneric import ( _ "embed" "os" + "path/filepath" "github.com/siderolabs/go-procfs/procfs" @@ -30,13 +31,13 @@ func (r *RPiGeneric) Name() string { } // Install implements the runtime.Board. -func (r *RPiGeneric) Install(disk string) (err error) { - err = copy.Dir("/usr/install/arm64/raspberrypi-firmware/boot", "/boot/EFI") +func (r *RPiGeneric) Install(options runtime.BoardInstallOptions) (err error) { + err = copy.Dir(filepath.Join(options.RPiFirmwarePath, "boot"), "/boot/EFI") if err != nil { return err } - err = copy.File("/usr/install/arm64/u-boot/rpi_generic/u-boot.bin", "/boot/EFI/u-boot.bin") + err = copy.File(filepath.Join(options.UBootPath, "rpi_generic/u-boot.bin"), "/boot/EFI/u-boot.bin") if err != nil { return err } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go index 8719161c7..4ff9719d8 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go @@ -35,13 +35,17 @@ type InstallOptions struct { Printf func(format string, v ...any) } -// BootAssets describes the assets to be installed by the booloader. +// BootAssets describes the assets to be installed by the bootloader. type BootAssets struct { KernelPath string InitramfsPath string UKIPath string SDBootPath string + + DTBPath string + UBootPath string + RPiFirmwarePath string } // FillDefaults fills in default paths to be used when in the context of the installer. @@ -61,4 +65,18 @@ func (assets *BootAssets) FillDefaults(arch string) { if assets.SDBootPath == "" { assets.SDBootPath = fmt.Sprintf(constants.SDBootAssetPath, arch) } + + if arch == "arm64" { + if assets.DTBPath == "" { + assets.DTBPath = fmt.Sprintf(constants.DTBAssetPath, arch) + } + + if assets.UBootPath == "" { + assets.UBootPath = fmt.Sprintf(constants.UBootAssetPath, arch) + } + + if assets.RPiFirmwarePath == "" { + assets.RPiFirmwarePath = fmt.Sprintf(constants.RPiFirmwareAssetPath, arch) + } + } } diff --git a/pkg/imager/filemap/filemap.go b/pkg/imager/filemap/filemap.go index 718a5d836..e90468aaf 100644 --- a/pkg/imager/filemap/filemap.go +++ b/pkg/imager/filemap/filemap.go @@ -10,6 +10,7 @@ import ( "bytes" "io" "os" + "path/filepath" "sort" v1 "github.com/google/go-containerregistry/pkg/v1" @@ -22,6 +23,35 @@ type File struct { SourcePath string } +// Walk the filesystem generating a filemap. +func Walk(sourceBasePath, imageBasePath string) ([]File, error) { + var filemap []File + + err := filepath.WalkDir(sourceBasePath, func(path string, d os.DirEntry, err error) error { + if err != nil { + return err + } + + if d.IsDir() { + return nil + } + + rel, err := filepath.Rel(sourceBasePath, path) + if err != nil { + return err + } + + filemap = append(filemap, File{ + ImagePath: filepath.Join(imageBasePath, rel), + SourcePath: path, + }) + + return nil + }) + + return filemap, err +} + // Layer creates a layer from a single file map. // // These layers are reproducible and consistent. diff --git a/pkg/imager/out.go b/pkg/imager/out.go index 64137a058..a35d5eca8 100644 --- a/pkg/imager/out.go +++ b/pkg/imager/out.go @@ -188,10 +188,13 @@ func (i *Imager) buildImage(ctx context.Context, path string, printf func(string ImageSecureboot: i.prof.SecureBootEnabled(), Version: i.prof.Version, BootAssets: options.BootAssets{ - KernelPath: i.prof.Input.Kernel.Path, - InitramfsPath: i.initramfsPath, - UKIPath: i.ukiPath, - SDBootPath: i.sdBootPath, + KernelPath: i.prof.Input.Kernel.Path, + InitramfsPath: i.initramfsPath, + UKIPath: i.ukiPath, + SDBootPath: i.sdBootPath, + DTBPath: i.prof.Input.DTB.Path, + UBootPath: i.prof.Input.UBoot.Path, + RPiFirmwarePath: i.prof.Input.RPiFirmware.Path, }, MountPrefix: scratchSpace, Printf: printf, @@ -282,6 +285,37 @@ func (i *Imager) outInstaller(ctx context.Context, path string, report *reporter ) } + for _, extraArtifact := range []struct { + sourcePath string + imagePath string + }{ + { + sourcePath: i.prof.Input.DTB.Path, + imagePath: strings.TrimLeft(fmt.Sprintf(constants.DTBAssetPath, i.prof.Arch), "/"), + }, + { + sourcePath: i.prof.Input.UBoot.Path, + imagePath: strings.TrimLeft(fmt.Sprintf(constants.UBootAssetPath, i.prof.Arch), "/"), + }, + { + sourcePath: i.prof.Input.RPiFirmware.Path, + imagePath: strings.TrimLeft(fmt.Sprintf(constants.RPiFirmwareAssetPath, i.prof.Arch), "/"), + }, + } { + if extraArtifact.sourcePath == "" { + continue + } + + var extraFiles []filemap.File + + extraFiles, err = filemap.Walk(extraArtifact.sourcePath, extraArtifact.imagePath) + if err != nil { + return fmt.Errorf("failed to walk extra artifact %s: %w", extraArtifact.sourcePath, err) + } + + artifacts = append(artifacts, extraFiles...) + } + artifactsLayer, err := filemap.Layer(artifacts) if err != nil { return fmt.Errorf("failed to create artifacts layer: %w", err) diff --git a/pkg/imager/profile/input.go b/pkg/imager/profile/input.go index 500a9670a..9ab968fb1 100644 --- a/pkg/imager/profile/input.go +++ b/pkg/imager/profile/input.go @@ -21,6 +21,11 @@ import ( "github.com/siderolabs/talos/pkg/machinery/constants" ) +const ( + arm64 = "arm64" + amd64 = "amd64" +) + // Input describes inputs for image generation. type Input struct { // Kernel is a vmlinuz file. @@ -31,6 +36,12 @@ type Input struct { SDStub FileAsset `yaml:"sdStub,omitempty"` // SDBoot is a sd-boot file (only for SecureBoot). SDBoot FileAsset `yaml:"sdBoot,omitempty"` + // DTB is a path to the device tree blobs (arm64 only). + DTB FileAsset `yaml:"dtb,omitempty"` + // UBoot is a path to the u-boot binary (arm64 only). + UBoot FileAsset `yaml:"uBoot,omitempty"` + // RPiFirmware is a path to the Raspberry Pi firmware (arm64 only). + RPiFirmware FileAsset `yaml:"rpiFirmware,omitempty"` // Base installer image to mutate. BaseInstaller ContainerAsset `yaml:"baseInstaller,omitempty"` // SecureBoot is a section with secureboot keys, only for SecureBoot enabled builds. @@ -79,7 +90,7 @@ const defaultSecureBootPrefix = "/secureboot" // FillDefaults fills default values for the input. // -//nolint:gocyclo +//nolint:gocyclo,cyclop func (i *Input) FillDefaults(arch, version string, secureboot bool) { var ( zeroFileAsset FileAsset @@ -94,6 +105,20 @@ func (i *Input) FillDefaults(arch, version string, secureboot bool) { i.Initramfs.Path = fmt.Sprintf(constants.InitramfsAssetPath, arch) } + if arch == arm64 { + if i.DTB == zeroFileAsset { + i.DTB.Path = fmt.Sprintf(constants.DTBAssetPath, arch) + } + + if i.UBoot == zeroFileAsset { + i.UBoot.Path = fmt.Sprintf(constants.UBootAssetPath, arch) + } + + if i.RPiFirmware == zeroFileAsset { + i.RPiFirmware.Path = fmt.Sprintf(constants.RPiFirmwareAssetPath, arch) + } + } + if i.BaseInstaller == zeroContainerAsset { i.BaseInstaller.ImageRef = fmt.Sprintf("%s:%s", images.DefaultInstallerImageRepository, version) } diff --git a/pkg/imager/profile/profile.go b/pkg/imager/profile/profile.go index 7d435b284..1fa2194b1 100644 --- a/pkg/imager/profile/profile.go +++ b/pkg/imager/profile/profile.go @@ -57,7 +57,7 @@ func (p *Profile) SecureBootEnabled() bool { // //nolint:gocyclo,cyclop func (p *Profile) Validate() error { - if p.Arch != "amd64" && p.Arch != "arm64" { + if p.Arch != amd64 && p.Arch != arm64 { return fmt.Errorf("invalid arch %q", p.Arch) } @@ -66,7 +66,7 @@ func (p *Profile) Validate() error { } if p.Board != "" { - if !(p.Arch == "arm64" && p.Platform == "metal") { + if !(p.Arch == arm64 && p.Platform == "metal") { return fmt.Errorf("board is only supported for metal arm64") } } diff --git a/pkg/machinery/constants/constants.go b/pkg/machinery/constants/constants.go index 36bf51cc4..2a3139223 100644 --- a/pkg/machinery/constants/constants.go +++ b/pkg/machinery/constants/constants.go @@ -529,6 +529,15 @@ const ( // SDBootAssetPath is the path to the SDBoot in the installer. SDBootAssetPath = "/usr/install/%s/" + SDBootAsset + // DTBAssetPath is the path to the device tree blobs in the installer. + DTBAssetPath = "/usr/install/%s/dtb" + + // UBootAssetPath is the path to the u-boot in the installer. + UBootAssetPath = "/usr/install/%s/u-boot" + + // RPiFirmwareAssetPath is the path to the raspberrypi firmware in the installer. + RPiFirmwareAssetPath = "/usr/install/%s/raspberrypi-firmware" + // PlatformKeyAsset defines a well known name for the platform key filename used for auto-enrolling. PlatformKeyAsset = "PK.auth"