| version 1.8, 2004/02/03 14:27:07 | version 1.36, 2012/01/08 18:26:10 | 
| Line 1 | Line 1 | 
 | /*      $Id$    */ |  | 
 |  |  | 
 | /* | /* | 
| * Copyright (c) 2003 NONAKA Kimihiro | * Copyright (c) 2003-2004 NONAKA Kimihiro | 
 | * All rights reserved. | * All rights reserved. | 
 | * | * | 
 | * Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | 
| Line 12 | Line 10 | 
 | * 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 32 | Line 28 | 
 | #include "ia32.mcr" | #include "ia32.mcr" | 
 |  |  | 
 | /* | /* | 
| * ¡¦¥ì¡£¥·¡¦¥¯¡¦¥æ¡¦¥¥¡¦ö§¥Í¥Û浡¼ | * åãÔ妾å⥯åãÊ夫å㥩åã°æ¥»¶ç¡¢  * | 
| * 4-31: ͽÌóºÑ¤ß | * 4-31: äººÑ¤ß | 
| *    3: RSVD: 0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤ÏͽÌó¥Ó¥Ã¥È°ãÈ¿¤Ç¤Ï¤Ê¤«¤Ã¤¿¡¥ | *    3: RSVD: 0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤ÏͽÌó¥Ó¥Ã¥È°ãÈ¿¤Ç¤Ï¤Ê¤«¤Ã¤¿¡¥ | 
| *             1 = ¥Ú¡¼¥¸¡¦¥Õ¥©¥ë¥È¤Î¸¶°ø¤Ï¡¤°ãÈ¿¤È¥Þ¡¼¥¯¤µ¤ì¤¿ PTE ¤Þ¤¿¤Ï | *             1 = ¥Ú¡¼¥¸¡¦¥Õ¥©¥ë¥È¤Î¸¶°ø¤Ï¡¤°ãÈ¿¤È¥Þ¡¼¥¯¤µ¤ì¤¿ PTE ¤Þ¤¿¤Ï | 
| *                 PDE ¤ÎͽÌó¥Ó¥Ã¥È°ÌÃ֤Τ¦¤Á°ì¤Ä¤Ç¡¤1 ¤¬¸¡½Ð¤µ¤ì¤¿¤³¤È¤Ç¤¢¤ë¡¥ | *                 PDE ¤ÎͽÌó¥Ó¥Ã¥È°ÌÃ֤Τ¦¤Á°ì¤Ä¤Ç¡¤1 ¤¬¸¡½Ð¤µ¤ì¤¿¤³¤È¤Ç¤¢¤ë¡¥ | 
| *    2: U/S:  0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤Ï¥×¥í¥»¥Ã¥µ¤¬¥¹¡¼¥Ñ¥Ð¥¤¥¶¡¦ | *    2: U/S:  0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤Ï¥×¥í¥»¥Ã¥µ¤¬¥¹¡¼¥Ñ¥Ð¥¤¥¶¡¦ | 
| *                 ¥â¡¼¥É¤Ç¼Â¹ÔÃæ¤Ë¹Ô¤ï¤ì¤¿¡¥ | *                 ¥â¡¼¥É¤Ç¼Â¹ÔÃæ¤Ë¹Ô¤ï¤ì¤¿¡¥ | 
| *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤Ï¥×¥í¥»¥Ã¥µ¤¬¥æ¡¼¥¶¡¦¥â¡¼¥É¤Ç | *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤Ï¥×¥í¥»¥Ã¥µ¤¬¥æ¡¼¥¶¡¦¥â¡¼¥É¤Ç | 
| *                 ¼Â¹ÔÃæ¤Ë¹Ô¤ï¤ì¤¿¡¥ | *                 ¼Â¹ÔÃæ¤Ë¹Ô¤ï¤ì¤¿¡¥ | 
| *    1: W/R:  0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤¬ÆÉ¤ß¼è¤ê¤Ç¤¢¤Ã¤¿¡¥ | *    1: W/R:  0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤¬ÆÉ¤ß¼è¤ê¤Ç¤¢¤Ã¤¿¡¥ | 
| *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤¬½ñ¤¹þ¤ß¤Ç¤¢¤Ã¤¿¡¥ | *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤¬½ñ¤¹þ¤ß¤Ç¤¢¤Ã¤¿¡¥ | 
| *    0: P:    0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤¬ÉԺߥڡ¼¥¸¤Ç¤¢¤Ã¤¿¡¥ | *    0: P:    0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤¬ÉԺߥڡ¼¥¸¤Ç¤¢¤Ã¤¿¡¥ | 
| *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤¬¥Ú¡¼¥¸¡¦¥ì¥Ù¥ëÊݸî°ãÈ¿¤Ç¤¢¤Ã¤¿¡¥ | *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤¬¥Ú¡¼¥¸¡¦¥ì¥Ù¥ëÊݸî°ãÈ¿¤Ç¤¢¤Ã¤¿¡¥ | 
 | */ | */ | 
 |  |  | 
 | /* | /* | 
| * ²¼´¬ 4.12. ¥Ú¡¼¥¸Êݸî¤È¥»¥°¥á¥ó¥ÈÊݸî¤ÎÁȤ߹ç¤ï¤» | * ä¸ 4.12. ¥Ú¡¼¥¸Êݸî¤È¥»¥°¥á¥ó¥ÈÊݸî¤ÎÁȤ߹ç¤ï¤» | 
| * ¡Öɽ 4-2. ¥Ú¡¼¥¸¡¦¥Ç¥£¥ì¥¯¥È¥ê¤È¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë¤ÎÊݸî¤ÎÁȤ߹ç¤ï¤»¡× | * ¡Öɽ 4-2. ¥Ú¡¼¥¸¡¦¥Ç¥£¥ì¥¯¥È¥ê¤È¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë¤ÎÊݸî¤ÎÁȤ߹ç¤ï¤»¡× | 
 | * | * | 
 | * +------------+------------+------------+ | * +------------+------------+------------+ | 
 | * |    PDE     |    PTE     |   merge    | | * |    PDE     |    PTE     |   merge    | | 
| Line 75 | Line 71 | 
 | * |  s  |  rw  |  s  |  rw  |  s  |  rw  | | * |  s  |  rw  |  s  |  rw  |  s  |  rw  | | 
 | * +-----+------+-----+------+-----+------+ | * +-----+------+-----+------+-----+------+ | 
 | * | * | 
| * ¡Ö¥£ rw/p : CR0 ¡¢¥Û WP ¡¦¥â¡¦¥Æ¡¦¥Í¡¢¥ã ON ¡¢¥Û¥»ø»î¦¥Ò¡¢¥Þ ro | * ãॵ rw/p : CR0 åá¥ç WP åãÆå¥ãåã°å¡ì ON åá¥çꢥ¨éð°å¢åá¥Ã ro | 
 | */ | */ | 
 |  |  | 
 | /* | /* | 
| * ¡¦â§ä§ô§¡Ö¡¦¥Ã¡¦¥µ¡¦¥±/PxE(¥»ê·¥å¥µ¥¤¥»¥Í)/CPL/CR0 ¡¢¥Í¡¦¥ì¡£¥·¡¦¥¯¡¦¡Ö¡¦¥Ã¡¦¥µ¡¦¥±¥¯¡Ö¡¢¥Û¥¨¥ê¥¥¯ | * åã¡£åã¡Öå㥧åâ¡Öåâ¥Ãå⥵å⥱/PxE(躴ꥣÐç½âí奡)/CPL/CR0 åᥣåãÔ妾å⥯åâ¡Öåâ¥Ãå⥵å⥱쪥¥åá¥çñö¡ÖèÁ   * | 
 | * +-----+-----+-----+-----+-----+---+ | * +-----+-----+-----+-----+-----+---+ | 
 | * | CR0 | CPL | PxE | PxE | ope |   | | * | CR0 | CPL | PxE | PxE | ope |   | | 
| Line 114 | Line 110 | 
 | #if !defined(USE_PAGE_ACCESS_TABLE) | #if !defined(USE_PAGE_ACCESS_TABLE) | 
 | #define page_access     0xd0ddd0ff | #define page_access     0xd0ddd0ff | 
 | #else   /* USE_PAGE_ACCESS_TABLE */ | #else   /* USE_PAGE_ACCESS_TABLE */ | 
| static const BYTE page_access_bit[32] = { | static const UINT8 page_access_bit[32] = { | 
 | 1,      /* CR0: n, CPL: s, PTE: s, PTE: r, ope: r */ | 1,      /* CR0: n, CPL: s, PTE: s, PTE: r, ope: r */ | 
 | 1,      /* CR0: n, CPL: s, PTE: s, PTE: r, ope: w */ | 1,      /* CR0: n, CPL: s, PTE: s, PTE: r, ope: w */ | 
 | 1,      /* CR0: n, CPL: s, PTE: s, PTE: w, ope: r */ | 1,      /* CR0: n, CPL: s, PTE: s, PTE: w, ope: r */ | 
| Line 159  static const BYTE page_access_bit[32] = | Line 155  static const BYTE page_access_bit[32] = | 
 |  |  | 
 | /* | /* | 
 | *-- | *-- | 
| * 32bit ʪÍý¥¢¥É¥ì¥¹ 4k ¥Ú¡¼¥¸ | * 32bit í饥íð¬å¤¤åã²å¦®å⥱ 4k åãÔ妾å⥯ | 
 | * | * | 
| * ¡¦ô§¥Ò¡¦¡Ö¡£¥ò¡¦¡Ö¡¦¥Î¡¦ø§¥± | * å㥧åã¶å¤¤å㥵åâ¡Öåã²å¦®å⥱ | 
 | *  31                    22 21                  12 11                       0 | *  31                    22 21                  12 11                       0 | 
 | * +------------------------+----------------------+--------------------------+ | * +------------------------+----------------------+--------------------------+ | 
| * |  ¡¦¥ì¡£¥·¡¦¥¯¡£¥ò¡¦¥Ì¡¦¡×¡¦ø§¥Ã¡¦¥Í¡¦ |   ¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë   |        ¥ª¥Õ¥»¥Ã¥È        | | * |  åãÔ妾å⥯å㥵åã®å¤¥åã¥ãåâ¥Ãåã°å¦¬  |   åãÔ妾å⥯å㥵åã¬å¦¾åãÌå¦   |        å⥧åãÊ夽åã¦å¥è        | | 
 | * +------------------------+----------------------+--------------------------+ | * +------------------------+----------------------+--------------------------+ | 
 | *             |                        |                       | | *             |                        |                       | | 
 | * +-----------+            +-----------+                       +----------+ | * +-----------+            +-----------+                       +----------+ | 
 | * |                        |                                              | | * |                        |                                              | | 
| * |  ¡¦¥ì¡£¥·¡¦¥¯¡£¥ò¡¦¥Ì¡¦¡×¡¦ø§¥Ã¡¦¥Í¡¦ |   ¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë            ¥Ú¡¼¥¸         | | * |  ¥Ú¡¼¥¸¡¦¥Ç¥£¥ì¥¯¥È¥ê  |   ¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë            ¥Ú¡¼¥¸         | | 
 | * | +--------------------+ | +-------------------+   +------------------+ | | * | +--------------------+ | +-------------------+   +------------------+ | | 
 | * | |                    | | |                   |   |                  | | | * | |                    | | |                   |   |                  | | | 
 | * | |                    | | +-------------------+   |                  | | | * | |                    | | +-------------------+   |                  | | | 
| Line 181  static const BYTE page_access_bit[32] = | Line 177  static const BYTE page_access_bit[32] = | 
 | *   |                    | | |                   | | |                  | | *   |                    | | |                   | | |                  | | 
 | * +>+--------------------+ +>+-------------------+ +>+------------------+ | * +>+--------------------+ +>+-------------------+ +>+------------------+ | 
 | * | | * | | 
| * +- CR3() | * +- CR3(ʪÍý¥¢¥É¥ì¥¹) | 
 | */ | */ | 
 |  |  | 
| static DWORD paging(DWORD laddr, int crw, int user_mode); | /* TLB */ | 
| #if defined(IA32_SUPPORT_TLB) | struct tlb_entry { | 
| static BOOL tlb_lookup(DWORD vaddr, int crw, DWORD* paddr); | UINT32  tag;    /* linear address */ | 
| static void tlb_update(DWORD paddr, DWORD entry, int crw); | #define TLB_ENTRY_TAG_VALID             (1 << 0) | 
| #endif | /*      pde & pte & CPU_PTE_WRITABLE    (1 << 1)        */ | 
|  | /*      pde & pte & CPU_PTE_USER_MODE   (1 << 2)        */ | 
|  | #define TLB_ENTRY_TAG_DIRTY             CPU_PTE_DIRTY           /* (1 << 6) */ | 
|  | #define TLB_ENTRY_TAG_GLOBAL            CPU_PTE_GLOBAL_PAGE     /* (1 << 8) */ | 
|  | #define TLB_ENTRY_TAG_MAX_SHIFT         12 | 
|  | UINT32  paddr;  /* physical address */ | 
|  | }; | 
|  | static void MEMCALL tlb_update(UINT32 laddr, UINT entry, int ucrw); | 
 |  |  | 
 |  | /* paging */ | 
 |  | static UINT32 MEMCALL paging(UINT32 laddr, int ucrw); | 
 |  |  | 
| DWORD MEMCALL | /* | 
| cpu_linear_memory_read(DWORD laddr, DWORD length, int code) | * linear memory access | 
|  | */ | 
|  | /* RMW */ | 
|  | UINT8 MEMCALL | 
|  | cpu_memory_access_la_RMW_b(UINT32 laddr, UINT32 (CPUCALL *func)(UINT32, void *), void *arg) | 
 | { | { | 
| DWORD paddr; | const int ucrw = CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE; | 
| DWORD remain;   /* page remain */ | struct tlb_entry *ep; | 
| DWORD r; | UINT32 paddr; | 
| DWORD shift = 0; | UINT32 result; | 
| DWORD value = 0; | UINT8 value; | 
| int crw; |  | 
| int pl; | /* TLB */ | 
|  | ep = tlb_lookup(laddr, ucrw); | 
| crw = CPU_PAGING_PAGE_READ; | if (ep != NULL) { | 
| crw |= code ? CPU_PAGING_PAGE_CODE : CPU_PAGING_PAGE_DATA; | paddr = ep->paddr + (laddr & PAGE_MASK); | 
| pl = (CPU_STAT_CPL == 3); | goto onepage; | 
|  | } | 
 |  |  | 
| /* XXX: 4MB pages... */ | /* paging */ | 
| remain = 0x1000 - (laddr & 0x00000fff); | paddr = paging(laddr, ucrw); | 
| for (;;) { | onepage: | 
| paddr = paging(laddr, crw, pl); | value = cpu_memoryread(paddr); | 
|  | result = (*func)(value, arg); | 
|  | cpu_memorywrite(paddr, (UINT8)result); | 
|  | return value; | 
|  | } | 
 |  |  | 
| r = (remain > length) ? length : remain; | UINT16 MEMCALL | 
| switch (r) { | cpu_memory_access_la_RMW_w(UINT32 laddr, UINT32 (CPUCALL *func)(UINT32, void *), void *arg) | 
| case 1: | { | 
| value |= (DWORD)cpu_memoryread(paddr) << shift; | const int ucrw = CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE; | 
| shift += 8; | struct tlb_entry *ep[2]; | 
| break; | UINT32 paddr[2]; | 
|  | UINT32 result; | 
|  | UINT16 value; | 
|  |  | 
|  | /* TLB */ | 
|  | ep[0] = tlb_lookup(laddr, ucrw); | 
|  | if (ep[0] != NULL) { | 
|  | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
|  | if ((laddr + 1) & PAGE_MASK) | 
|  | goto onepage; | 
|  |  | 
|  | ep[1] = tlb_lookup(laddr + 1, ucrw); | 
|  | if (ep[1] != NULL) { | 
|  | paddr[1] = ep[1]->paddr + (laddr & PAGE_MASK); | 
|  | goto separate; | 
|  | } | 
|  | } | 
 |  |  | 
| case 2: | /* paging */ | 
| value |= (DWORD)cpu_memoryread_w(paddr) << shift; | paddr[0] = paging(laddr, ucrw); | 
| shift += 16; | if ((laddr + 1) & PAGE_MASK) { | 
| break; | onepage: | 
|  | value = cpu_memoryread_w(paddr[0]); | 
|  | result = (*func)(value, arg); | 
|  | cpu_memorywrite_w(paddr[0], (UINT16)result); | 
|  | return value; | 
|  | } | 
 |  |  | 
| case 3: | paddr[1] = paging(laddr + 1, ucrw); | 
| value |= (DWORD)cpu_memoryread_w(paddr) << shift; | separate: | 
| shift += 16; | value = cpu_memoryread_b(paddr[0]); | 
| value |= (DWORD)cpu_memoryread(paddr + 2) << shift; | value += (UINT16)cpu_memoryread_b(paddr[1]) << 8; | 
| shift += 8; | result = (*func)(value, arg); | 
| break; | cpu_memorywrite(paddr[0], (UINT8)result); | 
|  | cpu_memorywrite(paddr[1], (UINT8)(result >> 8)); | 
|  | return value; | 
|  | } | 
 |  |  | 
| case 4: | UINT32 MEMCALL | 
| value = cpu_memoryread_d(paddr); | cpu_memory_access_la_RMW_d(UINT32 laddr, UINT32 (CPUCALL *func)(UINT32, void *), void *arg) | 
| break; | { | 
|  | const int ucrw = CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE; | 
|  | struct tlb_entry *ep[2]; | 
|  | UINT32 paddr[2]; | 
|  | UINT32 result; | 
|  | UINT32 value; | 
|  | int remain; | 
|  |  | 
|  | /* TLB */ | 
|  | ep[0] = tlb_lookup(laddr, ucrw); | 
|  | if (ep[0] != NULL) { | 
|  | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
|  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
|  | if (remain >= 4) | 
|  | goto onepage; | 
|  |  | 
|  | ep[1] = tlb_lookup(laddr + remain, ucrw); | 
|  | if (ep[1] != NULL) { | 
|  | paddr[1] = ep[1]->paddr + (laddr & PAGE_MASK); | 
|  | goto separate; | 
|  | } | 
|  | } | 
 |  |  | 
| default: | /* paging */ | 
| ia32_panic("cpu_linear_memory_read(): out of range (r = %d)\n", r); | paddr[0] = paging(laddr, ucrw); | 
| break; | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
|  | if (remain >= 4) { | 
|  | onepage: | 
|  | value = cpu_memoryread_d(paddr[0]); | 
|  | result = (*func)(value, arg); | 
|  | cpu_memorywrite_d(paddr[0], result); | 
|  | return value; | 
|  | } | 
|  |  | 
|  | paddr[1] = paging(laddr + remain, ucrw); | 
|  | separate: | 
|  | 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_w(paddr[1]) << 8; | 
|  | value += (UINT32)cpu_memoryread(paddr[1] + 2) << 24; | 
|  | result = (*func)(value, arg); | 
|  | cpu_memorywrite(paddr[0], (UINT8)result); | 
|  | cpu_memorywrite_w(paddr[1], (UINT16)(result >> 8)); | 
|  | cpu_memorywrite(paddr[1] + 2, (UINT8)(result >> 24)); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | ia32_panic("cpu_memory_access_la_RMW_d: out of range (remain=%d)\n", remain); | 
|  | value = 0;      /* XXX compiler happy */ | 
|  | break; | 
|  | } | 
|  | return value; | 
|  | } | 
|  |  | 
|  | /* read */ | 
|  | UINT8 MEMCALL | 
|  | cpu_linear_memory_read_b(UINT32 laddr, int ucrw) | 
|  | { | 
|  | struct tlb_entry *ep; | 
|  | UINT32 paddr; | 
|  |  | 
|  | /* TLB */ | 
|  | ep = tlb_lookup(laddr, ucrw); | 
|  | if (ep != NULL) { | 
|  | paddr = ep->paddr + (laddr & PAGE_MASK); | 
|  | return cpu_memoryread(paddr); | 
|  | } | 
|  |  | 
|  | /* paging */ | 
|  | paddr = paging(laddr, ucrw); | 
|  | return cpu_memoryread(paddr); | 
|  | } | 
|  |  | 
|  | UINT16 MEMCALL | 
|  | cpu_linear_memory_read_w(UINT32 laddr, int ucrw) | 
|  | { | 
|  | struct tlb_entry *ep[2]; | 
|  | UINT32 paddr[2]; | 
|  | UINT16 value; | 
|  |  | 
|  | /* TLB */ | 
|  | ep[0] = tlb_lookup(laddr, ucrw); | 
|  | if (ep[0] != NULL) { | 
|  | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
|  | if ((laddr + 1) & PAGE_MASK) | 
|  | return cpu_memoryread_w(paddr[0]); | 
|  |  | 
|  | ep[1] = tlb_lookup(laddr + 1, ucrw); | 
|  | if (ep[1] != NULL) { | 
|  | paddr[1] = ep[1]->paddr; | 
|  | goto separate; | 
 | } | } | 
 |  | } | 
 |  |  | 
| length -= r; | /* paging */ | 
| if (length == 0) | paddr[0] = paging(laddr, ucrw); | 
| break; | if ((laddr + 1) & PAGE_MASK) | 
|  | return cpu_memoryread_w(paddr[0]); | 
|  |  | 
|  | paddr[1] = paging(laddr + 1, ucrw); | 
|  | separate: | 
|  | value = cpu_memoryread_b(paddr[0]); | 
|  | value += (UINT16)cpu_memoryread_b(paddr[1]) << 8; | 
|  | return value; | 
|  | } | 
 |  |  | 
| laddr += r; | UINT32 MEMCALL | 
| remain -= r; | cpu_linear_memory_read_d(UINT32 laddr, int ucrw) | 
| if (remain <= 0) { | { | 
| /* next page */ | struct tlb_entry *ep[2]; | 
| remain += 0x1000; | UINT32 paddr[2]; | 
|  | UINT32 value; | 
|  | UINT remain; | 
|  |  | 
|  | /* TLB */ | 
|  | ep[0] = tlb_lookup(laddr, ucrw); | 
|  | if (ep[0] != NULL) { | 
|  | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
|  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
|  | if (remain >= sizeof(value)) | 
|  | return cpu_memoryread_d(paddr[0]); | 
|  |  | 
|  | ep[1] = tlb_lookup(laddr + remain, ucrw); | 
|  | if (ep[1] != NULL) { | 
|  | paddr[1] = ep[1]->paddr; | 
|  | goto separate; | 
 | } | } | 
 | } | } | 
 |  |  | 
 |  | /* paging */ | 
 |  | paddr[0] = paging(laddr, ucrw); | 
 |  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
 |  | if (remain >= sizeof(value)) | 
 |  | return cpu_memoryread_d(paddr[0]); | 
 |  |  | 
 |  | paddr[1] = paging(laddr + remain, ucrw); | 
 |  | separate: | 
 |  | 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_w(paddr[1]) << 8; | 
 |  | value += (UINT32)cpu_memoryread(paddr[1] + 2) << 24; | 
 |  | break; | 
 |  |  | 
 |  | default: | 
 |  | ia32_panic("cpu_linear_memory_read_d: out of range (remain=%d)\n", remain); | 
 |  | value = 0;      /* XXX compiler happy */ | 
 |  | break; | 
 |  | } | 
 | return value; | return value; | 
 | } | } | 
 |  |  | 
 |  | UINT64 MEMCALL | 
 |  | cpu_linear_memory_read_q(UINT32 laddr, int ucrw) | 
 |  | { | 
 |  | struct tlb_entry *ep[2]; | 
 |  | UINT32 paddr[2]; | 
 |  | UINT64 value; | 
 |  | UINT remain; | 
 |  |  | 
 |  | /* TLB */ | 
 |  | ep[0] = tlb_lookup(laddr, ucrw); | 
 |  | if (ep[0] != NULL) { | 
 |  | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
 |  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
 |  | if (remain >= sizeof(value)) | 
 |  | return cpu_memoryread_d(paddr[0]); | 
 |  |  | 
 |  | ep[1] = tlb_lookup(laddr + remain, ucrw); | 
 |  | if (ep[1] != NULL) { | 
 |  | paddr[1] = ep[1]->paddr; | 
 |  | goto separate; | 
 |  | } | 
 |  | } | 
 |  |  | 
 |  | /* paging */ | 
 |  | paddr[0] = paging(laddr, ucrw); | 
 |  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
 |  | if (remain >= sizeof(value)) | 
 |  | return cpu_memoryread_q(paddr[0]); | 
 |  |  | 
 |  | paddr[1] = paging(laddr + remain, ucrw); | 
 |  | separate: | 
 |  | 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] + 2) << 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 = 0;      /* XXX compiler happy */ | 
 |  | break; | 
 |  | } | 
 |  | return value; | 
 |  | } | 
 |  |  | 
 |  | REG80 MEMCALL | 
 |  | cpu_linear_memory_read_f(UINT32 laddr, int ucrw) | 
 |  | { | 
 |  | struct tlb_entry *ep[2]; | 
 |  | UINT32 paddr[2]; | 
 |  | REG80 value; | 
 |  | UINT remain; | 
 |  | UINT i, j; | 
 |  |  | 
 |  | /* TLB */ | 
 |  | ep[0] = tlb_lookup(laddr, ucrw); | 
 |  | if (ep[0] != NULL) { | 
 |  | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
 |  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
 |  | if (remain >= sizeof(value)) | 
 |  | return cpu_memoryread_f(paddr[0]); | 
 |  |  | 
 |  | ep[1] = tlb_lookup(laddr + remain, ucrw); | 
 |  | if (ep[1] != NULL) { | 
 |  | paddr[1] = ep[1]->paddr; | 
 |  | goto separate; | 
 |  | } | 
 |  | } | 
 |  |  | 
 |  | /* paging */ | 
 |  | paddr[0] = paging(laddr, ucrw); | 
 |  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
 |  | if (remain >= sizeof(value)) | 
 |  | return cpu_memoryread_f(paddr[0]); | 
 |  |  | 
 |  | paddr[1] = paging(laddr + remain, ucrw); | 
 |  | separate: | 
 |  | 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; | 
 |  | } | 
 |  |  | 
 |  | /* write */ | 
 | void MEMCALL | void MEMCALL | 
| cpu_linear_memory_write(DWORD laddr, DWORD length, DWORD value) | cpu_linear_memory_write_b(UINT32 laddr, UINT8 value, int ucrw) | 
 | { | { | 
| DWORD paddr; | struct tlb_entry *ep; | 
| DWORD remain;   /* page remain */ | UINT32 paddr; | 
| DWORD r; |  | 
| int crw; |  | 
| int pl; |  | 
|  |  | 
| crw = CPU_PAGING_PAGE_WRITE; |  | 
| crw |= CPU_PAGING_PAGE_DATA; |  | 
| pl = (CPU_STAT_CPL == 3); |  | 
 |  |  | 
| /* XXX: 4MB pages... */ | /* TLB */ | 
| remain = 0x1000 - (laddr & 0x00000fff); | ep = tlb_lookup(laddr, ucrw); | 
| for (;;) { | if (ep != NULL) { | 
| paddr = paging(laddr, crw, pl); | paddr = ep->paddr + (laddr & PAGE_MASK); | 
|  | cpu_memorywrite(paddr, value); | 
|  | return; | 
|  | } | 
 |  |  | 
| r = (remain > length) ? length : remain; | /* paging */ | 
| switch (r) { | paddr = paging(laddr, ucrw); | 
| case 1: | cpu_memorywrite(paddr, value); | 
| cpu_memorywrite(paddr, value & 0xff); | } | 
| value >>= 8; |  | 
| break; |  | 
 |  |  | 
| case 2: | void MEMCALL | 
| cpu_memorywrite_w(paddr, value & 0xffff); | cpu_linear_memory_write_w(UINT32 laddr, UINT16 value, int ucrw) | 
| value >>= 16; | { | 
| break; | struct tlb_entry *ep[2]; | 
|  | UINT32 paddr[2]; | 
 |  |  | 
| case 3: | /* TLB */ | 
| cpu_memorywrite_w(paddr, value & 0xffff); | ep[0] = tlb_lookup(laddr, ucrw); | 
| value >>= 16; | if (ep[0] != NULL) { | 
| cpu_memorywrite(paddr + 2, value & 0xff); | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
| value >>= 8; | if ((laddr + 1) & PAGE_MASK) { | 
| break; | cpu_memorywrite_w(paddr[0], value); | 
|  | return; | 
|  | } | 
 |  |  | 
| case 4: | ep[1] = tlb_lookup(laddr + 1, ucrw); | 
| cpu_memorywrite_d(paddr, value); | if (ep[1] != NULL) { | 
| break; | paddr[1] = ep[1]->paddr; | 
|  | goto separate; | 
|  | } | 
|  | } | 
 |  |  | 
| default: | /* paging */ | 
| ia32_panic("cpu_linear_memory_write(): out of range (r = %d)\n", r); | paddr[0] = paging(laddr, ucrw); | 
| break; | if ((laddr + 1) & PAGE_MASK) { | 
|  | cpu_memorywrite_w(paddr[0], value); | 
|  | return; | 
|  | } | 
|  |  | 
|  | paddr[1] = paging(laddr + 1, ucrw); | 
|  | separate: | 
|  | cpu_memorywrite(paddr[0], (UINT8)value); | 
|  | cpu_memorywrite(paddr[1], (UINT8)(value >> 8)); | 
|  | } | 
|  |  | 
|  | void MEMCALL | 
|  | cpu_linear_memory_write_d(UINT32 laddr, UINT32 value, int ucrw) | 
|  | { | 
|  | struct tlb_entry *ep[2]; | 
|  | UINT32 paddr[2]; | 
|  | UINT remain; | 
|  |  | 
|  | /* TLB */ | 
|  | ep[0] = tlb_lookup(laddr, ucrw); | 
|  | if (ep[0] != NULL) { | 
|  | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
|  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
|  | if (remain >= sizeof(value)) { | 
|  | cpu_memorywrite_d(paddr[0], value); | 
|  | return; | 
 | } | } | 
 |  |  | 
| length -= r; | ep[1] = tlb_lookup(laddr + remain, ucrw); | 
| if (length == 0) | if (ep[1] != NULL) { | 
| break; | paddr[1] = ep[1]->paddr; | 
|  | goto separate; | 
|  | } | 
|  | } | 
 |  |  | 
| laddr += r; | /* paging */ | 
| remain -= r; | paddr[0] = paging(laddr, ucrw); | 
| if (remain <= 0) { | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
| /* next page */ | if (remain >= sizeof(value)) { | 
| remain += 0x1000; | cpu_memorywrite_d(paddr[0], value); | 
|  | return; | 
|  | } | 
|  |  | 
|  | paddr[1] = paging(laddr + remain, ucrw); | 
|  | separate: | 
|  | 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_w(paddr[1], (UINT16)(value >> 8)); | 
|  | cpu_memorywrite(paddr[1] + 2, (UINT8)(value >> 24)); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | ia32_panic("cpu_linear_memory_write_d: out of range (remain=%d)\n", remain); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void MEMCALL | 
|  | cpu_linear_memory_write_q(UINT32 laddr, UINT64 value, int ucrw) | 
|  | { | 
|  | struct tlb_entry *ep[2]; | 
|  | UINT32 paddr[2]; | 
|  | UINT remain; | 
|  |  | 
|  | /* TLB */ | 
|  | ep[0] = tlb_lookup(laddr, ucrw); | 
|  | if (ep[0] != NULL) { | 
|  | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
|  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
|  | if (remain >= sizeof(value)) { | 
|  | cpu_memorywrite_q(paddr[0], value); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ep[1] = tlb_lookup(laddr + remain, ucrw); | 
|  | if (ep[1] != NULL) { | 
|  | paddr[1] = ep[1]->paddr; | 
|  | goto separate; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* paging */ | 
|  | paddr[0] = paging(laddr, ucrw); | 
|  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
|  | if (remain >= sizeof(value)) { | 
|  | cpu_memorywrite_q(paddr[0], value); | 
|  | return; | 
|  | } | 
|  |  | 
|  | paddr[1] = paging(laddr + remain, ucrw); | 
|  | separate: | 
|  | switch (remain) { | 
|  | case 7: | 
|  | 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; | 
|  |  | 
|  | case 6: | 
|  | cpu_memorywrite_w(paddr[0], (UINT16)value); | 
|  | cpu_memorywrite_d(paddr[0] + 2, (UINT32)(value >> 16)); | 
|  | cpu_memorywrite_w(paddr[1], (UINT16)(value >> 48)); | 
|  | break; | 
|  |  | 
|  | case 5: | 
|  | cpu_memorywrite(paddr[0], (UINT8)value); | 
|  | cpu_memorywrite_d(paddr[0] + 1, (UINT32)(value >> 8)); | 
|  | cpu_memorywrite_w(paddr[1], (UINT16)(value >> 40)); | 
|  | cpu_memorywrite(paddr[1] + 2, (UINT8)(value >> 56)); | 
|  | break; | 
|  |  | 
|  | case 4: | 
|  | 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; | 
|  |  | 
|  | case 2: | 
|  | 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; | 
|  |  | 
|  | case 1: | 
|  | 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; | 
|  |  | 
|  | default: | 
|  | ia32_panic("cpu_linear_memory_write_q: out of range (remain=%d)\n", remain); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void MEMCALL | 
|  | cpu_linear_memory_write_f(UINT32 laddr, const REG80 *value, int ucrw) | 
|  | { | 
|  | struct tlb_entry *ep[2]; | 
|  | UINT32 paddr[2]; | 
|  | UINT remain; | 
|  | UINT i, j; | 
|  |  | 
|  | /* TLB */ | 
|  | ep[0] = tlb_lookup(laddr, ucrw); | 
|  | if (ep[0] != NULL) { | 
|  | paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK); | 
|  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
|  | if (remain >= sizeof(value)) { | 
|  | cpu_memorywrite_f(paddr[0], value); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ep[1] = tlb_lookup(laddr + remain, ucrw); | 
|  | if (ep[1] != NULL) { | 
|  | paddr[1] = ep[1]->paddr; | 
|  | goto separate; | 
 | } | } | 
 | } | } | 
 |  |  | 
 |  | /* paging */ | 
 |  | paddr[0] = paging(laddr, ucrw); | 
 |  | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
 |  | if (remain >= sizeof(value)) { | 
 |  | cpu_memorywrite_f(paddr[0], value); | 
 |  | return; | 
 |  | } | 
 |  |  | 
 |  | paddr[1] = paging(laddr + remain, ucrw); | 
 |  | separate: | 
 |  | for (i = 0; i < remain; ++i) { | 
 |  | cpu_memorywrite(paddr[0] + i, value->b[i]); | 
 |  | } | 
 |  | for (j = 0; i < 10; ++i, ++j) { | 
 |  | cpu_memorywrite(paddr[1] + j, value->b[i]); | 
 |  | } | 
 | } | } | 
 |  |  | 
 |  | /* | 
 |  | * linear address memory access function | 
 |  | */ | 
 | void MEMCALL | void MEMCALL | 
| paging_check(DWORD laddr, DWORD length, int rw) | cpu_memory_access_la_region(UINT32 laddr, UINT length, int ucrw, UINT8 *data) | 
 | { | { | 
| DWORD paddr; | UINT32 paddr; | 
| DWORD remain;   /* page remain */ | UINT remain;    /* page remain */ | 
| DWORD r; | UINT r; | 
| int crw; |  | 
| int pl; |  | 
 |  |  | 
| crw = rw; | if (length == 0) | 
| pl = (CPU_STAT_CPL == 3); | return; | 
 |  |  | 
| /* XXX: 4MB pages... */ | remain = PAGE_SIZE - (laddr & PAGE_MASK); | 
| remain = 0x1000 - (laddr & 0x00000fff); |  | 
 | for (;;) { | for (;;) { | 
| paddr = paging(laddr, crw, pl); | if (!CPU_STAT_PAGING) { | 
|  | paddr = laddr; | 
|  | } else { | 
|  | paddr = paging(laddr, ucrw); | 
|  | } | 
 |  |  | 
 | r = (remain > length) ? length : remain; | r = (remain > length) ? length : remain; | 
 |  | if (!(ucrw & CPU_PAGE_WRITE)) { | 
 |  | cpu_memoryread_region(paddr, data, r); | 
 |  | } else { | 
 |  | cpu_memorywrite_region(paddr, data, r); | 
 |  | } | 
 |  |  | 
 | length -= r; | length -= r; | 
 | if (length == 0) | if (length == 0) | 
 | break; | break; | 
 |  |  | 
 |  | data += r; | 
 | laddr += r; | laddr += r; | 
 | remain -= r; | remain -= r; | 
 | if (remain <= 0) { | if (remain <= 0) { | 
 | /* next page */ | /* next page */ | 
| remain += 0x1000; | remain += PAGE_SIZE; | 
 | } | } | 
 | } | } | 
 | } | } | 
 |  |  | 
| static DWORD | UINT32 MEMCALL | 
| paging(DWORD laddr, int crw, int user_mode) | laddr2paddr(const UINT32 laddr, int ucrw) | 
 | { | { | 
 | DWORD paddr;    /* physical address */ |  | 
 | DWORD pde_addr; /* page directory entry address */ |  | 
 | DWORD pde;      /* page directory entry */ |  | 
 | DWORD pte_addr; /* page table entry address */ |  | 
 | DWORD pte;      /* page table entry */ |  | 
 | DWORD bit; |  | 
 | DWORD err; |  | 
 |  |  | 
| #if defined(IA32_SUPPORT_TLB) | return paging(laddr, ucrw); | 
| if (tlb_lookup(laddr, crw, &paddr)) | } | 
| return paddr; |  | 
| #endif  /* IA32_SUPPORT_TLB */ | /* | 
|  | * paging | 
|  | */ | 
|  | static UINT32 MEMCALL | 
|  | paging(UINT32 laddr, int ucrw) | 
|  | { | 
|  | UINT32 paddr;           /* physical address */ | 
|  | UINT32 pde_addr;        /* page directory entry address */ | 
|  | UINT32 pde;             /* page directory entry */ | 
|  | UINT32 pte_addr;        /* page table entry address */ | 
|  | UINT32 pte;             /* page table entry */ | 
|  | UINT bit; | 
|  | UINT err; | 
|  | struct tlb_entry *ep; | 
|  |  | 
|  | ep = tlb_lookup(laddr, ucrw); | 
|  | if (ep != NULL) | 
|  | return ep->paddr + (laddr & PAGE_MASK); | 
 |  |  | 
| pde_addr = (CPU_CR3 & CPU_CR3_PD_MASK) | ((laddr >> 20) & 0xffc); | pde_addr = CPU_STAT_PDE_BASE + ((laddr >> 20) & 0xffc); | 
 | pde = cpu_memoryread_d(pde_addr); | pde = cpu_memoryread_d(pde_addr); | 
 | if (!(pde & CPU_PDE_PRESENT)) { | if (!(pde & CPU_PDE_PRESENT)) { | 
| VERBOSE(("paging: PDE is not present")); | VERBOSE(("paging: PTE page is not present")); | 
 | VERBOSE(("paging: CPU_CR3 = 0x%08x", CPU_CR3)); | VERBOSE(("paging: CPU_CR3 = 0x%08x", CPU_CR3)); | 
 | VERBOSE(("paging: laddr = 0x%08x, pde_addr = 0x%08x, pde = 0x%08x", laddr, pde_addr, pde)); | VERBOSE(("paging: laddr = 0x%08x, pde_addr = 0x%08x, pde = 0x%08x", laddr, pde_addr, pde)); | 
 | err = 0; | err = 0; | 
| Line 375  paging(DWORD laddr, int crw, int user_mo | Line 902  paging(DWORD laddr, int crw, int user_mo | 
 | cpu_memorywrite_d(pde_addr, pde); | cpu_memorywrite_d(pde_addr, pde); | 
 | } | } | 
 |  |  | 
| #if CPU_FAMILY >= 5 | pte_addr = (pde & CPU_PDE_BASEADDR_MASK) + ((laddr >> 10) & 0xffc); | 
| /* no support PAE */ | pte = cpu_memoryread_d(pte_addr); | 
| __ASSERT(!(CPU_CR4 & CPU_CR4_PAE)); | if (!(pte & CPU_PTE_PRESENT)) { | 
|  | VERBOSE(("paging: page is not present")); | 
| if ((CPU_CR4 & CPU_CR4_PSE) && (pde & CPU_PDE_PAGE_SIZE)) { | VERBOSE(("paging: laddr = 0x%08x, pde_addr = 0x%08x, pde = 0x%08x", laddr, pde_addr, pde)); | 
| /* 4MB page size */ | VERBOSE(("paging: pte_addr = 0x%08x, pte = 0x%08x", pte_addr, pte)); | 
|  | err = 0; | 
| /* fake PTE bit */ | goto pf_exception; | 
| pte = pde | CPU_PTE_DIRTY; |  | 
| pte_addr = 0;   /* compiler happy */ |  | 
|  |  | 
| /* make physical address */ |  | 
| paddr = (pde & CPU_PDE_4M_BASEADDR_MASK) | (laddr & 0x003fffff); |  | 
| } else |  | 
| #endif  /* CPU_FAMILY >= 5 */ |  | 
| { |  | 
| /* 4KB page size */ |  | 
| pte_addr = (pde & CPU_PDE_BASEADDR_MASK) | ((laddr >> 10) & 0xffc); |  | 
| pte = cpu_memoryread_d(pte_addr); |  | 
| if (!(pte & CPU_PTE_PRESENT)) { |  | 
| VERBOSE(("paging: PTE is not present")); |  | 
| VERBOSE(("paging: laddr = 0x%08x, pde_addr = 0x%08x, pde = 0x%08x", laddr, pde_addr, pde)); |  | 
| VERBOSE(("paging: pte_addr = 0x%08x, pte = 0x%08x", pte_addr, pte)); |  | 
| err = 0; |  | 
| goto pf_exception; |  | 
| } |  | 
| if (!(pte & CPU_PTE_ACCESS)) { |  | 
| pte |= CPU_PTE_ACCESS; |  | 
| cpu_memorywrite_d(pte_addr, pte); |  | 
| } |  | 
|  |  | 
| /* make physical address */ |  | 
| paddr = (pte & CPU_PTE_BASEADDR_MASK) | (laddr & 0x00000fff); |  | 
 | } | } | 
 |  | if (!(pte & CPU_PTE_ACCESS)) { | 
 |  | pte |= CPU_PTE_ACCESS; | 
 |  | cpu_memorywrite_d(pte_addr, pte); | 
 |  | } | 
 |  |  | 
 |  | /* make physical address */ | 
 |  | paddr = (pte & CPU_PTE_BASEADDR_MASK) + (laddr & PAGE_MASK); | 
 |  |  | 
| bit  = crw & CPU_PAGING_PAGE_WRITE; | bit  = ucrw & (CPU_PAGE_WRITE|CPU_PAGE_USER_MODE); | 
 | bit |= (pde & pte & (CPU_PTE_WRITABLE|CPU_PTE_USER_MODE)); | bit |= (pde & pte & (CPU_PTE_WRITABLE|CPU_PTE_USER_MODE)); | 
| bit |= (user_mode << 3); | bit |= CPU_STAT_WP; | 
| bit |= (CPU_CR0 & CPU_CR0_WP) >> 12; |  | 
 |  |  | 
 | #if !defined(USE_PAGE_ACCESS_TABLE) | #if !defined(USE_PAGE_ACCESS_TABLE) | 
 | if (!(page_access & (1 << bit))) | if (!(page_access & (1 << bit))) | 
| Line 429  paging(DWORD laddr, int crw, int user_mo | Line 937  paging(DWORD laddr, int crw, int user_mo | 
 | goto pf_exception; | goto pf_exception; | 
 | } | } | 
 |  |  | 
| if ((crw & CPU_PAGING_PAGE_WRITE) && !(pte & CPU_PTE_DIRTY)) { | if ((ucrw & CPU_PAGE_WRITE) && !(pte & CPU_PTE_DIRTY)) { | 
 | pte |= CPU_PTE_DIRTY; | pte |= CPU_PTE_DIRTY; | 
 | cpu_memorywrite_d(pte_addr, pte); | cpu_memorywrite_d(pte_addr, pte); | 
 | } | } | 
 |  |  | 
| #if defined(IA32_SUPPORT_TLB) | tlb_update(laddr, pte, (bit & (CPU_PTE_WRITABLE|CPU_PTE_USER_MODE)) + ((ucrw & CPU_PAGE_CODE) ? 1 : 0)); | 
| tlb_update(paddr, pte, crw); |  | 
| #endif  /* IA32_SUPPORT_TLB */ |  | 
 |  |  | 
 | return paddr; | return paddr; | 
 |  |  | 
 | pf_exception: | pf_exception: | 
 | CPU_CR2 = laddr; | CPU_CR2 = laddr; | 
| err |= ((crw & CPU_PAGING_PAGE_WRITE) << 1) | (user_mode << 2); | err |= (ucrw & CPU_PAGE_WRITE) << 1; | 
|  | err |= (ucrw & CPU_PAGE_USER_MODE) >> 1; | 
 | EXCEPTION(PF_EXCEPTION, err); | EXCEPTION(PF_EXCEPTION, err); | 
 | return 0;       /* compiler happy */ | return 0;       /* compiler happy */ | 
 | } | } | 
 |  |  | 
 | #if defined(IA32_SUPPORT_TLB) |  | 
 | /* | /* | 
 | * TLB | * TLB | 
 | */ | */ | 
| typedef struct { | #define TLB_TAG_SHIFT           TLB_ENTRY_TAG_MAX_SHIFT | 
| BYTE    valid;  /* TLB entry is valid */ | #define TLB_TAG_MASK            (~((1 << TLB_TAG_SHIFT) - 1)) | 
| BYTE    global; /* this TLB entry is global */ | #define TLB_GET_TAG_ADDR(ep)    ((ep)->tag & TLB_TAG_MASK) | 
| BYTE    score; | #define TLB_SET_TAG_ADDR(ep, addr) \ | 
| BYTE    pad; | do { \ | 
|  | (ep)->tag &= ~TLB_TAG_MASK; \ | 
| DWORD   tag; | (ep)->tag |= (addr) & TLB_TAG_MASK; \ | 
| DWORD   mask;   /* 4K or 2M or 4M */ | } while (/*CONSTCOND(*/ 0) | 
|  |  | 
|  | #define TLB_IS_VALID(ep)        ((ep)->tag & TLB_ENTRY_TAG_VALID) | 
|  | #define TLB_SET_VALID(ep)       ((ep)->tag = TLB_ENTRY_TAG_VALID) | 
|  | #define TLB_SET_INVALID(ep)     ((ep)->tag = 0) | 
|  |  | 
|  | #define TLB_IS_WRITABLE(ep)     ((ep)->tag & CPU_PTE_WRITABLE) | 
|  | #define TLB_IS_USERMODE(ep)     ((ep)->tag & CPU_PTE_USER_MODE) | 
|  | #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) | 
|  | #else | 
|  | #define TLB_IS_GLOBAL(ep)       0 | 
|  | #endif | 
 |  |  | 
| DWORD   paddr;  /* physical addr */ | #define TLB_SET_TAG_FLAGS(ep, entry, bit) \ | 
| } TLB_ENTRY_T; | do { \ | 
|  | (ep)->tag |= (entry) & (CPU_PTE_GLOBAL_PAGE|CPU_PTE_DIRTY); \ | 
|  | (ep)->tag |= (bit) & (CPU_PTE_WRITABLE|CPU_PTE_USER_MODE); \ | 
|  | } while (/*CONSTCOND*/ 0) | 
|  |  | 
|  | #define NTLB            2       /* 0: DTLB, 1: ITLB */ | 
|  | #define NENTRY          (1 << 6) | 
|  | #define TLB_ENTRY_SHIFT 12 | 
|  | #define TLB_ENTRY_MASK  (NENTRY - 1) | 
 |  |  | 
 | typedef struct { | typedef struct { | 
| BYTE            kind; | struct tlb_entry entry[NENTRY]; | 
| #define TLB_KIND_INSTRUCTION    (1 << 1) | } tlb_t; | 
| #define TLB_KIND_DATA           (1 << 2) | static tlb_t tlb[NTLB]; | 
| #define TLB_KIND_COMBINE        (TLB_KIND_INSTRUCTION|TLB_KIND_DATA) |  | 
| #define TLB_KIND_SMALL          (1 << 3) |  | 
| #define TLB_KIND_LARGE          (1 << 4) |  | 
| #define TLB_KIND_BOTH           (TLB_KIND_SMALL|TLB_KIND_LARGE) |  | 
|  |  | 
| BYTE            way;    /* n-way associative */ |  | 
| BYTE            idx;    /* number of TLB index */ |  | 
| BYTE            bpad; |  | 
|  |  | 
| WORD            num;    /* number of TLB entry */ |  | 
| WORD            wpad; |  | 
|  |  | 
| TLB_ENTRY_T*    entry;  /* entry[assoc][idx] or entry[assoc] if idx == 1*/ |  | 
| } TLB_T; |  | 
|  |  | 
| static int ntlb; |  | 
| static TLB_T tlb[4];    /* i TLB, i (lp) TLB, d TLB, d (lp) TLB */ |  | 
|  |  | 
| #if defined(IA32_PROFILE_TLB) |  | 
| /* profiling */ |  | 
| static DWORD tlb_hits; |  | 
| static DWORD tlb_misses; |  | 
| static DWORD tlb_lookups; |  | 
| static DWORD tlb_updates; |  | 
| static DWORD tlb_flushes; |  | 
| static DWORD tlb_global_flushes; |  | 
| static DWORD tlb_entry_flushes; |  | 
|  |  | 
| #define PROFILE_INC(v)  (v)++; |  | 
| #else   /* !IA32_PROFILE_TLB */ |  | 
| #define PROFILE_INC(v) |  | 
| #endif  /* IA32_PROFILE_TLB */ |  | 
 |  |  | 
 | void | void | 
| tlb_init() | tlb_init(void) | 
 | { | { | 
 | int i; |  | 
 |  |  | 
 | for (i = 0; i < NELEMENTS(tlb); i++) { |  | 
 | if (tlb[i].entry) { |  | 
 | free(tlb[i].entry); |  | 
 | } |  | 
 | } |  | 
 | memset(tlb, 0, sizeof(tlb)); | memset(tlb, 0, sizeof(tlb)); | 
 |  |  | 
 | #if defined(IA32_PROFILE_TLB) |  | 
 | tlb_hits = 0; |  | 
 | tlb_misses = 0; |  | 
 | tlb_lookups = 0; |  | 
 | tlb_updates = 0; |  | 
 | tlb_flushes = 0; |  | 
 | tlb_global_flushes = 0; |  | 
 | tlb_entry_flushes = 0; |  | 
 | #endif  /* IA32_PROFILE_TLB */ |  | 
 |  |  | 
 | /* XXX ¡¦¥é¡¦ú§¥µ¡¦¥Æ¡¦¥ª¥·þÌ¥Õ¡¢¥Ò¡¢¥¡¢¥½¡¢¥ã¡¢¥Æ¡¢¥Ë TLB ¥±¥¹¥¿¥ç¡¢ò¹½ÃÛ¤¹¤*/ |  | 
 |  |  | 
 | /* ¤È¤ê¤¢¤¨¤º i486 ·Á¼°¤Ç¡Ä */ |  | 
 | /* combine (I/D) TLB: 4KB Pages, 4-way set associative 32 entries */ |  | 
 | ntlb = 1; |  | 
 | tlb[0].kind = TLB_KIND_COMBINE | TLB_KIND_SMALL; |  | 
 | tlb[0].num = 32; |  | 
 | tlb[0].way = 4; |  | 
 | tlb[0].idx = tlb[0].num / tlb[0].way; |  | 
 |  |  | 
 | for (i = 0; i < ntlb; i++) { |  | 
 | tlb[i].entry = (TLB_ENTRY_T*)calloc(sizeof(TLB_ENTRY_T), tlb[i].num); |  | 
 | if (tlb[i].entry == 0) { |  | 
 | ia32_panic("tlb_init(): can't alloc TLB entry\n"); |  | 
 | } |  | 
 | } |  | 
 | } | } | 
 |  |  | 
| void | void MEMCALL | 
 | tlb_flush(BOOL allflush) | tlb_flush(BOOL allflush) | 
 | { | { | 
| TLB_ENTRY_T* ep; | struct tlb_entry *ep; | 
| int i, j; | int i; | 
|  | int n; | 
 |  |  | 
 | if (allflush) { | if (allflush) { | 
| PROFILE_INC(tlb_global_flushes); | tlb_init(); | 
| } else { | return; | 
| PROFILE_INC(tlb_flushes); |  | 
 | } | } | 
 |  |  | 
| for (i = 0; i < ntlb; i++) { | for (n = 0; n < NTLB; n++) { | 
| ep = tlb[i].entry; | for (i = 0; i < NENTRY ; i++) { | 
| for (j = 0; j < tlb[i].num; j++, ep++) { | ep = &tlb[n].entry[i]; | 
| if (ep->valid && (allflush || !ep->global)) { | if (TLB_IS_VALID(ep) && !TLB_IS_GLOBAL(ep)) { | 
| ep->valid = 0; | TLB_SET_INVALID(ep); | 
| PROFILE_INC(tlb_entry_flushes); |  | 
 | } | } | 
 | } | } | 
 | } | } | 
 | } | } | 
 |  |  | 
| void | void MEMCALL | 
| tlb_flush_page(DWORD vaddr) | tlb_flush_page(UINT32 laddr) | 
 | { | { | 
| TLB_ENTRY_T* ep; | struct tlb_entry *ep; | 
 | int idx; | int idx; | 
| int i; | int n; | 
 |  |  | 
| for (i = 0; i < ntlb; i++) { | idx = (laddr >> TLB_ENTRY_SHIFT) & TLB_ENTRY_MASK; | 
| if (tlb[i].idx == 1) { |  | 
| /* fully set associative */ |  | 
| idx = 0; |  | 
| } else { |  | 
| if (tlb[i].kind & TLB_KIND_SMALL) { |  | 
| idx = (vaddr >> 12) & (tlb[i].idx - 1); |  | 
| } else { |  | 
| idx = (vaddr >> 22) & (tlb[i].idx - 1); |  | 
| } |  | 
| } |  | 
 |  |  | 
| /* search */ | for (n = 0; n < NTLB; n++) { | 
| ep = &tlb[i].entry[idx * tlb[i].way]; | ep = &tlb[n].entry[idx]; | 
| for (i = 0; i < tlb[i].way; i++) { | if (TLB_IS_VALID(ep)) { | 
| if (ep->valid) { | if ((laddr & TLB_TAG_MASK) == TLB_GET_TAG_ADDR(ep)) { | 
| if ((vaddr & ep->mask) == ep->tag) { | TLB_SET_INVALID(ep); | 
| ep->valid = 0; |  | 
| PROFILE_INC(tlb_entry_flushes); |  | 
| break; |  | 
| } |  | 
 | } | } | 
 | } | } | 
 | } | } | 
 | } | } | 
 |  |  | 
| static BOOL | struct tlb_entry * MEMCALL | 
| tlb_lookup(DWORD laddr, int crw, DWORD* paddr) | tlb_lookup(UINT32 laddr, int ucrw) | 
 | { | { | 
| TLB_ENTRY_T* ep; | struct tlb_entry *ep; | 
|  | UINT bit; | 
 | int idx; | int idx; | 
| int i; | int n; | 
 |  |  | 
| PROFILE_INC(tlb_lookups); | n = (ucrw & CPU_PAGE_CODE) ? 1 : 0; | 
|  | idx = (laddr >> TLB_ENTRY_SHIFT) & TLB_ENTRY_MASK; | 
| crw &= CPU_PAGING_PAGE_CODE | CPU_PAGING_PAGE_DATA; | ep = &tlb[n].entry[idx]; | 
| for (i = 0; i < ntlb; i++) { |  | 
| if (tlb[i].kind & crw) { | if (TLB_IS_VALID(ep)) { | 
| if (tlb[i].idx == 1) { | if ((laddr & TLB_TAG_MASK) == TLB_GET_TAG_ADDR(ep)) { | 
| /* fully set associative */ | bit = ucrw & (CPU_PAGE_WRITE|CPU_PAGE_USER_MODE); | 
| idx = 0; | bit |= ep->tag & (CPU_PTE_WRITABLE|CPU_PTE_USER_MODE); | 
| } else { | bit |= CPU_STAT_WP; | 
| if (tlb[i].kind & TLB_KIND_SMALL) { | #if !defined(USE_PAGE_ACCESS_TABLE) | 
| idx = (laddr >> 12) & (tlb[i].idx - 1); | if ((page_access & (1 << bit))) | 
| } else { | #else | 
| idx = (laddr >> 22) & (tlb[i].idx - 1); | if (page_access_bit[bit]) | 
| } | #endif | 
| } | { | 
|  | if (!(ucrw & CPU_PAGE_WRITE) || TLB_IS_DIRTY(ep)) { | 
| /* search */ | return ep; | 
| ep = &tlb[i].entry[idx * tlb[i].way]; |  | 
| for (i = 0; i < tlb[i].way; i++) { |  | 
| if (ep->valid) { |  | 
| if ((laddr & ep->mask) == ep->tag) { |  | 
| if (ep->score != (BYTE)~0) |  | 
| ep->score++; |  | 
| *paddr = ep->paddr; |  | 
| PROFILE_INC(tlb_hits); |  | 
| return TRUE; |  | 
| } |  | 
 | } | } | 
 | } | } | 
 | } | } | 
 | } | } | 
| PROFILE_INC(tlb_misses); | return NULL; | 
| return FALSE; |  | 
 | } | } | 
 |  |  | 
| static void | static void MEMCALL | 
| tlb_update(DWORD paddr, DWORD entry, int crw) | tlb_update(UINT32 laddr, UINT entry, int bit) | 
 | { | { | 
| TLB_ENTRY_T* ep; | struct tlb_entry *ep; | 
 | int idx; | int idx; | 
| int i, j; | int n; | 
| int min_way; |  | 
| WORD min_score = ~0; |  | 
|  |  | 
| PROFILE_INC(tlb_updates); |  | 
|  |  | 
| crw &= CPU_PAGING_PAGE_CODE | CPU_PAGING_PAGE_DATA; |  | 
| for (i = 0; i < ntlb; i++) { |  | 
| if (tlb[i].kind & crw) { |  | 
| if (tlb[i].idx == 1) { |  | 
| /* fully set associative */ |  | 
| idx = 0; |  | 
| } else { |  | 
| /* n-way set associative */ |  | 
| if (!(entry & CPU_PDE_PAGE_SIZE)) { |  | 
| if (!(tlb[i].kind & TLB_KIND_SMALL)) |  | 
| continue; |  | 
| idx = (entry >> 12) & (tlb[i].idx - 1); |  | 
| } else { |  | 
| if (!(tlb[i].kind & TLB_KIND_LARGE)) |  | 
| continue; |  | 
| idx = (entry >> 22) & (tlb[i].idx - 1); |  | 
| } |  | 
| } |  | 
|  |  | 
| /* search */ |  | 
| ep = &tlb[i].entry[idx * tlb[i].way]; |  | 
| for (min_way = 0, j = 0; j < tlb[i].way; j++, ep++) { |  | 
| if (ep->valid) { |  | 
| if (min_score >= ep->score) { |  | 
| min_way = j; |  | 
| min_score = ep->score; |  | 
| } |  | 
| } else { |  | 
| min_way = j; |  | 
| min_score = 0; |  | 
| break; |  | 
| } |  | 
| } |  | 
|  |  | 
| /* replace */ |  | 
| ep = &tlb[i].entry[idx * tlb[i].way + min_way]; |  | 
| ep->valid = 1; |  | 
| ep->global = (entry & CPU_PTE_GLOBAL_PAGE) ? 1 : 0; |  | 
| ep->score = 0; |  | 
| ep->mask = (entry & CPU_PDE_PAGE_SIZE) ?  CPU_PDE_4M_BASEADDR_MASK : CPU_PTE_BASEADDR_MASK; |  | 
| ep->tag = entry & ep->mask; |  | 
| ep->paddr = paddr; |  | 
| break; |  | 
| } |  | 
| } |  | 
| __ASSERT(i != ntlb); |  | 
| } |  | 
| #else   /* !IA32_SUPPORT_TLB */ |  | 
| void |  | 
| tlb_init() |  | 
| { |  | 
|  |  | 
| /* nothing to do */ |  | 
| } |  | 
|  |  | 
| void |  | 
| tlb_flush(BOOL allflush) |  | 
| { |  | 
|  |  | 
| (void)allflush; |  | 
| } |  | 
|  |  | 
| void |  | 
| tlb_flush_page(DWORD laddr) |  | 
| { |  | 
 |  |  | 
| (void)laddr; | n = bit & 1; | 
|  | idx = (laddr >> TLB_ENTRY_SHIFT) & TLB_ENTRY_MASK; | 
|  | ep = &tlb[n].entry[idx]; | 
|  |  | 
|  | TLB_SET_VALID(ep); | 
|  | TLB_SET_TAG_ADDR(ep, laddr); | 
|  | TLB_SET_TAG_FLAGS(ep, entry, bit); | 
|  | ep->paddr = entry & CPU_PTE_BASEADDR_MASK; | 
 | } | } | 
 | #endif  /* IA32_SUPPORT_TLB */ |  |