blob: 9febf84caa6b32e0d8b44b9e6b15b62086d17dd4 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2014 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <lib/bootargs.h>
24
25#include <trace.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <err.h>
29#include <string.h>
30#include <lk/init.h>
31
32#if WITH_KERNEL_VM
33#include <kernel/vm.h>
34#endif
35
36#define LOCAL_TRACE 0
37
38/* saved by the main entry point in lk */
39extern ulong lk_boot_args[4];
40
41static bool boot_args_valid = false;
42static struct lk_boot_arg *boot_args;
43
44#define LK_BOOT_ARG_MAGIC 'lkbt'
45
46/* lk style boot args are spread across the 4 incoming argument pointers as follows:
47 *
48 * [0] = LK_BOOT_ARG_MAGIC
49 * [1] = pointer to lk_boot_arg list
50 * [2] = unused
51 * [3] = xor of ULONG_MAX and the previous 3
52 */
53
54#define LK_BOOT_ARG_TYPE_INITIAL 'args'
55#define LK_BOOT_ARG_TYPE_COMMAND_LINE 'cmdl'
56#define LK_BOOT_ARG_TYPE_BOOTIMAGE 'bimg'
57#define LK_BOOT_ARG_TYPE_END 0
58
59struct lk_boot_arg {
60 uint32_t type;
61 uint32_t len;
62
63 uint8_t data[];
64};
65
66struct lk_boot_arg_bootimage {
67 uint64_t offset;
68 size_t len;
69
70 char device[];
71};
72
73static void *find_end(void *buf, size_t buf_len)
74{
75 uint8_t *ptr = (uint8_t *)buf;
76 struct lk_boot_arg *arg = (struct lk_boot_arg *)ptr;
77
78 while (arg->type != LK_BOOT_ARG_TYPE_END) {
79 ptr += sizeof(struct lk_boot_arg) + arg->len;
80
81 if ((uintptr_t)ptr - (uintptr_t)buf > buf_len)
82 return NULL;
83
84 arg = (struct lk_boot_arg *)ptr;
85 }
86
87 return ptr;
88}
89
90status_t bootargs_start(void *buf, size_t buf_len)
91{
92 if (buf_len < sizeof(struct lk_boot_arg))
93 return ERR_NO_MEMORY;
94
95 memset(buf, 0, buf_len);
96
97 struct lk_boot_arg *arg = (struct lk_boot_arg *)buf;
98 arg->type = LK_BOOT_ARG_TYPE_INITIAL;
99 arg->len = 0;
100
101 return NO_ERROR;
102}
103
104status_t bootargs_add_command_line(void *buf, size_t buf_len, const char *str)
105{
106 struct lk_boot_arg *arg = find_end(buf, buf_len);
107 if (!arg)
108 return ERR_NO_MEMORY;
109
110 arg->type = LK_BOOT_ARG_TYPE_COMMAND_LINE;
111 arg->len = ROUNDUP(strlen(str) + 1, 4);
112 memset(arg->data, 0, arg->len);
113 strcpy((char *)arg->data, str);
114
115 return NO_ERROR;
116}
117
118status_t bootargs_add_bootimage_pointer(void *buf, size_t buf_len, const char *device, uint64_t offset, size_t len)
119{
120 struct lk_boot_arg *arg = find_end(buf, buf_len);
121 if (!arg)
122 return ERR_NO_MEMORY;
123
124 arg->type = LK_BOOT_ARG_TYPE_BOOTIMAGE;
125 size_t string_len = device ? ROUNDUP(strlen(device) + 1, 4) : 0;
126 arg->len = string_len + sizeof(struct lk_boot_arg_bootimage);
127
128 struct lk_boot_arg_bootimage *bi = (struct lk_boot_arg_bootimage *)arg->data;
129
130 bi->offset = offset;
131 bi->len = len;
132 if (device) {
133 memset(bi->device, 0, string_len);
134 strcpy(bi->device, device);
135 }
136
137 return NO_ERROR;
138}
139
140void bootargs_generate_lk_arg_values(ulong buf, ulong args[4])
141{
142 args[0] = LK_BOOT_ARG_MAGIC;
143 args[1] = buf;
144 args[2] = 0;
145 args[3] = ULONG_MAX ^ args[0] ^ args[1] ^ args[2];
146}
147
148static void bootargs_init_hook(uint level)
149{
150 LTRACE_ENTRY;
151
152 /* see if there are any lk style boot arguments here */
153 if (lk_boot_args[0] != LK_BOOT_ARG_MAGIC) {
154 LTRACEF("failed magic check\n");
155 return;
156 }
157
158 if (lk_boot_args[3] != (ULONG_MAX ^ lk_boot_args[0] ^ lk_boot_args[1] ^ lk_boot_args[2])) {
159 LTRACEF("failed checksum\n");
160 return;
161 }
162
163 /* parse the boot arg pointer */
164#if WITH_KERNEL_VM
165 boot_args = paddr_to_kvaddr(lk_boot_args[1]);
166#else
167 boot_args = (void *)lk_boot_args[1];
168#endif
169
170 if (!boot_args) {
171 LTRACEF("null or invalid boot pointer\n");
172 return;
173 }
174
175 /* see if the initial entry is the right one */
176 if (boot_args[0].type != LK_BOOT_ARG_TYPE_INITIAL) {
177 LTRACEF("bad initial arg\n");
178 return;
179 }
180
181 /* looks good */
182 boot_args_valid = true;
183
184 LTRACEF("valid args found\n");
185}
186
187bool bootargs_are_valid(void)
188{
189 return boot_args_valid;
190}
191
192static struct lk_boot_arg *find_tag(uint32_t tag)
193{
194 if (!boot_args_valid)
195 return NULL;
196
197 struct lk_boot_arg *arg = boot_args;
198
199 while (arg->type != LK_BOOT_ARG_TYPE_END) {
200 if (arg->type == tag)
201 return arg;
202
203 arg = (struct lk_boot_arg *)((uintptr_t)arg + sizeof(struct lk_boot_arg) + arg->len);
204 }
205
206 return NULL;
207}
208
209const char *bootargs_get_command_line(void)
210{
211 struct lk_boot_arg *arg = find_tag(LK_BOOT_ARG_TYPE_COMMAND_LINE);
212 if (!arg)
213 return NULL;
214
215 // XXX validate it
216
217 return (const char *)arg->data;
218}
219
220status_t bootargs_get_bootimage_pointer(uint64_t *offset, size_t *len, const char **device)
221{
222 struct lk_boot_arg *arg = find_tag(LK_BOOT_ARG_TYPE_BOOTIMAGE);
223 if (!arg)
224 return ERR_NOT_FOUND;
225
226 // XXX validate it
227
228 struct lk_boot_arg_bootimage *bi = (struct lk_boot_arg_bootimage *)arg->data;
229
230 if (device) {
231 if (arg->len != sizeof(struct lk_boot_arg_bootimage)) {
232 /* string is present */
233 *device = bi->device;
234 } else {
235 *device = NULL;
236 }
237 }
238
239 if (offset)
240 *offset = bi->offset;
241 if (len)
242 *len = bi->len;
243
244 return NO_ERROR;
245}
246
247LK_INIT_HOOK(bootargs, bootargs_init_hook, LK_INIT_LEVEL_THREADING);
248