| version 1.2, 2003/12/11 15:06:50 | version 1.18, 2004/03/23 18:38:07 | 
| Line 1 | Line 1 | 
 | /*      $Id$    */ | /*      $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 32 | Line 32 | 
 | #include "ia32.mcr" | #include "ia32.mcr" | 
 |  |  | 
 | /* | /* | 
 | * ページ・ディレクトリ・エントリ (4K バイトページ使用時) |  | 
 | * |  | 
 | *  31                                    12 11   9 8  7 6 5  4   3   2   1  0 |  | 
 | * +----------------------------------------+------+-+--+-+-+---+---+---+---+-+ |  | 
 | * |   ページ・テーブルのベース・アドレス   |使用可|G|PS|0|A|PCD|PWT|U/S|R/W|P| |  | 
 | * +----------------------------------------+------+-+--+-+-+---+---+---+---+-+ |  | 
 | *                                              |   |  | | |  |   |   |   |  | |  | 
 | * 9-11: システム・プログラマが使用可能 --------+   |  | | |  |   |   |   |  | |  | 
 | *    8: グローバル・ページ(無視される) ------------+  | | |  |   |   |   |  | |  | 
 | *    7: ページ・サイズ (0 = 4k バイトページ) ---------+ | |  |   |   |   |  | |  | 
 | *    6: 予約 (0) ---------------------------------------+ |  |   |   |   |  | |  | 
 | *    5: アクセス -----------------------------------------+  |   |   |   |  | |  | 
 | *    4: キャッシュ無効 --------------------------------------+   |   |   |  | |  | 
 | *    3: ライトスルー --------------------------------------------+   |   |  | |  | 
 | *    2: ユーザ/スーパバイザ (0 = スーパバイザ) ---------------------+   |  | |  | 
 | *    1: 読み取り/書き込み (0 = 読み取りのみ) ---------------------------+  | |  | 
 | *    0: ページ存在 ---------------------------------------------------------+ |  | 
 | */ |  | 
 | #define CPU_PDE_BASEADDR_MASK   0xfffff000 |  | 
 | #define CPU_PDE_PAGE_SIZE       (1 << 7) |  | 
 | #define CPU_PDE_ACCESS          (1 << 5) |  | 
 | #define CPU_PDE_CACHE_DISABLE   (1 << 4) |  | 
 | #define CPU_PDE_WRITE_THROUGH   (1 << 3) |  | 
 | #define CPU_PDE_USER_MODE       (1 << 2) |  | 
 | #define CPU_PDE_WRITABLE        (1 << 1) |  | 
 | #define CPU_PDE_PRESENT         (1 << 0) |  | 
 |  |  | 
 | /* |  | 
 | * ページ・ディレクトリ・エントリ (4M バイトページ使用時) |  | 
 | * |  | 
 | *  31                        22 21       12 11   9 8  7 6 5  4   3   2   1  0 |  | 
 | * +----------------------------+-----------+------+-+--+-+-+---+---+---+---+-+ |  | 
 | * |ページテーブルの物理アドレス|  予約済み |使用可|G|PS|D|A|PCD|PWT|U/S|R/W|P| |  | 
 | * +----------------------------+-----------+------+-+--+-+-+---+---+---+---+-+ |  | 
 | *                                              |   |  | | |  |   |   |   |  | |  | 
 | * 9-11: システム・プログラマが使用可能 --------+   |  | | |  |   |   |   |  | |  | 
 | *    8: グローバル・ページ ------------------------+  | | |  |   |   |   |  | |  | 
 | *    7: ページ・サイズ (1 = 4M バイトページ) ---------+ | |  |   |   |   |  | |  | 
 | *    6: ダーティ ---------------------------------------+ |  |   |   |   |  | |  | 
 | *    5: アクセス -----------------------------------------+  |   |   |   |  | |  | 
 | *    4: キャッシュ無効 --------------------------------------+   |   |   |  | |  | 
 | *    3: ライトスルー --------------------------------------------+   |   |  | |  | 
 | *    2: ユーザ/スーパバイザ (0 = スーパバイザ) ---------------------+   |  | |  | 
 | *    1: 読み取り/書き込み (0 = 読み取りのみ) ---------------------------+  | |  | 
 | *    0: ページ存在 ---------------------------------------------------------+ |  | 
 | */ |  | 
 | #define CPU_PDE_4M_BASEADDR_MASK        0xffc00000 |  | 
 | #define CPU_PDE_4M_GLOBAL_PAGE          (1 << 8) |  | 
 | #define CPU_PDE_4M_PAGE_SIZE            (1 << 7) |  | 
 | #define CPU_PDE_4M_DIRTY                (1 << 6) |  | 
 | #define CPU_PDE_4M_ACCESS               (1 << 5) |  | 
 | #define CPU_PDE_4M_CACHE_DISABLE        (1 << 4) |  | 
 | #define CPU_PDE_4M_WRITE_THROUGH        (1 << 3) |  | 
 | #define CPU_PDE_4M_USER_MODE            (1 << 2) |  | 
 | #define CPU_PDE_4M_WRITABLE             (1 << 1) |  | 
 | #define CPU_PDE_4M_PRESENT              (1 << 0) |  | 
 |  |  | 
 | /* |  | 
 | * ページ・テーブル・エントリ (4k バイト・ページ) |  | 
 | * |  | 
 | *  31                                    12 11   9 8 7 6 5  4   3   2   1  0 |  | 
 | * +----------------------------------------+------+-+-+-+-+---+---+---+---+-+ |  | 
 | * |        ページのベース・アドレス        |使用可|G|0|D|A|PCD|PWT|U/S|R/W|P| |  | 
 | * +----------------------------------------+------+-+-+-+-+---+---+---+---+-+ |  | 
 | *                                              |   | | | |  |   |   |   |  | |  | 
 | *  9-11: システム・プログラマが使用可能 -------+   | | | |  |   |   |   |  | |  | 
 | *     8: グローバル・ページ -----------------------+ | | |  |   |   |   |  | |  | 
 | *     7: 予約 (0) -----------------------------------+ | |  |   |   |   |  | |  | 
 | *     6: ダーティ -------------------------------------+ |  |   |   |   |  | |  | 
 | *     5: アクセス ---------------------------------------+  |   |   |   |  | |  | 
 | *     4: キャッシュ無効 ------------------------------------+   |   |   |  | |  | 
 | *     3: ライトスルー ------------------------------------------+   |   |  | |  | 
 | *     2: ユーザ/スーパバイザ (0 = スーパバイザ) -------------------+   |  | |  | 
 | *     1: 読み取り/書き込み (0 = 読み取りのみ) -------------------------+  | |  | 
 | *     0: ページ存在 -------------------------------------------------------+ |  | 
 | */ |  | 
 | #define CPU_PTE_BASEADDR_MASK   0xfffff000 |  | 
 | #define CPU_PTE_GLOBAL_PAGE     (1 << 8) |  | 
 | #define CPU_PTE_DIRTY           (1 << 6) |  | 
 | #define CPU_PTE_ACCESS          (1 << 5) |  | 
 | #define CPU_PTE_CACHE_DISABLE   (1 << 4) |  | 
 | #define CPU_PTE_WRITE_THROUGH   (1 << 3) |  | 
 | #define CPU_PTE_USER_MODE       (1 << 2) |  | 
 | #define CPU_PTE_WRITABLE        (1 << 1) |  | 
 | #define CPU_PTE_PRESENT         (1 << 0) |  | 
 |  |  | 
 | /* |  | 
 | * ページフォルト例外 | * ページフォルト例外 | 
 | * | * | 
 | * 4-31: 予約済み | * 4-31: 予約済み | 
| Line 199 | Line 112 | 
 | * +-----+-----------+-----+-----+---+ | * +-----+-----------+-----+-----+---+ | 
 | */ | */ | 
 | #if !defined(USE_PAGE_ACCESS_TABLE) | #if !defined(USE_PAGE_ACCESS_TABLE) | 
| static const DWORD page_access = 0xd0cdd0ff; | #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 230  static const BYTE page_access_bit[32] = | Line 143  static const BYTE page_access_bit[32] = | 
 | 1,      /* CR0: p, CPL: s, PTE: u, PTE: r, ope: r */ | 1,      /* CR0: p, CPL: s, PTE: u, PTE: r, ope: r */ | 
 | 0,      /* CR0: p, CPL: s, PTE: u, PTE: r, ope: w */ | 0,      /* CR0: p, CPL: s, PTE: u, PTE: r, ope: w */ | 
 | 1,      /* CR0: p, CPL: s, PTE: u, PTE: w, ope: r */ | 1,      /* CR0: p, CPL: s, PTE: u, PTE: w, ope: r */ | 
| 0,      /* CR0: p, CPL: s, PTE: u, PTE: w, ope: w */ | 1,      /* CR0: p, CPL: s, PTE: u, PTE: w, ope: w */ | 
 |  |  | 
 | 0,      /* CR0: p, CPL: u, PTE: s, PTE: r, ope: r */ | 0,      /* CR0: p, CPL: u, PTE: s, PTE: r, ope: r */ | 
 | 0,      /* CR0: p, CPL: u, PTE: s, PTE: r, ope: w */ | 0,      /* CR0: p, CPL: u, PTE: s, PTE: r, ope: w */ | 
| Line 271  static const BYTE page_access_bit[32] = | Line 184  static const BYTE page_access_bit[32] = | 
 | * +- CR3(物理アドレス) | * +- CR3(物理アドレス) | 
 | */ | */ | 
 |  |  | 
| static DWORD paging(DWORD laddr, int crw, int user_mode); | static UINT32 paging(const UINT32 laddr, const int crw, const int user_mode); | 
 | #if defined(IA32_SUPPORT_TLB) | #if defined(IA32_SUPPORT_TLB) | 
| static BOOL tlb_lookup(DWORD vaddr, int crw, DWORD* paddr); | static BOOL tlb_lookup(const UINT32 vaddr, const int crw, UINT32 *paddr); | 
| static void tlb_update(DWORD paddr, DWORD entry, int crw); | static void tlb_update(const UINT32 laddr, const UINT entry, const int crw); | 
 | #endif | #endif | 
 |  |  | 
 |  |  | 
| DWORD MEMCALL | void MEMCALL | 
| cpu_linear_memory_read(DWORD laddr, DWORD length, int code) | cpu_memory_access_la_region(UINT32 laddr, UINT length, const int crw, const int user_mode, BYTE *data) | 
 | { | { | 
| DWORD paddr; | UINT32 paddr; | 
| DWORD remain;   /* page remain */ | UINT remain;    /* page remain */ | 
| DWORD r; | UINT r; | 
| DWORD value = 0; |  | 
| int crw; | if (length == 0) | 
| int pl; | return; | 
|  |  | 
| crw = CPU_PAGING_PAGE_READ; |  | 
| crw |= code ? CPU_PAGING_PAGE_CODE : CPU_PAGING_PAGE_DATA; |  | 
| pl = (CPU_STAT_CPL == 3); |  | 
 |  |  | 
 | /* XXX: 4MB pages... */ |  | 
 | remain = 0x1000 - (laddr & 0x00000fff); | remain = 0x1000 - (laddr & 0x00000fff); | 
 | for (;;) { | for (;;) { | 
| paddr = paging(laddr, crw, pl); | if (!CPU_STAT_PAGING) { | 
|  | paddr = laddr; | 
|  | } else { | 
|  | paddr = paging(laddr, crw, user_mode); | 
|  | } | 
 |  |  | 
 | r = (remain > length) ? length : remain; | r = (remain > length) ? length : remain; | 
| switch (r) { | if (!(crw & CPU_PAGE_WRITE)) { | 
| case 1: | cpu_memoryread_region(paddr, data, r); | 
| value = (value << 8) | cpu_memoryread(paddr); | } else { | 
|  | cpu_memorywrite_region(paddr, data, r); | 
|  | } | 
|  |  | 
|  | length -= r; | 
|  | if (length == 0) | 
 | break; | break; | 
 |  |  | 
| case 2: | data += r; | 
| value = (value << 16) | cpu_memoryread_w(paddr); | laddr += r; | 
|  | remain -= r; | 
|  | if (remain <= 0) { | 
|  | /* next page */ | 
|  | remain += 0x1000; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | UINT32 MEMCALL | 
|  | cpu_memory_access_la_RMW(UINT32 laddr, UINT length, const int user_mode, UINT32 (*func)(UINT32, void *), void *arg) | 
|  | { | 
|  | const int crw = (CPU_PAGE_WRITE|CPU_PAGE_DATA); | 
|  | UINT32 result, value; | 
|  | UINT32 paddr[2]; | 
|  | UINT remain; | 
|  |  | 
|  | paddr[0] = paging(laddr, crw, user_mode); | 
|  | remain = 0x1000 - (laddr & 0x00000fff); | 
|  | if (remain >= length) { | 
|  | /* fast mode */ | 
|  | switch (length) { | 
|  | case 4: | 
|  | value = cpu_memoryread_d(paddr[0]); | 
|  | result = (*func)(value, arg); | 
|  | cpu_memorywrite_d(paddr[0], result); | 
 | break; | break; | 
 |  |  | 
| case 3: | case 2: | 
| value <<= 24; | value = cpu_memoryread_w(paddr[0]); | 
| value |= cpu_memoryread_w(paddr) << 8; | result = (*func)(value, arg); | 
| value |= cpu_memoryread(paddr + 2); | cpu_memorywrite_w(paddr[0], (UINT16)result); | 
 | break; | break; | 
 |  |  | 
| case 4: | case 1: | 
| value = cpu_memoryread_d(paddr); | value = cpu_memoryread(paddr[0]); | 
|  | result = (*func)(value, arg); | 
|  | cpu_memorywrite(paddr[0], (UINT8)result); | 
 | break; | break; | 
 |  |  | 
 | default: | default: | 
| ia32_panic("cpu_linear_memory_read(): out of range\n"); | ia32_panic("cpu_memory_access_la_RMW(): invalid length (length = %d)\n", length); | 
|  | value = 0;      /* compiler happy */ | 
 | break; | break; | 
 | } | } | 
 |  | return value; | 
 |  | } | 
 |  |  | 
 |  | /* slow mode */ | 
 |  | paddr[1] = paging(laddr + remain, crw, user_mode); | 
 |  | 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], (BYTE)(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); | 
 |  | value = 0;      /* compiler happy */ | 
 |  | break; | 
 |  | } | 
 |  | return value; | 
 |  | } | 
 |  |  | 
 |  | UINT32 MEMCALL | 
 |  | cpu_linear_memory_read(UINT32 laddr, UINT length, const int crw, const int user_mode) | 
 |  | { | 
 |  | UINT32 value; | 
 |  | UINT32 paddr[2]; | 
 |  | UINT remain; | 
 |  |  | 
| if (length == r) | paddr[0] = paging(laddr, crw, user_mode); | 
|  | remain = 0x1000 - (laddr & 0x00000fff); | 
|  | if (remain >= length) { | 
|  | /* fast mode */ | 
|  | switch (length) { | 
|  | case 4: | 
|  | value = cpu_memoryread_d(paddr[0]); | 
 | break; | break; | 
 |  |  | 
| length -= r; | case 2: | 
| remain -= r; | value = cpu_memoryread_w(paddr[0]); | 
| laddr += r; | break; | 
|  |  | 
|  | case 1: | 
|  | value = cpu_memoryread(paddr[0]); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | ia32_panic("cpu_linear_memory_read(): invalid length (length = %d)\n", length); | 
|  | value = 0;      /* compiler happy */ | 
|  | break; | 
|  | } | 
|  | return value; | 
 | } | } | 
 |  |  | 
 |  | /* slow mode */ | 
 |  | paddr[1] = paging(laddr + remain, crw, user_mode); | 
 |  | 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); | 
 |  | value = 0;      /* compiler happy */ | 
 |  | break; | 
 |  | } | 
 | return value; | return value; | 
 | } | } | 
 |  |  | 
 | void MEMCALL | void MEMCALL | 
| cpu_linear_memory_write(DWORD laddr, DWORD length, DWORD value) | cpu_linear_memory_write(UINT32 laddr, UINT32 value, UINT length, const int user_mode) | 
 | { | { | 
| DWORD paddr; | const int crw = (CPU_PAGE_WRITE|CPU_PAGE_DATA); | 
| DWORD remain;   /* page remain */ | UINT32 paddr[2]; | 
| DWORD r; | UINT remain; | 
| int pl; |  | 
|  |  | 
| pl = (CPU_STAT_CPL == 3); |  | 
 |  |  | 
| /* XXX: 4MB pages... */ | paddr[0] = paging(laddr, crw, user_mode); | 
 | remain = 0x1000 - (laddr & 0x00000fff); | remain = 0x1000 - (laddr & 0x00000fff); | 
| for (;;) { | if (remain >= length) { | 
| paddr = paging(laddr, CPU_PAGING_PAGE_WRITE|CPU_PAGING_PAGE_DATA, pl); | /* fast mode */ | 
|  | switch (length) { | 
| r = (remain > length) ? length : remain; | case 4: | 
| switch (r) { | cpu_memorywrite_d(paddr[0], value); | 
| case 1: |  | 
| cpu_memorywrite(paddr, value); |  | 
| value >>= 8; |  | 
 | break; | break; | 
 |  |  | 
 | case 2: | case 2: | 
| cpu_memorywrite_w(paddr, value); | cpu_memorywrite_w(paddr[0], (UINT16)value); | 
| value >>= 16; |  | 
 | break; | break; | 
 |  |  | 
| case 3: | case 1: | 
| cpu_memorywrite_w(paddr, value); | cpu_memorywrite(paddr[0], (UINT8)value); | 
| cpu_memorywrite(paddr, value >> 16); |  | 
| value >>= 24; |  | 
| break; |  | 
|  |  | 
| case 4: |  | 
| cpu_memorywrite_d(paddr, value); |  | 
 | break; | break; | 
 |  |  | 
 | default: | default: | 
| ia32_panic("cpu_linear_memory_write(): out of range\n"); | ia32_panic("cpu_linear_memory_write(): invalid length (length = %d)\n", length); | 
 | break; | break; | 
 | } | } | 
 |  | return; | 
 |  | } | 
 |  |  | 
| if (length == r) | /* slow mode */ | 
| break; | paddr[1] = paging(laddr + remain, crw, user_mode); | 
|  | switch (remain) { | 
|  | case 3: | 
|  | cpu_memorywrite(paddr[0], (UINT8)value); | 
|  | cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8)); | 
|  | cpu_memorywrite(paddr[1], (BYTE)(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; | 
|  | } | 
|  | } | 
|  |  | 
|  | void MEMCALL | 
|  | paging_check(UINT32 laddr, UINT length, const int crw, const int user_mode) | 
|  | { | 
|  | UINT32 paddr; | 
|  | UINT remain;    /* page remain */ | 
|  | UINT r; | 
|  |  | 
|  | remain = 0x1000 - (laddr & 0x00000fff); | 
|  | for (;;) { | 
|  | paddr = paging(laddr, crw, user_mode); | 
|  |  | 
|  | r = (remain > length) ? length : remain; | 
 |  |  | 
 | length -= r; | length -= r; | 
| remain -= r; | if (length == 0) | 
|  | break; | 
|  |  | 
 | laddr += r; | laddr += r; | 
 |  | remain -= r; | 
 |  | if (remain <= 0) { | 
 |  | /* next page */ | 
 |  | remain += 0x1000; | 
 |  | } | 
 | } | } | 
 | } | } | 
 |  |  | 
| void MEMCALL | static UINT32 | 
| paging_check(DWORD laddr, DWORD length, int rw) | paging(const UINT32 laddr, const int crw, const int user_mode) | 
 | { | { | 
| DWORD addr; | UINT32 paddr;           /* physical address */ | 
| int n; | UINT32 pde_addr;        /* page directory entry address */ | 
| int pl; | UINT32 pde;             /* page directory entry */ | 
|  | UINT32 pte_addr;        /* page table entry address */ | 
| pl = (CPU_STAT_CPL == 3); | UINT32 pte;             /* page table entry */ | 
|  | UINT bit; | 
| /* XXX: 4MB pages... */ | UINT err; | 
| n = ((laddr & 0xfff) + length) / 0x1000; |  | 
| addr = (laddr & ~0xfff); |  | 
| do { |  | 
| (void)paging(addr, rw, pl); |  | 
| addr += 0x1000; |  | 
| } while (--n > 0); |  | 
| } |  | 
|  |  | 
| static DWORD |  | 
| paging(DWORD laddr, int crw, int user_mode) |  | 
| { |  | 
| 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 = 0; |  | 
 |  |  | 
 | #if defined(IA32_SUPPORT_TLB) | #if defined(IA32_SUPPORT_TLB) | 
 | if (tlb_lookup(laddr, crw, &paddr)) | if (tlb_lookup(laddr, crw, &paddr)) | 
 | return paddr; | return paddr; | 
 | #endif  /* IA32_SUPPORT_TLB */ | #endif  /* IA32_SUPPORT_TLB */ | 
 |  |  | 
| 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: PTE page is not present")); | 
 |  | VERBOSE(("paging: CPU_CR3 = 0x%08x", CPU_CR3)); | 
 |  | VERBOSE(("paging: laddr = 0x%08x, pde_addr = 0x%08x, pde = 0x%08x", laddr, pde_addr, pde)); | 
 | err = 0; | err = 0; | 
 | goto pf_exception; | goto pf_exception; | 
 | } | } | 
| Line 429  paging(DWORD laddr, int crw, int user_mo | Line 489  paging(DWORD laddr, int crw, int user_mo | 
 | cpu_memorywrite_d(pde_addr, pde); | cpu_memorywrite_d(pde_addr, pde); | 
 | } | } | 
 |  |  | 
| /* no support PAE */ | pte_addr = (pde & CPU_PDE_BASEADDR_MASK) + ((laddr >> 10) & 0xffc); | 
| __ASSERT(!(CPU_CR4 & CPU_CR4_PAE)); | pte = cpu_memoryread_d(pte_addr); | 
|  | if (!(pte & CPU_PTE_PRESENT)) { | 
| if ((CPU_CR4 & CPU_CR4_PSE) && (pde & CPU_PDE_PAGE_SIZE)) { | VERBOSE(("paging: page is not present")); | 
| /* 4MB page size */ | 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)); | 
| /* fake PTE bit */ | err = 0; | 
| pte = pde | CPU_PTE_DIRTY; | goto pf_exception; | 
| pte_addr = 0;   /* compiler happy */ |  | 
|  |  | 
| /* make physical address */ |  | 
| paddr = (pde & CPU_PDE_4M_BASEADDR_MASK) | (laddr & 0x003fffff); |  | 
| } else { |  | 
| /* 4KB page size */ |  | 
| pte_addr = (pde & CPU_PDE_BASEADDR_MASK) | ((laddr >> 10) & 0xffc); |  | 
| pte = cpu_memoryread_d(pte_addr); |  | 
| if (!(pte & CPU_PTE_PRESENT)) { |  | 
| 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 & 0x00000fff); | 
 |  |  | 
| bit  = crw & 1; | bit  = crw & CPU_PAGE_WRITE; | 
 | 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 |= (user_mode << 3); | 
| bit |= (CPU_CR0 & CPU_CR0_WP) >> 12; | bit |= CPU_STAT_WP; | 
 |  |  | 
 | #if !defined(USE_PAGE_ACCESS_TABLE) | #if !defined(USE_PAGE_ACCESS_TABLE) | 
 | if (!(page_access & (1 << bit))) | if (!(page_access & (1 << bit))) | 
| Line 469  paging(DWORD laddr, int crw, int user_mo | Line 517  paging(DWORD laddr, int crw, int user_mo | 
 | if (!(page_access_bit[bit])) | if (!(page_access_bit[bit])) | 
 | #endif | #endif | 
 | { | { | 
 |  | VERBOSE(("paging: page access violation.")); | 
 |  | 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)); | 
 |  | VERBOSE(("paging: paddr = 0x%08x, bit = 0x%08x", paddr, bit)); | 
 | err = 1; | err = 1; | 
 | goto pf_exception; | goto pf_exception; | 
 | } | } | 
 |  |  | 
| if ((crw & 1) && !(pte & CPU_PTE_DIRTY)) { | if ((crw & 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) | #if defined(IA32_SUPPORT_TLB) | 
| tlb_update(paddr, pte, crw); | tlb_update(laddr, pte, crw); | 
 | #endif  /* IA32_SUPPORT_TLB */ | #endif  /* IA32_SUPPORT_TLB */ | 
 |  |  | 
 | return paddr; | return paddr; | 
 |  |  | 
 | pf_exception: | pf_exception: | 
 | CPU_CR2 = laddr; | CPU_CR2 = laddr; | 
| err |= ((crw & 1) << 1) | (user_mode << 2); | err |= ((crw & CPU_PAGE_WRITE) << 1) | (user_mode << 2); | 
 | EXCEPTION(PF_EXCEPTION, err); | EXCEPTION(PF_EXCEPTION, err); | 
 | return 0;       /* compiler happy */ | return 0;       /* compiler happy */ | 
 | } | } | 
| Line 495  pf_exception: | Line 547  pf_exception: | 
 | /* | /* | 
 | * TLB | * TLB | 
 | */ | */ | 
 |  |  | 
 |  | #if defined(IA32_PROFILE_TLB) | 
 |  | /* profiling */ | 
 | typedef struct { | typedef struct { | 
| BYTE    valid;  /* TLB entry is valid */ | UINT64 tlb_hits; | 
| BYTE    global; /* this TLB entry is global */ | UINT64 tlb_misses; | 
| BYTE    score; | UINT64 tlb_lookups; | 
| BYTE    pad; | UINT64 tlb_updates; | 
|  | UINT64 tlb_flushes; | 
|  | UINT64 tlb_global_flushes; | 
|  | UINT64 tlb_entry_flushes; | 
|  | } TLB_PROFILE_T; | 
 |  |  | 
| DWORD   tag; | static TLB_PROFILE_T tlb_profile; | 
| DWORD   mask;   /* 4K or 2M or 4M */ |  | 
|  | #define PROFILE_INC(v)  tlb_profile.v++ | 
|  | #else   /* !IA32_PROFILE_TLB */ | 
|  | #define PROFILE_INC(v) | 
|  | #endif  /* IA32_PROFILE_TLB */ | 
 |  |  | 
 | DWORD   paddr;  /* physical addr */ |  | 
 | } TLB_ENTRY_T; |  | 
 |  |  | 
 | typedef struct { | typedef struct { | 
| BYTE            kind; | UINT32  tag;    /* linear address */ | 
| #define TLB_KIND_INSTRUCTION    (1 << 1) | #define TLB_ENTRY_VALID         (1 << 0) | 
| #define TLB_KIND_DATA           (1 << 2) | #define TLB_ENTRY_GLOBAL        CPU_PTE_GLOBAL_PAGE | 
| #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 */ | UINT32  paddr;  /* physical address */ | 
| WORD            wpad; | } TLB_ENTRY_T; | 
 |  |  | 
| TLB_ENTRY_T*    entry;  /* entry[assoc][idx] or entry[assoc] if idx == 1*/ | #define TLB_GET_PADDR(ep, addr) ((ep)->paddr + ((addr) & ~CPU_PTE_BASEADDR_MASK)) | 
| } TLB_T; | #define TLB_SET_PADDR(ep, addr) ((ep)->paddr = (addr) & CPU_PTE_BASEADDR_MASK) | 
 |  |  | 
| static int ntlb; | #define TLB_TAG_SHIFT   17 | 
| static TLB_T tlb[4];    /* i TLB, i (lp) TLB, d TLB, d (lp) TLB */ | #define TLB_TAG_MASK    ~((1 << TLB_TAG_SHIFT) - 1) | 
|  | #define TLB_GET_TAG_ADDR(ep)    ((ep)->tag & TLB_TAG_MASK) | 
|  | #define TLB_SET_TAG_ADDR(ep, addr) \ | 
|  | ((ep)->tag = ((addr) & TLB_TAG_MASK) + ((ep)->tag & ~TLB_TAG_MASK)) | 
|  |  | 
|  | #define TLB_IS_VALID(ep)        ((ep)->tag & TLB_ENTRY_VALID) | 
|  | #define TLB_SET_VALID(ep)       ((ep)->tag |= TLB_ENTRY_VALID) | 
|  | #define TLB_CLEAR_VALID(ep)     ((ep)->tag &= ~TLB_ENTRY_VALID) | 
|  |  | 
|  | #if CPU_FAMILY == 4 | 
|  | #define TLB_IS_GLOBAL(ep)       FALSE | 
|  | #define TLB_SET_GLOBAL(ep)      (void)(ep) | 
|  | #define TLB_CLEAR_GLOBAL(ep)    (void)(ep) | 
|  | #else | 
|  | #define TLB_IS_GLOBAL(ep)       ((ep)->tag & TLB_ENTRY_GLOBAL) | 
|  | #define TLB_SET_GLOBAL(ep)      ((ep)->tag |= TLB_ENTRY_GLOBAL) | 
|  | #define TLB_CLEAR_GLOBAL(ep)    ((ep)->tag &= ~TLB_ENTRY_GLOBAL) | 
|  | #endif | 
 |  |  | 
 | #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)++; | #if CPU_FAMILY == 4 | 
| #else   /* !IA32_PROFILE_TLB */ | #define NTLB    1 | 
| #define PROFILE_INC(v) | #define NENTRY  (1 << 3) | 
| #endif  /* IA32_PROFILE_TLB */ | #define NWAY    (1 << 2) | 
|  |  | 
|  | #define TLB_ENTRY_SHIFT 12 | 
|  | #define TLB_ENTRY_MASK  (NENTRY - 1) | 
|  | #define TLB_WAY_SHIFT   15 | 
|  | #define TLB_WAY_MASK    (NWAY - 1) | 
|  | #endif | 
|  |  | 
|  | typedef struct { | 
|  | TLB_ENTRY_T     entry[NENTRY][NWAY]; | 
|  | } TLB_T; | 
|  |  | 
|  | static TLB_T 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) | #if defined(IA32_PROFILE_TLB) | 
| tlb_hits = 0; | memset(&tlb_profile, 0, sizeof(tlb_profile)); | 
| tlb_misses = 0; |  | 
| tlb_lookups = 0; |  | 
| tlb_updates = 0; |  | 
| tlb_flushes = 0; |  | 
| tlb_global_flushes = 0; |  | 
| tlb_entry_flushes = 0; |  | 
 | #endif  /* IA32_PROFILE_TLB */ | #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 | 
 | tlb_flush(BOOL allflush) | tlb_flush(BOOL allflush) | 
 | { | { | 
| TLB_ENTRY_T* ep; | TLB_ENTRY_T *ep; | 
 | int i, j; | int i, j; | 
 |  |  | 
 | if (allflush) { | if (allflush) { | 
| Line 596  tlb_flush(BOOL allflush) | Line 640  tlb_flush(BOOL allflush) | 
 | PROFILE_INC(tlb_flushes); | PROFILE_INC(tlb_flushes); | 
 | } | } | 
 |  |  | 
| for (i = 0; i < ntlb; i++) { | for (i = 0; i < NENTRY ; i++) { | 
| ep = tlb[i].entry; | for (j = 0; j < NWAY; j++) { | 
| for (j = 0; j < tlb[i].num; j++, ep++) { | ep = &tlb.entry[i][j]; | 
| if (ep->valid && (allflush || !ep->global)) { | if (TLB_IS_VALID(ep) && (!TLB_IS_GLOBAL(ep) || allflush)) { | 
| ep->valid = 0; | TLB_CLEAR_VALID(ep); | 
 | PROFILE_INC(tlb_entry_flushes); | PROFILE_INC(tlb_entry_flushes); | 
 | } | } | 
 | } | } | 
| Line 608  tlb_flush(BOOL allflush) | Line 652  tlb_flush(BOOL allflush) | 
 | } | } | 
 |  |  | 
 | void | void | 
| tlb_flush_page(DWORD vaddr) | tlb_flush_page(UINT32 laddr) | 
 | { | { | 
| TLB_ENTRY_T* ep; | TLB_ENTRY_T *ep; | 
 | int idx; | int idx; | 
| int i; | int way; | 
 |  |  | 
| for (i = 0; i < ntlb; i++) { | PROFILE_INC(tlb_flushes); | 
| 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 */ | idx = (laddr >> TLB_ENTRY_SHIFT) & (NENTRY - 1); | 
| ep = &tlb[i].entry[idx * tlb[i].way]; | way = (laddr >> TLB_WAY_SHIFT) & (NWAY - 1); | 
| for (i = 0; i < tlb[i].way; i++) { | ep = &tlb.entry[idx][way]; | 
| if (ep->valid) { |  | 
| if ((vaddr & ep->mask) == ep->tag) { | if (TLB_IS_VALID(ep)) { | 
| ep->valid = 0; | if ((laddr & TLB_TAG_MASK) == TLB_GET_TAG_ADDR(ep)) { | 
| PROFILE_INC(tlb_entry_flushes); | TLB_CLEAR_VALID(ep); | 
| break; | return; | 
| } |  | 
| } |  | 
 | } | } | 
 | } | } | 
 | } | } | 
 |  |  | 
 | static BOOL | static BOOL | 
| tlb_lookup(DWORD vaddr, int crw, DWORD* paddr) | tlb_lookup(const UINT32 laddr, const int crw, UINT32 *paddr) | 
 | { | { | 
| TLB_ENTRY_T* ep; | TLB_ENTRY_T *ep; | 
 | int idx; | int idx; | 
| int i; | int way; | 
 |  |  | 
 | PROFILE_INC(tlb_lookups); | PROFILE_INC(tlb_lookups); | 
 |  |  | 
| crw &= CPU_PAGING_PAGE_CODE | CPU_PAGING_PAGE_DATA; | idx = (laddr >> TLB_ENTRY_SHIFT) & (NENTRY - 1); | 
| for (i = 0; i < ntlb; i++) { | way = (laddr >> TLB_WAY_SHIFT) & (NWAY - 1); | 
| if (tlb[i].kind & crw) { | ep = &tlb.entry[idx][way]; | 
| if (tlb[i].idx == 1) { |  | 
| /* fully set associative */ | ep = &tlb.entry[idx][way]; | 
| idx = 0; | if (TLB_IS_VALID(ep)) { | 
| } else { | if ((laddr & TLB_TAG_MASK) == TLB_GET_TAG_ADDR(ep)) { | 
| if (tlb[i].kind & TLB_KIND_SMALL) { | *paddr = TLB_GET_PADDR(ep, laddr); | 
| idx = (vaddr >> 12) & (tlb[i].idx - 1); | PROFILE_INC(tlb_hits); | 
| } else { | return TRUE; | 
| idx = (vaddr >> 22) & (tlb[i].idx - 1); |  | 
| } |  | 
| } |  | 
|  |  | 
| /* search */ |  | 
| ep = &tlb[i].entry[idx * tlb[i].way]; |  | 
| for (i = 0; i < tlb[i].way; i++) { |  | 
| if (ep->valid) { |  | 
| if ((vaddr & ep->mask) == ep->tag) { |  | 
| if (ep->score != (BYTE)~0) |  | 
| ep->score++; |  | 
| *paddr = ep->paddr; |  | 
| PROFILE_INC(tlb_hits); |  | 
| return TRUE; |  | 
| } |  | 
| } |  | 
| } |  | 
 | } | } | 
 | } | } | 
 |  | (void)crw; | 
 | PROFILE_INC(tlb_misses); | PROFILE_INC(tlb_misses); | 
 | return FALSE; | return FALSE; | 
 | } | } | 
 |  |  | 
 | static void | static void | 
| tlb_update(DWORD paddr, DWORD entry, int crw) | tlb_update(const UINT32 laddr, const UINT entry, const int crw) | 
 | { | { | 
| TLB_ENTRY_T* ep; | TLB_ENTRY_T *ep; | 
 | int idx; | int idx; | 
| int i, j; | int way; | 
| int min_way; |  | 
| WORD min_score = ~0; |  | 
 |  |  | 
 | PROFILE_INC(tlb_updates); | PROFILE_INC(tlb_updates); | 
 |  |  | 
| crw &= CPU_PAGING_PAGE_CODE | CPU_PAGING_PAGE_DATA; | idx = (laddr >> TLB_ENTRY_SHIFT) & (NENTRY - 1); | 
| for (i = 0; i < ntlb; i++) { | way = (laddr >> TLB_WAY_SHIFT) & (NWAY - 1); | 
| if (tlb[i].kind & crw) { | ep = &tlb.entry[idx][way]; | 
| if (tlb[i].idx == 1) { |  | 
| /* fully set associative */ | TLB_SET_VALID(ep); | 
| idx = 0; | #if CPU_FAMILY >= 5 | 
| } else { | if (entry & CPU_PTE_GLOBAL_PAGE) { | 
| /* n-way set associative */ | TLB_SET_GLOBAL(ep); | 
| 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); | #endif | 
| } | TLB_SET_TAG_ADDR(ep, laddr); | 
| #else   /* !IA32_SUPPORT_TLB */ | TLB_SET_PADDR(ep, entry); | 
| void | (void)crw; | 
| tlb_init() |  | 
| { |  | 
|  |  | 
| /* nothing to do */ |  | 
| } |  | 
|  |  | 
| void |  | 
| tlb_flush(BOOL allflush) |  | 
| { |  | 
|  |  | 
| (void)allflush; |  | 
| } |  | 
|  |  | 
| void |  | 
| tlb_flush_page(DWORD vaddr) |  | 
| { |  | 
|  |  | 
| (void)vaddr; |  | 
 | } | } | 
 | #endif  /* IA32_SUPPORT_TLB */ | #endif  /* IA32_SUPPORT_TLB */ |