Annotation of qemu/roms/openbios/arch/x86/segment.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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