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

📄 helper.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  i386 helpers *  *  Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "exec.h"//#define DEBUG_PCALL#if 0#define raise_exception_err(a, b)\do {\    if (logfile)\        fprintf(logfile, "raise_exception line=%d\n", __LINE__);\    (raise_exception_err)(a, b);\} while (0)#endifconst uint8_t parity_table[256] = {    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,};/* modulo 17 table */const uint8_t rclw_table[32] = {    0, 1, 2, 3, 4, 5, 6, 7,     8, 9,10,11,12,13,14,15,   16, 0, 1, 2, 3, 4, 5, 6,    7, 8, 9,10,11,12,13,14,};/* modulo 9 table */const uint8_t rclb_table[32] = {    0, 1, 2, 3, 4, 5, 6, 7,     8, 0, 1, 2, 3, 4, 5, 6,    7, 8, 0, 1, 2, 3, 4, 5,     6, 7, 8, 0, 1, 2, 3, 4,};const CPU86_LDouble f15rk[7] ={    0.00000000000000000000L,    1.00000000000000000000L,    3.14159265358979323851L,  /*pi*/    0.30102999566398119523L,  /*lg2*/    0.69314718055994530943L,  /*ln2*/    1.44269504088896340739L,  /*l2e*/    3.32192809488736234781L,  /*l2t*/};    /* thread support */spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;void cpu_lock(void){    spin_lock(&global_cpu_lock);}void cpu_unlock(void){    spin_unlock(&global_cpu_lock);}void cpu_loop_exit(void){    /* NOTE: the register at this point must be saved by hand because       longjmp restore them */    regs_to_env();    longjmp(env->jmp_env, 1);}/* return non zero if error */static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,                               int selector){    SegmentCache *dt;    int index;    target_ulong ptr;    if (selector & 0x4)        dt = &env->ldt;    else        dt = &env->gdt;    index = selector & ~7;    if ((index + 7) > dt->limit)        return -1;    ptr = dt->base + index;    *e1_ptr = ldl_kernel(ptr);    *e2_ptr = ldl_kernel(ptr + 4);    return 0;}                                     static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2){    unsigned int limit;    limit = (e1 & 0xffff) | (e2 & 0x000f0000);    if (e2 & DESC_G_MASK)        limit = (limit << 12) | 0xfff;    return limit;}static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2){    return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));}static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2){    sc->base = get_seg_base(e1, e2);    sc->limit = get_seg_limit(e1, e2);    sc->flags = e2;}/* init the segment cache in vm86 mode. */static inline void load_seg_vm(int seg, int selector){    selector &= 0xffff;    cpu_x86_load_seg_cache(env, seg, selector,                            (selector << 4), 0xffff, 0);}static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,                                        uint32_t *esp_ptr, int dpl){    int type, index, shift;    #if 0    {        int i;        printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);        for(i=0;i<env->tr.limit;i++) {            printf("%02x ", env->tr.base[i]);            if ((i & 7) == 7) printf("\n");        }        printf("\n");    }#endif    if (!(env->tr.flags & DESC_P_MASK))        cpu_abort(env, "invalid tss");    type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;    if ((type & 7) != 1)        cpu_abort(env, "invalid tss type");    shift = type >> 3;    index = (dpl * 4 + 2) << shift;    if (index + (4 << shift) - 1 > env->tr.limit)        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);    if (shift == 0) {        *esp_ptr = lduw_kernel(env->tr.base + index);        *ss_ptr = lduw_kernel(env->tr.base + index + 2);    } else {        *esp_ptr = ldl_kernel(env->tr.base + index);        *ss_ptr = lduw_kernel(env->tr.base + index + 4);    }}/* XXX: merge with load_seg() */static void tss_load_seg(int seg_reg, int selector){    uint32_t e1, e2;    int rpl, dpl, cpl;    if ((selector & 0xfffc) != 0) {        if (load_segment(&e1, &e2, selector) != 0)            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);        if (!(e2 & DESC_S_MASK))            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);        rpl = selector & 3;        dpl = (e2 >> DESC_DPL_SHIFT) & 3;        cpl = env->hflags & HF_CPL_MASK;        if (seg_reg == R_CS) {            if (!(e2 & DESC_CS_MASK))                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);            /* XXX: is it correct ? */            if (dpl != rpl)                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);            if ((e2 & DESC_C_MASK) && dpl > rpl)                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);        } else if (seg_reg == R_SS) {            /* SS must be writable data */            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);            if (dpl != cpl || dpl != rpl)                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);        } else {            /* not readable code */            if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);            /* if data or non conforming code, checks the rights */            if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {                if (dpl < cpl || dpl < rpl)                    raise_exception_err(EXCP0A_TSS, selector & 0xfffc);            }        }        if (!(e2 & DESC_P_MASK))            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);        cpu_x86_load_seg_cache(env, seg_reg, selector,                        get_seg_base(e1, e2),                       get_seg_limit(e1, e2),                       e2);    } else {        if (seg_reg == R_SS || seg_reg == R_CS)             raise_exception_err(EXCP0A_TSS, selector & 0xfffc);    }}#define SWITCH_TSS_JMP  0#define SWITCH_TSS_IRET 1#define SWITCH_TSS_CALL 2/* XXX: restore CPU state in registers (PowerPC case) */static void switch_tss(int tss_selector,                        uint32_t e1, uint32_t e2, int source,                       uint32_t next_eip){    int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;    target_ulong tss_base;    uint32_t new_regs[8], new_segs[6];    uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;    uint32_t old_eflags, eflags_mask;    SegmentCache *dt;    int index;    target_ulong ptr;    type = (e2 >> DESC_TYPE_SHIFT) & 0xf;#ifdef DEBUG_PCALL    if (loglevel & CPU_LOG_PCALL)        fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);#endif    /* if task gate, we read the TSS segment and we load it */    if (type == 5) {        if (!(e2 & DESC_P_MASK))            raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);        tss_selector = e1 >> 16;        if (tss_selector & 4)            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);        if (load_segment(&e1, &e2, tss_selector) != 0)            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);        if (e2 & DESC_S_MASK)            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;        if ((type & 7) != 1)            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);    }    if (!(e2 & DESC_P_MASK))        raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);    if (type & 8)        tss_limit_max = 103;    else        tss_limit_max = 43;    tss_limit = get_seg_limit(e1, e2);    tss_base = get_seg_base(e1, e2);    if ((tss_selector & 4) != 0 ||         tss_limit < tss_limit_max)        raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);    old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;    if (old_type & 8)        old_tss_limit_max = 103;    else        old_tss_limit_max = 43;    /* read all the registers from the new TSS */    if (type & 8) {        /* 32 bit */        new_cr3 = ldl_kernel(tss_base + 0x1c);        new_eip = ldl_kernel(tss_base + 0x20);        new_eflags = ldl_kernel(tss_base + 0x24);        for(i = 0; i < 8; i++)            new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));        for(i = 0; i < 6; i++)            new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));        new_ldt = lduw_kernel(tss_base + 0x60);        new_trap = ldl_kernel(tss_base + 0x64);    } else {        /* 16 bit */        new_cr3 = 0;        new_eip = lduw_kernel(tss_base + 0x0e);        new_eflags = lduw_kernel(tss_base + 0x10);        for(i = 0; i < 8; i++)            new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;        for(i = 0; i < 4; i++)            new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));        new_ldt = lduw_kernel(tss_base + 0x2a);        new_segs[R_FS] = 0;        new_segs[R_GS] = 0;        new_trap = 0;    }        /* NOTE: we must avoid memory exceptions during the task switch,       so we make dummy accesses before */    /* XXX: it can still fail in some cases, so a bigger hack is       necessary to valid the TLB after having done the accesses */    v1 = ldub_kernel(env->tr.base);    v2 = ldub_kernel(env->tr.base + old_tss_limit_max);    stb_kernel(env->tr.base, v1);    stb_kernel(env->tr.base + old_tss_limit_max, v2);        /* clear busy bit (it is restartable) */    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {        target_ulong ptr;        uint32_t e2;        ptr = env->gdt.base + (env->tr.selector & ~7);        e2 = ldl_kernel(ptr + 4);        e2 &= ~DESC_TSS_BUSY_MASK;        stl_kernel(ptr + 4, e2);    }    old_eflags = compute_eflags();    if (source == SWITCH_TSS_IRET)        old_eflags &= ~NT_MASK;        /* save the current state in the old TSS */    if (type & 8) {        /* 32 bit */        stl_kernel(env->tr.base + 0x20, next_eip);        stl_kernel(env->tr.base + 0x24, old_eflags);        stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);        stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);        stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);        stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);        stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);        stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);        stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);        stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);        for(i = 0; i < 6; i++)            stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);    } else {        /* 16 bit */        stw_kernel(env->tr.base + 0x0e, next_eip);        stw_kernel(env->tr.base + 0x10, old_eflags);        stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);        stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);        stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);        stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);        stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);        stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);        stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);        stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);        for(i = 0; i < 4; i++)            stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);    }        /* now if an exception occurs, it will occurs in the next task       context */    if (source == SWITCH_TSS_CALL) {        stw_kernel(tss_base, env->tr.selector);        new_eflags |= NT_MASK;    }    /* set busy bit */    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {        target_ulong ptr;        uint32_t e2;        ptr = env->gdt.base + (tss_selector & ~7);        e2 = ldl_kernel(ptr + 4);        e2 |= DESC_TSS_BUSY_MASK;        stl_kernel(ptr + 4, e2);    }    /* set the new CPU state */    /* from this point, any exception which occurs can give problems */    env->cr[0] |= CR0_TS_MASK;    env->hflags |= HF_TS_MASK;    env->tr.selector = tss_selector;    env->tr.base = tss_base;    env->tr.limit = tss_limit;    env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;

⌨️ 快捷键说明

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