blob: a727e8b244721a0e9bcd9d3c621826b1aede14e1 [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 {
38 fmt.Println("Usage: mkimage <UEFI payload> <image path>")
39 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),
58 End: mibToSectors(128) - 1,
59 },
60 {
61 Type: SmalltownDataPartition,
62 Name: "SIGNOS-DATA",
63 Start: mibToSectors(128),
64 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 Brunae0d90d2019-09-05 17:53:56 +0200107 if err := diskImg.File.Close(); err != nil {
108 fmt.Printf("Failed to write image: %v", err)
109 os.Exit(1)
110 }
111 fmt.Println("Success! You can now boot smalltown.img")
112}