2 * Protected by a GNU AFFERO GPLv3
4 * Sylvain Bertrand <sylvain.bertrand@legeek.net>
14 #define strtou64 strtoul
20 #define EFI_VARIABLE_NON_VOLATILE 0x00000001
21 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
22 #define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
24 #define LOAD_OPTION_ACTIVE 0x00000001
26 #define PARTITION_UUID 1
27 #define PARTITION_NUMBER 2
28 #define PARTITION_START_LBA 3
29 #define PARTITION_LBAS_N 4
31 #define LOADER_FILE_PATH 6
41 /* brain damaged mixed-endian guid */
42 static void guid_write(void *dest
, struct guid_t
*src
)
51 *p32
= htole32(src
->blk_0
); /* little endian */
54 *p16
= htole16(src
->blk_1
); /* little endian */
57 *p16
= htole16(src
->blk_2
); /* little endian */
60 *p16
= htobe16(src
->blk_3
); /* big endian */
70 static void guid_read_from_args(struct guid_t
*guid
, void *arg
)
77 memset(guid
, 0, sizeof(*guid
));
78 end
= arg
+ strlen(arg
);
81 blk_end
= strchr(blk_start
, '-');
85 guid
->blk_0
= (u32
)strtou64(blk_start
, 0, 16);
86 blk_start
= blk_end
+ 1;
89 blk_end
= strchr(blk_start
, '-');
93 guid
->blk_1
= (u16
)strtou64(blk_start
, 0, 16);
94 blk_start
= blk_end
+ 1;
97 blk_end
= strchr(blk_start
, '-');
101 guid
->blk_2
= (u16
)strtou64(blk_start
, 0, 16);
102 blk_start
= blk_end
+ 1;
103 if (blk_start
>= end
)
105 blk_end
= strchr(blk_start
, '-');
109 guid
->blk_3
= (u16
)strtou64(blk_start
, 0, 16);
111 blk_start
= blk_end
+ 1;
112 if (blk_start
>= end
)
114 blk_end
= blk_start
+ 12; /* 6 bytes */
119 guid
->blk_4
[0] = (u8
)strtou64(&blk_start
[0], 0, 16);
124 guid
->blk_4
[1] = (u8
)strtou64(&blk_start
[2], 0, 16);
129 guid
->blk_4
[2] = (u8
)strtou64(&blk_start
[4], 0, 16);
134 guid
->blk_4
[3] = (u8
)strtou64(&blk_start
[6], 0, 16);
137 save
= blk_start
[10];
139 guid
->blk_4
[4] = (u8
)strtou64(&blk_start
[8], 0, 16);
140 blk_start
[10] = save
;
142 guid
->blk_4
[5] = (u8
)strtou64(&blk_start
[10], 0, 16);
145 static void usage(void)
148 Generate a UEFI load option variable on the standard output intended for linux\n\
149 efivarfs: /sys/firmware/efi/efivars/BootXXXX-8be4df61-93ca-11d2-aa0d-00e098032b8c\n\
150 Use a command like \"nyangpt\" in order to get the partition UUID (not the\n\
151 filesystem UUID), number (starting from 1), starting LBA, size in cound of LBAs.\n\
152 Don't forget to create/update\n\
153 /sys/firmware/efi/efivars/BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c.\n\
155 nyanefivars partition_uuid partition_number partition_starting_lba partition_size_lbas description_ascii loader_file_path_ascii [loader_arguments_ascii]\n"
159 int main(int args_n
, u8
**args
)
173 u16 FilePathListLength
;
176 u16 HardDriveMediaDevicePath_Length
;
177 struct guid_t partition_guid
;
178 u32 partition_number
;
179 u64 partition_start_lba
;
180 u64 partition_lbas_n
;
181 u16 FilePathMediaDevicePath_Length
;
183 ssize_t written_bytes_n
;
185 if (args_n
!= 7 && args_n
!= 8)
189 /* linux specific, the variable attrs goes as a header */
190 UEFIVarAttrs
= EFI_VARIABLE_NON_VOLATILE
191 | EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
192 buf_bytes_n
= sizeof(UEFIVarAttrs
);
193 buf
= realloc(buf
, (size_t)buf_bytes_n
);
195 *p32
= htole32(UEFIVarAttrs
);
197 LoadOptionAttrs
= LOAD_OPTION_ACTIVE
;
198 buf_bytes_n
+= sizeof(LoadOptionAttrs
);
199 buf
= realloc(buf
, (size_t)buf_bytes_n
);
200 p32
= (u32
*)(buf
+ sizeof(UEFIVarAttrs
));
201 *p32
= htole32(LoadOptionAttrs
);
202 /* we don't know FilePathListLength yet */
203 buf_bytes_n
+= sizeof(FilePathListLength
);
204 buf
= realloc(buf
, (size_t)buf_bytes_n
);
206 desc_bytes_n
= (strlen(args
[DESCRIPTION
]) + 1) * 2; /* account for the 0 terminating ucs2 char */
207 buf_bytes_n
+= desc_bytes_n
;
208 buf
= realloc(buf
, (size_t)buf_bytes_n
);
209 p8_src
= args
[DESCRIPTION
];
210 p8_dst
= buf
+ sizeof(UEFIVarAttrs
)
211 + sizeof(LoadOptionAttrs
)
212 + sizeof(FilePathListLength
);
213 loop
{ /* ascii to ucs2 */
214 p8_dst
[0] = p8_src
[0];
221 /* Hard Drive Media Device Path -- START */
222 HardDriveMediaDevicePath_Length
= 42;
223 buf_bytes_n
+= HardDriveMediaDevicePath_Length
;
224 buf
= realloc(buf
, (size_t)buf_bytes_n
);
225 p8
= buf
+ sizeof(UEFIVarAttrs
)
226 + sizeof(LoadOptionAttrs
)
227 + sizeof(FilePathListLength
)
229 p8
[0] = 0x04; /* Media Device Path */
230 p8
[1] = 0x01; /* Hard Drive */
231 p8
[2] = (u8
)HardDriveMediaDevicePath_Length
; /* length */
233 partition_number
= (u32
)strtou64(args
[PARTITION_NUMBER
], 0, 10);
234 p32
= (u32
*)(p8
+ 4);
235 *p32
= htole32(partition_number
);
236 partition_start_lba
= strtou64(args
[PARTITION_START_LBA
], 0, 10);
237 p64
= (u64
*)(p8
+ 8);
238 *p64
= htole64(partition_start_lba
);
239 partition_lbas_n
= strtou64(args
[PARTITION_LBAS_N
], 0, 10);
240 p64
= (u64
*)(p8
+ 16);
241 *p64
= htole64(partition_lbas_n
);
242 guid_read_from_args(&partition_guid
, args
[PARTITION_UUID
]);
243 guid_write(p8
+ 24, &partition_guid
);
244 p8
[40] = 0x02; /* GUID partition table */
245 p8
[41] = 0x02; /* GUID signature */
246 /* Hard Drive Media Device Path -- END */
247 /* File Path Media Device Path -- START */
248 FilePathMediaDevicePath_Length
= 4 + (strlen(args
[LOADER_FILE_PATH
])
250 buf_bytes_n
+= FilePathMediaDevicePath_Length
;
251 buf
= realloc(buf
, (size_t)buf_bytes_n
);
252 p8
= buf
+ sizeof(UEFIVarAttrs
)
253 + sizeof(LoadOptionAttrs
)
254 + sizeof(FilePathListLength
)
256 + HardDriveMediaDevicePath_Length
;
257 p8
[0] = 0x04; /* Media Device Path */
258 p8
[1] = 0x04; /* File Path */
259 p16
= (u16
*)(p8
+ 2);
260 *p16
= htole16(FilePathMediaDevicePath_Length
);
261 p8_src
= args
[LOADER_FILE_PATH
];
263 loop
{ /* ascii to ucs2 */
264 p8_dst
[0] = p8_src
[0];
271 /* File Path Media Device Path -- END */
272 /* Device Path End Structure */
274 buf
= realloc(buf
, (size_t)buf_bytes_n
);
275 p8
= buf
+ sizeof(UEFIVarAttrs
)
276 + sizeof(LoadOptionAttrs
)
277 + sizeof(FilePathListLength
)
279 + HardDriveMediaDevicePath_Length
280 + FilePathMediaDevicePath_Length
;
281 p8
[0] = 0x7f; /* End of Hardware Device Path */
282 p8
[1] = 0xff; /* End Entire Device Path */
283 p8
[2] = 0x04; /* u16 0x004, the bytes count of this structure */
285 /* we don't know FilePathListLength now */
286 FilePathListLength
= HardDriveMediaDevicePath_Length
287 + FilePathMediaDevicePath_Length
+ 4;
288 p16
= (u16
*)(buf
+ sizeof(UEFIVarAttrs
)
289 + sizeof(LoadOptionAttrs
));
290 *p16
= htole16(FilePathListLength
);
291 /* loader arguments */
293 buf_bytes_n
+= strlen(args
[LOADER_ARGS
]) * 2; /* no terminating 0 */
294 buf
= realloc(buf
, (size_t)buf_bytes_n
);
295 p8_src
= args
[LOADER_ARGS
];
296 p8_dst
= buf
+ sizeof(UEFIVarAttrs
)
297 + sizeof(LoadOptionAttrs
)
298 + sizeof(FilePathListLength
)
300 + FilePathListLength
;
301 loop
{ /* ascii to ucs2 */
305 p8_dst
[0] = p8_src
[0];
312 written_bytes_n
= write(1, buf
, buf_bytes_n
);
313 if (written_bytes_n
!= buf_bytes_n
) {
314 fprintf(stderr
, "ERROR:unable to write properly on the standard output the load option variable data\n");
326 #undef EFI_VARIABLE_NON_VOLATILE
327 #undef EFI_VARIABLE_BOOTSERVICE_ACCESS
328 #undef EFI_VARIABLE_RUNTIME_ACCESS
330 #undef LOAD_OPTION_ACTIVE
332 #undef PARTITION_UUID
333 #undef PARTITION_NUMBER
334 #undef PARTITION_START_LBA
335 #undef PARTITION_LBAS_N
337 #undef LOADER_FILE_PATH