|
1 | 1 | #include <stdint.h> |
2 | 2 | #include <mem/vmem.h> |
| 3 | +#include <interrupt/irq.h> |
3 | 4 |
|
| 5 | +// 仮想メモリオフセット |
4 | 6 | static int32_t vmem_offset = 0; |
5 | 7 |
|
| 8 | +// デフォルトの物理アドレス→仮想アドレス変換関数 |
| 9 | +static uint32_t default_phys2virt(uint32_t phys) { |
| 10 | + if (vmem_offset == 0) return phys; |
| 11 | + return (uint32_t)((int32_t)phys + vmem_offset); |
| 12 | +} |
| 13 | + |
| 14 | +// 現在の仮想メモリモード |
| 15 | +static vmem_mode_t current_mode = VMEM_MODE_IDENTITY; |
| 16 | +// 物理→仮想変換関数 |
| 17 | +static vmem_phys2virt_fn phys2virt = default_phys2virt; |
| 18 | + |
| 19 | +// 仮想アドレス→物理アドレス変換 |
6 | 20 | uint32_t vmem_virt_to_phys(uint32_t virt) { |
7 | | - if (vmem_offset == 0) return virt; |
8 | | - if ((int32_t)virt - vmem_offset < 0) return 0; |
9 | | - return (uint32_t)((int32_t)virt - vmem_offset); |
| 21 | + if (current_mode == VMEM_MODE_IDENTITY) return virt; |
| 22 | + if (current_mode == VMEM_MODE_OFFSET) { |
| 23 | + if ((int32_t)virt - vmem_offset < 0) return 0; |
| 24 | + return (uint32_t)((int32_t)virt - vmem_offset); |
| 25 | + } |
| 26 | + |
| 27 | + uint32_t cr3; |
| 28 | + asm volatile("mov %%cr3, %%eax" : "=a" (cr3)); |
| 29 | + uint32_t pd_phys = cr3 & 0xFFFFF000; |
| 30 | + uint32_t pd_virt = phys2virt(pd_phys); |
| 31 | + if (pd_virt == 0) return 0; |
| 32 | + |
| 33 | + uint32_t pd_idx = (virt >> 22) & 0x3FF; |
| 34 | + uint32_t pt_idx = (virt >> 12) & 0x3FF; |
| 35 | + |
| 36 | + uint32_t *pd = (uint32_t *)(uintptr_t)pd_virt; |
| 37 | + uint32_t pde = pd[pd_idx]; |
| 38 | + if ((pde & 0x1) == 0) return 0; // 存在しない |
| 39 | + |
| 40 | + // 4MBページのチェック |
| 41 | + if (pde & 0x80) { |
| 42 | + // 4MBページ: ビット22..31が物理ベース |
| 43 | + uint32_t page_base = pde & 0xFFC00000; |
| 44 | + uint32_t offset = virt & 0x003FFFFF; |
| 45 | + return page_base | offset; |
| 46 | + } |
| 47 | + |
| 48 | + uint32_t pt_phys = pde & 0xFFFFF000; |
| 49 | + uint32_t pt_virt = phys2virt(pt_phys); |
| 50 | + if (pt_virt == 0) return 0; |
| 51 | + uint32_t *pt = (uint32_t *)(uintptr_t)pt_virt; |
| 52 | + uint32_t pte = pt[pt_idx]; |
| 53 | + if ((pte & 0x1) == 0) return 0; |
| 54 | + uint32_t page_base = pte & 0xFFFFF000; |
| 55 | + uint32_t offset = virt & 0xFFF; |
| 56 | + return page_base | offset; |
10 | 57 | } |
11 | 58 |
|
| 59 | +// 物理アドレス→仮想アドレス変換 |
12 | 60 | uint32_t vmem_phys_to_virt(uint32_t phys) { |
13 | | - if (vmem_offset == 0) return phys; |
14 | | - return (uint32_t)((int32_t)phys + vmem_offset); |
| 61 | + if (phys2virt) return phys2virt(phys); |
| 62 | + return phys; |
15 | 63 | } |
16 | 64 |
|
| 65 | +// オフセット設定 |
17 | 66 | void vmem_set_offset(int32_t offset) { |
18 | | - vmem_offset = offset; |
| 67 | + vmem_offset = offset; |
19 | 68 | } |
20 | 69 |
|
| 70 | +// リセット |
21 | 71 | void vmem_reset(void) { |
22 | | - vmem_offset = 0; |
| 72 | + vmem_offset = 0; |
| 73 | +} |
| 74 | + |
| 75 | +// モード設定 |
| 76 | +void vmem_set_mode(vmem_mode_t mode) { |
| 77 | + current_mode = mode; |
| 78 | +} |
| 79 | + |
| 80 | +// 物理→仮想変換関数の設定 |
| 81 | +void vmem_set_phys2virt(vmem_phys2virt_fn fn) { |
| 82 | + if (fn) phys2virt = fn; |
| 83 | + else phys2virt = default_phys2virt; |
23 | 84 | } |
0 commit comments