📄 mboot.c
字号:
#endif}static void init_mmap(struct multiboot_info *mbi) /* Get a full memory map from the BIOS to pass to the kernel. */{ com32sys_t regs_in, regs_out; struct AddrRangeDesc *e820; int e820_slots; size_t mem_lower, mem_upper, run_addr, mmap_size; register size_t sp; /* Default values for mem_lower and mem_upper in case the BIOS won't * tell us: 640K, and all memory up to the stack. */ asm volatile("movl %%esp, %0" : "=r" (sp)); mem_upper = (sp - MEM_HOLE_END) / 1024; mem_lower = (MEM_HOLE_START) / 1024;#ifdef DEBUG printf("Requesting memory map from BIOS:\n");#endif /* Ask the BIOS for the full memory map of the machine. We'll * build it in Multiboot format (i.e. with size fields) in the * bounce buffer, and then allocate some high memory to keep it in * until boot time. */ e820 = __com32.cs_bounce; e820_slots = 0; regs_out.ebx.l = 0; while(((void *)(e820 + 1)) < __com32.cs_bounce + __com32.cs_bounce_size) { e820->size = sizeof(*e820) - sizeof(e820->size); /* Ask the BIOS to fill in this descriptor */ regs_in.eax.l = 0xe820; /* "Get system memory map" */ regs_in.ebx.l = regs_out.ebx.l; /* Continuation value from last call */ regs_in.ecx.l = 20; /* Size of buffer to write into */ regs_in.edx.l = 0x534d4150; /* "SMAP" */ regs_in.es = SEG(&e820->BaseAddr); regs_in.edi.w[0] = OFFS(&e820->BaseAddr); __intcall(0x15, ®s_in, ®s_out); if ((regs_out.eflags.l & EFLAGS_CF) != 0 && regs_out.ebx.l != 0) break; /* End of map */ if (((regs_out.eflags.l & EFLAGS_CF) != 0 && regs_out.ebx.l == 0) || (regs_out.eax.l != 0x534d4150)) { /* Error */ printf("Error %x reading E820 memory map: %s.\n", (int) regs_out.eax.b[0], (regs_out.eax.b[0] == 0x80) ? "invalid command" : (regs_out.eax.b[0] == 0x86) ? "not supported" : "unknown error"); break; } /* Success */#ifdef DEBUG printf(" %#16.16Lx -- %#16.16Lx : ", e820->BaseAddr, e820->BaseAddr + e820->Length); switch (e820->Type) { case 1: printf("Available\n"); break; case 2: printf("Reserved\n"); break; case 3: printf("ACPI Reclaim\n"); break; case 4: printf("ACPI NVS\n"); break; default: printf("? (Reserved)\n"); break; }#endif if (e820->Type == 1) { if (e820->BaseAddr == 0) { mem_lower = MIN(MEM_HOLE_START, e820->Length) / 1024; } else if (e820->BaseAddr == MEM_HOLE_END) { mem_upper = MIN(0xfff00000, e820->Length) / 1024; } } /* Move to next slot */ e820++; e820_slots++; /* Done? */ if (regs_out.ebx.l == 0) break; } /* Record the simple information in the MBI */ mbi->flags |= MB_INFO_MEMORY; mbi->mem_lower = mem_lower; mbi->mem_upper = mem_upper; /* Record the full memory map in the MBI */ if (e820_slots != 0) { mmap_size = e820_slots * sizeof(*e820); /* Where will it live at run time? */ run_addr = place_low_section(mmap_size, 1); if (run_addr == 0) { printf("Fatal: can't find space for the e820 mmap.\n"); exit(1); } /* Where will it live now? */ e820 = (struct AddrRangeDesc *) next_load_addr; if (next_load_addr + mmap_size > section_addr) { printf("Fatal: out of memory storing the e820 mmap.\n"); exit(1); } next_load_addr += mmap_size; /* Copy it out of the bounce buffer */ memcpy(e820, __com32.cs_bounce, mmap_size); /* Remember to copy it again at run time */ add_section(run_addr, (char *) e820, mmap_size); /* Record it in the MBI */ mbi->flags |= MB_INFO_MEM_MAP; mbi->mmap_length = mmap_size; mbi->mmap_addr = run_addr; }}/* * Code for loading and parsing files. */static void load_file(char *filename, char **startp, size_t *sizep) /* Load a file into memory. Returns where it is and how big via * startp and sizep */{ gzFile fp; char *start; int bsize; printf("Loading %s.", filename); start = next_load_addr; startp[0] = start; sizep[0] = 0; /* Open the file */ if ((fp = gzopen(filename, "r")) == NULL) { printf("\nFatal: cannot open %s\n", filename); exit(1); } while (next_load_addr + LOAD_CHUNK <= section_addr) { bsize = gzread(fp, next_load_addr, LOAD_CHUNK); printf("%s","."); if (bsize < 0) { printf("\nFatal: read error in %s\n", filename); gzclose(fp); exit(1); } next_load_addr += bsize; sizep[0] += bsize; if (bsize < LOAD_CHUNK) { printf("%s","\n"); gzclose(fp); return; } } /* Running out of memory. Try and use up the last bit */ if (section_addr > next_load_addr) { bsize = gzread(fp, next_load_addr, section_addr - next_load_addr); printf("%s","."); } else { bsize = 0; } if (bsize < 0) { gzclose(fp); printf("\nFatal: read error in %s\n", filename); exit(1); } next_load_addr += bsize; sizep[0] += bsize; if (!gzeof(fp)) { gzclose(fp); printf("\nFatal: out of memory reading %s\n", filename); exit(1); } printf("%s","\n"); gzclose(fp); return;}static size_t load_kernel(char *cmdline) /* Load a multiboot/elf32 kernel and allocate run-time memory for it. * Returns the kernel's entry address. */{ unsigned int i; char *load_addr; /* Where the image was loaded */ size_t load_size; /* How big it is */ char *seg_addr; /* Where a segment was loaded */ size_t seg_size, bss_size; /* How big it is */ size_t run_addr, run_size; /* Where it should be put */ char *p; Elf32_Ehdr *ehdr; Elf32_Phdr *phdr; struct multiboot_header *mbh; printf("Kernel: %s\n", cmdline); load_addr = 0; load_size = 0; p = strchr(cmdline, ' '); if (p != NULL) *p = 0; load_file(cmdline, &load_addr, &load_size); if (load_size < 12) { printf("Fatal: %s is too short to be a multiboot kernel.", cmdline); exit(1); } if (p != NULL) *p = ' '; /* Look for a multiboot header in the first 8k of the file */ for (i = 0; i <= MIN(load_size - 12, MULTIBOOT_SEARCH - 12); i += 4) { mbh = (struct multiboot_header *)(load_addr + i); if (mbh->magic != MULTIBOOT_MAGIC || ((mbh->magic+mbh->flags+mbh->checksum) & 0xffffffff)) { /* Not a multiboot header */ continue; } if (mbh->flags & (MULTIBOOT_UNSUPPORTED | MULTIBOOT_VIDEO_MODE)) { /* Requires options we don't support */ printf("Fatal: Kernel requires multiboot options " "that I don't support: %#x.\n", mbh->flags & (MULTIBOOT_UNSUPPORTED|MULTIBOOT_VIDEO_MODE)); exit(1); } /* This kernel will do: figure out where all the pieces will live */ if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) { /* Use the offsets in the multiboot header */#ifdef DEBUG printf("Using multiboot header.\n");#endif /* Where is the code in the loaded file? */ seg_addr = ((char *)mbh) - (mbh->header_addr - mbh->load_addr); /* How much code is there? */ run_addr = mbh->load_addr; if (mbh->load_end_addr != 0) seg_size = mbh->load_end_addr - mbh->load_addr; else seg_size = load_size - (seg_addr - load_addr); /* How much memory will it take up? */ if (mbh->bss_end_addr != 0) run_size = mbh->bss_end_addr - mbh->load_addr; else run_size = seg_size; if (seg_size > run_size) { printf("Fatal: can't put %i bytes of kernel into %i bytes " "of memory.\n", seg_size, run_size); exit(1); } if (seg_addr + seg_size > load_addr + load_size) { printf("Fatal: multiboot load segment runs off the " "end of the file.\n"); exit(1); } /* Does it fit where it wants to be? */ place_kernel_section(run_addr, run_size); /* Put it on the relocation list */ if (seg_size < run_size) { /* Set up the kernel BSS too */ if (seg_size > 0) add_section(run_addr, seg_addr, seg_size); bss_size = run_size - seg_size; add_section(run_addr + seg_size, NULL, bss_size); } else { /* No BSS */ add_section(run_addr, seg_addr, run_size); } /* Done. */ return mbh->entry_addr; } else { /* Now look for an ELF32 header */ ehdr = (Elf32_Ehdr *)load_addr; if (*(unsigned long *)ehdr != 0x464c457f || ehdr->e_ident[EI_DATA] != ELFDATA2LSB || ehdr->e_ident[EI_CLASS] != ELFCLASS32 || ehdr->e_machine != EM_386) { printf("Fatal: kernel has neither ELF32/x86 nor multiboot load" " headers.\n"); exit(1); } if (ehdr->e_phoff + ehdr->e_phnum*sizeof (*phdr) > load_size) { printf("Fatal: malformed ELF header overruns EOF.\n"); exit(1); } if (ehdr->e_phnum <= 0) { printf("Fatal: ELF kernel has no program headers.\n"); exit(1); }#ifdef DEBUG printf("Using ELF header.\n");#endif if (ehdr->e_type != ET_EXEC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -