blob: a356ca5c3df84db6b641fa54073a11ba8340190d [file] [log] [blame]
Lorenz Brunae0d90d2019-09-05 17:53:56 +02001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package main
18
19import (
20 "fmt"
21 "io/ioutil"
22 "os"
Lorenz Brunae0d90d2019-09-05 17:53:56 +020023
24 "github.com/diskfs/go-diskfs"
25 "github.com/diskfs/go-diskfs/disk"
26 "github.com/diskfs/go-diskfs/filesystem"
27 "github.com/diskfs/go-diskfs/partition/gpt"
Lorenz Brunae0d90d2019-09-05 17:53:56 +020028)
29
30var SmalltownDataPartition gpt.Type = gpt.Type("9eeec464-6885-414a-b278-4305c51f7966")
31
32func mibToSectors(size uint64) uint64 {
33 return (size * 1024 * 1024) / 512
34}
35
Lorenz Brunae0d90d2019-09-05 17:53:56 +020036func main() {
Lorenz Brunf95909d2019-09-11 19:48:26 +020037 if len(os.Args) < 3 {
Lorenz Brun0bcaaee2019-11-06 12:42:39 +010038 fmt.Println("Usage: mkimage <UEFI payload> <output image path> <initramfs (optional)>")
Lorenz Brunf95909d2019-09-11 19:48:26 +020039 os.Exit(2)
40 }
Leopold Schabela71b5a42019-10-22 15:48:23 +020041 _ = os.Remove(os.Args[2])
Lorenz Brunf95909d2019-09-11 19:48:26 +020042 diskImg, err := diskfs.Create(os.Args[2], 3*1024*1024*1024, diskfs.Raw)
Lorenz Brunae0d90d2019-09-05 17:53:56 +020043 if err != nil {
44 fmt.Printf("Failed to create disk: %v", err)
45 os.Exit(1)
46 }
47
48 table := &gpt.Table{
49 // This is appropriate at least for virtio disks. Might need to be adjusted for real ones.
50 LogicalSectorSize: 512,
51 PhysicalSectorSize: 512,
52 ProtectiveMBR: true,
53 Partitions: []*gpt.Partition{
54 {
55 Type: gpt.EFISystemPartition,
56 Name: "ESP",
57 Start: mibToSectors(1),
Lorenz Brun0bcaaee2019-11-06 12:42:39 +010058 End: mibToSectors(256) - 1,
Lorenz Brunae0d90d2019-09-05 17:53:56 +020059 },
60 {
61 Type: SmalltownDataPartition,
62 Name: "SIGNOS-DATA",
Lorenz Brun0bcaaee2019-11-06 12:42:39 +010063 Start: mibToSectors(256),
Lorenz Brunae0d90d2019-09-05 17:53:56 +020064 End: mibToSectors(2560) - 1,
65 },
66 },
67 }
68 if err := diskImg.Partition(table); err != nil {
69 fmt.Printf("Failed to apply partition table: %v", err)
70 os.Exit(1)
71 }
72
73 fs, err := diskImg.CreateFilesystem(disk.FilesystemSpec{Partition: 1, FSType: filesystem.TypeFat32, VolumeLabel: "ESP"})
74 if err != nil {
75 fmt.Printf("Failed to create filesystem: %v", err)
76 os.Exit(1)
77 }
78 if err := fs.Mkdir("/EFI"); err != nil {
79 panic(err)
80 }
81 if err := fs.Mkdir("/EFI/BOOT"); err != nil {
82 panic(err)
83 }
84 if err := fs.Mkdir("/EFI/smalltown"); err != nil {
85 panic(err)
86 }
87 efiPayload, err := fs.OpenFile("/EFI/BOOT/BOOTX64.EFI", os.O_CREATE|os.O_RDWR)
88 if err != nil {
89 fmt.Printf("Failed to open EFI payload for writing: %v", err)
90 os.Exit(1)
91 }
92 efiPayloadSrc, err := os.Open(os.Args[1])
93 if err != nil {
94 fmt.Printf("Failed to open EFI payload for reading: %v", err)
95 os.Exit(1)
96 }
97 defer efiPayloadSrc.Close()
98 // If this is streamed (e.g. using io.Copy) it exposes a bug in diskfs, so do it in one go.
99 efiPayloadFull, err := ioutil.ReadAll(efiPayloadSrc)
100 if err != nil {
101 panic(err)
102 }
103 if _, err := efiPayload.Write(efiPayloadFull); err != nil {
104 fmt.Printf("Failed to write EFI payload: %v", err)
105 os.Exit(1)
106 }
Lorenz Brun0bcaaee2019-11-06 12:42:39 +0100107 initramfs, err := fs.OpenFile("/EFI/smalltown/initramfs.cpio.lz4", os.O_CREATE|os.O_RDWR)
108 if err != nil {
109 fmt.Printf("Failed to open initramfs for writing: %v", err)
110 os.Exit(1)
111 }
112 // If we have more than two arguments, the second one is the initramfs
113 if len(os.Args) > 3 {
114 initramfsSrc, err := os.Open(os.Args[3])
115 if err != nil {
116 fmt.Printf("Failed to open initramfs for reading: %v", err)
117 os.Exit(1)
118 }
119 initramfsFull, err := ioutil.ReadAll(initramfsSrc)
120 if err != nil {
121 fmt.Printf("Failed to read initramfs: %v", err)
122 os.Exit(1)
123 }
124 if _, err := initramfs.Write(initramfsFull); err != nil {
125 fmt.Printf("Failed to write initramfs: %v", err)
126 os.Exit(1)
127 }
128 }
Lorenz Brunae0d90d2019-09-05 17:53:56 +0200129 if err := diskImg.File.Close(); err != nil {
130 fmt.Printf("Failed to write image: %v", err)
131 os.Exit(1)
132 }
133 fmt.Println("Success! You can now boot smalltown.img")
134}