|
|
| version 1.25, 2004/06/15 13:50:13 | version 1.29, 2007/02/06 14:20:57 |
|---|---|
| Line 12 | Line 12 |
| * 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the | * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. | * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products | |
| * derived from this software without specific prior written permission. | |
| * | * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| Line 184 static const UINT8 page_access_bit[32] = | Line 182 static const UINT8 page_access_bit[32] = |
| * +- CR3(物理アドレス) | * +- CR3(物理アドレス) |
| */ | */ |
| static UINT32 MEMCALL paging(const UINT32 laddr, const int ucrw) GCC_ATTR_REGPARM; | static UINT32 MEMCALL paging(const UINT32 laddr, const int ucrw); |
| #if defined(IA32_SUPPORT_TLB) | #if defined(IA32_SUPPORT_TLB) |
| static void MEMCALL tlb_update(const UINT32 laddr, const UINT entry, const int ucrw) GCC_ATTR_REGPARM; | static void MEMCALL tlb_update(const UINT32 laddr, const UINT entry, const int ucrw); |
| #endif | #endif |
| #if defined(IA32_PAGING_EACHSIZE) | |
| UINT8 MEMCALL | UINT8 MEMCALL |
| cpu_memory_access_la_RMW_b(UINT32 laddr, UINT32 (*func)(UINT32, void *), void *arg) | cpu_memory_access_la_RMW_b(UINT32 laddr, UINT32 (*func)(UINT32, void *), void *arg) |
| { | { |
| Line 334 cpu_linear_memory_read_d(UINT32 laddr, c | Line 331 cpu_linear_memory_read_d(UINT32 laddr, c |
| case 1: | case 1: |
| value = cpu_memoryread(paddr[0]); | value = cpu_memoryread(paddr[0]); |
| value += (UINT32)cpu_memoryread(paddr[1]) << 8; | value += (UINT32)cpu_memoryread_w(paddr[1]) << 8; |
| value += (UINT32)cpu_memoryread_w(paddr[1] + 1) << 16; | value += (UINT32)cpu_memoryread(paddr[1] + 2) << 24; |
| break; | break; |
| default: | default: |
| ia32_panic("cpu_linear_memory_read_d(): out of range (remain = %d)\n", remain); | ia32_panic("cpu_linear_memory_read_d(): out of range (remain = %d)\n", remain); |
| return (UINT32)-1; | value = (UINT32)-1; |
| break; | |
| } | |
| return value; | |
| } | |
| } | |
| UINT64 MEMCALL | |
| cpu_linear_memory_read_q(UINT32 laddr, const int ucrw) | |
| { | |
| UINT32 paddr[2]; | |
| UINT64 value; | |
| UINT remain; | |
| paddr[0] = paging(laddr, ucrw); | |
| remain = 0x1000 - (laddr & 0x00000fff); | |
| if (remain >= 8) { | |
| return cpu_memoryread_q(paddr[0]); | |
| } else { | |
| paddr[1] = paging(laddr + remain, ucrw); | |
| switch (remain) { | |
| case 7: | |
| value = cpu_memoryread(paddr[0]); | |
| value += (UINT64)cpu_memoryread_w(paddr[0] + 1) << 8; | |
| value += (UINT64)cpu_memoryread_d(paddr[0] + 3) << 24; | |
| value += (UINT64)cpu_memoryread(paddr[1]) << 56; | |
| break; | |
| case 6: | |
| value = cpu_memoryread_w(paddr[0]); | |
| value += (UINT64)cpu_memoryread_d(paddr[0] + 2) << 16; | |
| value += (UINT64)cpu_memoryread_w(paddr[1]) << 48; | |
| break; | |
| case 5: | |
| value = cpu_memoryread(paddr[0]); | |
| value += (UINT64)cpu_memoryread_d(paddr[0] + 1) << 8; | |
| value += (UINT64)cpu_memoryread_w(paddr[1]) << 40; | |
| value += (UINT64)cpu_memoryread(paddr[1] + 1) << 56; | |
| break; | |
| case 4: | |
| value = cpu_memoryread_d(paddr[0]); | |
| value += (UINT64)cpu_memoryread_d(paddr[1]) << 32; | |
| break; | |
| case 3: | |
| value = cpu_memoryread(paddr[0]); | |
| value += (UINT64)cpu_memoryread_w(paddr[0] + 1) << 8; | |
| value += (UINT64)cpu_memoryread_d(paddr[1]) << 24; | |
| value += (UINT64)cpu_memoryread(paddr[1] + 4) << 56; | |
| break; | |
| case 2: | |
| value = cpu_memoryread_w(paddr[0]); | |
| value += (UINT64)cpu_memoryread_d(paddr[1]) << 16; | |
| value += (UINT64)cpu_memoryread_w(paddr[1] + 4) << 48; | |
| break; | |
| case 1: | |
| value = cpu_memoryread(paddr[0]); | |
| value += (UINT64)cpu_memoryread_d(paddr[1]) << 8; | |
| value += (UINT64)cpu_memoryread_w(paddr[1] + 4) << 40; | |
| value += (UINT64)cpu_memoryread(paddr[1] + 6) << 56; | |
| break; | |
| default: | |
| ia32_panic("cpu_linear_memory_read_q(): out of range (remain = %d)\n", remain); | |
| value = (UINT64)-1; | |
| break; | |
| } | |
| } | |
| return value; | |
| } | |
| REG80 MEMCALL | |
| cpu_linear_memory_read_f(UINT32 laddr, const int ucrw) | |
| { | |
| UINT32 paddr[2]; | |
| REG80 value; | |
| UINT remain; | |
| UINT i, j; | |
| paddr[0] = paging(laddr, ucrw); | |
| remain = 0x1000 - (laddr & 0x00000fff); | |
| if (remain >= 10) { | |
| return cpu_memoryread_f(paddr[0]); | |
| } else { | |
| paddr[1] = paging(laddr + remain, ucrw); | |
| for (i = 0; i < remain; ++i) { | |
| value.b[i] = cpu_memoryread(paddr[0] + i); | |
| } | |
| for (j = 0; i < 10; ++i, ++j) { | |
| value.b[i] = cpu_memoryread(paddr[1] + j); | |
| } | } |
| return value; | return value; |
| } | } |
| Line 399 cpu_linear_memory_write_d(UINT32 laddr, | Line 489 cpu_linear_memory_write_d(UINT32 laddr, |
| case 1: | case 1: |
| cpu_memorywrite(paddr[0], (UINT8)value); | cpu_memorywrite(paddr[0], (UINT8)value); |
| cpu_memorywrite(paddr[1], (UINT8)(value >> 8)); | cpu_memorywrite_w(paddr[1], (UINT16)(value >> 8)); |
| cpu_memorywrite_w(paddr[1] + 1, (UINT16)(value >> 16)); | cpu_memorywrite(paddr[1] + 2, (UINT8)(value >> 24)); |
| break; | break; |
| } | } |
| } | } |
| } | } |
| #else /* !IA32_PAGING_EACHSIZE */ | void MEMCALL |
| cpu_linear_memory_write_q(UINT32 laddr, UINT64 value, const int user_mode) | |
| UINT32 MEMCALL | |
| cpu_memory_access_la_RMW(UINT32 laddr, UINT length, UINT32 (*func)(UINT32, void *), void *arg) | |
| { | { |
| const int ucrw = CPU_PAGE_WRITE|CPU_PAGE_DATA|CPU_STAT_USER_MODE; | const int ucrw = CPU_PAGE_WRITE|CPU_PAGE_DATA|user_mode; |
| UINT32 result, value; | |
| UINT32 paddr[2]; | UINT32 paddr[2]; |
| UINT remain; | UINT remain; |
| paddr[0] = paging(laddr, ucrw); | paddr[0] = paging(laddr, ucrw); |
| remain = 0x1000 - (laddr & 0x00000fff); | remain = 0x1000 - (laddr & 0x00000fff); |
| if (remain >= length) { | if (remain >= 8) { |
| /* fast mode */ | cpu_memorywrite_q(paddr[0], value); |
| switch (length) { | } else { |
| case 4: | paddr[1] = paging(laddr + remain, ucrw); |
| value = cpu_memoryread_d(paddr[0]); | switch (remain) { |
| result = (*func)(value, arg); | case 7: |
| cpu_memorywrite_d(paddr[0], result); | cpu_memorywrite(paddr[0], (UINT8)value); |
| cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8)); | |
| cpu_memorywrite_d(paddr[0] + 3, (UINT32)(value >> 24)); | |
| cpu_memorywrite(paddr[1], (UINT8)(value >> 56)); | |
| break; | break; |
| case 2: | case 6: |
| value = cpu_memoryread_w(paddr[0]); | cpu_memorywrite_d(paddr[0] + 2, (UINT32)(value >> 16)); |
| result = (*func)(value, arg); | cpu_memorywrite_w(paddr[1], (UINT16)(value >> 48)); |
| cpu_memorywrite_w(paddr[0], (UINT16)result); | |
| break; | break; |
| case 1: | case 5: |
| value = cpu_memoryread(paddr[0]); | cpu_memorywrite(paddr[0], (UINT8)value); |
| result = (*func)(value, arg); | cpu_memorywrite_d(paddr[0] + 1, (UINT32)(value >> 8)); |
| cpu_memorywrite(paddr[0], (UINT8)result); | cpu_memorywrite_w(paddr[1], (UINT16)(value >> 40)); |
| cpu_memorywrite(paddr[1] + 2, (UINT8)(value >> 56)); | |
| break; | break; |
| default: | |
| ia32_panic("cpu_memory_access_la_RMW(): invalid length (length = %d)\n", length); | |
| return (UINT32)-1; | |
| } | |
| return value; | |
| } | |
| /* slow mode */ | |
| paddr[1] = paging(laddr + remain, ucrw); | |
| switch (remain) { | |
| case 3: | |
| value = cpu_memoryread(paddr[0]); | |
| value += (UINT32)cpu_memoryread_w(paddr[0] + 1) << 8; | |
| value += (UINT32)cpu_memoryread(paddr[1]) << 24; | |
| result = (*func)(value, arg); | |
| cpu_memorywrite(paddr[0], (UINT8)result); | |
| cpu_memorywrite_w(paddr[0] + 1, (UINT16)(result >> 8)); | |
| cpu_memorywrite(paddr[1], (UINT8)(result >> 24)); | |
| break; | |
| case 2: | |
| value = cpu_memoryread_w(paddr[0]); | |
| value += (UINT32)cpu_memoryread_w(paddr[1]) << 16; | |
| result = (*func)(value, arg); | |
| cpu_memorywrite_w(paddr[0], (UINT16)result); | |
| cpu_memorywrite_w(paddr[1], (UINT16)(result >> 16)); | |
| break; | |
| case 1: | |
| value = cpu_memoryread(paddr[0]); | |
| value += (UINT32)cpu_memoryread(paddr[1]) << 8; | |
| if (length == 4) { | |
| value += (UINT32)cpu_memoryread_w(paddr[1] + 1) << 16; | |
| } | |
| result = (*func)(value, arg); | |
| cpu_memorywrite(paddr[0], (UINT8)result); | |
| cpu_memorywrite(paddr[1], (UINT8)(result >> 8)); | |
| if (length == 4) { | |
| cpu_memorywrite_w(paddr[1] + 1, (UINT16)(result >> 16)); | |
| } | |
| break; | |
| default: | |
| ia32_panic("cpu_memory_access_la_RMW(): out of range (remain = %d)\n", remain); | |
| return (UINT32)-1; | |
| } | |
| return value; | |
| } | |
| UINT32 MEMCALL | |
| cpu_linear_memory_read(UINT32 laddr, UINT length, const int ucrw) | |
| { | |
| UINT32 value; | |
| UINT32 paddr[2]; | |
| UINT remain; | |
| paddr[0] = paging(laddr, ucrw); | |
| remain = 0x1000 - (laddr & 0x00000fff); | |
| if (remain >= length) { | |
| /* fast mode */ | |
| switch (length) { | |
| case 4: | case 4: |
| value = cpu_memoryread_d(paddr[0]); | cpu_memorywrite_d(paddr[0], (UINT32)value); |
| cpu_memorywrite_d(paddr[1], (UINT32)(value >> 32)); | |
| break; | |
| case 3: | |
| cpu_memorywrite(paddr[0], (UINT8)value); | |
| cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8)); | |
| cpu_memorywrite_d(paddr[1], (UINT32)(value >> 24)); | |
| cpu_memorywrite(paddr[1] + 4, (UINT8)(value >> 56)); | |
| break; | break; |
| case 2: | case 2: |
| value = cpu_memoryread_w(paddr[0]); | cpu_memorywrite_w(paddr[0], (UINT16)value); |
| cpu_memorywrite_d(paddr[1], (UINT32)(value >> 16)); | |
| cpu_memorywrite_w(paddr[1] + 4, (UINT16)(value >> 48)); | |
| break; | break; |
| case 1: | case 1: |
| value = cpu_memoryread(paddr[0]); | cpu_memorywrite(paddr[0], (UINT8)value); |
| cpu_memorywrite_d(paddr[1], (UINT32)(value >> 8)); | |
| cpu_memorywrite_w(paddr[1] + 4, (UINT16)(value >> 40)); | |
| cpu_memorywrite(paddr[1] + 6, (UINT8)(value >> 56)); | |
| break; | break; |
| default: | |
| ia32_panic("cpu_linear_memory_read(): invalid length (length = %d)\n", length); | |
| return (UINT32)-1; | |
| } | } |
| return value; | |
| } | |
| /* slow mode */ | |
| paddr[1] = paging(laddr + remain, ucrw); | |
| switch (remain) { | |
| case 3: | |
| value = cpu_memoryread(paddr[0]); | |
| value += (UINT32)cpu_memoryread_w(paddr[0] + 1) << 8; | |
| value += (UINT32)cpu_memoryread(paddr[1]) << 24; | |
| break; | |
| case 2: | |
| value = cpu_memoryread_w(paddr[0]); | |
| value += (UINT32)cpu_memoryread_w(paddr[1]) << 16; | |
| break; | |
| case 1: | |
| value = cpu_memoryread(paddr[0]); | |
| value += (UINT32)cpu_memoryread(paddr[1]) << 8; | |
| if (length == 4) { | |
| value += (UINT32)cpu_memoryread_w(paddr[1] + 1) << 16; | |
| } | |
| break; | |
| default: | |
| ia32_panic("cpu_linear_memory_read(): out of range (remain = %d)\n", remain); | |
| return (UINT32)-1; | |
| } | } |
| return value; | |
| } | } |
| void MEMCALL | void MEMCALL |
| cpu_linear_memory_write(UINT32 laddr, UINT32 value, UINT length, const int user_mode) | cpu_linear_memory_write_f(UINT32 laddr, const REG80 *value, const int user_mode) |
| { | { |
| const int ucrw = CPU_PAGE_WRITE|CPU_PAGE_DATA|user_mode; | const int ucrw = CPU_PAGE_WRITE|CPU_PAGE_DATA|user_mode; |
| UINT32 paddr[2]; | UINT32 paddr[2]; |
| UINT remain; | UINT remain; |
| UINT i, j; | |
| paddr[0] = paging(laddr, ucrw); | paddr[0] = paging(laddr, ucrw); |
| remain = 0x1000 - (laddr & 0x00000fff); | remain = 0x1000 - (laddr & 0x00000fff); |
| if (remain >= length) { | if (remain >= 10) { |
| /* fast mode */ | cpu_memorywrite_f(paddr[0], value); |
| switch (length) { | } else { |
| case 4: | paddr[1] = paging(laddr + remain, ucrw); |
| cpu_memorywrite_d(paddr[0], value); | for (i = 0; i < remain; ++i) { |
| break; | cpu_memorywrite(paddr[0] + i, value->b[i]); |
| case 2: | |
| cpu_memorywrite_w(paddr[0], (UINT16)value); | |
| break; | |
| case 1: | |
| cpu_memorywrite(paddr[0], (UINT8)value); | |
| break; | |
| default: | |
| ia32_panic("cpu_linear_memory_write(): invalid length (length = %d)\n", length); | |
| break; | |
| } | } |
| return; | for (j = 0; i < 10; ++i, ++j) { |
| } | cpu_memorywrite(paddr[1] + j, value->b[i]); |
| /* slow mode */ | |
| paddr[1] = paging(laddr + remain, ucrw); | |
| switch (remain) { | |
| case 3: | |
| cpu_memorywrite(paddr[0], (UINT8)value); | |
| cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8)); | |
| cpu_memorywrite(paddr[1], (UINT8)(value >> 24)); | |
| break; | |
| case 2: | |
| cpu_memorywrite_w(paddr[0], (UINT16)value); | |
| cpu_memorywrite_w(paddr[1], (UINT16)(value >> 16)); | |
| break; | |
| case 1: | |
| cpu_memorywrite(paddr[0], (UINT8)value); | |
| cpu_memorywrite(paddr[1], (UINT8)(value >> 8)); | |
| if (length == 4) { | |
| cpu_memorywrite_w(paddr[1] + 1, (UINT16)(value >> 16)); | |
| } | } |
| break; | |
| default: | |
| ia32_panic("cpu_linear_memory_write(): out of range (remain = %d)\n", remain); | |
| break; | |
| } | } |
| } | } |
| #endif /* IA32_PAGING_EACHSIZE */ | |
| void MEMCALL | void MEMCALL |
| cpu_memory_access_la_region(UINT32 laddr, UINT length, const int ucrw, BYTE *data) | cpu_memory_access_la_region(UINT32 laddr, UINT length, const int ucrw, BYTE *data) |
| Line 782 do { \ | Line 755 do { \ |
| #define TLB_IS_WRITABLE(ep) ((ep)->tag & CPU_PTE_WRITABLE) | #define TLB_IS_WRITABLE(ep) ((ep)->tag & CPU_PTE_WRITABLE) |
| #define TLB_IS_USERMODE(ep) ((ep)->tag & CPU_PTE_USER_MODE) | #define TLB_IS_USERMODE(ep) ((ep)->tag & CPU_PTE_USER_MODE) |
| #define TLB_IS_DIRTY(ep) ((ep)->tag & TLB_ENTRY_TAG_DIRTY) | #define TLB_IS_DIRTY(ep) ((ep)->tag & TLB_ENTRY_TAG_DIRTY) |
| #if (CPU_FEATURES & CPU_FEATURE_PGE) == CPU_FEATURE_PGE | |
| #define TLB_IS_GLOBAL(ep) ((ep)->tag & TLB_ENTRY_TAG_GLOBAL) | #define TLB_IS_GLOBAL(ep) ((ep)->tag & TLB_ENTRY_TAG_GLOBAL) |
| #else | |
| #define TLB_IS_GLOBAL(ep) FALSE | |
| #endif | |
| #define TLB_SET_TAG_FLAGS(ep, entry, bit) \ | #define TLB_SET_TAG_FLAGS(ep, entry, bit) \ |
| do { \ | do { \ |