|
|
1.1 ! root 1: /* Segmentation of the i386 architecture. ! 2: * ! 3: * 2003-07 by SONE Takeshi ! 4: */ ! 5: ! 6: #include "config.h" ! 7: #include "kernel/kernel.h" ! 8: #include "libopenbios/sys_info.h" ! 9: #include "relocate.h" ! 10: #include "segment.h" ! 11: ! 12: #define printf printk ! 13: #ifdef CONFIG_DEBUG_BOOT ! 14: #define debug printk ! 15: #else ! 16: #define debug(x...) ! 17: #endif ! 18: ! 19: /* i386 lgdt argument */ ! 20: struct gdtarg { ! 21: unsigned short limit; ! 22: unsigned int base; ! 23: } __attribute__((packed)); ! 24: ! 25: /* How far the virtual address (used in C) is different from physical ! 26: * address. Since we start in flat mode, the initial value is zero. */ ! 27: unsigned long virt_offset = 0; ! 28: ! 29: /* GDT, the global descriptor table */ ! 30: struct segment_desc gdt[NUM_SEG] = { ! 31: /* 0x00: null segment */ ! 32: {0, 0, 0, 0, 0, 0}, ! 33: /* 0x08: flat code segment */ ! 34: {0xffff, 0, 0, 0x9f, 0xcf, 0}, ! 35: /* 0x10: flat data segment */ ! 36: {0xffff, 0, 0, 0x93, 0xcf, 0}, ! 37: /* 0x18: code segment for relocated execution */ ! 38: {0xffff, 0, 0, 0x9f, 0xcf, 0}, ! 39: /* 0x20: data segment for relocated execution */ ! 40: {0xffff, 0, 0, 0x93, 0xcf, 0}, ! 41: }; ! 42: ! 43: ! 44: void relocate(struct sys_info *info) ! 45: { ! 46: int i; ! 47: unsigned long prog_addr; ! 48: unsigned long prog_size; ! 49: unsigned long addr, new_base; ! 50: unsigned long long segsize; ! 51: unsigned long new_offset; ! 52: unsigned d0, d1, d2; ! 53: struct gdtarg gdtarg; ! 54: #define ALIGNMENT 16 ! 55: ! 56: prog_addr = virt_to_phys(&_start); ! 57: prog_size = virt_to_phys(&_end) - virt_to_phys(&_start); ! 58: debug("Current location: %#lx-%#lx\n", prog_addr, prog_addr+prog_size-1); ! 59: ! 60: new_base = 0; ! 61: for (i = 0; i < info->n_memranges; i++) { ! 62: if (info->memrange[i].base >= 1ULL<<32) ! 63: continue; ! 64: segsize = info->memrange[i].size; ! 65: if (info->memrange[i].base + segsize > 1ULL<<32) ! 66: segsize = (1ULL<<32) - info->memrange[i].base; ! 67: if (segsize < prog_size+ALIGNMENT) ! 68: continue; ! 69: addr = info->memrange[i].base + segsize - prog_size; ! 70: addr &= ~(ALIGNMENT-1); ! 71: if (addr >= prog_addr && addr < prog_addr + prog_size) ! 72: continue; ! 73: if (prog_addr >= addr && prog_addr < addr + prog_size) ! 74: continue; ! 75: if (addr > new_base) ! 76: new_base = addr; ! 77: } ! 78: if (new_base == 0) { ! 79: printf("Can't find address to relocate\n"); ! 80: return; ! 81: } ! 82: ! 83: debug("Relocating to %#lx-%#lx... ", ! 84: new_base, new_base + prog_size - 1); ! 85: ! 86: /* New virtual address offset */ ! 87: new_offset = new_base - (unsigned long) &_start; ! 88: ! 89: /* Tweak the GDT */ ! 90: gdt[RELOC_CODE].base_0 = (unsigned short) new_offset; ! 91: gdt[RELOC_CODE].base_16 = (unsigned char) (new_offset>>16); ! 92: gdt[RELOC_CODE].base_24 = (unsigned char) (new_offset>>24); ! 93: gdt[RELOC_DATA].base_0 = (unsigned short) new_offset; ! 94: gdt[RELOC_DATA].base_16 = (unsigned char) (new_offset>>16); ! 95: gdt[RELOC_DATA].base_24 = (unsigned char) (new_offset>>24); ! 96: ! 97: /* Load new GDT and reload segments */ ! 98: gdtarg.base = new_offset + (unsigned long) gdt; ! 99: gdtarg.limit = GDT_LIMIT; ! 100: __asm__ __volatile__ ( ! 101: "rep; movsb\n\t" /* copy everything */ ! 102: "lgdt %3\n\t" ! 103: "ljmp %4, $1f\n1:\t" ! 104: "movw %5, %%ds\n\t" ! 105: "movw %5, %%es\n\t" ! 106: "movw %5, %%fs\n\t" ! 107: "movw %5, %%gs\n\t" ! 108: "movw %5, %%ss\n" ! 109: : "=&S" (d0), "=&D" (d1), "=&c" (d2) ! 110: : "m" (gdtarg), "n" (RELOC_CS), "q" ((unsigned short) RELOC_DS), ! 111: "0" (&_start), "1" (new_base), "2" (prog_size)); ! 112: ! 113: virt_offset = new_offset; ! 114: debug("ok\n"); ! 115: } ! 116: ! 117: #if 0 ! 118: /* Copy GDT to new location and reload it */ ! 119: void move_gdt(unsigned long newgdt) ! 120: { ! 121: struct gdtarg gdtarg; ! 122: ! 123: debug("Moving GDT to %#lx...", newgdt); ! 124: memcpy(phys_to_virt(newgdt), gdt, sizeof gdt); ! 125: gdtarg.base = newgdt; ! 126: gdtarg.limit = GDT_LIMIT; ! 127: debug("reloading GDT..."); ! 128: __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg)); ! 129: debug("reloading CS for fun..."); ! 130: __asm__ __volatile__ ("ljmp %0, $1f\n1:" : : "n" (RELOC_CS)); ! 131: debug("ok\n"); ! 132: } ! 133: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.