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

📄 segment.c

📁 open source bios with linux platform, very good and can be reused.
💻 C
字号:
/* Segmentation of the i386 architecture. * * 2003-07 by SONE Takeshi */#include "openbios/config.h"#include "openbios/kernel.h"#include "sys_info.h"#include "relocate.h"#include "segment.h"#define printf printk#ifdef CONFIG_DEBUG_BOOT#define debug printk#else#define debug(x...)#endif/* i386 lgdt argument */struct gdtarg {    unsigned short limit;    unsigned int base;} __attribute__((packed));/* How far the virtual address (used in C) is different from physical  * address. Since we start in flat mode, the initial value is zero. */unsigned long virt_offset = 0;/* GDT, the global descriptor table */struct segment_desc gdt[NUM_SEG] = {    /* 0x00: null segment */    {0, 0, 0, 0, 0, 0},    /* 0x08: flat code segment */    {0xffff, 0, 0, 0x9f, 0xcf, 0},    /* 0x10: flat data segment */    {0xffff, 0, 0, 0x93, 0xcf, 0},    /* 0x18: code segment for relocated execution */    {0xffff, 0, 0, 0x9f, 0xcf, 0},    /* 0x20: data segment for relocated execution */    {0xffff, 0, 0, 0x93, 0xcf, 0},};extern char _start[], _end[];void relocate(struct sys_info *info){    int i;    unsigned long prog_addr;    unsigned long prog_size;    unsigned long addr, new_base;    unsigned long long segsize;    unsigned long new_offset;    unsigned d0, d1, d2;    struct gdtarg gdtarg;#define ALIGNMENT 16    prog_addr = virt_to_phys(&_start);    prog_size = virt_to_phys(&_end) - virt_to_phys(&_start);    debug("Current location: %#lx-%#lx\n", prog_addr, prog_addr+prog_size-1);    new_base = 0;    for (i = 0; i < info->n_memranges; i++) {	if (info->memrange[i].base >= 1ULL<<32)	    continue;	segsize = info->memrange[i].size;	if (info->memrange[i].base + segsize > 1ULL<<32)	    segsize = (1ULL<<32) - info->memrange[i].base;	if (segsize < prog_size+ALIGNMENT)	    continue;	addr = info->memrange[i].base + segsize - prog_size;	addr &= ~(ALIGNMENT-1);	if (addr >= prog_addr && addr < prog_addr + prog_size)	    continue;	if (prog_addr >= addr && prog_addr < addr + prog_size)	    continue;	if (addr > new_base)	    new_base = addr;    }    if (new_base == 0) {	printf("Can't find address to relocate\n");	return;    }    debug("Relocating to %#lx-%#lx... ",	    new_base, new_base + prog_size - 1);    /* New virtual address offset */    new_offset = new_base - (unsigned long) &_start;    /* Tweak the GDT */    gdt[RELOC_CODE].base_0 = (unsigned short) new_offset;    gdt[RELOC_CODE].base_16 = (unsigned char) (new_offset>>16);    gdt[RELOC_CODE].base_24 = (unsigned char) (new_offset>>24);    gdt[RELOC_DATA].base_0 = (unsigned short) new_offset;    gdt[RELOC_DATA].base_16 = (unsigned char) (new_offset>>16);    gdt[RELOC_DATA].base_24 = (unsigned char) (new_offset>>24);    /* Load new GDT and reload segments */    gdtarg.base = new_offset + (unsigned long) gdt;    gdtarg.limit = GDT_LIMIT;    __asm__ __volatile__ (	    "rep; movsb\n\t" /* copy everything */	    "lgdt %3\n\t"	    "ljmp %4, $1f\n1:\t"	    "movw %5, %%ds\n\t"	    "movw %5, %%es\n\t"	    "movw %5, %%fs\n\t"	    "movw %5, %%gs\n\t"	    "movw %5, %%ss\n"	    : "=&S" (d0), "=&D" (d1), "=&c" (d2)	    : "m" (gdtarg), "n" (RELOC_CS), "q" ((unsigned short) RELOC_DS), 	    "0" (&_start), "1" (new_base), "2" (prog_size));    virt_offset = new_offset;    debug("ok\n");}#if 0/* Copy GDT to new location and reload it */void move_gdt(unsigned long newgdt){    struct gdtarg gdtarg;    debug("Moving GDT to %#lx...", newgdt);    memcpy(phys_to_virt(newgdt), gdt, sizeof gdt);    gdtarg.base = newgdt;    gdtarg.limit = GDT_LIMIT;    debug("reloading GDT...");    __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg));    debug("reloading CS for fun...");    __asm__ __volatile__ ("ljmp %0, $1f\n1:" : : "n" (RELOC_CS));    debug("ok\n");}#endif

⌨️ 快捷键说明

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