-
Notifications
You must be signed in to change notification settings - Fork 8
/
linux.c
110 lines (96 loc) · 3.17 KB
/
linux.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
* stubby
*
* Copyright (c) 2020 Cisco Systems, Inc. <[email protected]>
*
* This file was originally copied from systemd under the LGPL-2.1+ license
* and that license has been preserved in this project. The systemd source
* repository can be found at https://github.com/systemd/systemd.
*
*/
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "stubby_efi.h"
#include "linux.h"
#include "util.h"
#ifdef __i386__
#define __regparm0__ __attribute__((regparm(0)))
#else
#define __regparm0__
#endif
typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table,
struct boot_params *params) __regparm0__;
static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params)
{
handover_f handover;
UINTN start = (UINTN)params->hdr.code32_start;
#ifdef __x86_64__
asm volatile ("cli");
start += 512;
#endif
handover = (handover_f)(start + params->hdr.handover_offset);
handover(image, ST, params);
}
EFI_STATUS linux_exec(EFI_HANDLE *image,
CHAR8 *cmdline, UINTN cmdline_len,
UINTN linux_addr,
UINTN initrd_addr, UINTN initrd_size)
{
struct boot_params *image_params;
struct boot_params *boot_params;
UINT8 setup_sectors;
EFI_PHYSICAL_ADDRESS addr;
EFI_STATUS err;
image_params = (struct boot_params *) linux_addr;
if (image_params->hdr.boot_flag != 0xAA55 ||
image_params->hdr.header != SETUP_MAGIC ||
image_params->hdr.version < 0x20b ||
!image_params->hdr.relocatable_kernel)
return EFI_LOAD_ERROR;
boot_params = (struct boot_params *) 0xFFFFFFFF;
err = uefi_call_wrapper(BS->AllocatePages, 4,
AllocateMaxAddress,
EfiLoaderData,
EFI_SIZE_TO_PAGES(0x4000),
(EFI_PHYSICAL_ADDRESS *) &boot_params);
if (EFI_ERROR(err))
return err;
ZeroMem(boot_params, 0x4000);
CopyMem(&boot_params->hdr, &image_params->hdr,
sizeof(struct setup_header));
boot_params->hdr.type_of_loader = 0xff;
setup_sectors = image_params->hdr.setup_sects > 0 ?
image_params->hdr.setup_sects : 4;
boot_params->hdr.code32_start = (UINT32)linux_addr + \
(setup_sectors + 1) * 512;
if (cmdline) {
addr = 0xA0000;
err = uefi_call_wrapper(BS->AllocatePages, 4,
AllocateMaxAddress,
EfiLoaderData,
EFI_SIZE_TO_PAGES(cmdline_len + 1),
&addr);
if (EFI_ERROR(err))
return err;
CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len);
((CHAR8 *)(UINTN)addr)[cmdline_len] = 0;
boot_params->hdr.cmd_line_ptr = (UINT32)addr;
}
boot_params->hdr.ramdisk_image = (UINT32)initrd_addr;
boot_params->hdr.ramdisk_size = (UINT32)initrd_size;
linux_efi_handover(image, boot_params);
return EFI_LOAD_ERROR;
}