⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux_load.c

📁 open source bios with linux platform, very good and can be reused.
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (*sep == '=') {	    val = sep + 1;	    len = end - val;	} else {	    val = 0;	    len = 0;	}	/* Only initrd= and mem= are handled here. vga= is not,	 * which I believe is a paramter to the realmode part of Linux,	 * which we don't execute. */	if (strcmp(name, "initrd") == 0) {	    if (!val)		printf("Missing filename to initrd parameter\n");	    else {		initrd = malloc(len + 1);		memcpy(initrd, val, len);		initrd[len] = 0;		debug("initrd=%s\n", initrd);	    }	    /* Don't pass this to kernel */	    to_kern = 0;	} else if (strcmp(name, "mem") == 0) {	    if (!val)		printf("Missing value for mem parameter\n");	    else {		forced_memsize = strtoull_with_suffix(val, (char**)&val, 0);		if (forced_memsize == 0)		    printf("Invalid mem option, ignored\n");		if (val != end) {		    printf("Garbage after mem=<size>, ignored\n");		    forced_memsize = 0;		}		debug("mem=%Lu\n", forced_memsize);	    }	    /* mem= is for both loader and kernel */	    to_kern = 1;	} else	    to_kern = 1;	if (to_kern) {	    /* Copy to kernel command line buffer */	    if (k_len != 0)		kern_cmdline[k_len++] = ' '; /* put separator */	    len = end - start;	    if (k_len + len >= COMMAND_LINE_SIZE) {		len = COMMAND_LINE_SIZE - k_len - 1;		if (!toolong) {		    printf("Kernel command line is too long; truncated to "			    "%d bytes\n", COMMAND_LINE_SIZE-1);		    toolong = 1;		}	    }	    memcpy(kern_cmdline + k_len, start, len);	    k_len += len;	}	start = end;	while (*start == ' ')	    start++;    }    kern_cmdline[k_len] = 0;    debug("kernel command line (%d bytes): \"%s\"\n", k_len, kern_cmdline);    return initrd;}/* Set command line location */static void set_command_line_loc(struct linux_params *params,	struct linux_header *hdr){    if (hdr->protocol_version >= 0x202) {	/* new style */	params->cmd_line_ptr = COMMAND_LINE_LOC;    } else {	/* old style */	params->cl_magic = CL_MAGIC_VALUE;	params->cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC;    }}/* Load 32-bit part of kernel */static int load_linux_kernel(struct linux_header *hdr, uint32_t kern_addr){    uint32_t kern_offset, kern_size;    if (hdr->setup_sects == 0)	hdr->setup_sects = 4;    kern_offset = (hdr->setup_sects + 1) * 512;    file_seek(kern_offset);    kern_size = file_size() - kern_offset;    debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size);#if 0    if (using_devsize) {	printf("Attempt to load up to end of device as kernel; "		"specify the image size\n");	return 0;    }#endif    printf("Loading kernel... ");    if (lfile_read(phys_to_virt(kern_addr), kern_size) != kern_size) {	printf("Can't read kernel\n");	return 0;    }    printf("ok\n");    return kern_size;}static int load_initrd(struct linux_header *hdr, struct sys_info *info,	uint32_t kern_end, struct linux_params *params, const char *initrd_file){    uint32_t max;    uint32_t start, end, size;    uint64_t forced;    extern char _start[], _end[];    if (!file_open(initrd_file)) {	printf("Can't open initrd: %s\n", initrd_file);	return -1;    }#if 0    if (using_devsize) {	printf("Attempt to load up to end of device as initrd; "		"specify the image size\n");	return -1;    }#endif    size = file_size();    /* Find out the kernel's restriction on how high the initrd can be     * placed */    if (hdr->protocol_version >= 0x203)	max = hdr->initrd_addr_max;    else	max = 0x38000000; /* Hardcoded value for older kernels */        /* FILO itself is at the top of RAM. (relocated)     * So, try putting initrd just below us. */    end = virt_to_phys(_start);    if (end > max)	end = max;    /* If "mem=" option is given, we have to put the initrd within     * the specified range. */    if (forced_memsize) {	forced = forced_memsize;	if (forced > max)	    forced = max;	/* If the "mem=" is lower, it's easy */	if (forced <= end)	    end = forced;	else {	    /* Otherwise, see if we can put it above us */	    if (virt_to_phys(_end) + size <= forced)		end = forced; /* Ok */	}    }    start = end - size;    start &= ~0xfff; /* page align */    end = start + size;    debug("start=%#x end=%#x\n", start, end);    if (start < kern_end) {	printf("Initrd is too big to fit in memory\n");	return -1;    }    printf("Loading initrd... ");    if (lfile_read(phys_to_virt(start), size) != size) {	printf("Can't read initrd\n");	return -1;    }    printf("ok\n");    params->initrd_start = start;    params->initrd_size = size;    return 0;}static void hardware_setup(void){    /* Disable nmi */    outb(0x80, 0x70);    /* Make sure any coprocessor is properly reset.. */    outb(0, 0xf0);    outb(0, 0xf1);    /* we're getting screwed again and again by this problem of the 8259.      * so we're going to leave this lying around for inclusion into      * crt0.S on an as-needed basis.      *     * well, that went ok, I hope. Now we have to reprogram the interrupts :-(     * we put them right after the intel-reserved hardware interrupts, at     * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really     * messed this up with the original PC, and they haven't been able to     * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,     * which is used for the internal hardware interrupts as well. We just     * have to reprogram the 8259's, and it isn't fun.     */    outb(0x11, 0x20);		/* initialization sequence to 8259A-1 */    outb(0x11, 0xA0);		/* and to 8259A-2 */    outb(0x20, 0x21);		/* start of hardware int's (0x20) */    outb(0x28, 0xA1);		/* start of hardware int's 2 (0x28) */    outb(0x04, 0x21);		/* 8259-1 is master */    outb(0x02, 0xA1);		/* 8259-2 is slave */    outb(0x01, 0x21);		/* 8086 mode for both */    outb(0x01, 0xA1);    outb(0xFF, 0xA1);		/* mask off all interrupts for now */    outb(0xFB, 0x21);		/* mask all irq's but irq2 which is cascaded */}/* Start Linux */static int start_linux(uint32_t kern_addr, struct linux_params *params){    struct segment_desc *linux_gdt;    struct context *ctx;    //extern int cursor_x, cursor_y;    ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0);    /* Linux expects GDT being in low memory */    linux_gdt = phys_to_virt(GDT_LOC);    memset(linux_gdt, 0, 13*sizeof(struct segment_desc));    /* Normal kernel code/data segments */    linux_gdt[2] = gdt[FLAT_CODE];    linux_gdt[3] = gdt[FLAT_DATA];    /* 2.6 kernel uses 12 and 13, but head.S uses backward-compatible     * segments (2 and 3), so it SHOULD not be a problem.      * However, some distro kernels (eg. RH9) with backported threading      * patch use 12 and 13 also when booting... */    linux_gdt[12] = gdt[FLAT_CODE];    linux_gdt[13] = gdt[FLAT_DATA];    ctx->gdt_base = GDT_LOC;    ctx->gdt_limit = 14*8-1;    ctx->cs = 0x10;    ctx->ds = 0x18;    ctx->es = 0x18;    ctx->fs = 0x18;    ctx->gs = 0x18;    ctx->ss = 0x18;    /* Parameter location */    ctx->esi = virt_to_phys(params);    /* Entry point */    ctx->eip = kern_addr;    debug("eip=%#x\n", kern_addr);    printf("Jumping to entry point...\n");#ifdef VGA_CONSOLE    /* Update VGA cursor position.     * This must be here because the printf changes the value! */    params->orig_x = cursor_x;    params->orig_y = cursor_y;#endif        /* Go... */    ctx = switch_to(ctx);    /* It's impossible but... */    printf("Returned with eax=%#x\n", ctx->eax);    return ctx->eax;}int linux_load(struct sys_info *info, const char *file, const char *cmdline){    struct linux_header hdr;    struct linux_params *params;    uint32_t kern_addr, kern_size;    char *initrd_file = 0;    if (!file_open(file))	return -1;    kern_addr = load_linux_header(&hdr);    if (kern_addr == 0)	return LOADER_NOT_SUPPORT;    params = phys_to_virt(LINUX_PARAM_LOC);    init_linux_params(params, &hdr);    set_memory_size(params, info);    initrd_file = parse_command_line(cmdline, phys_to_virt(COMMAND_LINE_LOC));    set_command_line_loc(params, &hdr);    kern_size = load_linux_kernel(&hdr, kern_addr);    if (kern_size == 0) {	if (initrd_file)	    free(initrd_file);	return -1;    }    if (initrd_file) {	if (load_initrd(&hdr, info, kern_addr+kern_size, params, initrd_file)		!= 0) {	    free(initrd_file);	    return -1;	}	free(initrd_file);    }    hardware_setup();    start_linux(kern_addr, params);    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -