esp.c 10.6 KB
Newer Older
bzt's avatar
bzt committed
1
2
3
/*
 * mkbootimg/esp.c
 *
bzt's avatar
bzt committed
4
 * Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
bzt's avatar
bzt committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * 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.
 *
 * This file is part of the BOOTBOOT Protocol package.
 * @brief Generate EFI System Partition
bzt's avatar
bzt committed
28
 * See https://gitlab.com/bztsrc/bootboot/raw/binaries/specs/efifat.pdf
bzt's avatar
bzt committed
29
30
31
32
33
 *
 */
#include "main.h"
#include "data.h"

bzt's avatar
bzt committed
34
char *initrdnames[NUMARCH+1] = { "INITRD", "AARCH64", "X86_64", "RISCV64" };
bzt's avatar
bzt committed
35
36
37
38
39
40
41
42
43
44
45
46
int nextcluster = 3, lastcluster = 0, bpc, esp_size, esp_bbs = 0;
unsigned char *esp, *data;
uint16_t *fat16_1 = NULL, *fat16_2;
uint32_t *fat32_1 = NULL, *fat32_2;

/**
 * Add a FAT directory entry
 */
unsigned char *esp_adddirent(unsigned char *ptr, char *name, int type, int cluster, int size)
{
    int i, j;
    memset(ptr, ' ', 11);
bzt's avatar
bzt committed
47
    if(name[0] == '.') memcpy((char*)ptr, name, strlen(name));
bzt's avatar
bzt committed
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    else
        for(i = j = 0; j < 11 && name[i]; i++, j++) {
            if(name[i] >= 'a' && name[i] <= 'z') ptr[j] = name[i] - ('a' - 'A');
            else if(name[i] == '.') { j = 7; continue; }
            else ptr[j] = name[i];
        }
    ptr[0xB] = type;
    i = (ts->tm_hour << 11) | (ts->tm_min << 5) | (ts->tm_sec/2);
    ptr[0xE] = ptr[0x16] = i & 0xFF; ptr[0xF] = ptr[0x17] = (i >> 8) & 0xFF;
    i = ((ts->tm_year+1900-1980) << 9) | ((ts->tm_mon+1) << 5) | (ts->tm_mday);
    ptr[0x10] = ptr[0x12] = ptr[0x18] = i & 0xFF; ptr[0x11] = ptr[0x13] = ptr[0x19] = (i >> 8) & 0xFF;
    ptr[0x1A] = cluster & 0xFF; ptr[0x1B] = (cluster >> 8) & 0xFF;
    ptr[0x14] = (cluster >> 16) & 0xFF; ptr[0x15] = (cluster >> 24) & 0xFF;
    ptr[0x1C] = size & 0xFF; ptr[0x1D] = (size >> 8) & 0xFF;
    ptr[0x1E] = (size >> 16) & 0xFF; ptr[0x1F] = (size >> 24) & 0xFF;
    return ptr + 32;
}

/**
 * Create a directory
 */
unsigned char *esp_mkdir(unsigned char *ptr, char *directory, int parent)
{
    unsigned char *ptr2 = data + nextcluster * bpc;
    ptr = esp_adddirent(ptr, directory, 0x10, nextcluster, 0);
    if(fat16_1) fat16_1[nextcluster] = fat16_2[nextcluster] = 0xFFFF;
    else fat32_1[nextcluster] = fat32_2[nextcluster] = 0x0FFFFFFF;
    ptr2 = esp_adddirent(ptr2, ".", 0x10, nextcluster, 0);
    ptr2 = esp_adddirent(ptr2, "..", 0x10, parent, 0);
    lastcluster = nextcluster;
    nextcluster++;
    return ptr2;
}

/**
 * Add a file to the boot partition
 */
unsigned char *esp_addfile(unsigned char *ptr, char *name, unsigned char *content, int size)
{
    unsigned char *ptr2 = data + nextcluster * bpc;
    int i;
    ptr = esp_adddirent(ptr, name, 0, nextcluster, size);
    if(content && size) {
        memcpy(ptr2, content, size);
bzt's avatar
bzt committed
92
        for(i = 0; i < ((size + bpc-1) & ~(bpc-1)); i += bpc, nextcluster++) {
bzt's avatar
bzt committed
93
94
95
96
97
98
99
100
101
            if(fat16_1) fat16_1[nextcluster] = fat16_2[nextcluster] = nextcluster+1;
            else fat32_1[nextcluster] = fat32_2[nextcluster] = nextcluster+1;
        }
        if(fat16_1) fat16_1[nextcluster-1] = fat16_2[nextcluster-1] = 0xFFFF;
        else fat32_1[nextcluster-1] = fat32_2[nextcluster-1] = 0x0FFFFFFF;
    }
    return ptr;
}

bzt's avatar
bzt committed
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
 * Add a compressed file to the boot partition
 */
unsigned char *esp_addzfile(unsigned char *ptr, char *name, unsigned char *content, int size, unsigned long int len)
{
    unsigned char *buf = malloc(len);
    if(!buf) { fprintf(stderr,"mkbootimg: %s\r\n",lang[ERR_MEM]); exit(1); }
    if(uncompress(buf,&len,content,size) == Z_OK && len > 0)
        ptr = esp_addfile(ptr, name, buf, len);
    free(buf);
    return ptr;
}

bzt's avatar
bzt committed
115
116
117
118
119
120
121
122
123
124
/**
 * Create EFI System Partition with FAT16 or FAT32
 */
void esp_makepart()
{
    unsigned char *rootdir, *ptr;
    int i = (initrd_size[0] + 2047 + initrd_size[1] + 2047 + 1024*1024-1)/1024/1024 + 3, spf, boot = 0;

    if(boot_size < i) boot_size = i;
    /* we must force 16M at least, because if FAT16 has too few clusters, some UEFI thinks it's FAT12... */
bzt's avatar
bzt committed
125
    if(boot_size < 8) boot_size = 8;
bzt's avatar
bzt committed
126
    if(boot_fat == 16 && boot_size >= 128) boot_fat = 32;
bzt's avatar
bzt committed
127
128
    /* we must force 128M, because if FAT32 has too few clusters, some UEFI thinks it's FAT16... */
    i = (iso9660 ? 128 : 33);
bzt's avatar
bzt committed
129
130
131
132
    if(boot_fat == 32 && boot_size < i) boot_size = i;
    esp_size = boot_size*1024*1024;

    esp = malloc(esp_size);
bzt's avatar
bzt committed
133
    if(!esp) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(2); }
bzt's avatar
bzt committed
134
135
    memset(esp, 0, esp_size);
    /* Volume Boot Record */
bzt's avatar
bzt committed
136
    memcpy(esp, binary_boot_bin, 512);
bzt's avatar
bzt committed
137
138
139
140
141
142
    esp[0x1FE]=0x55; esp[0x1FF]=0xAA;
    /* use 4 sectors per cluster to ensure data is always 2048 bytes aligned for ISO9660, that's
     * a good default for FAT16 anyway. For FAT32 we only use 1 sector per cluster if no ISO9660
     * requested and the disk size is small */
    esp[0xC] = 2; esp[0x10] = 2; esp[0x15] = 0xF8; esp[0x1FE] = 0x55; esp[0x1FF] = 0xAA;
    esp[0x18] = 0x20; esp[0x1A] = 0x40;
bzt's avatar
bzt committed
143
    i = (esp_size + 511) / 512; if(i < 65536) memcpy(esp + 0x13, &i, 2); else memcpy(esp + 0x20, &i, 4);
bzt's avatar
bzt committed
144
    if(boot_fat == 16) {
bzt's avatar
bzt committed
145
        esp[0xD] = 4; esp[0xE] = 4; esp[0x12] = 2;
bzt's avatar
bzt committed
146
147
148
149
150
151
152
153
154
155
156
        bpc = esp[0xD] * 512;
        spf = ((esp_size/bpc)*2 + 511) / 512;
        esp[0x16] = spf & 0xFF; esp[0x17] = (spf >> 8) & 0xFF;
        esp[0x24] = 0x80; esp[0x26] = 0x29; esp[0x27] = 0xB0; esp[0x28] = 0x07; esp[0x29] = 0xB0; esp[0x2A] = 0x07;
        memcpy(esp + 0x2B, "EFI System FAT16   ", 19);
        rootdir = esp + (spf*esp[0x10]+esp[0xE]) * 512;
        data = rootdir + ((((esp[0x12]<<8)|esp[0x11])*32 - 4096) & ~2047);
        fat16_1 = (uint16_t*)(&esp[esp[0xE] * 512]);
        fat16_2 = (uint16_t*)(&esp[(esp[0xE]+spf) * 512]);
        fat16_1[0] = fat16_2[0] = 0xFFF8; fat16_1[1] = fat16_2[1] = 0xFFFF;
    } else {
bzt's avatar
bzt committed
157
        esp[0xD] = iso9660 || boot_size >= 128 ? 4 : 1; esp[0xE] = 8;
bzt's avatar
bzt committed
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
        bpc = esp[0xD] * 512;
        spf = ((esp_size/bpc)*4) / 512 - 8;
        esp[0x24] = spf & 0xFF; esp[0x25] = (spf >> 8) & 0xFF; esp[0x26] = (spf >> 16) & 0xFF; esp[0x27] = (spf >> 24) & 0xFF;
        esp[0x2C] = 2; esp[0x30] = 1; esp[0x32] = 6; esp[0x40] = 0x80;
        esp[0x42] = 0x29; esp[0x43] = 0xB0; esp[0x44] = 0x07; esp[0x45] = 0xB0; esp[0x46] = 0x07;
        memcpy(esp + 0x47, "EFI System FAT32   ", 19);
        memcpy(esp + 0x200, "RRaA", 4); memcpy(esp + 0x3E4, "rrAa", 4);
        for(i = 0; i < 8; i++) esp[0x3E8 + i] = 0xFF;
        esp[0x3FE] = 0x55; esp[0x3FF] = 0xAA;
        rootdir = esp + (spf*esp[0x10]+esp[0xE]) * 512;
        data = rootdir - 2*bpc;
        fat32_1 = (uint32_t*)(&esp[esp[0xE] * 512]);
        fat32_2 = (uint32_t*)(&esp[(esp[0xE]+spf) * 512]);
        fat32_1[0] = fat32_2[0] = fat32_1[2] = fat32_2[2] = 0x0FFFFFF8; fat32_1[1] = fat32_2[1] = 0x0FFFFFFF;
    }
    /* label in root directory */
    rootdir = esp_adddirent(rootdir, ".", 8, 0, 0);
    memcpy(rootdir - 32, "EFI System ", 11);
    /* add contents */
    for(i = 0; i < NUMARCH && initrd_arch[i]; i++)
        boot |= (1 << (initrd_arch[i] - 1));

180
    /* add loader's directory with config and initrds */
bzt's avatar
bzt committed
181
182
183
184
185
186
187
188
189
    ptr = esp_mkdir(rootdir, "BOOTBOOT", 0); rootdir += 32;
    ptr = esp_addfile(ptr, "CONFIG", (unsigned char*)config, strlen(config));
    if(!initrd_arch[1]) {
        ptr = esp_addfile(ptr, initrdnames[0], initrd_buf[0], initrd_size[0]);
    } else {
        for(i = 0; i < NUMARCH && initrd_arch[i]; i++) {
            ptr = esp_addfile(ptr, initrdnames[(int)initrd_arch[i]], initrd_buf[i], initrd_size[i]);
        }
    }
190
    /* add loader code */
bzt's avatar
bzt committed
191
192
193
194
195
196
197
198
199
    if(boot & (1 << 6)) {
        /* additional platform */
    }
    if(boot & (1 << 5)) {
        /* additional platform */
    }
    if(boot & (1 << 4)) {
        /* additional platform */
    }
bzt's avatar
bzt committed
200
    if(boot & (1 << 3)) {
bzt's avatar
bzt committed
201
        /* additional platform */
bzt's avatar
bzt committed
202
203
    }
    if(boot & (1 << 2)) {
bzt's avatar
bzt committed
204
205
206
        /*** Risc-V 64 Microchip Icicle ***/
        /* start and end address has to be added to the GPT too in a special partition */
        bbp_start = ((data + nextcluster * bpc)-esp) / 512;
bzt's avatar
bzt committed
207
        rootdir = esp_addzfile(rootdir, "PAYLOAD.BIN", binary_bootboot_rv64, sizeof(binary_bootboot_rv64), sizeof_bootboot_rv64);
bzt's avatar
bzt committed
208
        bbp_end = (((data + nextcluster * bpc)-esp) / 512) - 1;
bzt's avatar
bzt committed
209
210
    }
    if(boot & (1 << 1)) {
211
212
213
214
        /*** x86 PC (BIOS) ***/
        /* start address has to be saved in PMBR too */
        esp_bbs = ((data + nextcluster * bpc)-esp) / 512;
        memcpy(esp + 0x1B0, &esp_bbs, 4);
bzt's avatar
bzt committed
215
        rootdir = esp_addzfile(rootdir, "BOOTBOOT.BIN", binary_bootboot_bin, sizeof(binary_bootboot_bin), sizeof_bootboot_bin);
bzt's avatar
bzt committed
216
        /*** x86 PC (UEFI) ***/
bzt's avatar
bzt committed
217
218
        ptr = esp_mkdir(rootdir, "EFI", 0); rootdir += 32;
        ptr = esp_mkdir(ptr, "BOOT", lastcluster);
bzt's avatar
bzt committed
219
        ptr = esp_addzfile(ptr, "BOOTX64.EFI", binary_bootboot_efi, sizeof(binary_bootboot_efi), sizeof_bootboot_efi);
bzt's avatar
bzt committed
220
221
    }
    if(boot & (1 << 0)) {
bzt's avatar
bzt committed
222
        /*** Raspberry Pi ***/
bzt's avatar
bzt committed
223
224
225
226
227
        ptr = esp_addzfile(rootdir, "KERNEL8.IMG", binary_bootboot_img, sizeof(binary_bootboot_img), sizeof_bootboot_img);
        ptr = esp_addzfile(ptr, "BOOTCODE.BIN", binary_bootcode_bin, sizeof(binary_bootcode_bin), sizeof_bootcode_bin);
        ptr = esp_addzfile(ptr, "FIXUP.DAT", binary_fixup_dat, sizeof(binary_fixup_dat), sizeof_fixup_dat);
        ptr = esp_addzfile(ptr, "START.ELF", binary_start_elf, sizeof(binary_start_elf), sizeof_start_elf);
        ptr = esp_addzfile(ptr, "LICENCE.BCM", binary_LICENCE_broadcom, sizeof(binary_LICENCE_broadcom), sizeof_LICENCE_broadcom);
bzt's avatar
bzt committed
228
229
230
231
232
233
234
235
236
    }
    /* update fields in FS Information Sector */
    if(boot_fat == 32) {
        nextcluster -= 2;
        i = ((esp_size - (spf*esp[0x10]+esp[0xE]) * 512)/bpc) - nextcluster;
        esp[0x3E8] = i & 0xFF; esp[0x3E9] = (i >> 8) & 0xFF;
        esp[0x3EA] = (i >> 16) & 0xFF; esp[0x3EB] = (i >> 24) & 0xFF;
        esp[0x3EC] = nextcluster & 0xFF; esp[0x3ED] = (nextcluster >> 8) & 0xFF;
        esp[0x3EE] = (nextcluster >> 16) & 0xFF; esp[0x3EF] = (nextcluster >> 24) & 0xFF;
bzt's avatar
bzt committed
237
238
        /* copy backup boot sectors */
        memcpy(esp + (esp[0x32]*512), esp, 1024);
bzt's avatar
bzt committed
239
240
241
    }
}