Root/
| 1 | #pypp 0 |
| 2 | // Iris: micro-kernel for a capability-based operating system. |
| 3 | // mips/arch.ccp: Most mips-specific parts. |
| 4 | // Copyright 2009 Bas Wijnen <wijnen@debian.org> |
| 5 | // |
| 6 | // This program is free software: you can redistribute it and/or modify |
| 7 | // it under the terms of the GNU General Public License as published by |
| 8 | // the Free Software Foundation, either version 3 of the License, or |
| 9 | // (at your option) any later version. |
| 10 | // |
| 11 | // This program is distributed in the hope that it will be useful, |
| 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | // GNU General Public License for more details. |
| 15 | // |
| 16 | // You should have received a copy of the GNU General Public License |
| 17 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | |
| 19 | #define ARCH |
| 20 | #include "kernel.hh" |
| 21 | |
| 22 | void kThread_arch_init (kThread *thread): |
| 23 | thread->arch.at = 0 |
| 24 | for unsigned i = 0; i < 2; ++i: |
| 25 | thread->arch.v[i] = 0 |
| 26 | for unsigned i = 0; i < 4; ++i: |
| 27 | thread->arch.a[i] = 0 |
| 28 | for unsigned i = 0; i < 10; ++i: |
| 29 | thread->arch.t[i] = 0 |
| 30 | thread->arch.gp = 0 |
| 31 | thread->arch.fp = 0 |
| 32 | thread->arch.ra = 0 |
| 33 | thread->arch.hi = 0 |
| 34 | thread->arch.lo = 0 |
| 35 | |
| 36 | void kPage_arch_init (kPage *page): |
| 37 | page->arch.prev_mapped = NULL |
| 38 | page->arch.next_mapped = NULL |
| 39 | |
| 40 | void kThread_arch_receive (kThread *thread, Iris::Num protected_data, Iris::Num *data): |
| 41 | thread->arch.a[0] = data[0].l |
| 42 | thread->arch.a[1] = data[0].h |
| 43 | thread->arch.a[2] = data[1].l |
| 44 | thread->arch.a[3] = data[1].h |
| 45 | thread->arch.t[0] = protected_data.l |
| 46 | thread->arch.t[1] = protected_data.h |
| 47 | |
| 48 | unsigned *kThread_arch_info (kThread *thread, unsigned num): |
| 49 | switch num: |
| 50 | case 1: |
| 51 | return &thread->arch.at |
| 52 | case 2: |
| 53 | return &thread->arch.v[0] |
| 54 | case 3: |
| 55 | return &thread->arch.v[1] |
| 56 | case 4: |
| 57 | return &thread->arch.a[0] |
| 58 | case 5: |
| 59 | return &thread->arch.a[1] |
| 60 | case 6: |
| 61 | return &thread->arch.a[2] |
| 62 | case 7: |
| 63 | return &thread->arch.a[3] |
| 64 | case 8: |
| 65 | return &thread->arch.t[0] |
| 66 | case 9: |
| 67 | return &thread->arch.t[1] |
| 68 | case 10: |
| 69 | return &thread->arch.t[2] |
| 70 | case 11: |
| 71 | return &thread->arch.t[3] |
| 72 | case 12: |
| 73 | return &thread->arch.t[4] |
| 74 | case 13: |
| 75 | return &thread->arch.t[5] |
| 76 | case 14: |
| 77 | return &thread->arch.t[6] |
| 78 | case 15: |
| 79 | return &thread->arch.t[7] |
| 80 | case 16: |
| 81 | return &thread->arch.s[0] |
| 82 | case 17: |
| 83 | return &thread->arch.s[1] |
| 84 | case 18: |
| 85 | return &thread->arch.s[2] |
| 86 | case 19: |
| 87 | return &thread->arch.s[3] |
| 88 | case 20: |
| 89 | return &thread->arch.s[4] |
| 90 | case 21: |
| 91 | return &thread->arch.s[5] |
| 92 | case 22: |
| 93 | return &thread->arch.s[6] |
| 94 | case 23: |
| 95 | return &thread->arch.s[7] |
| 96 | case 24: |
| 97 | return &thread->arch.t[8] |
| 98 | case 25: |
| 99 | return &thread->arch.t[9] |
| 100 | case 26: |
| 101 | return &thread->arch.gp |
| 102 | case 27: |
| 103 | return &thread->sp |
| 104 | case 28: |
| 105 | return &thread->arch.fp |
| 106 | case 29: |
| 107 | return &thread->arch.ra |
| 108 | default: |
| 109 | return NULL |
| 110 | |
| 111 | void kMemory_arch_init (kMemory *mem): |
| 112 | mem->arch.asid = 1 |
| 113 | mem->arch.directory = NULL |
| 114 | mem->arch.shadow = NULL |
| 115 | |
| 116 | static void tlb_reset (kMemory *mem, unsigned address, unsigned value): |
| 117 | //kdebug_line () |
| 118 | unsigned asid = mem->arch.asid |
| 119 | if asids[asid] != (unsigned)mem: |
| 120 | //kdebug ("not resetting tlb, because the asid is not in use.\n") |
| 121 | return |
| 122 | //kdebug ("resetting tlb for ") |
| 123 | //kdebug_num (address) |
| 124 | //kdebug ("\n") |
| 125 | cp0_set (CP0_ENTRY_HI, address | asid) |
| 126 | __asm__ volatile ("tlbp") |
| 127 | unsigned idx |
| 128 | cp0_get (CP0_INDEX, idx) |
| 129 | if !(idx & (1 << 31)): |
| 130 | __asm__ volatile ("tlbr") |
| 131 | if address & (1 << PAGE_BITS): |
| 132 | cp0_set (CP0_ENTRY_LO1, value) |
| 133 | else: |
| 134 | cp0_set (CP0_ENTRY_LO0, value) |
| 135 | __asm__ volatile ("tlbwi") |
| 136 | #if 0 |
| 137 | kdebug ("tlb reset ") |
| 138 | unsigned hi, lo0, lo1 |
| 139 | cp0_get (CP0_ENTRY_LO0, lo0) |
| 140 | cp0_get (CP0_ENTRY_LO1, lo1) |
| 141 | cp0_get (CP0_ENTRY_HI, hi) |
| 142 | kdebug_num (idx, 2) |
| 143 | kdebug ('|') |
| 144 | kdebug_num (lo0) |
| 145 | kdebug (":") |
| 146 | kdebug_num (lo1) |
| 147 | kdebug (" for ") |
| 148 | kdebug_num (hi) |
| 149 | kdebug ("\n") |
| 150 | #endif |
| 151 | cp0_set (CP0_ENTRY_HI, old_current->address_space->arch.asid) |
| 152 | |
| 153 | static unsigned make_entry_lo (kPage *page): |
| 154 | //kdebug_line () |
| 155 | if !page->frame: |
| 156 | //kdebug ("not mapping because there is no frame\n") |
| 157 | return 0 |
| 158 | unsigned flags |
| 159 | if page->flags & Iris::Page::UNCACHED: |
| 160 | flags = 0x10 | 0x2 |
| 161 | else: |
| 162 | // 18 is write-back cache; 00 is write-through cache. |
| 163 | flags = 0x18 | 0x2 |
| 164 | if ~page->flags & Iris::Page::MAPPED_READONLY: |
| 165 | flags |= 0x4 |
| 166 | return ((page->frame & ~0x80000000) >> 6) | flags |
| 167 | |
| 168 | bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address): |
| 169 | if page->mapping != ~0: |
| 170 | mem->unmap (page) |
| 171 | if address == ~0: |
| 172 | return true |
| 173 | if address >= 0x80000000: |
| 174 | dpanic (address, "trying to map to kernel address") |
| 175 | return false |
| 176 | if address & ~PAGE_MASK: |
| 177 | dpanic (address, "mapping not page-aligned") |
| 178 | address &= PAGE_MASK |
| 179 | if !mem->arch.directory: |
| 180 | //kdebug ("creating directory\n") |
| 181 | mem->arch.directory = (Table **)mem->zalloc () |
| 182 | if !mem->arch.directory: |
| 183 | dpanic (0, "unable to allocate directory") |
| 184 | return false |
| 185 | mem->arch.shadow = (kPageP *)mem->zalloc () |
| 186 | if !mem->arch.shadow: |
| 187 | dpanic (0, "unable to allocate shadow directory") |
| 188 | mem->zfree ((unsigned)mem->arch.directory) |
| 189 | mem->arch.directory = NULL |
| 190 | return false |
| 191 | Table *table = mem->arch.directory[address >> 21] |
| 192 | if !table: |
| 193 | //kdebug ("creating table\n") |
| 194 | table = (Table *)mem->zalloc () |
| 195 | if !table: |
| 196 | dpanic (0, "unable to allocate table") |
| 197 | //if mem->arch.first_table == ~0: |
| 198 | // mem->zfree ((unsigned)mem->arch.directory) |
| 199 | // mem->zfree ((unsigned)mem->arch.shadow) |
| 200 | // mem->arch.directory = NULL |
| 201 | // mem->arch.shadow = NULL |
| 202 | return false |
| 203 | mem->arch.directory[address >> 21] = table |
| 204 | unsigned idx = (address >> 12) & ((1 << 9) - 1) |
| 205 | if table->entrylo[idx]: |
| 206 | kdebug ("page already mapped: ") |
| 207 | kdebug_num (idx, 3) |
| 208 | kdebug (";") |
| 209 | kdebug_num (table->entrylo[idx]) |
| 210 | kdebug ("/") |
| 211 | kdebug_num ((unsigned)table->page[idx]) |
| 212 | kdebug (" table: ") |
| 213 | kdebug_num ((unsigned)table) |
| 214 | kdebug ("\n") |
| 215 | mem->unmap (table->page[idx]) |
| 216 | table->entrylo[idx] = make_entry_lo (page) |
| 217 | table->page[idx] = page |
| 218 | #if 0 |
| 219 | kdebug ("mapped ") |
| 220 | kdebug_num (page->frame) |
| 221 | kdebug (" at address ") |
| 222 | kdebug_num (address) |
| 223 | kdebug ('\n') |
| 224 | #endif |
| 225 | page->mapping = address |
| 226 | page->arch.next_mapped = mem->arch.shadow[address >> 21] |
| 227 | if page->arch.next_mapped: |
| 228 | page->arch.next_mapped->arch.prev_mapped = page |
| 229 | mem->arch.shadow[address >> 21] = page |
| 230 | tlb_reset (mem, address, table->entrylo[idx]) |
| 231 | return true |
| 232 | |
| 233 | void kMemory_arch_unmap (kMemory *mem, kPage *page): |
| 234 | //kdebug_line () |
| 235 | unsigned didx = page->mapping >> 21 |
| 236 | unsigned tidx = (page->mapping >> 12) & ((1 << 9) - 1) |
| 237 | Table *table = mem->arch.directory[didx] |
| 238 | table->entrylo[tidx] = 0 |
| 239 | table->page[tidx] = NULL |
| 240 | if page->arch.next_mapped: |
| 241 | page->arch.next_mapped->arch.prev_mapped = page->arch.prev_mapped |
| 242 | if page->arch.prev_mapped: |
| 243 | page->arch.prev_mapped->arch.next_mapped = page->arch.next_mapped |
| 244 | else: |
| 245 | mem->arch.shadow[didx] = page->arch.next_mapped |
| 246 | page->arch.prev_mapped = NULL |
| 247 | page->arch.next_mapped = NULL |
| 248 | tlb_reset (mem, page->mapping, 0) |
| 249 | page->mapping = ~0 |
| 250 | |
| 251 | kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address): |
| 252 | //kdebug_line () |
| 253 | if address >= 0x80000000 || !mem->arch.directory: |
| 254 | return NULL |
| 255 | Table *table = mem->arch.directory[address >> 21] |
| 256 | if !table: |
| 257 | return NULL |
| 258 | return table->page[(address >> 12) & ((1 << 9) - 1)] |
| 259 | |
| 260 | void kPage_arch_update_mapping (kPage *page): |
| 261 | //kdebug_line () |
| 262 | if page->mapping == ~0: |
| 263 | return |
| 264 | unsigned target = make_entry_lo (page) |
| 265 | unsigned de = page->mapping >> 21 |
| 266 | unsigned te = (page->mapping >> 12) & ((1 << 9) - 1) |
| 267 | page->address_space->arch.directory[de]->entrylo[te] = target |
| 268 | tlb_reset (page->address_space, page->mapping, target) |
| 269 | |
| 270 | typedef unsigned cacheline[8] |
| 271 | void arch_uncache_page (unsigned page): |
| 272 | for cacheline *line = (cacheline *)page; line < (cacheline *)(page + PAGE_SIZE); ++line: |
| 273 | __asm__ volatile ("lw $k0, %0; cache 0x10, 0($k0); cache 0x11, 0($k0)" :: "m"(line)) |
| 274 | |
| 275 | void arch_register_interrupt (unsigned num, kReceiver *r): |
| 276 | arch_interrupt_receiver[num] = r |
| 277 | // And enable or disable the interrupt. |
| 278 | if r: |
| 279 | //if num != 0x18: |
| 280 | // kdebug ("enabled interrupt ") |
| 281 | // kdebug_num (num) |
| 282 | // kdebug (", state: ") |
| 283 | // kdebug_num (INTC_IMR) |
| 284 | // kdebug ("\n") |
| 285 | intc_unmask_irq (num) |
| 286 | else: |
| 287 | //kdebug ("disabled interrupt ") |
| 288 | //kdebug_num (num) |
| 289 | //kdebug ("\n") |
| 290 | intc_mask_irq (num) |
| 291 |
Branches:
master
