1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
23 #define SETUP_MAGIC 0x53726448 /* "HdrS" */
25 UINT8 boot_sector
[0x01f1];
46 UINT32 bootsect_kludge
;
49 UINT8 ext_loader_type
;
52 UINT32 kernel_alignment
;
53 UINT8 relocatable_kernel
;
57 UINT32 hardware_subarch
;
58 UINT64 hardware_subarch_data
;
59 UINT32 payload_offset
;
60 UINT32 payload_length
;
64 UINT32 handover_offset
;
65 } __attribute__((packed
));
68 typedef VOID(*handover_f
)(VOID
*image
, EFI_SYSTEM_TABLE
*table
, struct SetupHeader
*setup
);
69 static inline VOID
linux_efi_handover(EFI_HANDLE image
, struct SetupHeader
*setup
) {
73 handover
= (handover_f
)((UINTN
)setup
->code32_start
+ 512 + setup
->handover_offset
);
74 handover(image
, ST
, setup
);
77 typedef VOID(*handover_f
)(VOID
*image
, EFI_SYSTEM_TABLE
*table
, struct SetupHeader
*setup
) __attribute__((regparm(0)));
78 static inline VOID
linux_efi_handover(EFI_HANDLE image
, struct SetupHeader
*setup
) {
81 handover
= (handover_f
)((UINTN
)setup
->code32_start
+ setup
->handover_offset
);
82 handover(image
, ST
, setup
);
86 EFI_STATUS
linux_exec(EFI_HANDLE
*image
,
87 CHAR8
*cmdline
, UINTN cmdline_len
,
89 UINTN initrd_addr
, UINTN initrd_size
) {
90 struct SetupHeader
*image_setup
;
91 struct SetupHeader
*boot_setup
;
92 EFI_PHYSICAL_ADDRESS addr
;
95 image_setup
= (struct SetupHeader
*)(linux_addr
);
96 if (image_setup
->signature
!= 0xAA55 || image_setup
->header
!= SETUP_MAGIC
)
97 return EFI_LOAD_ERROR
;
99 if (image_setup
->version
< 0x20b || !image_setup
->relocatable_kernel
)
100 return EFI_LOAD_ERROR
;
103 err
= uefi_call_wrapper(BS
->AllocatePages
, 4, AllocateMaxAddress
, EfiLoaderData
,
104 EFI_SIZE_TO_PAGES(0x4000), &addr
);
107 boot_setup
= (struct SetupHeader
*)(UINTN
)addr
;
108 ZeroMem(boot_setup
, 0x4000);
109 CopyMem(boot_setup
, image_setup
, sizeof(struct SetupHeader
));
110 boot_setup
->loader_id
= 0xff;
112 boot_setup
->code32_start
= (UINT32
)linux_addr
+ (image_setup
->setup_secs
+1) * 512;
116 err
= uefi_call_wrapper(BS
->AllocatePages
, 4, AllocateMaxAddress
, EfiLoaderData
,
117 EFI_SIZE_TO_PAGES(cmdline_len
+ 1), &addr
);
120 CopyMem((VOID
*)(UINTN
)addr
, cmdline
, cmdline_len
);
121 ((CHAR8
*)addr
)[cmdline_len
] = 0;
122 boot_setup
->cmd_line_ptr
= (UINT32
)addr
;
125 boot_setup
->ramdisk_start
= (UINT32
)initrd_addr
;
126 boot_setup
->ramdisk_len
= (UINT32
)initrd_size
;
128 linux_efi_handover(image
, boot_setup
);
129 return EFI_LOAD_ERROR
;