|
| 1 | +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def |
| 2 | +index 95fd18d..3a50f3c 100644 |
| 3 | +--- a/grub-core/Makefile.core.def |
| 4 | ++++ b/grub-core/Makefile.core.def |
| 5 | +@@ -254,6 +254,7 @@ kernel = { |
| 6 | + xen = term/xen/console.c; |
| 7 | + xen = disk/xen/xendisk.c; |
| 8 | + xen = commands/boot.c; |
| 9 | ++ xen = kern/xen/cmdline.c; |
| 10 | + |
| 11 | + i386_xen_pvh = commands/boot.c; |
| 12 | + i386_xen_pvh = disk/xen/xendisk.c; |
| 13 | +@@ -261,6 +262,7 @@ kernel = { |
| 14 | + i386_xen_pvh = kern/i386/xen/tsc.c; |
| 15 | + i386_xen_pvh = kern/i386/xen/pvh.c; |
| 16 | + i386_xen_pvh = kern/xen/init.c; |
| 17 | ++ i386_xen_pvh = kern/xen/cmdline.c; |
| 18 | + i386_xen_pvh = term/xen/console.c; |
| 19 | + |
| 20 | + ia64_efi = kern/ia64/efi/startup.S; |
| 21 | +diff --git a/grub-core/kern/i386/xen/pvh.c b/grub-core/kern/i386/xen/pvh.c |
| 22 | +index 91fbca8..9fb0480 100644 |
| 23 | +--- a/grub-core/kern/i386/xen/pvh.c |
| 24 | ++++ b/grub-core/kern/i386/xen/pvh.c |
| 25 | +@@ -352,6 +352,22 @@ grub_xen_setup_pvh (void) |
| 26 | + grub_xen_mm_init_regions (); |
| 27 | + |
| 28 | + grub_rsdp_addr = pvh_start_info->rsdp_paddr; |
| 29 | ++ int xen_cmdline_fits = 0; |
| 30 | ++ char *xen_cmdline = (char *) pvh_start_info->cmdline_paddr; |
| 31 | ++ for (int i = 0; i < 1024; i++) |
| 32 | ++ { |
| 33 | ++ if (xen_cmdline[i] == '\0') |
| 34 | ++ { |
| 35 | ++ xen_cmdline_fits = 1; |
| 36 | ++ break; |
| 37 | ++ } |
| 38 | ++ } |
| 39 | ++ if (xen_cmdline_fits == 1) |
| 40 | ++ { |
| 41 | ++ grub_strncpy ((char *) grub_xen_start_page_addr->cmd_line, |
| 42 | ++ (char *) pvh_start_info->cmdline_paddr, |
| 43 | ++ MAX_GUEST_CMDLINE); |
| 44 | ++ } |
| 45 | + } |
| 46 | + |
| 47 | + grub_err_t |
| 48 | +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c |
| 49 | +index 8e89763..c078075 100644 |
| 50 | +--- a/grub-core/kern/main.c |
| 51 | ++++ b/grub-core/kern/main.c |
| 52 | +@@ -35,6 +35,10 @@ |
| 53 | + #include <grub/machine/memory.h> |
| 54 | + #endif |
| 55 | + |
| 56 | ++#if defined (GRUB_MACHINE_XEN) || defined (GRUB_MACHINE_XEN_PVH) |
| 57 | ++#include <grub/xen.h> |
| 58 | ++#endif |
| 59 | ++ |
| 60 | + grub_addr_t |
| 61 | + grub_modules_get_end (void) |
| 62 | + { |
| 63 | +@@ -362,6 +366,14 @@ grub_main (void) |
| 64 | + grub_env_export ("root"); |
| 65 | + grub_env_export ("prefix"); |
| 66 | + |
| 67 | ++ /* |
| 68 | ++ * Parse command line parameters from Xen and export them as environment |
| 69 | ++ * variables |
| 70 | ++ */ |
| 71 | ++#if defined (GRUB_MACHINE_XEN) || defined (GRUB_MACHINE_XEN_PVH) |
| 72 | ++ grub_parse_xen_cmdline (); |
| 73 | ++#endif |
| 74 | ++ |
| 75 | + /* Reclaim space used for modules. */ |
| 76 | + reclaim_module_space (); |
| 77 | + |
| 78 | +diff --git a/grub-core/kern/xen/cmdline.c b/grub-core/kern/xen/cmdline.c |
| 79 | +new file mode 100644 |
| 80 | +index 0000000..7626799 |
| 81 | +--- /dev/null |
| 82 | ++++ b/grub-core/kern/xen/cmdline.c |
| 83 | +@@ -0,0 +1,223 @@ |
| 84 | ++/* |
| 85 | ++ * GRUB -- GRand Unified Bootloader |
| 86 | ++ * Copyright (C) 2025 Free Software Foundation, Inc. |
| 87 | ++ * |
| 88 | ++ * GRUB is free software: you can redistribute it and/or modify |
| 89 | ++ * it under the terms of the GNU General Public License as published by |
| 90 | ++ * the Free Software Foundation, either version 3 of the License, or |
| 91 | ++ * (at your option) any later version. |
| 92 | ++ * |
| 93 | ++ * GRUB is distributed in the hope that it will be useful, |
| 94 | ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 95 | ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 96 | ++ * GNU General Public License for more details. |
| 97 | ++ * |
| 98 | ++ * You should have received a copy of the GNU General Public License |
| 99 | ++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
| 100 | ++ */ |
| 101 | ++ |
| 102 | ++#include <grub/env.h> |
| 103 | ++#include <grub/misc.h> |
| 104 | ++#include <grub/mm.h> |
| 105 | ++#include <grub/xen.h> |
| 106 | ++ |
| 107 | ++#define PARSER_HIT_BACKSLASH 0x1 |
| 108 | ++#define PARSER_IN_SINGLE_QUOTES 0x2 |
| 109 | ++#define PARSER_IN_DOUBLE_QUOTES 0x4 |
| 110 | ++#define PARSER_BASE_WORD_LEN 16 |
| 111 | ++ |
| 112 | ++grub_size_t word_list_len; |
| 113 | ++char **word_list; |
| 114 | ++grub_size_t current_word_len; |
| 115 | ++grub_size_t current_word_pos; |
| 116 | ++char *current_word; |
| 117 | ++char current_char; |
| 118 | ++grub_size_t param_dict_len; |
| 119 | ++char **param_keys; |
| 120 | ++char **param_vals; |
| 121 | ++ |
| 122 | ++static void |
| 123 | ++append_char_to_word (void) |
| 124 | ++{ |
| 125 | ++ if (current_word_pos == current_word_len) |
| 126 | ++ { |
| 127 | ++ current_word_len *= 2; |
| 128 | ++ current_word = grub_realloc (current_word, current_word_len); |
| 129 | ++ } |
| 130 | ++ |
| 131 | ++ current_word[current_word_pos] = current_char; |
| 132 | ++ current_word_pos++; |
| 133 | ++} |
| 134 | ++ |
| 135 | ++static void |
| 136 | ++append_word_to_list (void) |
| 137 | ++{ |
| 138 | ++ for (grub_size_t i = 0; i < current_word_pos; i++) |
| 139 | ++ { |
| 140 | ++ if (current_word[i] <= 0x1F || current_word[i] >= 0x7F) |
| 141 | ++ { |
| 142 | ++ grub_free (current_word); |
| 143 | ++ goto reset_word; |
| 144 | ++ } |
| 145 | ++ } |
| 146 | ++ current_char = '\0'; |
| 147 | ++ append_char_to_word (); |
| 148 | ++ current_word_len = grub_strlen (current_word) + 1; |
| 149 | ++ current_word = grub_realloc (current_word, current_word_len); |
| 150 | ++ word_list_len++; |
| 151 | ++ word_list = grub_realloc (word_list, word_list_len * sizeof (char *)); |
| 152 | ++ word_list[word_list_len - 1] = current_word; |
| 153 | ++ |
| 154 | ++reset_word: |
| 155 | ++ current_word_len = PARSER_BASE_WORD_LEN; |
| 156 | ++ current_word_pos = 0; |
| 157 | ++ current_word = grub_malloc (current_word_len); |
| 158 | ++} |
| 159 | ++ |
| 160 | ++int |
| 161 | ++check_key_is_safe (char *key, grub_size_t len) |
| 162 | ++{ |
| 163 | ++ /* |
| 164 | ++ * Ensure only a-z, A-Z, and _ are allowed. |
| 165 | ++ */ |
| 166 | ++ for (grub_size_t i = 0; i < len; i++) |
| 167 | ++ { |
| 168 | ++ if (! ((key[i] >= 'A' && key[i] <= 'Z') |
| 169 | ++ || (key[i] >= 'a' && key[i] <= 'z') |
| 170 | ++ || (key[i] == '_') ) ) |
| 171 | ++ { |
| 172 | ++ return 0; |
| 173 | ++ } |
| 174 | ++ } |
| 175 | ++ return 1; |
| 176 | ++} |
| 177 | ++ |
| 178 | ++void |
| 179 | ++grub_parse_xen_cmdline (void) |
| 180 | ++{ |
| 181 | ++ word_list = grub_malloc (0); |
| 182 | ++ current_word_len = PARSER_BASE_WORD_LEN; |
| 183 | ++ current_word = grub_malloc (current_word_len); |
| 184 | ++ param_keys = grub_malloc (0); |
| 185 | ++ param_vals = grub_malloc (0); |
| 186 | ++ |
| 187 | ++ grub_uint8_t parse_flags = 0; |
| 188 | ++ char *cmdline = (char *)grub_xen_start_page_addr->cmd_line; |
| 189 | ++ |
| 190 | ++ for (grub_size_t i = 0; i < grub_strlen (cmdline); i++) |
| 191 | ++ { |
| 192 | ++ current_char = cmdline[i]; |
| 193 | ++ |
| 194 | ++ if (parse_flags & PARSER_HIT_BACKSLASH) |
| 195 | ++ { |
| 196 | ++ parse_flags ^= PARSER_HIT_BACKSLASH; |
| 197 | ++ append_char_to_word (); |
| 198 | ++ continue; |
| 199 | ++ } |
| 200 | ++ |
| 201 | ++ if (current_char == '\\') |
| 202 | ++ { |
| 203 | ++ parse_flags ^= PARSER_HIT_BACKSLASH; |
| 204 | ++ continue; |
| 205 | ++ } |
| 206 | ++ |
| 207 | ++ if (current_char == '\'') |
| 208 | ++ { |
| 209 | ++ if (parse_flags & PARSER_IN_DOUBLE_QUOTES) |
| 210 | ++ { |
| 211 | ++ append_char_to_word (); |
| 212 | ++ continue; |
| 213 | ++ } |
| 214 | ++ |
| 215 | ++ parse_flags ^= PARSER_IN_SINGLE_QUOTES; |
| 216 | ++ continue; |
| 217 | ++ } |
| 218 | ++ |
| 219 | ++ if (current_char == '"') |
| 220 | ++ { |
| 221 | ++ if (parse_flags & PARSER_IN_SINGLE_QUOTES) |
| 222 | ++ { |
| 223 | ++ append_char_to_word (); |
| 224 | ++ continue; |
| 225 | ++ } |
| 226 | ++ |
| 227 | ++ parse_flags ^= PARSER_IN_DOUBLE_QUOTES; |
| 228 | ++ continue; |
| 229 | ++ } |
| 230 | ++ |
| 231 | ++ if (current_char == ' ') |
| 232 | ++ { |
| 233 | ++ if (parse_flags & PARSER_IN_SINGLE_QUOTES |
| 234 | ++ || parse_flags & PARSER_IN_DOUBLE_QUOTES) |
| 235 | ++ { |
| 236 | ++ append_char_to_word (); |
| 237 | ++ continue; |
| 238 | ++ } |
| 239 | ++ |
| 240 | ++ append_word_to_list (); |
| 241 | ++ continue; |
| 242 | ++ } |
| 243 | ++ |
| 244 | ++ append_char_to_word (); |
| 245 | ++ } |
| 246 | ++ |
| 247 | ++ if (current_word_pos > 0) |
| 248 | ++ { |
| 249 | ++ append_word_to_list (); |
| 250 | ++ } |
| 251 | ++ |
| 252 | ++ param_keys = grub_realloc (param_keys, word_list_len * sizeof (char *)); |
| 253 | ++ param_vals = grub_realloc (param_vals, word_list_len * sizeof (char *)); |
| 254 | ++ for (grub_size_t i = 0; i < word_list_len; i++) |
| 255 | ++ { |
| 256 | ++ current_word = word_list[i]; |
| 257 | ++ current_word_len = grub_strlen (current_word) + 1; |
| 258 | ++ char *current_word_eq_ptr = grub_strchr (current_word, '='); |
| 259 | ++ if (current_word_eq_ptr) |
| 260 | ++ { |
| 261 | ++ grub_size_t eq_idx |
| 262 | ++ = (grub_size_t)(current_word_eq_ptr - current_word); |
| 263 | ++ grub_size_t pre_eq_len |
| 264 | ++ = current_word_len - (current_word_len - eq_idx); |
| 265 | ++ grub_size_t post_eq_len = current_word_len - eq_idx - 1; |
| 266 | ++ if (check_key_is_safe (current_word, pre_eq_len)) |
| 267 | ++ { |
| 268 | ++ param_keys[param_dict_len] = grub_malloc (pre_eq_len + 1); |
| 269 | ++ param_vals[param_dict_len] = grub_malloc (post_eq_len + 1); |
| 270 | ++ grub_strncpy (param_keys[param_dict_len], |
| 271 | ++ current_word, pre_eq_len); |
| 272 | ++ grub_strncpy (param_vals[param_dict_len], |
| 273 | ++ current_word + pre_eq_len + 1, post_eq_len); |
| 274 | ++ param_keys[param_dict_len][pre_eq_len] = '\0'; |
| 275 | ++ param_vals[param_dict_len][post_eq_len] = '\0'; |
| 276 | ++ param_dict_len++; |
| 277 | ++ } |
| 278 | ++ } |
| 279 | ++ else |
| 280 | ++ { |
| 281 | ++ if (check_key_is_safe (current_word, current_word_len - 1)) |
| 282 | ++ { |
| 283 | ++ param_keys[param_dict_len] = grub_malloc (current_word_len + 1); |
| 284 | ++ param_vals[param_dict_len] = grub_malloc (2); |
| 285 | ++ grub_strncpy (param_keys[param_dict_len], |
| 286 | ++ current_word, current_word_len); |
| 287 | ++ param_keys[param_dict_len][current_word_len] = '\0'; |
| 288 | ++ grub_strcpy (param_vals[param_dict_len], "1\0"); |
| 289 | ++ param_dict_len++; |
| 290 | ++ } |
| 291 | ++ } |
| 292 | ++ } |
| 293 | ++ |
| 294 | ++ for (grub_size_t i = 0; i < param_dict_len; i++) |
| 295 | ++ { |
| 296 | ++ grub_env_set (param_keys[i], param_vals[i]); |
| 297 | ++ grub_env_export (param_keys[i]); |
| 298 | ++ grub_free (param_keys[i]); |
| 299 | ++ grub_free (param_vals[i]); |
| 300 | ++ grub_free (word_list[i]); |
| 301 | ++ } |
| 302 | ++ |
| 303 | ++ grub_free (param_keys); |
| 304 | ++ grub_free (param_vals); |
| 305 | ++ grub_free (word_list); |
| 306 | ++} |
| 307 | +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c |
| 308 | +index 90121e9..818ceb3 100644 |
| 309 | +--- a/grub-core/loader/i386/linux.c |
| 310 | ++++ b/grub-core/loader/i386/linux.c |
| 311 | +@@ -64,6 +64,10 @@ GRUB_MOD_LICENSE ("GPLv3+"); |
| 312 | + #define ACCEPTS_PURE_TEXT 1 |
| 313 | + #endif |
| 314 | + |
| 315 | ++#ifdef GRUB_MACHINE_XEN_PVH |
| 316 | ++#include <grub/xen.h> |
| 317 | ++#endif |
| 318 | ++ |
| 319 | + static grub_dl_t my_mod; |
| 320 | + |
| 321 | + static grub_size_t linux_mem_size; |
| 322 | +diff --git a/include/grub/xen.h b/include/grub/xen.h |
| 323 | +index 91cb7cf..7f9efee 100644 |
| 324 | +--- a/include/grub/xen.h |
| 325 | ++++ b/include/grub/xen.h |
| 326 | +@@ -89,6 +89,8 @@ void grub_console_init (void); |
| 327 | + void grub_xendisk_fini (void); |
| 328 | + void grub_xendisk_init (void); |
| 329 | + |
| 330 | ++void grub_parse_xen_cmdline (void); |
| 331 | ++ |
| 332 | + #ifdef __x86_64__ |
| 333 | + typedef grub_uint64_t grub_xen_mfn_t; |
| 334 | + #else |
0 commit comments