1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
22 #define SETUP_MAGIC 0x53726448 /* "HdrS" */
24 UINT8 boot_sector
[0x01f1];
45 UINT32 bootsect_kludge
;
48 UINT8 ext_loader_type
;
51 UINT32 kernel_alignment
;
52 UINT8 relocatable_kernel
;
56 UINT32 hardware_subarch
;
57 UINT64 hardware_subarch_data
;
58 UINT32 payload_offset
;
59 UINT32 payload_length
;
63 UINT32 handover_offset
;
64 } __attribute__((packed
));
67 typedef VOID(*handover_f
)(VOID
*image
, EFI_SYSTEM_TABLE
*table
, struct SetupHeader
*setup
);
68 static inline VOID
linux_efi_handover(EFI_HANDLE image
, struct SetupHeader
*setup
) {
72 handover
= (handover_f
)((UINTN
)setup
->code32_start
+ 512 + setup
->handover_offset
);
73 handover(image
, ST
, setup
);
76 typedef VOID(*handover_f
)(VOID
*image
, EFI_SYSTEM_TABLE
*table
, struct SetupHeader
*setup
) __attribute__((regparm(0)));
77 static inline VOID
linux_efi_handover(EFI_HANDLE image
, struct SetupHeader
*setup
) {
80 handover
= (handover_f
)((UINTN
)setup
->code32_start
+ setup
->handover_offset
);
81 handover(image
, ST
, setup
);
85 EFI_STATUS
linux_exec(EFI_HANDLE
*image
,
86 CHAR8
*cmdline
, UINTN cmdline_len
,
88 UINTN initrd_addr
, UINTN initrd_size
) {
89 struct SetupHeader
*image_setup
;
90 struct SetupHeader
*boot_setup
;
91 EFI_PHYSICAL_ADDRESS addr
;
94 image_setup
= (struct SetupHeader
*)(linux_addr
);
95 if (image_setup
->signature
!= 0xAA55 || image_setup
->header
!= SETUP_MAGIC
)
96 return EFI_LOAD_ERROR
;
98 if (image_setup
->version
< 0x20b || !image_setup
->relocatable_kernel
)
99 return EFI_LOAD_ERROR
;
102 err
= uefi_call_wrapper(BS
->AllocatePages
, 4, AllocateMaxAddress
, EfiLoaderData
,
103 EFI_SIZE_TO_PAGES(0x4000), &addr
);
106 boot_setup
= (struct SetupHeader
*)(UINTN
)addr
;
107 ZeroMem(boot_setup
, 0x4000);
108 CopyMem(boot_setup
, image_setup
, sizeof(struct SetupHeader
));
109 boot_setup
->loader_id
= 0xff;
111 boot_setup
->code32_start
= (UINT32
)linux_addr
+ (image_setup
->setup_secs
+1) * 512;
115 err
= uefi_call_wrapper(BS
->AllocatePages
, 4, AllocateMaxAddress
, EfiLoaderData
,
116 EFI_SIZE_TO_PAGES(cmdline_len
+ 1), &addr
);
119 CopyMem((VOID
*)(UINTN
)addr
, cmdline
, cmdline_len
);
120 ((CHAR8
*)addr
)[cmdline_len
] = 0;
121 boot_setup
->cmd_line_ptr
= (UINT32
)addr
;
124 boot_setup
->ramdisk_start
= (UINT32
)initrd_addr
;
125 boot_setup
->ramdisk_len
= (UINT32
)initrd_size
;
127 linux_efi_handover(image
, boot_setup
);
128 return EFI_LOAD_ERROR
;