Annotation of qemu/roms/openbios/arch/amd64/segment.c, revision 1.1

1.1     ! root        1: /* Segmentation of the AMD64 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: extern char _start[], _end[];
        !            44: 
        !            45: void relocate(struct sys_info *info)
        !            46: {
        !            47:     int i;
        !            48:     unsigned long prog_addr;
        !            49:     unsigned long prog_size;
        !            50:     unsigned long addr, new_base;
        !            51:     unsigned long long segsize;
        !            52:     unsigned long new_offset;
        !            53:     unsigned d0, d1, d2;
        !            54:     struct gdtarg gdtarg;
        !            55: #define ALIGNMENT 16
        !            56: 
        !            57:     prog_addr = virt_to_phys(&_start);
        !            58:     prog_size = virt_to_phys(&_end) - virt_to_phys(&_start);
        !            59:     debug("Current location: %#lx-%#lx\n", prog_addr, prog_addr+prog_size-1);
        !            60: 
        !            61:     new_base = 0;
        !            62:     for (i = 0; i < info->n_memranges; i++) {
        !            63:        if (info->memrange[i].base >= 1ULL<<32)
        !            64:            continue;
        !            65:        segsize = info->memrange[i].size;
        !            66:        if (info->memrange[i].base + segsize > 1ULL<<32)
        !            67:            segsize = (1ULL<<32) - info->memrange[i].base;
        !            68:        if (segsize < prog_size+ALIGNMENT)
        !            69:            continue;
        !            70:        addr = info->memrange[i].base + segsize - prog_size;
        !            71:        addr &= ~(ALIGNMENT-1);
        !            72:        if (addr >= prog_addr && addr < prog_addr + prog_size)
        !            73:            continue;
        !            74:        if (prog_addr >= addr && prog_addr < addr + prog_size)
        !            75:            continue;
        !            76:        if (addr > new_base)
        !            77:            new_base = addr;
        !            78:     }
        !            79:     if (new_base == 0) {
        !            80:        printf("Can't find address to relocate\n");
        !            81:        return;
        !            82:     }
        !            83: 
        !            84:     debug("Relocating to %#lx-%#lx... ",
        !            85:            new_base, new_base + prog_size - 1);
        !            86: 
        !            87:     /* New virtual address offset */
        !            88:     new_offset = new_base - (unsigned long) &_start;
        !            89: 
        !            90:     /* Tweak the GDT */
        !            91:     gdt[RELOC_CODE].base_0 = (unsigned short) new_offset;
        !            92:     gdt[RELOC_CODE].base_16 = (unsigned char) (new_offset>>16);
        !            93:     gdt[RELOC_CODE].base_24 = (unsigned char) (new_offset>>24);
        !            94:     gdt[RELOC_DATA].base_0 = (unsigned short) new_offset;
        !            95:     gdt[RELOC_DATA].base_16 = (unsigned char) (new_offset>>16);
        !            96:     gdt[RELOC_DATA].base_24 = (unsigned char) (new_offset>>24);
        !            97: 
        !            98:     /* Load new GDT and reload segments */
        !            99:     gdtarg.base = new_offset + (unsigned long) gdt;
        !           100:     gdtarg.limit = GDT_LIMIT;
        !           101:     __asm__ __volatile__ (
        !           102:            "rep; movsb\n\t" /* copy everything */
        !           103:            "lgdt %3\n\t"
        !           104:            "ljmp %4, $1f\n1:\t"
        !           105:            "movw %5, %%ds\n\t"
        !           106:            "movw %5, %%es\n\t"
        !           107:            "movw %5, %%fs\n\t"
        !           108:            "movw %5, %%gs\n\t"
        !           109:            "movw %5, %%ss\n"
        !           110:            : "=&S" (d0), "=&D" (d1), "=&c" (d2)
        !           111:            : "m" (gdtarg), "n" (RELOC_CS), "q" ((unsigned short) RELOC_DS),
        !           112:            "0" (&_start), "1" (new_base), "2" (prog_size));
        !           113: 
        !           114:     virt_offset = new_offset;
        !           115:     debug("ok\n");
        !           116: }
        !           117: 
        !           118: #if 0
        !           119: /* Copy GDT to new location and reload it */
        !           120: void move_gdt(unsigned long newgdt)
        !           121: {
        !           122:     struct gdtarg gdtarg;
        !           123: 
        !           124:     debug("Moving GDT to %#lx...", newgdt);
        !           125:     memcpy(phys_to_virt(newgdt), gdt, sizeof gdt);
        !           126:     gdtarg.base = newgdt;
        !           127:     gdtarg.limit = GDT_LIMIT;
        !           128:     debug("reloading GDT...");
        !           129:     __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg));
        !           130:     debug("reloading CS for fun...");
        !           131:     __asm__ __volatile__ ("ljmp %0, $1f\n1:" : : "n" (RELOC_CS));
        !           132:     debug("ok\n");
        !           133: }
        !           134: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.