|
|
| version 1.17, 2004/03/25 15:08:32 | version 1.20, 2005/03/09 17:12:34 |
|---|---|
| Line 252 cpu_stack_pop_check(UINT16 s, descriptor | Line 252 cpu_stack_pop_check(UINT16 s, descriptor |
| } | } |
| } | } |
| #if defined(IA32_SUPPORT_PREFETCH_QUEUE) | |
| /* | |
| * code prefetch | |
| */ | |
| #define CPU_PREFETCHQ_MASK (CPU_PREFETCH_QUEUE_LENGTH - 1) | |
| INLINE static MEMCALL void | |
| cpu_prefetch(UINT32 address) | |
| { | |
| UINT offset = address & CPU_PREFETCHQ_MASK; | |
| UINT length = CPU_PREFETCH_QUEUE_LENGTH - offset; | |
| cpu_memory_access_la_region(address, length, CPU_PAGE_READ_CODE|CPU_STAT_USER_MODE, CPU_PREFETCHQ + offset); | |
| CPU_PREFETCHQ_REMAIN = (SINT8)length; | |
| } | |
| INLINE static MEMCALL UINT8 | |
| cpu_prefetchq(UINT32 address) | |
| { | |
| UINT8 v; | |
| CPU_PREFETCHQ_REMAIN--; | |
| v = CPU_PREFETCHQ[address & CPU_PREFETCHQ_MASK]; | |
| return v; | |
| } | |
| INLINE static MEMCALL UINT16 | |
| cpu_prefetchq_w(UINT32 address) | |
| { | |
| BYTE *p; | |
| UINT16 v; | |
| CPU_PREFETCHQ_REMAIN -= 2; | |
| p = CPU_PREFETCHQ + (address & CPU_PREFETCHQ_MASK); | |
| v = LOADINTELWORD(p); | |
| return v; | |
| } | |
| INLINE static MEMCALL UINT32 | |
| cpu_prefetchq_3(UINT32 address) | |
| { | |
| BYTE *p; | |
| UINT32 v; | |
| CPU_PREFETCHQ_REMAIN -= 3; | |
| p = CPU_PREFETCHQ + (address & CPU_PREFETCHQ_MASK); | |
| v = LOADINTELWORD(p); | |
| v += ((UINT32)p[2]) << 16; | |
| return v; | |
| } | |
| INLINE static MEMCALL UINT32 | |
| cpu_prefetchq_d(UINT32 address) | |
| { | |
| BYTE *p; | |
| UINT32 v; | |
| CPU_PREFETCHQ_REMAIN -= 4; | |
| p = CPU_PREFETCHQ + (address & CPU_PREFETCHQ_MASK); | |
| v = LOADINTELDWORD(p); | |
| return v; | |
| } | |
| #endif /* IA32_SUPPORT_PREFETCH_QUEUE */ | |
| #if defined(IA32_SUPPORT_DEBUG_REGISTER) | #if defined(IA32_SUPPORT_DEBUG_REGISTER) |
| INLINE static void | INLINE static void |
| check_memory_break_point(UINT32 address, UINT length, UINT rw) | check_memory_break_point(UINT32 address, UINT length, UINT rw) |
| Line 339 check_memory_break_point(UINT32 address, | Line 274 check_memory_break_point(UINT32 address, |
| #define check_memory_break_point(address, length, rw) | #define check_memory_break_point(address, length, rw) |
| #endif | #endif |
| /* | /* |
| * code fetch | * code fetch |
| */ | */ |
| #define ucrw (CPU_PAGE_READ_CODE | CPU_STAT_USER_MODE) | |
| UINT8 MEMCALL | UINT8 MEMCALL |
| cpu_codefetch(UINT32 offset) | cpu_codefetch(UINT32 offset) |
| { | { |
| descriptor_t *sd; | descriptor_t *sd; |
| UINT32 addr; | UINT32 addr; |
| #if defined(IA32_SUPPORT_TLB) | |
| TLB_ENTRY_T *ep; | |
| #endif | |
| sd = &CPU_STAT_SREG(CPU_CS_INDEX); | sd = &CPU_STAT_SREG(CPU_CS_INDEX); |
| if (offset <= sd->u.seg.limit) { | if (offset <= sd->u.seg.limit) { |
| addr = sd->u.seg.segbase + offset; | addr = sd->u.seg.segbase + offset; |
| #if defined(IA32_SUPPORT_PREFETCH_QUEUE) | |
| if (CPU_PREFETCHQ_REMAIN <= 0) { | |
| cpu_prefetch(addr); | |
| } | |
| return cpu_prefetchq(addr); | |
| #else /* !IA32_SUPPORT_PREFETCH_QUEUE */ | |
| if (!CPU_STAT_PAGING) | if (!CPU_STAT_PAGING) |
| return cpu_memoryread(addr); | return cpu_memoryread(addr); |
| return cpu_linear_memory_read_b(addr, CPU_PAGE_READ_CODE | CPU_STAT_USER_MODE); | #if defined(IA32_SUPPORT_TLB) |
| #endif /* IA32_SUPPORT_PREFETCH_QUEUE */ | ep = tlb_lookup(addr, ucrw); |
| if (ep != NULL && ep->memp != NULL) { | |
| return ep->memp[addr & 0xfff]; | |
| } | |
| #endif | |
| return cpu_linear_memory_read_b(addr, ucrw); | |
| } | } |
| EXCEPTION(GP_EXCEPTION, 0); | EXCEPTION(GP_EXCEPTION, 0); |
| return 0; /* compiler happy */ | return 0; /* compiler happy */ |
| Line 371 cpu_codefetch_w(UINT32 offset) | Line 311 cpu_codefetch_w(UINT32 offset) |
| { | { |
| descriptor_t *sd; | descriptor_t *sd; |
| UINT32 addr; | UINT32 addr; |
| #if defined(IA32_SUPPORT_PREFETCH_QUEUE) | #if defined(IA32_SUPPORT_TLB) |
| UINT16 v; | TLB_ENTRY_T *ep; |
| UINT16 value; | |
| #endif | #endif |
| sd = &CPU_STAT_SREG(CPU_CS_INDEX); | sd = &CPU_STAT_SREG(CPU_CS_INDEX); |
| if (offset <= sd->u.seg.limit - 1) { | if (offset <= sd->u.seg.limit - 1) { |
| addr = sd->u.seg.segbase + offset; | addr = sd->u.seg.segbase + offset; |
| #if defined(IA32_SUPPORT_PREFETCH_QUEUE) | |
| if (CPU_PREFETCHQ_REMAIN <= 0) { | |
| cpu_prefetch(addr); | |
| } | |
| if (CPU_PREFETCHQ_REMAIN >= 2) { | |
| return cpu_prefetchq_w(addr); | |
| } | |
| v = cpu_prefetchq(addr); | |
| addr++; | |
| cpu_prefetch(addr); | |
| v += (UINT16)cpu_prefetchq(addr) << 8; | |
| return v; | |
| #else /* !IA32_SUPPORT_PREFETCH_QUEUE */ | |
| if (!CPU_STAT_PAGING) | if (!CPU_STAT_PAGING) |
| return cpu_memoryread_w(addr); | return cpu_memoryread_w(addr); |
| return cpu_linear_memory_read_w(addr, CPU_PAGE_READ_CODE | CPU_STAT_USER_MODE); | #if defined(IA32_SUPPORT_TLB) |
| #endif /* IA32_SUPPORT_PREFETCH_QUEUE */ | ep = tlb_lookup(addr, ucrw); |
| if (ep != NULL && ep->memp != NULL) { | |
| if ((addr + 1) & 0x00000fff) { | |
| return LOADINTELWORD(ep->memp + (addr & 0xfff)); | |
| } | |
| value = ep->memp[0xfff]; | |
| ep = tlb_lookup(addr + 1, ucrw); | |
| if (ep != NULL && ep->memp != NULL) { | |
| value += (UINT16)ep->memp[0] << 8; | |
| return value; | |
| } | |
| } | |
| #endif | |
| return cpu_linear_memory_read_w(addr, ucrw); | |
| } | } |
| EXCEPTION(GP_EXCEPTION, 0); | EXCEPTION(GP_EXCEPTION, 0); |
| return 0; /* compiler happy */ | return 0; /* compiler happy */ |
| Line 406 cpu_codefetch_d(UINT32 offset) | Line 346 cpu_codefetch_d(UINT32 offset) |
| { | { |
| descriptor_t *sd; | descriptor_t *sd; |
| UINT32 addr; | UINT32 addr; |
| #if defined(IA32_SUPPORT_PREFETCH_QUEUE) | #if defined(IA32_SUPPORT_TLB) |
| UINT32 v; | TLB_ENTRY_T *ep[2]; |
| UINT32 value; | |
| UINT remain; | |
| #endif | #endif |
| sd = &CPU_STAT_SREG(CPU_CS_INDEX); | sd = &CPU_STAT_SREG(CPU_CS_INDEX); |
| if (offset <= sd->u.seg.limit - 3) { | if (offset <= sd->u.seg.limit - 3) { |
| addr = sd->u.seg.segbase + offset; | addr = sd->u.seg.segbase + offset; |
| #if defined(IA32_SUPPORT_PREFETCH_QUEUE) | |
| if (CPU_PREFETCHQ_REMAIN <= 0) { | |
| cpu_prefetch(addr); | |
| } | |
| if (CPU_PREFETCHQ_REMAIN >= 4) { | |
| return cpu_prefetchq_d(addr); | |
| } else { | |
| switch (CPU_PREFETCHQ_REMAIN) { | |
| case 1: | |
| v = cpu_prefetchq(addr); | |
| addr++; | |
| cpu_prefetch(addr); | |
| v += (UINT32)cpu_prefetchq_3(addr) << 8; | |
| break; | |
| case 2: | |
| v = cpu_prefetchq_w(addr); | |
| addr += 2; | |
| cpu_prefetch(addr); | |
| v += (UINT32)cpu_prefetchq_w(addr) << 16; | |
| break; | |
| case 3: | |
| v = cpu_prefetchq_3(addr); | |
| addr += 3; | |
| cpu_prefetch(addr); | |
| v += (UINT32)cpu_prefetchq(addr) << 24; | |
| break; | |
| default: | |
| ia32_panic("cpu_codefetch_d: remain bytes is invalid"); | |
| v = 0; /* compiler happy */ | |
| break; | |
| } | |
| return v; | |
| } | |
| #else /* !IA32_SUPPORT_PREFETCH_QUEUE */ | |
| if (!CPU_STAT_PAGING) | if (!CPU_STAT_PAGING) |
| return cpu_memoryread_d(addr); | return cpu_memoryread_d(addr); |
| return cpu_linear_memory_read_d(addr, CPU_PAGE_READ_CODE | CPU_STAT_USER_MODE); | #if defined(IA32_SUPPORT_TLB) |
| #endif /* IA32_SUPPORT_PREFETCH_QUEUE */ | ep[0] = tlb_lookup(addr, ucrw); |
| if (ep[0] != NULL && ep[0]->memp != NULL) { | |
| remain = 0x1000 - (addr & 0xfff); | |
| if (remain >= 4) { | |
| return LOADINTELDWORD(ep[0]->memp + (addr & 0xfff)); | |
| } | |
| ep[1] = tlb_lookup(addr + remain, ucrw); | |
| if (ep[1] != NULL && ep[1]->memp != NULL) { | |
| switch (remain) { | |
| case 3: | |
| value = ep[0]->memp[0xffd]; | |
| value += (UINT32)LOADINTELWORD(ep[0]->memp + 0xffe) << 8; | |
| value += (UINT32)ep[1]->memp[0] << 24; | |
| break; | |
| case 2: | |
| value = LOADINTELWORD(ep[0]->memp + 0xffe); | |
| value += (UINT32)LOADINTELWORD(ep[1]->memp + 0) << 16; | |
| break; | |
| case 1: | |
| value = ep[0]->memp[0xfff]; | |
| value += (UINT32)LOADINTELWORD(ep[1]->memp + 0) << 8; | |
| value += (UINT32)ep[1]->memp[2] << 24; | |
| break; | |
| default: | |
| ia32_panic("cpu_codefetch_d(): out of range. (remain = %d)\n", remain); | |
| return (UINT32)-1; | |
| } | |
| return value; | |
| } | |
| } | |
| #endif | |
| return cpu_linear_memory_read_d(addr, ucrw); | |
| } | } |
| EXCEPTION(GP_EXCEPTION, 0); | EXCEPTION(GP_EXCEPTION, 0); |
| return 0; /* compiler happy */ | return 0; /* compiler happy */ |
| } | } |
| /* | |
| * additional physical address memory access functions | |
| */ | |
| UINT64 MEMCALL | |
| cpu_memoryread_q(UINT32 address) | |
| { | |
| UINT64 value; | |
| value = cpu_memoryread_d(address); | |
| value += (UINT64)cpu_memoryread_d(address + 4) << 32; | |
| return value; | |
| } | |
| REG80 MEMCALL | |
| cpu_memoryread_f(UINT32 address) | |
| { | |
| REG80 value; | |
| UINT i; | |
| for (i = 0; i < sizeof(REG80); ++i) { | |
| value.b[i] = cpu_memoryread(address + i); | |
| } | |
| return value; | |
| } | |
| void MEMCALL | |
| cpu_memorywrite_q(UINT32 address, UINT64 value) | |
| { | |
| cpu_memorywrite_d(address, (UINT32)value); | |
| cpu_memorywrite_d(address + 4, (UINT32)(value >> 32)); | |
| } | |
| void MEMCALL | |
| cpu_memorywrite_f(UINT32 address, const REG80 *value) | |
| { | |
| UINT i; | |
| for (i = 0; i < sizeof(REG80); ++i) { | |
| cpu_memorywrite(address + i, value->b[i]); | |
| } | |
| } | |
| /* | /* |
| * virtual address memory access functions | * virtual address memory access functions |
| Line 468 cpu_codefetch_d(UINT32 offset) | Line 450 cpu_codefetch_d(UINT32 offset) |
| VIRTUAL_ADDRESS_MEMORY_ACCESS_FUNCTION(b, UINT8, 1) | VIRTUAL_ADDRESS_MEMORY_ACCESS_FUNCTION(b, UINT8, 1) |
| VIRTUAL_ADDRESS_MEMORY_ACCESS_FUNCTION(w, UINT16, 2) | VIRTUAL_ADDRESS_MEMORY_ACCESS_FUNCTION(w, UINT16, 2) |
| VIRTUAL_ADDRESS_MEMORY_ACCESS_FUNCTION(d, UINT32, 4) | VIRTUAL_ADDRESS_MEMORY_ACCESS_FUNCTION(d, UINT32, 4) |
| UINT64 MEMCALL | |
| cpu_vmemoryread_q(int idx, UINT32 offset) | |
| { | |
| descriptor_t *sd; | |
| UINT32 addr; | |
| int exc; | |
| __ASSERT((unsigned int)idx < CPU_SEGREG_NUM); | |
| sd = &CPU_STAT_SREG(idx); | |
| if (!sd->valid) { | |
| exc = GP_EXCEPTION; | |
| goto err; | |
| } | |
| if (!(sd->flag & CPU_DESC_FLAG_READABLE)) { | |
| cpu_memoryread_check(sd, offset, 8, | |
| (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION); | |
| } else { | |
| switch (sd->type) { | |
| case 4: case 5: case 6: case 7: | |
| if (offset - (8 - 1) <= sd->u.seg.limit) | |
| goto range_failure; | |
| break; | |
| default: | |
| if (offset > sd->u.seg.limit - (8 - 1)) | |
| goto range_failure; | |
| break; | |
| } | |
| } | |
| addr = sd->u.seg.segbase + offset; | |
| check_memory_break_point(addr, 8, CPU_DR7_RW_RO); | |
| if (!CPU_STAT_PAGING) | |
| return cpu_memoryread_q(addr); | |
| return cpu_linear_memory_read_q(addr, CPU_PAGE_READ_DATA | CPU_STAT_USER_MODE); | |
| range_failure: | |
| if (idx == CPU_SS_INDEX) { | |
| exc = SS_EXCEPTION; | |
| } else { | |
| exc = GP_EXCEPTION; | |
| } | |
| VERBOSE(("cpu_vmemoryread_q: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit)); | |
| err: | |
| EXCEPTION(exc, 0); | |
| return 0; /* compiler happy */ | |
| } | |
| void MEMCALL | |
| cpu_vmemorywrite_q(int idx, UINT32 offset, UINT64 value) | |
| { | |
| descriptor_t *sd; | |
| UINT32 addr; | |
| int exc; | |
| __ASSERT((unsigned int)idx < CPU_SEGREG_NUM); | |
| sd = &CPU_STAT_SREG(idx); | |
| if (!sd->valid) { | |
| exc = GP_EXCEPTION; | |
| goto err; | |
| } | |
| if (!(sd->flag & CPU_DESC_FLAG_WRITABLE)) { | |
| cpu_memorywrite_check(sd, offset, 8, | |
| (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION); | |
| } else { | |
| switch (sd->type) { | |
| case 6: case 7: | |
| if (offset - (8 - 1) <= sd->u.seg.limit) | |
| goto range_failure; | |
| break; | |
| default: | |
| if (offset > sd->u.seg.limit - (8 - 1)) | |
| goto range_failure; | |
| break; | |
| } | |
| } | |
| addr = sd->u.seg.segbase + offset; | |
| check_memory_break_point(addr, 8, CPU_DR7_RW_RW); | |
| if (!CPU_STAT_PAGING) { | |
| cpu_memorywrite_q(addr, value); | |
| } else { | |
| cpu_linear_memory_write_q(addr, value, CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE); | |
| } | |
| return; | |
| range_failure: | |
| if (idx == CPU_SS_INDEX) { | |
| exc = SS_EXCEPTION; | |
| } else { | |
| exc = GP_EXCEPTION; | |
| } | |
| VERBOSE(("cpu_vmemorywrite_q: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit)); | |
| err: | |
| EXCEPTION(exc, 0); | |
| } | |
| REG80 MEMCALL | |
| cpu_vmemoryread_f(int idx, UINT32 offset) | |
| { | |
| descriptor_t *sd; | |
| UINT32 addr; | |
| int exc; | |
| __ASSERT((unsigned int)idx < CPU_SEGREG_NUM); | |
| sd = &CPU_STAT_SREG(idx); | |
| if (!sd->valid) { | |
| exc = GP_EXCEPTION; | |
| goto err; | |
| } | |
| if (!(sd->flag & CPU_DESC_FLAG_READABLE)) { | |
| cpu_memoryread_check(sd, offset, 10, | |
| (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION); | |
| } else { | |
| switch (sd->type) { | |
| case 4: case 5: case 6: case 7: | |
| if (offset - (10 - 1) <= sd->u.seg.limit) | |
| goto range_failure; | |
| break; | |
| default: | |
| if (offset > sd->u.seg.limit - (10 - 1)) | |
| goto range_failure; | |
| break; | |
| } | |
| } | |
| addr = sd->u.seg.segbase + offset; | |
| check_memory_break_point(addr, 10, CPU_DR7_RW_RO); | |
| if (!CPU_STAT_PAGING) | |
| return cpu_memoryread_f(addr); | |
| return cpu_linear_memory_read_f(addr, CPU_PAGE_READ_DATA | CPU_STAT_USER_MODE); | |
| range_failure: | |
| if (idx == CPU_SS_INDEX) { | |
| exc = SS_EXCEPTION; | |
| } else { | |
| exc = GP_EXCEPTION; | |
| } | |
| VERBOSE(("cpu_vmemoryread_f: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit)); | |
| err: | |
| EXCEPTION(exc, 0); | |
| { | |
| REG80 dummy; | |
| memset(&dummy, 0, sizeof(dummy)); | |
| return dummy; /* compiler happy */ | |
| } | |
| } | |
| void MEMCALL | |
| cpu_vmemorywrite_f(int idx, UINT32 offset, const REG80 *value) | |
| { | |
| descriptor_t *sd; | |
| UINT32 addr; | |
| int exc; | |
| __ASSERT((unsigned int)idx < CPU_SEGREG_NUM); | |
| sd = &CPU_STAT_SREG(idx); | |
| if (!sd->valid) { | |
| exc = GP_EXCEPTION; | |
| goto err; | |
| } | |
| if (!(sd->flag & CPU_DESC_FLAG_WRITABLE)) { | |
| cpu_memorywrite_check(sd, offset, 10, | |
| (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION); | |
| } else { | |
| switch (sd->type) { | |
| case 6: case 7: | |
| if (offset - (10 - 1) <= sd->u.seg.limit) | |
| goto range_failure; | |
| break; | |
| default: | |
| if (offset > sd->u.seg.limit - (10 - 1)) | |
| goto range_failure; | |
| break; | |
| } | |
| } | |
| addr = sd->u.seg.segbase + offset; | |
| check_memory_break_point(addr, 10, CPU_DR7_RW_RW); | |
| if (!CPU_STAT_PAGING) { | |
| cpu_memorywrite_f(addr, value); | |
| } else { | |
| cpu_linear_memory_write_f(addr, value, CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE); | |
| } | |
| return; | |
| range_failure: | |
| if (idx == CPU_SS_INDEX) { | |
| exc = SS_EXCEPTION; | |
| } else { | |
| exc = GP_EXCEPTION; | |
| } | |
| VERBOSE(("cpu_vmemorywrite_f: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit)); | |
| err: | |
| EXCEPTION(exc, 0); | |
| } |