|
|
1.1 ! root 1: /* ! 2: * Linux/i386 loader ! 3: * Supports bzImage, zImage and Image format. ! 4: * ! 5: * Based on work by Steve Gehlbach. ! 6: * Portions are taken from mkelfImage. ! 7: * ! 8: * 2003-09 by SONE Takeshi ! 9: */ ! 10: ! 11: #include "config.h" ! 12: #include "kernel/kernel.h" ! 13: #include "libopenbios/bindings.h" ! 14: #include "libopenbios/sys_info.h" ! 15: #include "context.h" ! 16: #include "segment.h" ! 17: #include "libc/diskio.h" ! 18: #include "boot.h" ! 19: ! 20: #define printf printk ! 21: #define debug printk ! 22: #define strtoull_with_suffix strtol ! 23: ! 24: #define LINUX_PARAM_LOC 0x90000 ! 25: #define COMMAND_LINE_LOC 0x91000 ! 26: #define GDT_LOC 0x92000 ! 27: #define STACK_LOC 0x93000 ! 28: ! 29: #define E820MAX 32 /* number of entries in E820MAP */ ! 30: struct e820entry { ! 31: unsigned long long addr; /* start of memory segment */ ! 32: unsigned long long size; /* size of memory segment */ ! 33: unsigned long type; /* type of memory segment */ ! 34: #define E820_RAM 1 ! 35: #define E820_RESERVED 2 ! 36: #define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ ! 37: #define E820_NVS 4 ! 38: }; ! 39: ! 40: /* The header of Linux/i386 kernel */ ! 41: struct linux_header { ! 42: uint8_t reserved1[0x1f1]; /* 0x000 */ ! 43: uint8_t setup_sects; /* 0x1f1 */ ! 44: uint16_t root_flags; /* 0x1f2 */ ! 45: uint8_t reserved2[6]; /* 0x1f4 */ ! 46: uint16_t vid_mode; /* 0x1fa */ ! 47: uint16_t root_dev; /* 0x1fc */ ! 48: uint16_t boot_sector_magic; /* 0x1fe */ ! 49: /* 2.00+ */ ! 50: uint8_t reserved3[2]; /* 0x200 */ ! 51: uint8_t header_magic[4]; /* 0x202 */ ! 52: uint16_t protocol_version; /* 0x206 */ ! 53: uint32_t realmode_swtch; /* 0x208 */ ! 54: uint16_t start_sys; /* 0x20c */ ! 55: uint16_t kver_addr; /* 0x20e */ ! 56: uint8_t type_of_loader; /* 0x210 */ ! 57: uint8_t loadflags; /* 0x211 */ ! 58: uint16_t setup_move_size; /* 0x212 */ ! 59: uint32_t code32_start; /* 0x214 */ ! 60: uint32_t ramdisk_image; /* 0x218 */ ! 61: uint32_t ramdisk_size; /* 0x21c */ ! 62: uint8_t reserved4[4]; /* 0x220 */ ! 63: /* 2.01+ */ ! 64: uint16_t heap_end_ptr; /* 0x224 */ ! 65: uint8_t reserved5[2]; /* 0x226 */ ! 66: /* 2.02+ */ ! 67: uint32_t cmd_line_ptr; /* 0x228 */ ! 68: /* 2.03+ */ ! 69: uint32_t initrd_addr_max; /* 0x22c */ ! 70: } __attribute__ ((packed)); ! 71: ! 72: ! 73: /* Paramters passed to 32-bit part of Linux ! 74: * This is another view of the structure above.. */ ! 75: struct linux_params { ! 76: uint8_t orig_x; /* 0x00 */ ! 77: uint8_t orig_y; /* 0x01 */ ! 78: uint16_t ext_mem_k; /* 0x02 -- EXT_MEM_K sits here */ ! 79: uint16_t orig_video_page; /* 0x04 */ ! 80: uint8_t orig_video_mode; /* 0x06 */ ! 81: uint8_t orig_video_cols; /* 0x07 */ ! 82: uint16_t unused2; /* 0x08 */ ! 83: uint16_t orig_video_ega_bx; /* 0x0a */ ! 84: uint16_t unused3; /* 0x0c */ ! 85: uint8_t orig_video_lines; /* 0x0e */ ! 86: uint8_t orig_video_isVGA; /* 0x0f */ ! 87: uint16_t orig_video_points; /* 0x10 */ ! 88: ! 89: /* VESA graphic mode -- linear frame buffer */ ! 90: uint16_t lfb_width; /* 0x12 */ ! 91: uint16_t lfb_height; /* 0x14 */ ! 92: uint16_t lfb_depth; /* 0x16 */ ! 93: uint32_t lfb_base; /* 0x18 */ ! 94: uint32_t lfb_size; /* 0x1c */ ! 95: uint16_t cl_magic; /* 0x20 */ ! 96: #define CL_MAGIC_VALUE 0xA33F ! 97: uint16_t cl_offset; /* 0x22 */ ! 98: uint16_t lfb_linelength; /* 0x24 */ ! 99: uint8_t red_size; /* 0x26 */ ! 100: uint8_t red_pos; /* 0x27 */ ! 101: uint8_t green_size; /* 0x28 */ ! 102: uint8_t green_pos; /* 0x29 */ ! 103: uint8_t blue_size; /* 0x2a */ ! 104: uint8_t blue_pos; /* 0x2b */ ! 105: uint8_t rsvd_size; /* 0x2c */ ! 106: uint8_t rsvd_pos; /* 0x2d */ ! 107: uint16_t vesapm_seg; /* 0x2e */ ! 108: uint16_t vesapm_off; /* 0x30 */ ! 109: uint16_t pages; /* 0x32 */ ! 110: uint8_t reserved4[12]; /* 0x34 -- 0x3f reserved for future expansion */ ! 111: ! 112: //struct apm_bios_info apm_bios_info; /* 0x40 */ ! 113: uint8_t apm_bios_info[0x40]; ! 114: //struct drive_info_struct drive_info; /* 0x80 */ ! 115: uint8_t drive_info[0x20]; ! 116: //struct sys_desc_table sys_desc_table; /* 0xa0 */ ! 117: uint8_t sys_desc_table[0x140]; ! 118: uint32_t alt_mem_k; /* 0x1e0 */ ! 119: uint8_t reserved5[4]; /* 0x1e4 */ ! 120: uint8_t e820_map_nr; /* 0x1e8 */ ! 121: uint8_t reserved6[9]; /* 0x1e9 */ ! 122: uint16_t mount_root_rdonly; /* 0x1f2 */ ! 123: uint8_t reserved7[4]; /* 0x1f4 */ ! 124: uint16_t ramdisk_flags; /* 0x1f8 */ ! 125: #define RAMDISK_IMAGE_START_MASK 0x07FF ! 126: #define RAMDISK_PROMPT_FLAG 0x8000 ! 127: #define RAMDISK_LOAD_FLAG 0x4000 ! 128: uint8_t reserved8[2]; /* 0x1fa */ ! 129: uint16_t orig_root_dev; /* 0x1fc */ ! 130: uint8_t reserved9[1]; /* 0x1fe */ ! 131: uint8_t aux_device_info; /* 0x1ff */ ! 132: uint8_t reserved10[2]; /* 0x200 */ ! 133: uint8_t param_block_signature[4]; /* 0x202 */ ! 134: uint16_t param_block_version; /* 0x206 */ ! 135: uint8_t reserved11[8]; /* 0x208 */ ! 136: uint8_t loader_type; /* 0x210 */ ! 137: #define LOADER_TYPE_LOADLIN 1 ! 138: #define LOADER_TYPE_BOOTSECT_LOADER 2 ! 139: #define LOADER_TYPE_SYSLINUX 3 ! 140: #define LOADER_TYPE_ETHERBOOT 4 ! 141: #define LOADER_TYPE_KERNEL 5 ! 142: uint8_t loader_flags; /* 0x211 */ ! 143: uint8_t reserved12[2]; /* 0x212 */ ! 144: uint32_t kernel_start; /* 0x214 */ ! 145: uint32_t initrd_start; /* 0x218 */ ! 146: uint32_t initrd_size; /* 0x21c */ ! 147: uint8_t reserved12_5[8]; /* 0x220 */ ! 148: uint32_t cmd_line_ptr; /* 0x228 */ ! 149: uint8_t reserved13[164]; /* 0x22c */ ! 150: struct e820entry e820_map[E820MAX]; /* 0x2d0 */ ! 151: uint8_t reserved16[688]; /* 0x550 */ ! 152: #define COMMAND_LINE_SIZE 256 ! 153: /* Command line is copied here by 32-bit i386/kernel/head.S. ! 154: * So I will follow the boot protocol, rather than putting it ! 155: * directly here. --ts1 */ ! 156: uint8_t command_line[COMMAND_LINE_SIZE]; /* 0x800 */ ! 157: uint8_t reserved17[1792]; /* 0x900 - 0x1000 */ ! 158: }; ! 159: ! 160: static uint64_t forced_memsize; ! 161: static int fd; ! 162: ! 163: static unsigned long file_size(void) ! 164: { ! 165: long long fpos, fsize; ! 166: ! 167: /* Save current position */ ! 168: fpos = tell(fd); ! 169: ! 170: /* Go to end of file and get position */ ! 171: seek_io(fd, -1); ! 172: fsize = tell(fd); ! 173: ! 174: /* Go back to old position */ ! 175: seek_io(fd, 0); ! 176: seek_io(fd, fpos); ! 177: ! 178: return fsize; ! 179: } ! 180: ! 181: /* Load the first part the file and check if it's Linux */ ! 182: static uint32_t load_linux_header(struct linux_header *hdr) ! 183: { ! 184: int load_high; ! 185: uint32_t kern_addr; ! 186: ! 187: if (read_io(fd, hdr, sizeof *hdr) != sizeof *hdr) { ! 188: debug("Can't read Linux header\n"); ! 189: return 0; ! 190: } ! 191: if (hdr->boot_sector_magic != 0xaa55) { ! 192: debug("Not a Linux kernel image\n"); ! 193: return 0; ! 194: } ! 195: ! 196: /* Linux is found. Print some information */ ! 197: if (memcmp(hdr->header_magic, "HdrS", 4) != 0) { ! 198: /* This may be floppy disk image or something. ! 199: * Perform a simple (incomplete) sanity check. */ ! 200: if (hdr->setup_sects >= 16 ! 201: || file_size() - (hdr->setup_sects<<9) >= 512<<10) { ! 202: debug("This looks like a bootdisk image but not like Linux...\n"); ! 203: return 0; ! 204: } ! 205: ! 206: printf("Possible very old Linux"); ! 207: /* This kernel does not even have a protocol version. ! 208: * Force the value. */ ! 209: hdr->protocol_version = 0; /* pre-2.00 */ ! 210: } else ! 211: printf("Found Linux"); ! 212: if (hdr->protocol_version >= 0x200 && hdr->kver_addr) { ! 213: char kver[256]; ! 214: seek_io(fd, hdr->kver_addr + 0x200); ! 215: if (read_io(fd, kver, sizeof kver) != 0) { ! 216: kver[255] = 0; ! 217: printf(" version %s", kver); ! 218: } ! 219: } ! 220: debug(" (protocol %#x)", hdr->protocol_version); ! 221: load_high = 0; ! 222: if (hdr->protocol_version >= 0x200) { ! 223: debug(" (loadflags %#x)", hdr->loadflags); ! 224: load_high = hdr->loadflags & 1; ! 225: } ! 226: if (load_high) { ! 227: printf(" bzImage"); ! 228: kern_addr = 0x100000; ! 229: } else { ! 230: printf(" zImage or Image"); ! 231: kern_addr = 0x1000; ! 232: } ! 233: printf(".\n"); ! 234: ! 235: return kern_addr; ! 236: } ! 237: ! 238: /* Set up parameters for 32-bit kernel */ ! 239: static void ! 240: init_linux_params(struct linux_params *params, struct linux_header *hdr) ! 241: { ! 242: debug("Setting up paramters at %#lx\n", virt_to_phys(params)); ! 243: memset(params, 0, sizeof *params); ! 244: ! 245: /* Copy some useful values from header */ ! 246: params->mount_root_rdonly = hdr->root_flags; ! 247: params->orig_root_dev = hdr->root_dev; ! 248: ! 249: /* Video parameters. ! 250: * This assumes we have VGA in standard 80x25 text mode, ! 251: * just like our vga.c does. ! 252: * Cursor position is filled later to allow some more printf's. */ ! 253: params->orig_video_mode = 3; ! 254: params->orig_video_cols = 80; ! 255: params->orig_video_lines = 25; ! 256: params->orig_video_isVGA = 1; ! 257: params->orig_video_points = 16; ! 258: ! 259: params->loader_type = 0xff; /* Unregistered Linux loader */ ! 260: } ! 261: ! 262: /* Memory map */ ! 263: static void ! 264: set_memory_size(struct linux_params *params, struct sys_info *info) ! 265: { ! 266: int i; ! 267: uint64_t end; ! 268: uint32_t ramtop = 0; ! 269: struct e820entry *linux_map; ! 270: struct memrange *filo_map; ! 271: ! 272: linux_map = params->e820_map; ! 273: filo_map = info->memrange; ! 274: for (i = 0; i < info->n_memranges; i++, linux_map++, filo_map++) { ! 275: if (i < E820MAX) { ! 276: /* Convert to BIOS e820 style */ ! 277: linux_map->addr = filo_map->base; ! 278: linux_map->size = filo_map->size; ! 279: linux_map->type = E820_RAM; ! 280: debug("%016Lx - %016Lx\n", linux_map->addr, ! 281: linux_map->addr + linux_map->size); ! 282: params->e820_map_nr = i+1; ! 283: } ! 284: ! 285: /* Find out top of RAM. XXX This ignores hole above 1MB */ ! 286: end = filo_map->base + filo_map->size; ! 287: if (end < (1ULL << 32)) { /* don't count memory above 4GB */ ! 288: if (end > ramtop) ! 289: ramtop = (uint32_t) end; ! 290: } ! 291: } ! 292: debug("ramtop=%#x\n", ramtop); ! 293: /* Size of memory above 1MB in KB */ ! 294: params->alt_mem_k = (ramtop - (1<<20)) >> 10; ! 295: /* old style, 64MB max */ ! 296: if (ramtop >= (64<<20)) ! 297: params->ext_mem_k = (63<<10); ! 298: else ! 299: params->ext_mem_k = params->alt_mem_k; ! 300: debug("ext_mem_k=%d, alt_mem_k=%d\n", params->ext_mem_k, params->alt_mem_k); ! 301: } ! 302: ! 303: /* ! 304: * Parse command line ! 305: * Some parameters, like initrd=<file>, are not passed to kernel, ! 306: * we are responsible to process them. ! 307: * Parameters for kernel are copied to kern_cmdline. Returns name of initrd. ! 308: */ ! 309: static char *parse_command_line(const char *orig_cmdline, char *kern_cmdline) ! 310: { ! 311: const char *start, *sep, *end, *val; ! 312: char name[64]; ! 313: int len; ! 314: int k_len; ! 315: int to_kern; ! 316: char *initrd = NULL; ! 317: int toolong = 0; ! 318: ! 319: forced_memsize = 0; ! 320: ! 321: if (!orig_cmdline) { ! 322: *kern_cmdline = 0; ! 323: return NULL; ! 324: } ! 325: ! 326: k_len = 0; ! 327: debug("original command line: \"%s\"\n", orig_cmdline); ! 328: debug("kernel command line at %#lx\n", virt_to_phys(kern_cmdline)); ! 329: ! 330: start = orig_cmdline; ! 331: while (*start == ' ') ! 332: start++; ! 333: while (*start) { ! 334: end = strchr(start, ' '); ! 335: if (!end) ! 336: end = start + strlen(start); ! 337: sep = strchr(start, '='); ! 338: if (!sep || sep > end) ! 339: sep = end; ! 340: len = sep - start; ! 341: if (len >= sizeof(name)) ! 342: len = sizeof(name) - 1; ! 343: memcpy(name, start, len); ! 344: name[len] = 0; ! 345: ! 346: if (*sep == '=') { ! 347: val = sep + 1; ! 348: len = end - val; ! 349: } else { ! 350: val = NULL; ! 351: len = 0; ! 352: } ! 353: ! 354: /* Only initrd= and mem= are handled here. vga= is not, ! 355: * which I believe is a paramter to the realmode part of Linux, ! 356: * which we don't execute. */ ! 357: if (strcmp(name, "initrd") == 0) { ! 358: if (!val) ! 359: printf("Missing filename to initrd parameter\n"); ! 360: else { ! 361: initrd = malloc(len + 1); ! 362: memcpy(initrd, val, len); ! 363: initrd[len] = 0; ! 364: debug("initrd=%s\n", initrd); ! 365: } ! 366: /* Don't pass this to kernel */ ! 367: to_kern = 0; ! 368: } else if (strcmp(name, "mem") == 0) { ! 369: if (!val) ! 370: printf("Missing value for mem parameter\n"); ! 371: else { ! 372: forced_memsize = strtoull_with_suffix(val, (char**)&val, 0); ! 373: if (forced_memsize == 0) ! 374: printf("Invalid mem option, ignored\n"); ! 375: if (val != end) { ! 376: printf("Garbage after mem=<size>, ignored\n"); ! 377: forced_memsize = 0; ! 378: } ! 379: debug("mem=%Lu\n", forced_memsize); ! 380: } ! 381: /* mem= is for both loader and kernel */ ! 382: to_kern = 1; ! 383: } else ! 384: to_kern = 1; ! 385: ! 386: if (to_kern) { ! 387: /* Copy to kernel command line buffer */ ! 388: if (k_len != 0) ! 389: kern_cmdline[k_len++] = ' '; /* put separator */ ! 390: len = end - start; ! 391: if (k_len + len >= COMMAND_LINE_SIZE) { ! 392: len = COMMAND_LINE_SIZE - k_len - 1; ! 393: if (!toolong) { ! 394: printf("Kernel command line is too long; truncated to " ! 395: "%d bytes\n", COMMAND_LINE_SIZE-1); ! 396: toolong = 1; ! 397: } ! 398: } ! 399: memcpy(kern_cmdline + k_len, start, len); ! 400: k_len += len; ! 401: } ! 402: ! 403: start = end; ! 404: while (*start == ' ') ! 405: start++; ! 406: } ! 407: kern_cmdline[k_len] = 0; ! 408: debug("kernel command line (%d bytes): \"%s\"\n", k_len, kern_cmdline); ! 409: ! 410: return initrd; ! 411: } ! 412: ! 413: /* Set command line location */ ! 414: static void set_command_line_loc(struct linux_params *params, ! 415: struct linux_header *hdr) ! 416: { ! 417: if (hdr->protocol_version >= 0x202) { ! 418: /* new style */ ! 419: params->cmd_line_ptr = COMMAND_LINE_LOC; ! 420: } else { ! 421: /* old style */ ! 422: params->cl_magic = CL_MAGIC_VALUE; ! 423: params->cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC; ! 424: } ! 425: } ! 426: ! 427: /* Load 32-bit part of kernel */ ! 428: static int load_linux_kernel(struct linux_header *hdr, uint32_t kern_addr) ! 429: { ! 430: uint32_t kern_offset, kern_size; ! 431: ! 432: if (hdr->setup_sects == 0) ! 433: hdr->setup_sects = 4; ! 434: kern_offset = (hdr->setup_sects + 1) * 512; ! 435: seek_io(fd, kern_offset); ! 436: kern_size = file_size() - kern_offset; ! 437: debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size); ! 438: ! 439: #if 0 ! 440: if (using_devsize) { ! 441: printf("Attempt to load up to end of device as kernel; " ! 442: "specify the image size\n"); ! 443: return 0; ! 444: } ! 445: #endif ! 446: ! 447: printf("Loading kernel... "); ! 448: if (read_io(fd, phys_to_virt(kern_addr), kern_size) != kern_size) { ! 449: printf("Can't read kernel\n"); ! 450: return 0; ! 451: } ! 452: printf("ok\n"); ! 453: ! 454: return kern_size; ! 455: } ! 456: ! 457: static int load_initrd(struct linux_header *hdr, struct sys_info *info, ! 458: uint32_t kern_end, struct linux_params *params, const char *initrd_file) ! 459: { ! 460: uint32_t max; ! 461: uint32_t start, end, size; ! 462: uint64_t forced; ! 463: ! 464: fd = open_io(initrd_file); ! 465: if (fd == -1) { ! 466: printf("Can't open initrd: %s\n", initrd_file); ! 467: return -1; ! 468: } ! 469: ! 470: #if 0 ! 471: if (using_devsize) { ! 472: printf("Attempt to load up to end of device as initrd; " ! 473: "specify the image size\n"); ! 474: return -1; ! 475: } ! 476: #endif ! 477: ! 478: size = file_size(); ! 479: ! 480: ! 481: /* Find out the kernel's restriction on how high the initrd can be ! 482: * placed */ ! 483: if (hdr->protocol_version >= 0x203) ! 484: max = hdr->initrd_addr_max; ! 485: else ! 486: max = 0x38000000; /* Hardcoded value for older kernels */ ! 487: ! 488: /* FILO itself is at the top of RAM. (relocated) ! 489: * So, try putting initrd just below us. */ ! 490: end = virt_to_phys(_start); ! 491: if (end > max) ! 492: end = max; ! 493: ! 494: /* If "mem=" option is given, we have to put the initrd within ! 495: * the specified range. */ ! 496: if (forced_memsize) { ! 497: forced = forced_memsize; ! 498: if (forced > max) ! 499: forced = max; ! 500: /* If the "mem=" is lower, it's easy */ ! 501: if (forced <= end) ! 502: end = forced; ! 503: else { ! 504: /* Otherwise, see if we can put it above us */ ! 505: if (virt_to_phys(_end) + size <= forced) ! 506: end = forced; /* Ok */ ! 507: } ! 508: } ! 509: ! 510: start = end - size; ! 511: start &= ~0xfff; /* page align */ ! 512: end = start + size; ! 513: ! 514: debug("start=%#x end=%#x\n", start, end); ! 515: ! 516: if (start < kern_end) { ! 517: printf("Initrd is too big to fit in memory\n"); ! 518: return -1; ! 519: } ! 520: ! 521: printf("Loading initrd... "); ! 522: if (read_io(fd, phys_to_virt(start), size) != size) { ! 523: printf("Can't read initrd\n"); ! 524: return -1; ! 525: } ! 526: printf("ok\n"); ! 527: ! 528: params->initrd_start = start; ! 529: params->initrd_size = size; ! 530: ! 531: close_io(fd); ! 532: ! 533: return 0; ! 534: } ! 535: ! 536: static void hardware_setup(void) ! 537: { ! 538: /* Disable nmi */ ! 539: outb(0x80, 0x70); ! 540: ! 541: /* Make sure any coprocessor is properly reset.. */ ! 542: outb(0, 0xf0); ! 543: outb(0, 0xf1); ! 544: ! 545: /* we're getting screwed again and again by this problem of the 8259. ! 546: * so we're going to leave this lying around for inclusion into ! 547: * crt0.S on an as-needed basis. ! 548: * ! 549: * well, that went ok, I hope. Now we have to reprogram the interrupts :-( ! 550: * we put them right after the intel-reserved hardware interrupts, at ! 551: * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really ! 552: * messed this up with the original PC, and they haven't been able to ! 553: * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, ! 554: * which is used for the internal hardware interrupts as well. We just ! 555: * have to reprogram the 8259's, and it isn't fun. ! 556: */ ! 557: ! 558: outb(0x11, 0x20); /* initialization sequence to 8259A-1 */ ! 559: outb(0x11, 0xA0); /* and to 8259A-2 */ ! 560: ! 561: outb(0x20, 0x21); /* start of hardware int's (0x20) */ ! 562: outb(0x28, 0xA1); /* start of hardware int's 2 (0x28) */ ! 563: ! 564: outb(0x04, 0x21); /* 8259-1 is master */ ! 565: outb(0x02, 0xA1); /* 8259-2 is slave */ ! 566: ! 567: outb(0x01, 0x21); /* 8086 mode for both */ ! 568: outb(0x01, 0xA1); ! 569: ! 570: outb(0xFF, 0xA1); /* mask off all interrupts for now */ ! 571: outb(0xFB, 0x21); /* mask all irq's but irq2 which is cascaded */ ! 572: } ! 573: ! 574: /* Start Linux */ ! 575: static int start_linux(uint32_t kern_addr, struct linux_params *params) ! 576: { ! 577: struct segment_desc *linux_gdt; ! 578: struct context *ctx; ! 579: //extern int cursor_x, cursor_y; ! 580: ! 581: ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0); ! 582: ! 583: /* Linux expects GDT being in low memory */ ! 584: linux_gdt = phys_to_virt(GDT_LOC); ! 585: memset(linux_gdt, 0, 13*sizeof(struct segment_desc)); ! 586: /* Normal kernel code/data segments */ ! 587: linux_gdt[2] = gdt[FLAT_CODE]; ! 588: linux_gdt[3] = gdt[FLAT_DATA]; ! 589: /* 2.6 kernel uses 12 and 13, but head.S uses backward-compatible ! 590: * segments (2 and 3), so it SHOULD not be a problem. ! 591: * However, some distro kernels (eg. RH9) with backported threading ! 592: * patch use 12 and 13 also when booting... */ ! 593: linux_gdt[12] = gdt[FLAT_CODE]; ! 594: linux_gdt[13] = gdt[FLAT_DATA]; ! 595: ctx->gdt_base = GDT_LOC; ! 596: ctx->gdt_limit = 14*8-1; ! 597: ctx->cs = 0x10; ! 598: ctx->ds = 0x18; ! 599: ctx->es = 0x18; ! 600: ctx->fs = 0x18; ! 601: ctx->gs = 0x18; ! 602: ctx->ss = 0x18; ! 603: ! 604: /* Parameter location */ ! 605: ctx->esi = virt_to_phys(params); ! 606: ! 607: /* Entry point */ ! 608: ctx->eip = kern_addr; ! 609: ! 610: debug("eip=%#x\n", kern_addr); ! 611: printf("Jumping to entry point...\n"); ! 612: ! 613: #ifdef VGA_CONSOLE ! 614: /* Update VGA cursor position. ! 615: * This must be here because the printf changes the value! */ ! 616: params->orig_x = cursor_x; ! 617: params->orig_y = cursor_y; ! 618: #endif ! 619: ! 620: /* Go... */ ! 621: ctx = switch_to(ctx); ! 622: ! 623: /* It's impossible but... */ ! 624: printf("Returned with eax=%#x\n", ctx->eax); ! 625: ! 626: return ctx->eax; ! 627: } ! 628: ! 629: int linux_load(struct sys_info *info, const char *file, const char *cmdline) ! 630: { ! 631: struct linux_header hdr; ! 632: struct linux_params *params; ! 633: uint32_t kern_addr, kern_size; ! 634: char *initrd_file = NULL; ! 635: ! 636: fd = open_io(file); ! 637: if (fd == -1) { ! 638: return -1; ! 639: } ! 640: ! 641: kern_addr = load_linux_header(&hdr); ! 642: if (kern_addr == 0) ! 643: return LOADER_NOT_SUPPORT; ! 644: ! 645: params = phys_to_virt(LINUX_PARAM_LOC); ! 646: init_linux_params(params, &hdr); ! 647: set_memory_size(params, info); ! 648: initrd_file = parse_command_line(cmdline, phys_to_virt(COMMAND_LINE_LOC)); ! 649: set_command_line_loc(params, &hdr); ! 650: ! 651: kern_size = load_linux_kernel(&hdr, kern_addr); ! 652: if (kern_size == 0) { ! 653: if (initrd_file) ! 654: free(initrd_file); ! 655: return -1; ! 656: } ! 657: ! 658: if (initrd_file) { ! 659: if (load_initrd(&hdr, info, kern_addr+kern_size, params, initrd_file) ! 660: != 0) { ! 661: free(initrd_file); ! 662: return -1; ! 663: } ! 664: free(initrd_file); ! 665: } ! 666: ! 667: hardware_setup(); ! 668: ! 669: start_linux(kern_addr, params); ! 670: return 0; ! 671: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.