| 1 | /* |
|---|
| 2 | * This file is part of FILO. |
|---|
| 3 | * |
|---|
| 4 | * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc. |
|---|
| 5 | * Copyright (C) 2005-2010 coresystems GmbH |
|---|
| 6 | * |
|---|
| 7 | * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | * it under the terms of the GNU General Public License as published by |
|---|
| 9 | * the Free Software Foundation; version 2 of the License. |
|---|
| 10 | * |
|---|
| 11 | * This program is distributed in the hope that it will be useful, |
|---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | * GNU General Public License for more details. |
|---|
| 15 | * |
|---|
| 16 | * You should have received a copy of the GNU General Public License |
|---|
| 17 | * along with this program; if not, write to the Free Software |
|---|
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|---|
| 19 | */ |
|---|
| 20 | |
|---|
| 21 | #include <libpayload-config.h> |
|---|
| 22 | #include <libpayload.h> |
|---|
| 23 | #include <getopt.h> |
|---|
| 24 | |
|---|
| 25 | #include <config.h> |
|---|
| 26 | #include <fs.h> |
|---|
| 27 | #include <lib.h> |
|---|
| 28 | #include <grub/shared.h> |
|---|
| 29 | #include <arch/timer.h> |
|---|
| 30 | #ifdef CONFIG_USE_MD5_PASSWORDS |
|---|
| 31 | #include <grub/md5.h> |
|---|
| 32 | #endif |
|---|
| 33 | #include <pci.h> |
|---|
| 34 | |
|---|
| 35 | /* The default entry. */ |
|---|
| 36 | int default_entry = 0; |
|---|
| 37 | |
|---|
| 38 | int current_entryno; |
|---|
| 39 | |
|---|
| 40 | // from disk_io: |
|---|
| 41 | int buf_drive = -1; |
|---|
| 42 | unsigned long current_drive = GRUB_INVALID_DRIVE; |
|---|
| 43 | // from common.c: |
|---|
| 44 | unsigned long saved_drive; |
|---|
| 45 | unsigned long saved_partition; |
|---|
| 46 | unsigned long saved_mem_upper; |
|---|
| 47 | // other.. |
|---|
| 48 | unsigned long install_partition = 0x20000; |
|---|
| 49 | unsigned long boot_drive = 0; |
|---|
| 50 | char config_file[128] = "\0"; |
|---|
| 51 | |
|---|
| 52 | kernel_t kernel_type; |
|---|
| 53 | |
|---|
| 54 | /* The fallback entry. */ |
|---|
| 55 | int fallback_entryno; |
|---|
| 56 | int fallback_entries[MAX_FALLBACK_ENTRIES]; |
|---|
| 57 | |
|---|
| 58 | int grub_timeout = -1; |
|---|
| 59 | |
|---|
| 60 | /* The password. */ |
|---|
| 61 | char *password = NULL; |
|---|
| 62 | /* The password type. */ |
|---|
| 63 | password_t password_type; |
|---|
| 64 | /* The flag for indicating that the user is authoritative. */ |
|---|
| 65 | int auth = 0; |
|---|
| 66 | |
|---|
| 67 | /* -------- FILO logic -------- */ |
|---|
| 68 | #define BOOT_LINE_LENGTH 1024 |
|---|
| 69 | char boot_line[BOOT_LINE_LENGTH] = { 0 }; |
|---|
| 70 | char root_device[16] = { 0 }; |
|---|
| 71 | /* ---------------------------- */ |
|---|
| 72 | |
|---|
| 73 | /* temporary space for run time checks */ |
|---|
| 74 | static char temp_space[BOOT_LINE_LENGTH]; |
|---|
| 75 | char initrd_space[BOOT_LINE_LENGTH]="\0"; |
|---|
| 76 | |
|---|
| 77 | int show_menu = 1; |
|---|
| 78 | |
|---|
| 79 | static int last_normal_color = -1, last_highlight_color = -1; |
|---|
| 80 | |
|---|
| 81 | /* Initialize the data for builtins. */ |
|---|
| 82 | void init_builtins(void) |
|---|
| 83 | { |
|---|
| 84 | kernel_type = KERNEL_TYPE_NONE; |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | /* Initialize the data for the configuration file. */ |
|---|
| 88 | void init_config(void) |
|---|
| 89 | { |
|---|
| 90 | password = NULL; |
|---|
| 91 | fallback_entryno = -1; |
|---|
| 92 | fallback_entries[0] = -1; |
|---|
| 93 | grub_timeout = -1; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | int check_password(char *entered, char *expected, password_t type) |
|---|
| 97 | { |
|---|
| 98 | switch (type) { |
|---|
| 99 | case PASSWORD_PLAIN: |
|---|
| 100 | return strcmp(entered, expected); |
|---|
| 101 | #ifdef CONFIG_USE_MD5_PASSWORDS |
|---|
| 102 | case PASSWORD_MD5: |
|---|
| 103 | return check_md5_password(entered, expected); |
|---|
| 104 | #endif |
|---|
| 105 | default: |
|---|
| 106 | /* unsupported password type: be secure */ |
|---|
| 107 | return 1; |
|---|
| 108 | } |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | /* boot */ |
|---|
| 112 | static int boot_func(char *arg, int flags) |
|---|
| 113 | { |
|---|
| 114 | int boot(const char *line); |
|---|
| 115 | int ret; |
|---|
| 116 | |
|---|
| 117 | if(!boot_line[0]) { |
|---|
| 118 | errnum = ERR_BOOT_COMMAND; |
|---|
| 119 | return 1; |
|---|
| 120 | } |
|---|
| 121 | |
|---|
| 122 | /* Set color back to black and white, or Linux booting will look |
|---|
| 123 | * very funny. |
|---|
| 124 | */ |
|---|
| 125 | console_setcolor((COLOR_BLACK << 4) | COLOR_WHITE, |
|---|
| 126 | (COLOR_WHITE << 4) | COLOR_BLACK); |
|---|
| 127 | |
|---|
| 128 | cls(); |
|---|
| 129 | |
|---|
| 130 | if (initrd_space[0]) { |
|---|
| 131 | strncat(boot_line, " initrd=", BOOT_LINE_LENGTH); |
|---|
| 132 | strncat(boot_line, initrd_space, BOOT_LINE_LENGTH); |
|---|
| 133 | } |
|---|
| 134 | |
|---|
| 135 | grub_printf("\nBooting '%s'\n", boot_line); |
|---|
| 136 | |
|---|
| 137 | ret = boot(boot_line); |
|---|
| 138 | |
|---|
| 139 | /* If we regain control, something went wrong. */ |
|---|
| 140 | |
|---|
| 141 | /* The menu color was changed and we failed to boot, so we |
|---|
| 142 | * need to restore the colors in order to make the menu look as |
|---|
| 143 | * it did before. |
|---|
| 144 | */ |
|---|
| 145 | if (last_normal_color != -1) { |
|---|
| 146 | console_setcolor(last_normal_color, last_highlight_color); |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | /* If no loader felt responsible for this image format, it's |
|---|
| 150 | * a bad file format, otherwise we don't really know. |
|---|
| 151 | */ |
|---|
| 152 | if (ret == LOADER_NOT_SUPPORT) |
|---|
| 153 | errnum = ERR_EXEC_FORMAT; |
|---|
| 154 | else |
|---|
| 155 | errnum = ERR_BOOT_FAILURE; |
|---|
| 156 | |
|---|
| 157 | return 1; |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | static struct builtin builtin_boot = { |
|---|
| 161 | "boot", |
|---|
| 162 | boot_func, |
|---|
| 163 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 164 | "boot", |
|---|
| 165 | "Boot the OS/chain-loader which has been loaded." |
|---|
| 166 | }; |
|---|
| 167 | |
|---|
| 168 | |
|---|
| 169 | /* color */ |
|---|
| 170 | /* Set new colors used for the menu interface. Support two methods to |
|---|
| 171 | * specify a color name: a direct integer representation and a symbolic |
|---|
| 172 | * color name. An example of the latter is "blink-light-gray/blue". */ |
|---|
| 173 | static int color_func(char *arg, int flags) |
|---|
| 174 | { |
|---|
| 175 | char *normal; |
|---|
| 176 | char *highlight; |
|---|
| 177 | int new_normal_color; |
|---|
| 178 | int new_highlight_color; |
|---|
| 179 | static char *color_list[16] = { |
|---|
| 180 | "black", |
|---|
| 181 | "red", |
|---|
| 182 | "green", |
|---|
| 183 | "brown", |
|---|
| 184 | "blue", |
|---|
| 185 | "magenta", |
|---|
| 186 | "cyan", |
|---|
| 187 | "light-gray", |
|---|
| 188 | "dark-gray", |
|---|
| 189 | "light-red", |
|---|
| 190 | "light-green", |
|---|
| 191 | "yellow", |
|---|
| 192 | "light-blue", |
|---|
| 193 | "light-magenta", |
|---|
| 194 | "light-cyan", |
|---|
| 195 | "white" |
|---|
| 196 | }; |
|---|
| 197 | |
|---|
| 198 | auto int color_number(char *str); |
|---|
| 199 | |
|---|
| 200 | /* Convert the color name STR into a VGA color number. */ |
|---|
| 201 | auto int color_number(char *str) { |
|---|
| 202 | char *ptr; |
|---|
| 203 | int i; |
|---|
| 204 | int color = 0; |
|---|
| 205 | |
|---|
| 206 | /* Find the separator. */ |
|---|
| 207 | for (ptr = str; *ptr && *ptr != '/'; ptr++); |
|---|
| 208 | |
|---|
| 209 | /* If not found, return -1. */ |
|---|
| 210 | if (!*ptr) |
|---|
| 211 | return -1; |
|---|
| 212 | |
|---|
| 213 | /* Terminate the string STR. */ |
|---|
| 214 | *ptr++ = 0; |
|---|
| 215 | |
|---|
| 216 | /* If STR contains the prefix "blink-", then set the `blink' bit in COLOR. */ |
|---|
| 217 | if (substring("blink-", str) <= 0) { |
|---|
| 218 | color = 0x80; |
|---|
| 219 | str += 6; |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | /* Search for the foreground color name. */ |
|---|
| 223 | for (i = 0; i < 16; i++) |
|---|
| 224 | if (strcmp(color_list[i], str) == 0) { |
|---|
| 225 | color |= i; |
|---|
| 226 | break; |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | if (i == 16) |
|---|
| 230 | return -1; |
|---|
| 231 | |
|---|
| 232 | str = ptr; |
|---|
| 233 | nul_terminate(str); |
|---|
| 234 | |
|---|
| 235 | /* Search for the background color name. */ |
|---|
| 236 | for (i = 0; i < 8; i++) |
|---|
| 237 | if (strcmp(color_list[i], str) == 0) { |
|---|
| 238 | color |= (i <<4); |
|---|
| 239 | break; |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | if (i == 8) |
|---|
| 243 | return -1; |
|---|
| 244 | |
|---|
| 245 | return color; |
|---|
| 246 | } |
|---|
| 247 | |
|---|
| 248 | normal = arg; |
|---|
| 249 | highlight = skip_to(0, arg); |
|---|
| 250 | |
|---|
| 251 | new_normal_color = color_number(normal); |
|---|
| 252 | if (new_normal_color < 0 && !safe_parse_maxint(&normal, &new_normal_color)) { |
|---|
| 253 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 254 | return 1; |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | /* The second argument is optional, so set highlight_color to inverted NORMAL_COLOR. */ |
|---|
| 258 | if (!*highlight) |
|---|
| 259 | new_highlight_color = ((new_normal_color >> 4) |
|---|
| 260 | | ((new_normal_color & 0xf) << 4)); |
|---|
| 261 | else { |
|---|
| 262 | new_highlight_color = color_number(highlight); |
|---|
| 263 | if (new_highlight_color < 0 && !safe_parse_maxint(&highlight, &new_highlight_color)) { |
|---|
| 264 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 265 | return 1; |
|---|
| 266 | } |
|---|
| 267 | } |
|---|
| 268 | |
|---|
| 269 | console_setcolor(new_normal_color, new_highlight_color); |
|---|
| 270 | |
|---|
| 271 | // keep the state so we can restore after a failed boot |
|---|
| 272 | last_normal_color = new_normal_color; |
|---|
| 273 | last_highlight_color = new_highlight_color; |
|---|
| 274 | |
|---|
| 275 | return 0; |
|---|
| 276 | } |
|---|
| 277 | |
|---|
| 278 | static struct builtin builtin_color = { |
|---|
| 279 | "color", |
|---|
| 280 | color_func, |
|---|
| 281 | BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, |
|---|
| 282 | "color NORMAL [HIGHLIGHT]", |
|---|
| 283 | "Change the menu colors. The color NORMAL is used for most" |
|---|
| 284 | " lines in the menu, and the color HIGHLIGHT is used to highlight the" |
|---|
| 285 | " line where the cursor points. If you omit HIGHLIGHT, then the" |
|---|
| 286 | " inverted color of NORMAL is used for the highlighted line." |
|---|
| 287 | " The format of a color is \"FG/BG\". FG and BG are symbolic color names." |
|---|
| 288 | " A symbolic color name must be one of these: black, blue, green," |
|---|
| 289 | " cyan, red, magenta, brown, light-gray, dark-gray, light-blue," |
|---|
| 290 | " light-green, light-cyan, light-red, light-magenta, yellow and white." |
|---|
| 291 | " But only the first eight names can be used for BG. You can prefix" |
|---|
| 292 | " \"blink-\" to FG if you want a blinking foreground color." |
|---|
| 293 | }; |
|---|
| 294 | |
|---|
| 295 | static int help_func(char *arg, int flags); |
|---|
| 296 | /* configfile */ |
|---|
| 297 | static int configfile_func(char *arg, int flags) |
|---|
| 298 | { |
|---|
| 299 | extern int is_opened, keep_cmdline_running; |
|---|
| 300 | |
|---|
| 301 | /* Check if the file ARG is present. */ |
|---|
| 302 | temp_space[0]=0; |
|---|
| 303 | copy_path_to_filo_bootline(arg, temp_space, 1); |
|---|
| 304 | if (temp_space[0]==0) { |
|---|
| 305 | return help_func("configfile",0); |
|---|
| 306 | } |
|---|
| 307 | if (!file_open(temp_space)) { |
|---|
| 308 | errnum = ERR_FILE_NOT_FOUND; |
|---|
| 309 | return 1; |
|---|
| 310 | } |
|---|
| 311 | |
|---|
| 312 | file_close(); |
|---|
| 313 | |
|---|
| 314 | /* Copy ARG to CONFIG_FILE. */ |
|---|
| 315 | memset(config_file, 0, 128); |
|---|
| 316 | copy_path_to_filo_bootline(arg, config_file, 1); |
|---|
| 317 | |
|---|
| 318 | /* Force to load the configuration file. */ |
|---|
| 319 | is_opened = 0; |
|---|
| 320 | keep_cmdline_running = 0; |
|---|
| 321 | |
|---|
| 322 | /* Make sure that the user will not be authoritative. */ |
|---|
| 323 | auth = 0; |
|---|
| 324 | |
|---|
| 325 | return 0; |
|---|
| 326 | } |
|---|
| 327 | |
|---|
| 328 | static struct builtin builtin_configfile = { |
|---|
| 329 | "configfile", |
|---|
| 330 | configfile_func, |
|---|
| 331 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 332 | "configfile FILE", |
|---|
| 333 | "Load FILE as the configuration file." |
|---|
| 334 | }; |
|---|
| 335 | |
|---|
| 336 | /* default */ |
|---|
| 337 | static int default_func(char *arg, int flags) |
|---|
| 338 | { |
|---|
| 339 | unsigned char buf[1]; |
|---|
| 340 | if (get_option(buf, "boot_default")) |
|---|
| 341 | buf[0] = 0xff; |
|---|
| 342 | |
|---|
| 343 | if ((unsigned char)buf[0] != 0xff) { |
|---|
| 344 | printf("Default override by CMOS.\n"); |
|---|
| 345 | return 0; |
|---|
| 346 | } |
|---|
| 347 | |
|---|
| 348 | if (!safe_parse_maxint(&arg, &default_entry)) |
|---|
| 349 | return 1; |
|---|
| 350 | |
|---|
| 351 | return 0; |
|---|
| 352 | } |
|---|
| 353 | |
|---|
| 354 | static struct builtin builtin_default = { |
|---|
| 355 | "default", |
|---|
| 356 | default_func, |
|---|
| 357 | BUILTIN_MENU, |
|---|
| 358 | #if 0 |
|---|
| 359 | "default [NUM]", |
|---|
| 360 | "Set the default entry to entry number NUM (if not specified, it is" |
|---|
| 361 | " 0, the first entry) or the entry number saved by savedefault." |
|---|
| 362 | #endif |
|---|
| 363 | }; |
|---|
| 364 | |
|---|
| 365 | #if CONFIG_DEVELOPER_TOOLS |
|---|
| 366 | /* dumpmem */ |
|---|
| 367 | static int dumpmem_func(char *arg, int flags) |
|---|
| 368 | { |
|---|
| 369 | int ret = string_to_args("dumpmem", arg); |
|---|
| 370 | unsigned int mem_base, mem_len; |
|---|
| 371 | void *i; |
|---|
| 372 | |
|---|
| 373 | if(ret || (string_argc != 3)) { |
|---|
| 374 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 375 | return 1; |
|---|
| 376 | } |
|---|
| 377 | |
|---|
| 378 | // FIXME |
|---|
| 379 | if (!safe_parse_maxint(&string_argv[1], &mem_base)) |
|---|
| 380 | return 1; |
|---|
| 381 | if (!safe_parse_maxint(&string_argv[2], &mem_len)) |
|---|
| 382 | return 1; |
|---|
| 383 | |
|---|
| 384 | grub_printf("Dumping memory at 0x%08x (0x%x bytes)\n", |
|---|
| 385 | mem_base, mem_len); |
|---|
| 386 | |
|---|
| 387 | for (i=phys_to_virt(mem_base); i<phys_to_virt(mem_base + mem_len); i++) { |
|---|
| 388 | if (((unsigned long)i & 0x0f) == 0) |
|---|
| 389 | grub_printf("\n%08x:", i); |
|---|
| 390 | unsigned char val = *((unsigned char *)i); |
|---|
| 391 | grub_printf(" %02x", val); |
|---|
| 392 | } |
|---|
| 393 | grub_printf("\n"); |
|---|
| 394 | |
|---|
| 395 | return 0; |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | static struct builtin builtin_dumpmem = { |
|---|
| 399 | "dumpmem", |
|---|
| 400 | dumpmem_func, |
|---|
| 401 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 402 | "dumpmem", |
|---|
| 403 | "Dump memory" |
|---|
| 404 | }; |
|---|
| 405 | |
|---|
| 406 | /* dumppm */ |
|---|
| 407 | static int dumppm_func(char *arg, int flags) |
|---|
| 408 | { |
|---|
| 409 | u16 pmbase; |
|---|
| 410 | |
|---|
| 411 | pmbase = pci_read_config16(PCI_DEV(0,0x1f, 0), 0x40) & 0xfffe; |
|---|
| 412 | |
|---|
| 413 | grub_printf("pmbase+0x0000: 0x%04x (PM1_STS)\n", inw(pmbase+0x0000)); |
|---|
| 414 | grub_printf("pmbase+0x0002: 0x%04x (PM1_EN)\n", inw(pmbase+0x0002)); |
|---|
| 415 | grub_printf("pmbase+0x0004: 0x%08x (PM1_CNT)\n", inl(pmbase+0x0004)); |
|---|
| 416 | grub_printf("pmbase+0x0008: 0x%08x (PM1_TMR)\n", inl(pmbase+0x0008)); |
|---|
| 417 | grub_printf("pmbase+0x0010: 0x%08x (PROC_CNT)\n", inl(pmbase+0x0010)); |
|---|
| 418 | grub_printf("pmbase+0x0020: 0x%08x (PM2_CNT)\n", inl(pmbase+0x0020)); |
|---|
| 419 | grub_printf("pmbase+0x0028: 0x%08x (GPE0_STS)\n", inl(pmbase+0x0028)); |
|---|
| 420 | grub_printf("pmbase+0x002c: 0x%08x (GPE0_EN)\n", inl(pmbase+0x002c)); |
|---|
| 421 | grub_printf("pmbase+0x0030: 0x%08x (SMI_EN)\n", inl(pmbase+0x0030)); |
|---|
| 422 | grub_printf("pmbase+0x0034: 0x%08x (SMI_STS)\n", inl(pmbase+0x0034)); |
|---|
| 423 | grub_printf("pmbase+0x0038: 0x%04x (ALT_GP_SMI_EN)\n", inw(pmbase+0x0038)); |
|---|
| 424 | grub_printf("pmbase+0x003a: 0x%04x (ALT_GP_SMI_STS)\n", inw(pmbase+0x003a)); |
|---|
| 425 | grub_printf("pmbase+0x0042: 0x%02x (GPE_CNTL)\n", inb(pmbase+0x0042)); |
|---|
| 426 | grub_printf("pmbase+0x0044: 0x%04x (DEVACT_STS)\n", inw(pmbase+0x0044)); |
|---|
| 427 | grub_printf("pmbase+0x0050: 0x%02x (SS_CNT)\n", inb(pmbase+0x0050)); |
|---|
| 428 | grub_printf("pmbase+0x0054: 0x%08x (C3_RES)\n", inl(pmbase+0x0054)); |
|---|
| 429 | #if 0 |
|---|
| 430 | // TCO |
|---|
| 431 | grub_printf("pmbase+0x0060: 0x%04x (TCO_RLD)\n", inw(pmbase+0x0060)); |
|---|
| 432 | grub_printf("pmbase+0x0062: 0x%02x (TCO_DAT_IN)\n", inb(pmbase+0x0062)); |
|---|
| 433 | grub_printf("pmbase+0x0063: 0x%02x (TCO_DAT_OUT)\n", inb(pmbase+0x0063)); |
|---|
| 434 | grub_printf("pmbase+0x0064: 0x%04x (TCO1_STS)\n", inw(pmbase+0x0064)); |
|---|
| 435 | grub_printf("pmbase+0x0066: 0x%04x (TCO2_STS)\n", inw(pmbase+0x0066)); |
|---|
| 436 | grub_printf("pmbase+0x0068: 0x%04x (TCO1_CNT)\n", inw(pmbase+0x0068)); |
|---|
| 437 | grub_printf("pmbase+0x006a: 0x%04x (TCO2_CNT)\n", inw(pmbase+0x006a)); |
|---|
| 438 | grub_printf("pmbase+0x006c: 0x%04x (TCO_MESSAGE)\n", inw(pmbase+0x006c)); |
|---|
| 439 | grub_printf("pmbase+0x006e: 0x%02x (TCO_WDCNT)\n", inb(pmbase+0x006e)); |
|---|
| 440 | grub_printf("pmbase+0x0070: 0x%02x (TCO_SW_IRQ_GEN)\n", inb(pmbase+0x0070)); |
|---|
| 441 | grub_printf("pmbase+0x0072: 0x%04x (TCO_TMR)\n", inw(pmbase+0x0072)); |
|---|
| 442 | #endif |
|---|
| 443 | return 0; |
|---|
| 444 | } |
|---|
| 445 | |
|---|
| 446 | static struct builtin builtin_dumppm = { |
|---|
| 447 | "dumppm", |
|---|
| 448 | dumppm_func, |
|---|
| 449 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 450 | "dumppm", |
|---|
| 451 | "Dump Powermanagement registers" |
|---|
| 452 | }; |
|---|
| 453 | #endif |
|---|
| 454 | |
|---|
| 455 | #if CONFIG_EXPERIMENTAL |
|---|
| 456 | #warning "FIND not implemented yet." |
|---|
| 457 | /* find */ |
|---|
| 458 | /* Search for the filename ARG in all of partitions. */ |
|---|
| 459 | static int find_func(char *arg, int flags) |
|---|
| 460 | { |
|---|
| 461 | char *filename = arg; |
|---|
| 462 | int got_file = 0; |
|---|
| 463 | |
|---|
| 464 | // the grub find works like this: |
|---|
| 465 | // |
|---|
| 466 | // for all disks |
|---|
| 467 | // for all partitions on disk |
|---|
| 468 | // open file |
|---|
| 469 | // if file exists |
|---|
| 470 | // print partition name |
|---|
| 471 | // set got_file to 1 |
|---|
| 472 | // |
|---|
| 473 | // dont they search all subdirectories? Thats a dumb find then.. :( |
|---|
| 474 | |
|---|
| 475 | /* We want to ignore any error here. */ |
|---|
| 476 | errnum = ERR_NONE; |
|---|
| 477 | |
|---|
| 478 | if (got_file) { |
|---|
| 479 | errnum = ERR_NONE; |
|---|
| 480 | return 0; |
|---|
| 481 | } |
|---|
| 482 | |
|---|
| 483 | errnum = ERR_FILE_NOT_FOUND; |
|---|
| 484 | return 1; |
|---|
| 485 | } |
|---|
| 486 | |
|---|
| 487 | static struct builtin builtin_find = { |
|---|
| 488 | "find", |
|---|
| 489 | find_func, |
|---|
| 490 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 491 | "find FILENAME", |
|---|
| 492 | "Search for the filename FILENAME in all of partitions and print the list of" |
|---|
| 493 | " the devices which contain the file." |
|---|
| 494 | }; |
|---|
| 495 | #endif |
|---|
| 496 | |
|---|
| 497 | /* help */ |
|---|
| 498 | #define MAX_SHORT_DOC_LEN 39 |
|---|
| 499 | #define MAX_LONG_DOC_LEN 66 |
|---|
| 500 | |
|---|
| 501 | static int help_func(char *arg, int flags) |
|---|
| 502 | { |
|---|
| 503 | int all = 0; |
|---|
| 504 | |
|---|
| 505 | if (memcmp(arg, "--all", sizeof("--all") - 1) == 0) { |
|---|
| 506 | all = 1; |
|---|
| 507 | arg = skip_to(0, arg); |
|---|
| 508 | } |
|---|
| 509 | |
|---|
| 510 | if (!*arg) { |
|---|
| 511 | /* Invoked with no argument. Print the list of the short docs. */ |
|---|
| 512 | struct builtin **builtin; |
|---|
| 513 | int left = 1; |
|---|
| 514 | |
|---|
| 515 | for (builtin = builtin_table; *builtin != 0; builtin++) { |
|---|
| 516 | int len; |
|---|
| 517 | int i; |
|---|
| 518 | |
|---|
| 519 | /* If this cannot be used in the command-line interface, |
|---|
| 520 | skip this. */ |
|---|
| 521 | if (!((*builtin)->flags & BUILTIN_CMDLINE)) |
|---|
| 522 | continue; |
|---|
| 523 | |
|---|
| 524 | /* If this doesn't need to be listed automatically and "--all" |
|---|
| 525 | is not specified, skip this. */ |
|---|
| 526 | if (!all && !((*builtin)->flags & BUILTIN_HELP_LIST)) |
|---|
| 527 | continue; |
|---|
| 528 | |
|---|
| 529 | len = strlen((*builtin)->short_doc); |
|---|
| 530 | /* If the length of SHORT_DOC is too long, truncate it. */ |
|---|
| 531 | if (len > MAX_SHORT_DOC_LEN - 1) |
|---|
| 532 | len = MAX_SHORT_DOC_LEN - 1; |
|---|
| 533 | |
|---|
| 534 | for (i = 0; i < len; i++) |
|---|
| 535 | grub_putchar((*builtin)->short_doc[i]); |
|---|
| 536 | |
|---|
| 537 | for (; i < MAX_SHORT_DOC_LEN; i++) |
|---|
| 538 | grub_putchar(' '); |
|---|
| 539 | |
|---|
| 540 | |
|---|
| 541 | if (!left) |
|---|
| 542 | grub_putchar('\n'); |
|---|
| 543 | |
|---|
| 544 | left = !left; |
|---|
| 545 | } |
|---|
| 546 | |
|---|
| 547 | /* If the last entry was at the left column, no newline was printed |
|---|
| 548 | at the end. */ |
|---|
| 549 | if (!left) |
|---|
| 550 | grub_putchar('\n'); |
|---|
| 551 | } else { |
|---|
| 552 | /* Invoked with one or more patterns. */ |
|---|
| 553 | do { |
|---|
| 554 | struct builtin **builtin; |
|---|
| 555 | char *next_arg; |
|---|
| 556 | |
|---|
| 557 | /* Get the next argument. */ |
|---|
| 558 | next_arg = skip_to(0, arg); |
|---|
| 559 | |
|---|
| 560 | /* Terminate ARG. */ |
|---|
| 561 | nul_terminate(arg); |
|---|
| 562 | |
|---|
| 563 | for (builtin = builtin_table; *builtin; builtin++) { |
|---|
| 564 | /* Skip this if this is only for the configuration file. */ |
|---|
| 565 | if (!((*builtin)->flags & BUILTIN_CMDLINE)) |
|---|
| 566 | continue; |
|---|
| 567 | |
|---|
| 568 | if (substring(arg, (*builtin)->name) < 1) { |
|---|
| 569 | char *doc = (*builtin)->long_doc; |
|---|
| 570 | |
|---|
| 571 | /* At first, print the name and the short doc. */ |
|---|
| 572 | grub_printf("%s: %s\n", (*builtin)->name, (*builtin)->short_doc); |
|---|
| 573 | |
|---|
| 574 | /* Print the long doc. */ |
|---|
| 575 | while (*doc) { |
|---|
| 576 | int len = strlen(doc); |
|---|
| 577 | int i; |
|---|
| 578 | |
|---|
| 579 | /* If LEN is too long, fold DOC. */ |
|---|
| 580 | if (len > MAX_LONG_DOC_LEN) { |
|---|
| 581 | /* Fold this line at the position of a space. */ |
|---|
| 582 | for (len = MAX_LONG_DOC_LEN; len > 0; len--) |
|---|
| 583 | if (doc[len - 1] == ' ') |
|---|
| 584 | break; |
|---|
| 585 | } |
|---|
| 586 | |
|---|
| 587 | grub_putstr(" "); |
|---|
| 588 | for (i = 0; i < len; i++) |
|---|
| 589 | grub_putchar(*doc++); |
|---|
| 590 | grub_putchar('\n'); |
|---|
| 591 | } |
|---|
| 592 | } |
|---|
| 593 | } |
|---|
| 594 | |
|---|
| 595 | arg = next_arg; |
|---|
| 596 | } |
|---|
| 597 | while (*arg); |
|---|
| 598 | } |
|---|
| 599 | refresh(); |
|---|
| 600 | return 0; |
|---|
| 601 | } |
|---|
| 602 | |
|---|
| 603 | static struct builtin builtin_help = { |
|---|
| 604 | "help", |
|---|
| 605 | help_func, |
|---|
| 606 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 607 | "help [--all] [PATTERN ...]", |
|---|
| 608 | "Display helpful information about builtin commands. Not all commands" |
|---|
| 609 | " aren't shown without the option `--all'." |
|---|
| 610 | }; |
|---|
| 611 | |
|---|
| 612 | /* hiddenmenu */ |
|---|
| 613 | static int hiddenmenu_func(char *arg, int flags) |
|---|
| 614 | { |
|---|
| 615 | show_menu = 0; |
|---|
| 616 | return 0; |
|---|
| 617 | } |
|---|
| 618 | |
|---|
| 619 | static struct builtin builtin_hiddenmenu = { |
|---|
| 620 | "hiddenmenu", |
|---|
| 621 | hiddenmenu_func, |
|---|
| 622 | BUILTIN_MENU, |
|---|
| 623 | #if 0 |
|---|
| 624 | "hiddenmenu", |
|---|
| 625 | "Hide the menu." |
|---|
| 626 | #endif |
|---|
| 627 | }; |
|---|
| 628 | |
|---|
| 629 | /** |
|---|
| 630 | * @param arg source pointer with grub device names |
|---|
| 631 | * @param path destination pointer (will be filled with filo device names) |
|---|
| 632 | * @param use_rootdev values other than zero mean the root device set by the "root" |
|---|
| 633 | * command is taken into regard here. This has to be zero when calling from root_func. |
|---|
| 634 | */ |
|---|
| 635 | |
|---|
| 636 | void copy_path_to_filo_bootline(char *arg, char *path, int use_rootdev) |
|---|
| 637 | { |
|---|
| 638 | char devicename[16]; |
|---|
| 639 | char drivername[16]; |
|---|
| 640 | int disk, part; |
|---|
| 641 | int i, len; |
|---|
| 642 | |
|---|
| 643 | |
|---|
| 644 | /* Clean up */ |
|---|
| 645 | memset(devicename, 0, 16); |
|---|
| 646 | memset(drivername, 0, 16); |
|---|
| 647 | |
|---|
| 648 | /* Copy over the driver name: "hd", "ud", "sd" ... */ |
|---|
| 649 | if (arg[0] == '(') { |
|---|
| 650 | i = 1; |
|---|
| 651 | /* Read until we encounter a number, a comma or a closing |
|---|
| 652 | * bracket |
|---|
| 653 | */ |
|---|
| 654 | while ((i <= 16) && (arg[i]) && (!isdigit(arg[i])) && (arg[i] != ',') |
|---|
| 655 | && (arg[i] != ')')) { |
|---|
| 656 | drivername[i - 1] = arg[i]; |
|---|
| 657 | i++; |
|---|
| 658 | } |
|---|
| 659 | } |
|---|
| 660 | |
|---|
| 661 | disk = -1; |
|---|
| 662 | part = -1; |
|---|
| 663 | |
|---|
| 664 | len = strlen(drivername); |
|---|
| 665 | if (len) { /* We have a driver. No idea if it exists though */ |
|---|
| 666 | // The driver should decide this: |
|---|
| 667 | len++; // skip driver name + opening bracket |
|---|
| 668 | |
|---|
| 669 | // XXX put @ handling in here, too for flash@addr and mem@addr |
|---|
| 670 | |
|---|
| 671 | if (isdigit(arg[len])) { |
|---|
| 672 | disk = arg[len] - '0'; |
|---|
| 673 | len++; |
|---|
| 674 | if (isdigit(arg[len])) { /* More than 9 drives? */ |
|---|
| 675 | /* ok, get one more number. No more than 99 drives */ |
|---|
| 676 | disk *= 10; |
|---|
| 677 | disk += arg[len] - '0'; |
|---|
| 678 | len++; |
|---|
| 679 | } |
|---|
| 680 | } |
|---|
| 681 | if (arg[len] == ',') { |
|---|
| 682 | len++; |
|---|
| 683 | part = arg[len] - '0'; |
|---|
| 684 | len++; |
|---|
| 685 | if (isdigit(arg[len])) { /* More than 9 partitions? */ |
|---|
| 686 | /* ok, get one more number. No more than 99 |
|---|
| 687 | * partitions */ |
|---|
| 688 | part *= 10; |
|---|
| 689 | part += arg[len] - '0'; |
|---|
| 690 | len++; |
|---|
| 691 | } |
|---|
| 692 | } |
|---|
| 693 | if (arg[len] != ')') { |
|---|
| 694 | grub_printf("Drive Error.\n"); |
|---|
| 695 | // set len = 0 --> just copy the drive name |
|---|
| 696 | len = 0; |
|---|
| 697 | } else { |
|---|
| 698 | len++; // skip closing bracket |
|---|
| 699 | } |
|---|
| 700 | } |
|---|
| 701 | |
|---|
| 702 | if (disk == -1) { |
|---|
| 703 | int cnt = 0; |
|---|
| 704 | len = 0; |
|---|
| 705 | while ((arg[cnt] != 0) && (arg[cnt+1] != 0)) { |
|---|
| 706 | if (arg[cnt] == ':' && arg[cnt+1] == '/') { |
|---|
| 707 | /* The user did specify a FILO name already */ |
|---|
| 708 | len = cnt; |
|---|
| 709 | break; |
|---|
| 710 | } |
|---|
| 711 | cnt++; |
|---|
| 712 | } |
|---|
| 713 | } else { |
|---|
| 714 | if (part == -1) { // No partition |
|---|
| 715 | sprintf(devicename, "%s%c:", drivername, disk + 'a'); |
|---|
| 716 | } else { // both disk and partition |
|---|
| 717 | sprintf(devicename, "%s%c%d:", drivername, disk + 'a', part + 1); |
|---|
| 718 | } |
|---|
| 719 | strncat(path, devicename, BOOT_LINE_LENGTH); |
|---|
| 720 | arg += len; // skip original drive name |
|---|
| 721 | } |
|---|
| 722 | |
|---|
| 723 | if (use_rootdev && !len) { // No drive was explicitly specified |
|---|
| 724 | if (strlen(root_device)) { // But someone set a root device |
|---|
| 725 | strncat(path, root_device, BOOT_LINE_LENGTH); |
|---|
| 726 | } |
|---|
| 727 | } |
|---|
| 728 | |
|---|
| 729 | /* Copy the rest over */ |
|---|
| 730 | strncat(path, arg, BOOT_LINE_LENGTH); |
|---|
| 731 | } |
|---|
| 732 | |
|---|
| 733 | /* initrd */ |
|---|
| 734 | static int initrd_func(char *arg, int flags) |
|---|
| 735 | { |
|---|
| 736 | initrd_space[0]=0; // Erase string |
|---|
| 737 | copy_path_to_filo_bootline(arg, initrd_space, 1); |
|---|
| 738 | if (!file_open(initrd_space)) { |
|---|
| 739 | initrd_space[0]=0; // Erase string |
|---|
| 740 | errnum = ERR_FILE_NOT_FOUND; |
|---|
| 741 | file_close(); |
|---|
| 742 | return 1; |
|---|
| 743 | } |
|---|
| 744 | |
|---|
| 745 | file_close(); |
|---|
| 746 | return 0; |
|---|
| 747 | } |
|---|
| 748 | |
|---|
| 749 | static struct builtin builtin_initrd = { |
|---|
| 750 | "initrd", |
|---|
| 751 | initrd_func, |
|---|
| 752 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 753 | "initrd FILE [ARG ...]", |
|---|
| 754 | "Load an initial ramdisk FILE for a Linux format boot image and set the" |
|---|
| 755 | " appropriate parameters in the Linux setup area in memory." |
|---|
| 756 | }; |
|---|
| 757 | |
|---|
| 758 | |
|---|
| 759 | #ifdef CONFIG_DEVELOPER_TOOLS |
|---|
| 760 | /* io */ |
|---|
| 761 | static int io_func(char *arg, int flags) |
|---|
| 762 | { |
|---|
| 763 | char *walk = arg; |
|---|
| 764 | unsigned int port = 0; |
|---|
| 765 | unsigned int value = 0; |
|---|
| 766 | unsigned int write_mode = 0; |
|---|
| 767 | unsigned int maxval=0xff, len=1; |
|---|
| 768 | |
|---|
| 769 | while ((*walk != 0) && (*walk != '.') && (*walk != '=')) { |
|---|
| 770 | port *= 16; |
|---|
| 771 | port += hex2bin(*walk); |
|---|
| 772 | walk++; |
|---|
| 773 | } |
|---|
| 774 | if (port > 0xffff) { |
|---|
| 775 | grub_printf("port too high\n"); |
|---|
| 776 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 777 | return 1; |
|---|
| 778 | } |
|---|
| 779 | |
|---|
| 780 | if (*walk == '.') { |
|---|
| 781 | walk++; |
|---|
| 782 | switch (*walk) { |
|---|
| 783 | case 'l': |
|---|
| 784 | case 'L': |
|---|
| 785 | len = 4; |
|---|
| 786 | maxval = 0xffffffff; |
|---|
| 787 | break; |
|---|
| 788 | case 'w': |
|---|
| 789 | case 'W': |
|---|
| 790 | len=2; |
|---|
| 791 | maxval = 0xffff; |
|---|
| 792 | break; |
|---|
| 793 | case 'b': |
|---|
| 794 | case 'B': |
|---|
| 795 | len=1; |
|---|
| 796 | maxval = 0xff; |
|---|
| 797 | break; |
|---|
| 798 | default: |
|---|
| 799 | grub_printf("width must be b, w, or l\n"); |
|---|
| 800 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 801 | return 1; |
|---|
| 802 | } |
|---|
| 803 | walk++; |
|---|
| 804 | } |
|---|
| 805 | |
|---|
| 806 | if (*walk == '=') { |
|---|
| 807 | while (*walk!=0 && *walk != '.') { |
|---|
| 808 | value *= 16; |
|---|
| 809 | value += hex2bin(*walk); |
|---|
| 810 | walk++; |
|---|
| 811 | } |
|---|
| 812 | |
|---|
| 813 | if (value > maxval) { |
|---|
| 814 | grub_printf("value too big.\n"); |
|---|
| 815 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 816 | return 1; |
|---|
| 817 | } |
|---|
| 818 | |
|---|
| 819 | write_mode = 1; |
|---|
| 820 | } |
|---|
| 821 | |
|---|
| 822 | if (write_mode) { |
|---|
| 823 | grub_printf ("out"); |
|---|
| 824 | switch (len) { |
|---|
| 825 | case 1: |
|---|
| 826 | grub_printf("b 0x%02x -> 0x%04x\n", value, port); |
|---|
| 827 | outb(value, port); |
|---|
| 828 | break; |
|---|
| 829 | case 2: |
|---|
| 830 | grub_printf("w 0x%04x -> 0x%04x\n", value, port); |
|---|
| 831 | outw(value, port); |
|---|
| 832 | break; |
|---|
| 833 | case 4: |
|---|
| 834 | grub_printf("l 0x%08x -> 0x%04x\n", value, port); |
|---|
| 835 | outl(value, port); |
|---|
| 836 | break; |
|---|
| 837 | } |
|---|
| 838 | } else { |
|---|
| 839 | grub_printf ("in"); |
|---|
| 840 | switch (len) { |
|---|
| 841 | case 1: |
|---|
| 842 | value = inb(port); |
|---|
| 843 | grub_printf("b 0x%04x: 0x%02x\n", port, value); |
|---|
| 844 | break; |
|---|
| 845 | case 2: |
|---|
| 846 | value = inw(port); |
|---|
| 847 | grub_printf("w 0x%04x: 0x%04x\n", port, value); |
|---|
| 848 | break; |
|---|
| 849 | case 4: |
|---|
| 850 | value = inl(port); |
|---|
| 851 | grub_printf("l 0x%04x: 0x%08x\n", port, value); |
|---|
| 852 | break; |
|---|
| 853 | } |
|---|
| 854 | } |
|---|
| 855 | |
|---|
| 856 | return 0; |
|---|
| 857 | } |
|---|
| 858 | |
|---|
| 859 | static struct builtin builtin_io = { |
|---|
| 860 | "io", |
|---|
| 861 | io_func, |
|---|
| 862 | BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST | BUILTIN_NO_ECHO, |
|---|
| 863 | "io port[.bwl][=val]", |
|---|
| 864 | "Read/write IO ports." |
|---|
| 865 | }; |
|---|
| 866 | #endif |
|---|
| 867 | |
|---|
| 868 | /* kernel */ |
|---|
| 869 | static int kernel_func(char *arg, int flags) |
|---|
| 870 | { |
|---|
| 871 | int i; |
|---|
| 872 | |
|---|
| 873 | kernel_type = KERNEL_TYPE_NONE; |
|---|
| 874 | |
|---|
| 875 | /* clear out boot_line. Kernel is the first thing */ |
|---|
| 876 | boot_line[0] = 0; // Erase string |
|---|
| 877 | |
|---|
| 878 | /* Get the real boot line and extract the kernel name */ |
|---|
| 879 | temp_space[0] = 0; // Erase string |
|---|
| 880 | copy_path_to_filo_bootline(arg, temp_space, 1); |
|---|
| 881 | i=0; while ((temp_space[i] != 0) && (temp_space[i]!=' ')) i++; |
|---|
| 882 | temp_space[i] = 0; |
|---|
| 883 | |
|---|
| 884 | if (!file_open(temp_space)) { |
|---|
| 885 | errnum = ERR_FILE_NOT_FOUND; |
|---|
| 886 | file_close(); |
|---|
| 887 | return 1; |
|---|
| 888 | } |
|---|
| 889 | |
|---|
| 890 | file_close(); |
|---|
| 891 | |
|---|
| 892 | /* Needed to pass grub checks */ |
|---|
| 893 | kernel_type = KERNEL_TYPE_LINUX; |
|---|
| 894 | |
|---|
| 895 | copy_path_to_filo_bootline(arg, boot_line, 1); |
|---|
| 896 | |
|---|
| 897 | return 0; |
|---|
| 898 | } |
|---|
| 899 | |
|---|
| 900 | static struct builtin builtin_kernel = { |
|---|
| 901 | "kernel", |
|---|
| 902 | kernel_func, |
|---|
| 903 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 904 | "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]", |
|---|
| 905 | "Attempt to load the primary boot image from FILE. The rest of the" |
|---|
| 906 | " line is passed verbatim as the \"kernel command line\". Any modules" |
|---|
| 907 | " must be reloaded after using this command. The option --type is used" |
|---|
| 908 | " to suggest what type of kernel to be loaded. TYPE must be either of" |
|---|
| 909 | " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and" |
|---|
| 910 | " \"multiboot\". The option --no-mem-option tells GRUB not to pass a" " Linux's mem option automatically." |
|---|
| 911 | }; |
|---|
| 912 | |
|---|
| 913 | /* lock */ |
|---|
| 914 | static int lock_func(char *arg, int flags) |
|---|
| 915 | { |
|---|
| 916 | if (!auth && password) { |
|---|
| 917 | errnum = ERR_PRIVILEGED; |
|---|
| 918 | return 1; |
|---|
| 919 | } |
|---|
| 920 | |
|---|
| 921 | return 0; |
|---|
| 922 | } |
|---|
| 923 | |
|---|
| 924 | static struct builtin builtin_lock = { |
|---|
| 925 | "lock", |
|---|
| 926 | lock_func, |
|---|
| 927 | BUILTIN_CMDLINE, |
|---|
| 928 | "lock", |
|---|
| 929 | "Break a command execution unless the user is authenticated." |
|---|
| 930 | }; |
|---|
| 931 | |
|---|
| 932 | #ifdef CONFIG_DEVELOPER_TOOLS |
|---|
| 933 | static int lspci_indent = 0; |
|---|
| 934 | static void lspci_scan_bus(int bus) |
|---|
| 935 | { |
|---|
| 936 | int slot, func; |
|---|
| 937 | unsigned int val; |
|---|
| 938 | unsigned char hdr; |
|---|
| 939 | int i; |
|---|
| 940 | |
|---|
| 941 | for (slot = 0; slot < 0x20; slot++) { |
|---|
| 942 | for (func = 0; func < 8; func++) { |
|---|
| 943 | pcidev_t dev = PCI_DEV(bus, slot, func); |
|---|
| 944 | |
|---|
| 945 | val = pci_read_config32(dev, REG_VENDOR_ID); |
|---|
| 946 | |
|---|
| 947 | /* Nobody home. */ |
|---|
| 948 | if (val == 0xffffffff || val == 0x00000000 || |
|---|
| 949 | val == 0x0000ffff || val == 0xffff0000) |
|---|
| 950 | continue; |
|---|
| 951 | |
|---|
| 952 | for (i=0; i<lspci_indent; i++) |
|---|
| 953 | grub_printf("| "); |
|---|
| 954 | grub_printf("|- %02x:%02x.%x [%04x:%04x]\n", bus, slot, func, |
|---|
| 955 | val & 0xffff, val >> 16); |
|---|
| 956 | |
|---|
| 957 | /* If this is a bridge, then follow it. */ |
|---|
| 958 | hdr = pci_read_config8(dev, REG_HEADER_TYPE); |
|---|
| 959 | hdr &= 0x7f; |
|---|
| 960 | if (hdr == HEADER_TYPE_BRIDGE || |
|---|
| 961 | hdr == HEADER_TYPE_CARDBUS) { |
|---|
| 962 | unsigned int busses; |
|---|
| 963 | |
|---|
| 964 | busses = pci_read_config32(dev, REG_PRIMARY_BUS); |
|---|
| 965 | lspci_indent++; |
|---|
| 966 | lspci_scan_bus((busses >> 8) & 0xff); |
|---|
| 967 | lspci_indent--; |
|---|
| 968 | } |
|---|
| 969 | } |
|---|
| 970 | } |
|---|
| 971 | } |
|---|
| 972 | |
|---|
| 973 | static void lspci_configspace(pcidev_t dev) |
|---|
| 974 | { |
|---|
| 975 | unsigned char cspace[256]; |
|---|
| 976 | int i, x, y; |
|---|
| 977 | |
|---|
| 978 | for (i = 0; i < 256; i ++) |
|---|
| 979 | cspace[i] = pci_read_config8(dev, i); |
|---|
| 980 | |
|---|
| 981 | for (y = 0; y < 16; y++) { |
|---|
| 982 | grub_printf("%x0:", y); |
|---|
| 983 | for (x = 0; x < 16; x++) |
|---|
| 984 | grub_printf(" %02x", cspace[(y * 16) + x]); |
|---|
| 985 | grub_printf("\n"); |
|---|
| 986 | } |
|---|
| 987 | |
|---|
| 988 | grub_printf("\n"); |
|---|
| 989 | } |
|---|
| 990 | |
|---|
| 991 | static int lspci_func(char *arg, int flags) |
|---|
| 992 | { |
|---|
| 993 | char *walk = arg; |
|---|
| 994 | int bus, slot, fn; |
|---|
| 995 | |
|---|
| 996 | if(strlen(walk)) { |
|---|
| 997 | pcidev_t dev; |
|---|
| 998 | |
|---|
| 999 | if((walk[1] != ':') && (walk[2] =! ':')) |
|---|
| 1000 | goto out; |
|---|
| 1001 | if(walk[1] == ':') { |
|---|
| 1002 | bus = hex2bin(walk[0]); |
|---|
| 1003 | walk+=2; |
|---|
| 1004 | } else { |
|---|
| 1005 | bus = (hex2bin(walk[0]) * 16) + hex2bin(walk[1]); |
|---|
| 1006 | walk+=3; |
|---|
| 1007 | } |
|---|
| 1008 | if((walk[1] != '.') && (walk[2] =! '.')) |
|---|
| 1009 | goto out; |
|---|
| 1010 | |
|---|
| 1011 | if(walk[1] == '.') { |
|---|
| 1012 | slot = hex2bin(walk[0]); |
|---|
| 1013 | walk+=2; |
|---|
| 1014 | } else { |
|---|
| 1015 | slot = (hex2bin(walk[0]) * 16) + hex2bin(walk[1]); |
|---|
| 1016 | walk+=3; |
|---|
| 1017 | } |
|---|
| 1018 | if (!walk[0]) |
|---|
| 1019 | goto out; |
|---|
| 1020 | |
|---|
| 1021 | fn=hex2bin(walk[0]); |
|---|
| 1022 | |
|---|
| 1023 | grub_printf("Dumping %x:%x.%x\n", bus, slot, fn); |
|---|
| 1024 | |
|---|
| 1025 | dev = PCI_DEV(bus, slot, fn); |
|---|
| 1026 | lspci_configspace(dev); |
|---|
| 1027 | return 0; |
|---|
| 1028 | } |
|---|
| 1029 | out: |
|---|
| 1030 | lspci_scan_bus(0); |
|---|
| 1031 | return 0; |
|---|
| 1032 | } |
|---|
| 1033 | |
|---|
| 1034 | static struct builtin builtin_lspci = { |
|---|
| 1035 | "lspci", |
|---|
| 1036 | lspci_func, |
|---|
| 1037 | BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST | BUILTIN_NO_ECHO, |
|---|
| 1038 | "lspci <device>", |
|---|
| 1039 | "Show PCI devices or dump PCI config space" |
|---|
| 1040 | }; |
|---|
| 1041 | #endif |
|---|
| 1042 | |
|---|
| 1043 | #ifdef CONFIG_USE_MD5_PASSWORDS |
|---|
| 1044 | /* md5crypt */ |
|---|
| 1045 | static int md5crypt_func(char *arg, int flags) |
|---|
| 1046 | { |
|---|
| 1047 | char crypted[36]; |
|---|
| 1048 | char key[32]; |
|---|
| 1049 | unsigned int seed; |
|---|
| 1050 | int i; |
|---|
| 1051 | const char *const seedchars = "./0123456789ABCDEFGHIJKLMNOPQRST" "UVWXYZabcdefghijklmnopqrstuvwxyz"; |
|---|
| 1052 | |
|---|
| 1053 | /* First create a salt. */ |
|---|
| 1054 | |
|---|
| 1055 | /* The magical prefix. */ |
|---|
| 1056 | memset(crypted, 0, sizeof(crypted)); |
|---|
| 1057 | memmove(crypted, "$1$", 3); |
|---|
| 1058 | |
|---|
| 1059 | /* Create the length of a salt. */ |
|---|
| 1060 | seed = currticks(); |
|---|
| 1061 | |
|---|
| 1062 | /* Generate a salt. */ |
|---|
| 1063 | for (i = 0; i < 8 && seed; i++) { |
|---|
| 1064 | /* FIXME: This should be more random. */ |
|---|
| 1065 | crypted[3 + i] = seedchars[seed & 0x3f]; |
|---|
| 1066 | seed >>= 6; |
|---|
| 1067 | } |
|---|
| 1068 | |
|---|
| 1069 | /* A salt must be terminated with `$', if it is less than 8 chars. */ |
|---|
| 1070 | crypted[3 + i] = '$'; |
|---|
| 1071 | |
|---|
| 1072 | #ifdef CONFIG_DEBUG_MD5CRYPT |
|---|
| 1073 | grub_printf("salt = %s\n", crypted); |
|---|
| 1074 | #endif |
|---|
| 1075 | |
|---|
| 1076 | /* Get a password. */ |
|---|
| 1077 | memset(key, 0, sizeof(key)); |
|---|
| 1078 | get_cmdline("Password: ", key, sizeof(key) - 1, '*', 0); |
|---|
| 1079 | |
|---|
| 1080 | /* Crypt the key. */ |
|---|
| 1081 | make_md5_password(key, crypted); |
|---|
| 1082 | |
|---|
| 1083 | grub_printf("Encrypted: %s\n", crypted); |
|---|
| 1084 | return 0; |
|---|
| 1085 | } |
|---|
| 1086 | |
|---|
| 1087 | static struct builtin builtin_md5crypt = { |
|---|
| 1088 | "md5crypt", |
|---|
| 1089 | md5crypt_func, |
|---|
| 1090 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 1091 | "md5crypt", |
|---|
| 1092 | "Generate a password in MD5 format." |
|---|
| 1093 | }; |
|---|
| 1094 | #endif /* CONFIG_USE_MD5_PASSWORDS */ |
|---|
| 1095 | |
|---|
| 1096 | /* password */ |
|---|
| 1097 | static int password_func(char *arg, int flags) |
|---|
| 1098 | { |
|---|
| 1099 | int len; |
|---|
| 1100 | password_t type = PASSWORD_PLAIN; |
|---|
| 1101 | |
|---|
| 1102 | #ifdef CONFIG_USE_MD5_PASSWORDS |
|---|
| 1103 | if (memcmp(arg, "--md5", 5) == 0) { |
|---|
| 1104 | type = PASSWORD_MD5; |
|---|
| 1105 | arg = skip_to(0, arg); |
|---|
| 1106 | } |
|---|
| 1107 | #endif |
|---|
| 1108 | if (memcmp(arg, "--", 2) == 0) { |
|---|
| 1109 | type = PASSWORD_UNSUPPORTED; |
|---|
| 1110 | arg = skip_to(0, arg); |
|---|
| 1111 | } |
|---|
| 1112 | |
|---|
| 1113 | if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0) { |
|---|
| 1114 | /* Do password check! */ |
|---|
| 1115 | char entered[32]; |
|---|
| 1116 | |
|---|
| 1117 | /* Wipe out any previously entered password */ |
|---|
| 1118 | entered[0] = 0; |
|---|
| 1119 | get_cmdline("Password: ", entered, 31, '*', 0); |
|---|
| 1120 | |
|---|
| 1121 | nul_terminate(arg); |
|---|
| 1122 | if (check_password(entered, arg, type) != 0) { |
|---|
| 1123 | errnum = ERR_PRIVILEGED; |
|---|
| 1124 | return 1; |
|---|
| 1125 | } |
|---|
| 1126 | } else { |
|---|
| 1127 | len = strlen(arg); |
|---|
| 1128 | |
|---|
| 1129 | /* PASSWORD NUL NUL ... */ |
|---|
| 1130 | if (len + 2 > PASSWORD_BUFLEN) { |
|---|
| 1131 | errnum = ERR_WONT_FIT; |
|---|
| 1132 | return 1; |
|---|
| 1133 | } |
|---|
| 1134 | |
|---|
| 1135 | /* Copy the password and clear the rest of the buffer. */ |
|---|
| 1136 | password = (char *) PASSWORD_BUF; |
|---|
| 1137 | memmove(password, arg, len); |
|---|
| 1138 | memset(password + len, 0, PASSWORD_BUFLEN - len); |
|---|
| 1139 | password_type = type; |
|---|
| 1140 | } |
|---|
| 1141 | return 0; |
|---|
| 1142 | } |
|---|
| 1143 | |
|---|
| 1144 | static struct builtin builtin_password = { |
|---|
| 1145 | "password", |
|---|
| 1146 | password_func, |
|---|
| 1147 | BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO, |
|---|
| 1148 | "password [--md5] PASSWD [FILE]", |
|---|
| 1149 | "If used in the first section of a menu file, disable all" |
|---|
| 1150 | " interactive editing control (menu entry editor and" |
|---|
| 1151 | " command line). If the password PASSWD is entered, it loads the" |
|---|
| 1152 | " FILE as a new config file and restarts the GRUB Stage 2. If you" |
|---|
| 1153 | " omit the argument FILE, then GRUB just unlocks privileged" |
|---|
| 1154 | " instructions. You can also use it in the script section, in" |
|---|
| 1155 | " which case it will ask for the password, before continueing." |
|---|
| 1156 | " The option --md5 tells GRUB that PASSWD is encrypted with" " md5crypt." |
|---|
| 1157 | }; |
|---|
| 1158 | |
|---|
| 1159 | /* pause */ |
|---|
| 1160 | static int pause_func(char *arg, int flags) |
|---|
| 1161 | { |
|---|
| 1162 | grub_printf("%s\n", arg); |
|---|
| 1163 | |
|---|
| 1164 | /* If ESC is returned, then abort this entry. */ |
|---|
| 1165 | if (ASCII_CHAR(getkey()) == 27) |
|---|
| 1166 | return 1; |
|---|
| 1167 | |
|---|
| 1168 | return 0; |
|---|
| 1169 | } |
|---|
| 1170 | |
|---|
| 1171 | static struct builtin builtin_pause = { |
|---|
| 1172 | "pause", |
|---|
| 1173 | pause_func, |
|---|
| 1174 | BUILTIN_CMDLINE | BUILTIN_NO_ECHO, |
|---|
| 1175 | "pause [MESSAGE ...]", |
|---|
| 1176 | "Print MESSAGE, then wait until a key is pressed." |
|---|
| 1177 | }; |
|---|
| 1178 | |
|---|
| 1179 | static int poweroff_func(char *arg, int flags) |
|---|
| 1180 | { |
|---|
| 1181 | void __attribute__((weak)) platform_poweroff(void); |
|---|
| 1182 | if (platform_poweroff) |
|---|
| 1183 | platform_poweroff(); |
|---|
| 1184 | else |
|---|
| 1185 | grub_printf("Poweroff not supported.\n"); |
|---|
| 1186 | |
|---|
| 1187 | // Will (hopefully) never return; |
|---|
| 1188 | return 0; |
|---|
| 1189 | } |
|---|
| 1190 | |
|---|
| 1191 | static struct builtin builtin_poweroff = { |
|---|
| 1192 | "poweroff", |
|---|
| 1193 | poweroff_func, |
|---|
| 1194 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 1195 | "poweroff", |
|---|
| 1196 | "Power off the system." |
|---|
| 1197 | }; |
|---|
| 1198 | |
|---|
| 1199 | #ifdef CONFIG_DEVELOPER_TOOLS |
|---|
| 1200 | static int probe_func(char *arg, int flags) |
|---|
| 1201 | { |
|---|
| 1202 | #if CONFIG_IDE_DISK |
|---|
| 1203 | int i; |
|---|
| 1204 | |
|---|
| 1205 | for (i=0; i<8; i++) |
|---|
| 1206 | ide_probe(i); |
|---|
| 1207 | #elif CONFIG_IDE_NEW_DISK |
|---|
| 1208 | int i; |
|---|
| 1209 | |
|---|
| 1210 | for (i=0; i<8; i++) |
|---|
| 1211 | ide_probe_verbose(i); |
|---|
| 1212 | #else |
|---|
| 1213 | grub_printf("No IDE driver.\n"); |
|---|
| 1214 | #endif |
|---|
| 1215 | |
|---|
| 1216 | return 0; |
|---|
| 1217 | } |
|---|
| 1218 | |
|---|
| 1219 | static struct builtin builtin_probe = { |
|---|
| 1220 | "probe", |
|---|
| 1221 | probe_func, |
|---|
| 1222 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 1223 | "probe", |
|---|
| 1224 | "Probe IDE drives" |
|---|
| 1225 | }; |
|---|
| 1226 | #endif |
|---|
| 1227 | |
|---|
| 1228 | static int reboot_func(char *arg, int flags) |
|---|
| 1229 | { |
|---|
| 1230 | void __attribute__((weak)) platform_reboot(void); |
|---|
| 1231 | |
|---|
| 1232 | if (platform_reboot) |
|---|
| 1233 | platform_reboot(); |
|---|
| 1234 | else |
|---|
| 1235 | grub_printf("Reboot not supported.\n"); |
|---|
| 1236 | |
|---|
| 1237 | // Will (hopefully) never return; |
|---|
| 1238 | return 0; |
|---|
| 1239 | } |
|---|
| 1240 | |
|---|
| 1241 | static struct builtin builtin_reboot = { |
|---|
| 1242 | "reboot", |
|---|
| 1243 | reboot_func, |
|---|
| 1244 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 1245 | "reboot", |
|---|
| 1246 | "Reboot the system." |
|---|
| 1247 | }; |
|---|
| 1248 | |
|---|
| 1249 | static int root_func(char *arg, int flags) |
|---|
| 1250 | { |
|---|
| 1251 | int len; |
|---|
| 1252 | |
|---|
| 1253 | root_device[0] = 0; /* Clear root device */ |
|---|
| 1254 | copy_path_to_filo_bootline(arg, root_device, 0); |
|---|
| 1255 | |
|---|
| 1256 | /* The following code handles an extra case |
|---|
| 1257 | * where the user specifies "root hde1" without |
|---|
| 1258 | * a trailing colon. |
|---|
| 1259 | */ |
|---|
| 1260 | len=strlen(root_device); |
|---|
| 1261 | if(root_device[len - 1] != ':') { |
|---|
| 1262 | root_device[len] = ':'; |
|---|
| 1263 | root_device[len + 1] = 0; |
|---|
| 1264 | } |
|---|
| 1265 | |
|---|
| 1266 | return 0; |
|---|
| 1267 | } |
|---|
| 1268 | |
|---|
| 1269 | static struct builtin builtin_root = { |
|---|
| 1270 | "root", |
|---|
| 1271 | root_func, |
|---|
| 1272 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 1273 | "root [DEVICE]", |
|---|
| 1274 | "Set the current \"root device\" to the device DEVICE." |
|---|
| 1275 | }; |
|---|
| 1276 | |
|---|
| 1277 | void __attribute__((weak)) serial_hardware_init(int port, int speed, int |
|---|
| 1278 | word_bits, int parity, int stop_bits); |
|---|
| 1279 | |
|---|
| 1280 | /* serial */ |
|---|
| 1281 | static int serial_func(char *arg, int flags) |
|---|
| 1282 | { |
|---|
| 1283 | unsigned short serial_port[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8 }; |
|---|
| 1284 | unsigned short port = 0x3f8; |
|---|
| 1285 | unsigned int speed = 9600; |
|---|
| 1286 | int word_len = 8; |
|---|
| 1287 | int parity = 0; |
|---|
| 1288 | int stop_bit_len = 1; |
|---|
| 1289 | |
|---|
| 1290 | /* Process GNU-style long options. |
|---|
| 1291 | FIXME: We should implement a getopt-like function, to avoid |
|---|
| 1292 | duplications. */ |
|---|
| 1293 | while (1) { |
|---|
| 1294 | if (memcmp(arg, "--unit=", sizeof("--unit=") - 1) == 0) { |
|---|
| 1295 | char *p = arg + sizeof("--unit=") - 1; |
|---|
| 1296 | int unit; |
|---|
| 1297 | |
|---|
| 1298 | if (!safe_parse_maxint(&p, &unit)) |
|---|
| 1299 | return 1; |
|---|
| 1300 | |
|---|
| 1301 | if (unit < 0 || unit > 3) { |
|---|
| 1302 | errnum = ERR_DEV_VALUES; |
|---|
| 1303 | return 1; |
|---|
| 1304 | } |
|---|
| 1305 | |
|---|
| 1306 | port = serial_port[unit]; |
|---|
| 1307 | } else if (memcmp(arg, "--speed=", sizeof("--speed=") - 1) == 0) { |
|---|
| 1308 | char *p = arg + sizeof("--speed=") - 1; |
|---|
| 1309 | int num; |
|---|
| 1310 | |
|---|
| 1311 | if (!safe_parse_maxint(&p, &num)) |
|---|
| 1312 | return 1; |
|---|
| 1313 | |
|---|
| 1314 | speed = (unsigned int) num; |
|---|
| 1315 | } else if (memcmp(arg, "--port=", sizeof("--port=") - 1) |
|---|
| 1316 | == 0) { |
|---|
| 1317 | char *p = arg + sizeof("--port=") - 1; |
|---|
| 1318 | int num; |
|---|
| 1319 | |
|---|
| 1320 | if (!safe_parse_maxint(&p, &num)) |
|---|
| 1321 | return 1; |
|---|
| 1322 | |
|---|
| 1323 | port = (unsigned short) num; |
|---|
| 1324 | } else if (memcmp(arg, "--word=", sizeof("--word=") - 1) |
|---|
| 1325 | == 0) { |
|---|
| 1326 | char *p = arg + sizeof("--word=") - 1; |
|---|
| 1327 | int len; |
|---|
| 1328 | |
|---|
| 1329 | if (!safe_parse_maxint(&p, &len)) |
|---|
| 1330 | return 1; |
|---|
| 1331 | |
|---|
| 1332 | switch (len) { |
|---|
| 1333 | case 5 ... 8: |
|---|
| 1334 | word_len = len; |
|---|
| 1335 | break; |
|---|
| 1336 | default: |
|---|
| 1337 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1338 | return 1; |
|---|
| 1339 | } |
|---|
| 1340 | } else if (memcmp(arg, "--stop=", sizeof("--stop=") - 1) |
|---|
| 1341 | == 0) { |
|---|
| 1342 | char *p = arg + sizeof("--stop=") - 1; |
|---|
| 1343 | int len; |
|---|
| 1344 | |
|---|
| 1345 | if (!safe_parse_maxint(&p, &len)) |
|---|
| 1346 | return 1; |
|---|
| 1347 | |
|---|
| 1348 | switch (len) { |
|---|
| 1349 | case 1 ... 2: |
|---|
| 1350 | stop_bit_len = len; |
|---|
| 1351 | break; |
|---|
| 1352 | default: |
|---|
| 1353 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1354 | return 1; |
|---|
| 1355 | } |
|---|
| 1356 | } else if (memcmp(arg, "--parity=", sizeof("--parity=") - 1) == 0) { |
|---|
| 1357 | char *p = arg + sizeof("--parity=") - 1; |
|---|
| 1358 | |
|---|
| 1359 | if (memcmp(p, "no", sizeof("no") - 1) == 0) |
|---|
| 1360 | parity = 0; |
|---|
| 1361 | else if (memcmp(p, "odd", sizeof("odd") - 1) |
|---|
| 1362 | == 0) |
|---|
| 1363 | parity = 1; |
|---|
| 1364 | else if (memcmp(p, "even", sizeof("even") - 1) |
|---|
| 1365 | == 0) |
|---|
| 1366 | parity = 2; |
|---|
| 1367 | else { |
|---|
| 1368 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1369 | return 1; |
|---|
| 1370 | } |
|---|
| 1371 | } else |
|---|
| 1372 | break; |
|---|
| 1373 | |
|---|
| 1374 | arg = skip_to(0, arg); |
|---|
| 1375 | } |
|---|
| 1376 | |
|---|
| 1377 | /* Initialize the serial unit. */ |
|---|
| 1378 | if (serial_hardware_init) |
|---|
| 1379 | serial_hardware_init(port, speed, word_len, parity, stop_bit_len); |
|---|
| 1380 | else |
|---|
| 1381 | grub_printf("This version of FILO does not have serial console support.\n"); |
|---|
| 1382 | |
|---|
| 1383 | return 0; |
|---|
| 1384 | } |
|---|
| 1385 | |
|---|
| 1386 | static struct builtin builtin_serial = { |
|---|
| 1387 | "serial", |
|---|
| 1388 | serial_func, |
|---|
| 1389 | BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST | BUILTIN_NO_ECHO, |
|---|
| 1390 | "serial [--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]", |
|---|
| 1391 | "Initialize a serial device. UNIT is a digit that specifies which serial" |
|---|
| 1392 | " device is used (e.g. 0 == COM1). If you need to specify the port number," |
|---|
| 1393 | " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length," |
|---|
| 1394 | " PARITY is the type of parity, which is one of `no', `odd' and `even'." |
|---|
| 1395 | " STOP is the length of stop bit(s). The option --device can be used only" |
|---|
| 1396 | " in the grub shell, which specifies the file name of a tty device. The" |
|---|
| 1397 | " default values are COM1, 9600, 8N1." |
|---|
| 1398 | }; |
|---|
| 1399 | |
|---|
| 1400 | #ifdef CONFIG_DEVELOPER_TOOLS |
|---|
| 1401 | static int setpci_func(char *arg, int flags) |
|---|
| 1402 | { |
|---|
| 1403 | char *walk = arg; |
|---|
| 1404 | int bus, slot, fn; |
|---|
| 1405 | pcidev_t dev; |
|---|
| 1406 | unsigned int reg=0; |
|---|
| 1407 | unsigned int len=1, maxval=0xff, value=0; |
|---|
| 1408 | int write_mode = 0; |
|---|
| 1409 | |
|---|
| 1410 | // setpci bus:dev.fn reg.[bwl][=val] |
|---|
| 1411 | |
|---|
| 1412 | if(!strlen(arg)) { |
|---|
| 1413 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1414 | return 1; |
|---|
| 1415 | } |
|---|
| 1416 | |
|---|
| 1417 | if((walk[1] != ':') && (walk[2] =! ':')) { |
|---|
| 1418 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1419 | return 1; |
|---|
| 1420 | } |
|---|
| 1421 | |
|---|
| 1422 | if(walk[1] == ':') { |
|---|
| 1423 | bus = hex2bin(walk[0]); |
|---|
| 1424 | walk+=2; |
|---|
| 1425 | } else { |
|---|
| 1426 | bus = (hex2bin(walk[0]) * 16) + hex2bin(walk[1]); |
|---|
| 1427 | walk+=3; |
|---|
| 1428 | } |
|---|
| 1429 | if((walk[1] != '.') && (walk[2] =! '.')) { |
|---|
| 1430 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1431 | return 1; |
|---|
| 1432 | } |
|---|
| 1433 | |
|---|
| 1434 | if(walk[1] == '.') { |
|---|
| 1435 | slot = hex2bin(walk[0]); |
|---|
| 1436 | walk+=2; |
|---|
| 1437 | } else { |
|---|
| 1438 | slot = (hex2bin(walk[0]) * 16) + hex2bin(walk[1]); |
|---|
| 1439 | walk+=3; |
|---|
| 1440 | } |
|---|
| 1441 | if (!walk[0]) { |
|---|
| 1442 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1443 | return 1; |
|---|
| 1444 | } |
|---|
| 1445 | |
|---|
| 1446 | fn=hex2bin(walk[0]); |
|---|
| 1447 | |
|---|
| 1448 | dev = PCI_DEV(bus, slot, fn); |
|---|
| 1449 | |
|---|
| 1450 | walk++; |
|---|
| 1451 | if (walk[0] != ' ') { |
|---|
| 1452 | grub_printf("No register specified\n"); |
|---|
| 1453 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1454 | return 1; |
|---|
| 1455 | } |
|---|
| 1456 | |
|---|
| 1457 | while (*walk!=0 && *walk != '.' && *walk != ':' ) { |
|---|
| 1458 | reg *= 16; |
|---|
| 1459 | reg += hex2bin(*walk); |
|---|
| 1460 | walk++; |
|---|
| 1461 | } |
|---|
| 1462 | |
|---|
| 1463 | if (reg > 0xff) { |
|---|
| 1464 | grub_printf("Only 256 byte config space supported.\n"); |
|---|
| 1465 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1466 | return 1; |
|---|
| 1467 | } |
|---|
| 1468 | |
|---|
| 1469 | if (*walk == '.') { |
|---|
| 1470 | walk++; |
|---|
| 1471 | switch (*walk) { |
|---|
| 1472 | case 'l': |
|---|
| 1473 | case 'L': |
|---|
| 1474 | len = 4; |
|---|
| 1475 | maxval = 0xffffffff; |
|---|
| 1476 | break; |
|---|
| 1477 | case 'w': |
|---|
| 1478 | case 'W': |
|---|
| 1479 | len=2; |
|---|
| 1480 | maxval = 0xffff; |
|---|
| 1481 | break; |
|---|
| 1482 | case 'b': |
|---|
| 1483 | case 'B': |
|---|
| 1484 | len=1; |
|---|
| 1485 | maxval = 0xff; |
|---|
| 1486 | break; |
|---|
| 1487 | default: |
|---|
| 1488 | grub_printf("width must be b, w, or l\n"); |
|---|
| 1489 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1490 | return 1; |
|---|
| 1491 | } |
|---|
| 1492 | walk++; |
|---|
| 1493 | } |
|---|
| 1494 | |
|---|
| 1495 | if (*walk == '=') { |
|---|
| 1496 | while (*walk!=0 && *walk != '.') { |
|---|
| 1497 | value *= 16; |
|---|
| 1498 | value += hex2bin(*walk); |
|---|
| 1499 | walk++; |
|---|
| 1500 | } |
|---|
| 1501 | |
|---|
| 1502 | if (value > maxval) { |
|---|
| 1503 | grub_printf("value too big.\n"); |
|---|
| 1504 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1505 | return 1; |
|---|
| 1506 | } |
|---|
| 1507 | |
|---|
| 1508 | write_mode = 1; |
|---|
| 1509 | } |
|---|
| 1510 | |
|---|
| 1511 | if (write_mode) { |
|---|
| 1512 | grub_printf ("pci_write_config"); |
|---|
| 1513 | switch (len) { |
|---|
| 1514 | case 1: |
|---|
| 1515 | grub_printf("8 0x%02x -> %x:%x.%x [%02x]\n", value, bus, slot, fn, reg); |
|---|
| 1516 | pci_write_config8(dev, reg, value); |
|---|
| 1517 | break; |
|---|
| 1518 | case 2: |
|---|
| 1519 | grub_printf("16 0x%04x -> %x:%x.%x [%02x]\n", value, bus, slot, fn, reg); |
|---|
| 1520 | pci_write_config16(dev, reg, value); |
|---|
| 1521 | break; |
|---|
| 1522 | case 4: |
|---|
| 1523 | grub_printf("32 0x%08x -> %x:%x.%x [%02x]\n", value, bus, slot, fn, reg); |
|---|
| 1524 | pci_write_config32(dev, reg, value); |
|---|
| 1525 | break; |
|---|
| 1526 | } |
|---|
| 1527 | } else { |
|---|
| 1528 | grub_printf ("pci_read_config"); |
|---|
| 1529 | switch (len) { |
|---|
| 1530 | case 1: |
|---|
| 1531 | value = pci_read_config8(dev, reg); |
|---|
| 1532 | grub_printf("8 %x:%x.%x [%02x] -> %02x\n", bus, slot, fn, reg, value); |
|---|
| 1533 | break; |
|---|
| 1534 | case 2: |
|---|
| 1535 | value = pci_read_config16(dev, reg); |
|---|
| 1536 | grub_printf("16 %x:%x.%x [%02x] -> %04x\n", bus, slot, fn, reg, value); |
|---|
| 1537 | break; |
|---|
| 1538 | case 4: |
|---|
| 1539 | value = pci_read_config32(dev, reg); |
|---|
| 1540 | grub_printf("32 %x:%x.%x [%02x] -> %08x\n", bus, slot, fn, reg, value); |
|---|
| 1541 | break; |
|---|
| 1542 | } |
|---|
| 1543 | } |
|---|
| 1544 | |
|---|
| 1545 | return 0; |
|---|
| 1546 | } |
|---|
| 1547 | |
|---|
| 1548 | static struct builtin builtin_setpci = { |
|---|
| 1549 | "setpci", |
|---|
| 1550 | setpci_func, |
|---|
| 1551 | BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST | BUILTIN_NO_ECHO, |
|---|
| 1552 | "setpci <device>[.bwl][=value]", |
|---|
| 1553 | "Show/change PCI config space values" |
|---|
| 1554 | }; |
|---|
| 1555 | #endif |
|---|
| 1556 | |
|---|
| 1557 | /* terminal */ |
|---|
| 1558 | static int terminal_func(char *arg, int flags) |
|---|
| 1559 | { |
|---|
| 1560 | int use_serial = 0, use_vga = 0; |
|---|
| 1561 | int terminal_changed = 0; |
|---|
| 1562 | /* The index of the default terminal in TERM_TABLE. */ |
|---|
| 1563 | int lines = 0; |
|---|
| 1564 | unsigned long term_flags = 0; |
|---|
| 1565 | |
|---|
| 1566 | /* Get GNU-style long options. */ |
|---|
| 1567 | while (1) { |
|---|
| 1568 | if (memcmp(arg, "--no-echo", sizeof("--no-echo") - 1) == 0) { |
|---|
| 1569 | /* ``--no-echo'' implies ``--no-edit''. */ |
|---|
| 1570 | term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT); |
|---|
| 1571 | } else if (memcmp(arg, "--no-edit", sizeof("--no-edit") - 1) == 0) { |
|---|
| 1572 | term_flags |= TERM_NO_EDIT; |
|---|
| 1573 | } else if (memcmp(arg, "--lines=", sizeof("--lines=") - 1) == 0) { |
|---|
| 1574 | char *val = arg + sizeof("--lines=") - 1; |
|---|
| 1575 | |
|---|
| 1576 | if (!safe_parse_maxint(&val, &lines)) |
|---|
| 1577 | return 1; |
|---|
| 1578 | |
|---|
| 1579 | /* Probably less than four is meaningless.... */ |
|---|
| 1580 | if (lines < 4) { |
|---|
| 1581 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1582 | return 1; |
|---|
| 1583 | } |
|---|
| 1584 | } else { |
|---|
| 1585 | while (*arg) { |
|---|
| 1586 | char *next = skip_to(0, arg); |
|---|
| 1587 | |
|---|
| 1588 | nul_terminate(arg); |
|---|
| 1589 | |
|---|
| 1590 | /* We also accept "terminal console" as GRUB |
|---|
| 1591 | * heritage. |
|---|
| 1592 | */ |
|---|
| 1593 | if (strcmp(arg, "serial") == 0) { |
|---|
| 1594 | use_serial = 1; |
|---|
| 1595 | terminal_changed = 1; |
|---|
| 1596 | } else if (strcmp(arg, "console") == 0) { |
|---|
| 1597 | use_vga = 1; |
|---|
| 1598 | terminal_changed = 1; |
|---|
| 1599 | } else if (strcmp(arg, "vga") == 0) { |
|---|
| 1600 | use_vga = 1; |
|---|
| 1601 | terminal_changed = 1; |
|---|
| 1602 | } else { |
|---|
| 1603 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1604 | return 1; |
|---|
| 1605 | } |
|---|
| 1606 | |
|---|
| 1607 | arg = next; |
|---|
| 1608 | break; |
|---|
| 1609 | } |
|---|
| 1610 | if (!*arg) |
|---|
| 1611 | break; |
|---|
| 1612 | continue; |
|---|
| 1613 | } |
|---|
| 1614 | |
|---|
| 1615 | arg = skip_to(0, arg); |
|---|
| 1616 | } |
|---|
| 1617 | |
|---|
| 1618 | if (terminal_changed) { |
|---|
| 1619 | curses_enable_serial(use_serial); |
|---|
| 1620 | curses_enable_vga(use_vga); |
|---|
| 1621 | terminal_flags = term_flags; |
|---|
| 1622 | } |
|---|
| 1623 | |
|---|
| 1624 | if (lines) |
|---|
| 1625 | max_lines = lines; |
|---|
| 1626 | else |
|---|
| 1627 | /* 25 would be a good default value. */ |
|---|
| 1628 | max_lines = 25; |
|---|
| 1629 | |
|---|
| 1630 | /* If no argument is specified, show current setting. */ |
|---|
| 1631 | if (! *arg) { |
|---|
| 1632 | grub_printf("Serial console terminal %s.\n", |
|---|
| 1633 | curses_serial_enabled()?"enabled":"disabled"); |
|---|
| 1634 | grub_printf("VGA console terminal %s.\n", |
|---|
| 1635 | curses_vga_enabled()?"enabled":"disabled"); |
|---|
| 1636 | grub_printf("Flags:%s%s\n", |
|---|
| 1637 | terminal_flags & TERM_NO_EDIT ? " (no edit)" : "", |
|---|
| 1638 | terminal_flags & TERM_NO_ECHO ? " (no echo)" : ""); |
|---|
| 1639 | } |
|---|
| 1640 | |
|---|
| 1641 | return 0; |
|---|
| 1642 | } |
|---|
| 1643 | |
|---|
| 1644 | static struct builtin builtin_terminal = { |
|---|
| 1645 | "terminal", |
|---|
| 1646 | terminal_func, |
|---|
| 1647 | BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST | BUILTIN_NO_ECHO, |
|---|
| 1648 | "terminal [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial]", |
|---|
| 1649 | "Select a terminal. When multiple terminals are specified, wait until" |
|---|
| 1650 | " you push any key to continue. If both console and serial are specified," |
|---|
| 1651 | " the terminal to which you input a key first will be selected. If no" |
|---|
| 1652 | " argument is specified, print current setting. If you specify --no-echo," |
|---|
| 1653 | " input characters won't be echoed." |
|---|
| 1654 | " If you specify --no-edit, the BASH-like editing feature will be disabled." |
|---|
| 1655 | " If --timeout is present, this command will wait at most for SECS" |
|---|
| 1656 | " seconds. The option --lines specifies the maximum number of lines." |
|---|
| 1657 | }; |
|---|
| 1658 | |
|---|
| 1659 | /* timeout */ |
|---|
| 1660 | static int timeout_func(char *arg, int flags) |
|---|
| 1661 | { |
|---|
| 1662 | if (!safe_parse_maxint(&arg, &grub_timeout)) |
|---|
| 1663 | return 1; |
|---|
| 1664 | |
|---|
| 1665 | return 0; |
|---|
| 1666 | } |
|---|
| 1667 | |
|---|
| 1668 | static struct builtin builtin_timeout = { |
|---|
| 1669 | "timeout", |
|---|
| 1670 | timeout_func, |
|---|
| 1671 | BUILTIN_MENU, |
|---|
| 1672 | #if 0 |
|---|
| 1673 | "timeout SEC", |
|---|
| 1674 | "Set a timeout, in SEC seconds, before automatically booting the" |
|---|
| 1675 | " default entry (normally the first entry defined)." |
|---|
| 1676 | #endif |
|---|
| 1677 | }; |
|---|
| 1678 | |
|---|
| 1679 | |
|---|
| 1680 | static int keymap_func(char *arg, int flags) |
|---|
| 1681 | { |
|---|
| 1682 | #ifdef CONFIG_PC_KEYBOARD |
|---|
| 1683 | if (keyboard_set_layout(arg)) { |
|---|
| 1684 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1685 | return 1; |
|---|
| 1686 | } |
|---|
| 1687 | return 0; |
|---|
| 1688 | #else |
|---|
| 1689 | errnum = ERR_BAD_ARGUMENT; |
|---|
| 1690 | return 1; |
|---|
| 1691 | #endif |
|---|
| 1692 | } |
|---|
| 1693 | |
|---|
| 1694 | static struct builtin builtin_keymap = { |
|---|
| 1695 | "keymap", |
|---|
| 1696 | keymap_func, |
|---|
| 1697 | BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST | BUILTIN_NO_ECHO, |
|---|
| 1698 | "keymap LANGCODE", |
|---|
| 1699 | "Select a keymap to use. Currently only 'us' and 'de' are supported." |
|---|
| 1700 | }; |
|---|
| 1701 | |
|---|
| 1702 | static int title_func(char *arg, int flags) |
|---|
| 1703 | { |
|---|
| 1704 | /* This function is not actually used at least currently. */ |
|---|
| 1705 | return 0; |
|---|
| 1706 | } |
|---|
| 1707 | |
|---|
| 1708 | static struct builtin builtin_title = { |
|---|
| 1709 | "title", |
|---|
| 1710 | title_func, |
|---|
| 1711 | BUILTIN_TITLE, |
|---|
| 1712 | #if 0 |
|---|
| 1713 | "title [NAME ...]", |
|---|
| 1714 | "Start a new boot entry, and set its name to the contents of the" |
|---|
| 1715 | " rest of the line, starting with the first non-space character." |
|---|
| 1716 | #endif |
|---|
| 1717 | }; |
|---|
| 1718 | |
|---|
| 1719 | static int cat_func(char *arg, int flags) |
|---|
| 1720 | { |
|---|
| 1721 | char buf[4096]; |
|---|
| 1722 | int len; |
|---|
| 1723 | |
|---|
| 1724 | temp_space[0]=0; |
|---|
| 1725 | copy_path_to_filo_bootline(arg, temp_space, 1); |
|---|
| 1726 | if (temp_space[0]==0) { |
|---|
| 1727 | return help_func("cat",0); |
|---|
| 1728 | } |
|---|
| 1729 | if (!file_open(temp_space)) { |
|---|
| 1730 | errnum = ERR_FILE_NOT_FOUND; |
|---|
| 1731 | return 1; |
|---|
| 1732 | } |
|---|
| 1733 | |
|---|
| 1734 | while ((len = file_read(buf, sizeof(buf))) != 0) { |
|---|
| 1735 | int cnt; |
|---|
| 1736 | for (cnt = 0; cnt < len; cnt++) { |
|---|
| 1737 | grub_putchar(buf[cnt]); |
|---|
| 1738 | } |
|---|
| 1739 | } |
|---|
| 1740 | |
|---|
| 1741 | file_close(); |
|---|
| 1742 | |
|---|
| 1743 | return 0; |
|---|
| 1744 | } |
|---|
| 1745 | |
|---|
| 1746 | static struct builtin builtin_cat = { |
|---|
| 1747 | "cat", |
|---|
| 1748 | cat_func, |
|---|
| 1749 | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|---|
| 1750 | "cat FILENAME", |
|---|
| 1751 | "Print the content of FILENAME to the terminal." |
|---|
| 1752 | }; |
|---|
| 1753 | |
|---|
| 1754 | /* README !!! XXX !!! This list has to be alphabetically ordered !!! */ |
|---|
| 1755 | |
|---|
| 1756 | struct builtin *builtin_table[] = { |
|---|
| 1757 | &builtin_boot, |
|---|
| 1758 | &builtin_cat, |
|---|
| 1759 | &builtin_color, |
|---|
| 1760 | &builtin_configfile, |
|---|
| 1761 | &builtin_default, |
|---|
| 1762 | #ifdef CONFIG_DEVELOPER_TOOLS |
|---|
| 1763 | &builtin_dumpmem, |
|---|
| 1764 | &builtin_dumppm, |
|---|
| 1765 | #endif |
|---|
| 1766 | #ifdef CONFIG_EXPERIMENTAL |
|---|
| 1767 | &builtin_find, |
|---|
| 1768 | #endif |
|---|
| 1769 | &builtin_help, |
|---|
| 1770 | &builtin_hiddenmenu, |
|---|
| 1771 | &builtin_initrd, |
|---|
| 1772 | #ifdef CONFIG_DEVELOPER_TOOLS |
|---|
| 1773 | &builtin_io, |
|---|
| 1774 | #endif |
|---|
| 1775 | &builtin_kernel, |
|---|
| 1776 | &builtin_keymap, |
|---|
| 1777 | &builtin_lock, |
|---|
| 1778 | #ifdef CONFIG_DEVELOPER_TOOLS |
|---|
| 1779 | &builtin_lspci, |
|---|
| 1780 | #endif |
|---|
| 1781 | #ifdef CONFIG_USE_MD5_PASSWORDS |
|---|
| 1782 | &builtin_md5crypt, |
|---|
| 1783 | #endif |
|---|
| 1784 | &builtin_password, |
|---|
| 1785 | &builtin_pause, |
|---|
| 1786 | &builtin_poweroff, |
|---|
| 1787 | #ifdef CONFIG_DEVELOPER_TOOLS |
|---|
| 1788 | &builtin_probe, |
|---|
| 1789 | #endif |
|---|
| 1790 | &builtin_reboot, |
|---|
| 1791 | &builtin_root, |
|---|
| 1792 | &builtin_serial, |
|---|
| 1793 | #ifdef CONFIG_DEVELOPER_TOOLS |
|---|
| 1794 | &builtin_setpci, |
|---|
| 1795 | #endif |
|---|
| 1796 | &builtin_terminal, |
|---|
| 1797 | &builtin_timeout, |
|---|
| 1798 | &builtin_title, |
|---|
| 1799 | 0 |
|---|
| 1800 | }; |
|---|