]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/vm.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / sim / ppc / vm.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21
22 #ifndef _VM_C_
23 #define _VM_C_
24
25 #if 0
26 #include "basics.h"
27 #include "registers.h"
28 #include "device.h"
29 #include "corefile.h"
30 #include "vm.h"
31 #include "interrupts.h"
32 #include "mon.h"
33 #endif
34
35 #include "cpu.h"
36
37 /* OEA vs VEA
38
39 For the VEA model, the VM layer is almost transparent. It's only
40 purpose is to maintain separate core_map's for the instruction
41 and data address spaces. This being so that writes to instruction
42 space or execution of a data space is prevented.
43
44 For the OEA model things are more complex. The reason for separate
45 instruction and data models becomes crucial. The OEA model is
46 built out of three parts. An instruction map, a data map and an
47 underlying structure that provides access to the VM data kept in
48 main memory. */
49
50
51 /* OEA data structures:
52
53 The OEA model maintains internal data structures that shadow the
54 semantics of the various OEA VM registers (BAT, SR, etc). This
55 allows a simple efficient model of the VM to be implemented.
56
57 Consistency between OEA registers and this model's internal data
58 structures is maintained by updating the structures at
59 `synchronization' points. Of particular note is that (at the time
60 of writing) the memory data types for BAT registers are rebuilt
61 when ever the processor moves between problem and system states.
62
63 Unpacked values are stored in the OEA so that they correctly align
64 to where they will be needed by the PTE address. */
65
66
67 /* Protection table:
68
69 Matrix of processor state, type of access and validity */
70
71 typedef enum {
72 om_supervisor_state,
73 om_problem_state,
74 nr_om_modes
75 } om_processor_modes;
76
77 typedef enum {
78 om_data_read, om_data_write,
79 om_instruction_read, om_access_any,
80 nr_om_access_types
81 } om_access_types;
82
83 static int om_valid_access[2][4][nr_om_access_types] = {
84 /* read, write, instruction, any */
85 /* K bit == 0 */
86 { /*r w i a pp */
87 { 1, 1, 1, 1 }, /* 00 */
88 { 1, 1, 1, 1 }, /* 01 */
89 { 1, 1, 1, 1 }, /* 10 */
90 { 1, 0, 1, 1 }, /* 11 */
91 },
92 /* K bit == 1 or P bit valid */
93 { /*r w i a pp */
94 { 0, 0, 0, 0 }, /* 00 */
95 { 1, 0, 1, 1 }, /* 01 */
96 { 1, 1, 1, 1 }, /* 10 */
97 { 1, 0, 1, 1 }, /* 11 */
98 }
99 };
100
101
102 /* Bat translation:
103
104 The bat data structure only contains information on valid BAT
105 translations for the current processor mode and type of access. */
106
107 typedef struct _om_bat {
108 unsigned_word block_effective_page_index;
109 unsigned_word block_effective_page_index_mask;
110 unsigned_word block_length_mask;
111 unsigned_word block_real_page_number;
112 int protection_bits;
113 } om_bat;
114
115 enum _nr_om_bat_registers {
116 nr_om_bat_registers = 4
117 };
118
119 typedef struct _om_bats {
120 int nr_valid_bat_registers;
121 om_bat bat[nr_om_bat_registers];
122 } om_bats;
123
124
125 /* Segment TLB:
126
127 In this model the 32 and 64 bit segment tables are treated in very
128 similar ways. The 32bit segment registers are treated as a
129 simplification of the 64bit segment tlb */
130
131 enum _om_segment_tlb_constants {
132 #if (WITH_TARGET_WORD_BITSIZE == 64)
133 sizeof_segment_table_entry_group = 128,
134 sizeof_segment_table_entry = 16,
135 #endif
136 om_segment_tlb_index_start_bit = 32,
137 om_segment_tlb_index_stop_bit = 35,
138 nr_om_segment_tlb_entries = 16,
139 nr_om_segment_tlb_constants
140 };
141
142 typedef struct _om_segment_tlb_entry {
143 int key[nr_om_modes];
144 om_access_types invalid_access; /* set to instruction if no_execute bit */
145 unsigned_word masked_virtual_segment_id; /* aligned ready for pte group addr */
146 #if (WITH_TARGET_WORD_BITSIZE == 64)
147 int is_valid;
148 unsigned_word masked_effective_segment_id;
149 #endif
150 } om_segment_tlb_entry;
151
152 typedef struct _om_segment_tlb {
153 om_segment_tlb_entry entry[nr_om_segment_tlb_entries];
154 } om_segment_tlb;
155
156
157 /* Page TLB:
158
159 This OEA model includes a small direct map Page TLB. The tlb is to
160 cut down on the need for the OEA to perform walks of the page hash
161 table. */
162
163 enum _om_page_tlb_constants {
164 om_page_tlb_index_start_bit = 46,
165 om_page_tlb_index_stop_bit = 51,
166 nr_om_page_tlb_entries = 64,
167 #if (WITH_TARGET_WORD_BITSIZE == 64)
168 sizeof_pte_group = 128,
169 sizeof_pte = 16,
170 #endif
171 #if (WITH_TARGET_WORD_BITSIZE == 32)
172 sizeof_pte_group = 64,
173 sizeof_pte = 8,
174 #endif
175 nr_om_page_tlb_constants
176 };
177
178 typedef struct _om_page_tlb_entry {
179 int protection;
180 int changed;
181 unsigned_word real_address_of_pte_1;
182 unsigned_word masked_virtual_segment_id;
183 unsigned_word masked_page;
184 unsigned_word masked_real_page_number;
185 } om_page_tlb_entry;
186
187 typedef struct _om_page_tlb {
188 om_page_tlb_entry entry[nr_om_page_tlb_entries];
189 } om_page_tlb;
190
191
192 /* memory translation:
193
194 OEA memory translation possibly involves BAT, SR, TLB and HTAB
195 information*/
196
197 typedef struct _om_map {
198
199 /* local cache of register values */
200 int is_relocate;
201 int is_problem_state;
202
203 /* block address translation */
204 om_bats *bat_registers;
205
206 /* failing that, translate ea to va using segment tlb */
207 #if (WITH_TARGET_WORD_BITSIZE == 64)
208 unsigned_word real_address_of_segment_table;
209 #endif
210 om_segment_tlb *segment_tlb;
211
212 /* then va to ra using hashed page table and tlb */
213 unsigned_word real_address_of_page_table;
214 unsigned_word page_table_hash_mask;
215 om_page_tlb *page_tlb;
216
217 /* physical memory for fetching page table entries */
218 core_map *physical;
219
220 /* address xor for PPC endian */
221 unsigned xor[WITH_XOR_ENDIAN];
222
223 } om_map;
224
225
226 /* VM objects:
227
228 External objects defined by vm.h */
229
230 struct _vm_instruction_map {
231 /* real memory for last part */
232 core_map *code;
233 /* translate effective to real */
234 om_map translation;
235 };
236
237 struct _vm_data_map {
238 /* translate effective to real */
239 om_map translation;
240 /* real memory for translated address */
241 core_map *read;
242 core_map *write;
243 };
244
245
246 /* VM:
247
248 Underlying memory object. For the VEA this is just the
249 core_map. For OEA it is the instruction and data memory
250 translation's */
251
252 struct _vm {
253
254 /* OEA: base address registers */
255 om_bats ibats;
256 om_bats dbats;
257
258 /* OEA: segment registers */
259 om_segment_tlb segment_tlb;
260
261 /* OEA: translation lookaside buffers */
262 om_page_tlb instruction_tlb;
263 om_page_tlb data_tlb;
264
265 /* real memory */
266 core *physical;
267
268 /* memory maps */
269 vm_instruction_map instruction_map;
270 vm_data_map data_map;
271
272 };
273
274
275 /* OEA Support procedures */
276
277
278 STATIC_INLINE_VM\
279 (unsigned_word)
280 om_segment_tlb_index(unsigned_word ea)
281 {
282 unsigned_word index = EXTRACTED(ea,
283 om_segment_tlb_index_start_bit,
284 om_segment_tlb_index_stop_bit);
285 return index;
286 }
287
288 STATIC_INLINE_VM\
289 (unsigned_word)
290 om_page_tlb_index(unsigned_word ea)
291 {
292 unsigned_word index = EXTRACTED(ea,
293 om_page_tlb_index_start_bit,
294 om_page_tlb_index_stop_bit);
295 return index;
296 }
297
298 STATIC_INLINE_VM\
299 (unsigned_word)
300 om_hash_page(unsigned_word masked_vsid,
301 unsigned_word ea)
302 {
303 unsigned_word extracted_ea = EXTRACTED(ea, 36, 51);
304 #if (WITH_TARGET_WORD_BITSIZE == 32)
305 unsigned_word masked_ea = INSERTED32(extracted_ea, 7, 31-6);
306 unsigned_word hash = masked_vsid ^ masked_ea;
307 #endif
308 #if (WITH_TARGET_WORD_BITSIZE == 64)
309 unsigned_word masked_ea = INSERTED64(extracted_ea, 18, 63-7);
310 unsigned_word hash = masked_vsid ^ masked_ea;
311 #endif
312 TRACE(trace_vm, ("ea=0x%lx - masked-vsid=0x%lx masked-ea=0x%lx hash=0x%lx\n",
313 (unsigned long)ea,
314 (unsigned long)masked_vsid,
315 (unsigned long)masked_ea,
316 (unsigned long)hash));
317 return hash;
318 }
319
320 STATIC_INLINE_VM\
321 (unsigned_word)
322 om_pte_0_api(unsigned_word pte_0)
323 {
324 #if (WITH_TARGET_WORD_BITSIZE == 32)
325 return EXTRACTED32(pte_0, 26, 31);
326 #endif
327 #if (WITH_TARGET_WORD_BITSIZE == 64)
328 return EXTRACTED64(pte_0, 52, 56);
329 #endif
330 }
331
332 STATIC_INLINE_VM\
333 (unsigned_word)
334 om_pte_0_hash(unsigned_word pte_0)
335 {
336 #if (WITH_TARGET_WORD_BITSIZE == 32)
337 return EXTRACTED32(pte_0, 25, 25);
338 #endif
339 #if (WITH_TARGET_WORD_BITSIZE == 64)
340 return EXTRACTED64(pte_0, 62, 62);
341 #endif
342 }
343
344 STATIC_INLINE_VM\
345 (int)
346 om_pte_0_valid(unsigned_word pte_0)
347 {
348 #if (WITH_TARGET_WORD_BITSIZE == 32)
349 return MASKED32(pte_0, 0, 0) != 0;
350 #endif
351 #if (WITH_TARGET_WORD_BITSIZE == 64)
352 return MASKED64(pte_0, 63, 63) != 0;
353 #endif
354 }
355
356 STATIC_INLINE_VM\
357 (unsigned_word)
358 om_ea_masked_page(unsigned_word ea)
359 {
360 return MASKED(ea, 36, 51);
361 }
362
363 STATIC_INLINE_VM\
364 (unsigned_word)
365 om_ea_masked_byte(unsigned_word ea)
366 {
367 return MASKED(ea, 52, 63);
368 }
369
370 /* return the VSID aligned for pte group addr */
371 STATIC_INLINE_VM\
372 (unsigned_word)
373 om_pte_0_masked_vsid(unsigned_word pte_0)
374 {
375 #if (WITH_TARGET_WORD_BITSIZE == 32)
376 return INSERTED32(EXTRACTED32(pte_0, 1, 24), 31-6-24+1, 31-6);
377 #endif
378 #if (WITH_TARGET_WORD_BITSIZE == 64)
379 return INSERTED64(EXTRACTED64(pte_0, 0, 51), 63-7-52+1, 63-7);
380 #endif
381 }
382
383 STATIC_INLINE_VM\
384 (unsigned_word)
385 om_pte_1_pp(unsigned_word pte_1)
386 {
387 return MASKED(pte_1, 62, 63); /*PP*/
388 }
389
390 STATIC_INLINE_VM\
391 (int)
392 om_pte_1_referenced(unsigned_word pte_1)
393 {
394 return EXTRACTED(pte_1, 55, 55);
395 }
396
397 STATIC_INLINE_VM\
398 (int)
399 om_pte_1_changed(unsigned_word pte_1)
400 {
401 return EXTRACTED(pte_1, 56, 56);
402 }
403
404 STATIC_INLINE_VM\
405 (int)
406 om_pte_1_masked_rpn(unsigned_word pte_1)
407 {
408 return MASKED(pte_1, 0, 51); /*RPN*/
409 }
410
411 STATIC_INLINE_VM\
412 (unsigned_word)
413 om_ea_api(unsigned_word ea)
414 {
415 return EXTRACTED(ea, 36, 41);
416 }
417
418
419 /* Page and Segment table read/write operators, these need to still
420 account for the PPC's XOR operation */
421
422 STATIC_INLINE_VM\
423 (unsigned_word)
424 om_read_word(om_map *map,
425 unsigned_word ra,
426 cpu *processor,
427 unsigned_word cia)
428 {
429 if (WITH_XOR_ENDIAN)
430 ra ^= map->xor[sizeof(instruction_word) - 1];
431 return core_map_read_word(map->physical, ra, processor, cia);
432 }
433
434 STATIC_INLINE_VM\
435 (void)
436 om_write_word(om_map *map,
437 unsigned_word ra,
438 unsigned_word val,
439 cpu *processor,
440 unsigned_word cia)
441 {
442 if (WITH_XOR_ENDIAN)
443 ra ^= map->xor[sizeof(instruction_word) - 1];
444 core_map_write_word(map->physical, ra, val, processor, cia);
445 }
446
447
448 /* Bring things into existance */
449
450 INLINE_VM\
451 (vm *)
452 vm_create(core *physical)
453 {
454 vm *virtual;
455
456 /* internal checks */
457 if (nr_om_segment_tlb_entries
458 != (1 << (om_segment_tlb_index_stop_bit
459 - om_segment_tlb_index_start_bit + 1)))
460 error("internal error - vm_create - problem with om_segment constants\n");
461 if (nr_om_page_tlb_entries
462 != (1 << (om_page_tlb_index_stop_bit
463 - om_page_tlb_index_start_bit + 1)))
464 error("internal error - vm_create - problem with om_page constants\n");
465
466 /* create the new vm register file */
467 virtual = ZALLOC(vm);
468
469 /* set up core */
470 virtual->physical = physical;
471
472 /* set up the address decoders */
473 virtual->instruction_map.translation.bat_registers = &virtual->ibats;
474 virtual->instruction_map.translation.segment_tlb = &virtual->segment_tlb;
475 virtual->instruction_map.translation.page_tlb = &virtual->instruction_tlb;
476 virtual->instruction_map.translation.is_relocate = 0;
477 virtual->instruction_map.translation.is_problem_state = 0;
478 virtual->instruction_map.translation.physical = core_readable(physical);
479 virtual->instruction_map.code = core_readable(physical);
480
481 virtual->data_map.translation.bat_registers = &virtual->dbats;
482 virtual->data_map.translation.segment_tlb = &virtual->segment_tlb;
483 virtual->data_map.translation.page_tlb = &virtual->data_tlb;
484 virtual->data_map.translation.is_relocate = 0;
485 virtual->data_map.translation.is_problem_state = 0;
486 virtual->data_map.translation.physical = core_readable(physical);
487 virtual->data_map.read = core_readable(physical);
488 virtual->data_map.write = core_writeable(physical);
489
490 return virtual;
491 }
492
493
494 STATIC_INLINE_VM\
495 (om_bat *)
496 om_effective_to_bat(om_map *map,
497 unsigned_word ea)
498 {
499 int curr_bat = 0;
500 om_bats *bats = map->bat_registers;
501 int nr_bats = bats->nr_valid_bat_registers;
502
503 for (curr_bat = 0; curr_bat < nr_bats; curr_bat++) {
504 om_bat *bat = bats->bat + curr_bat;
505 if ((ea & bat->block_effective_page_index_mask)
506 != bat->block_effective_page_index)
507 continue;
508 return bat;
509 }
510
511 return NULL;
512 }
513
514
515 STATIC_INLINE_VM\
516 (om_segment_tlb_entry *)
517 om_effective_to_virtual(om_map *map,
518 unsigned_word ea,
519 cpu *processor,
520 unsigned_word cia)
521 {
522 /* first try the segment tlb */
523 om_segment_tlb_entry *segment_tlb_entry = (map->segment_tlb->entry
524 + om_segment_tlb_index(ea));
525
526 #if (WITH_TARGET_WORD_BITSIZE == 32)
527 TRACE(trace_vm, ("ea=0x%lx - sr[%ld] - masked-vsid=0x%lx va=0x%lx%07lx\n",
528 (unsigned long)ea,
529 (long)om_segment_tlb_index(ea),
530 (unsigned long)segment_tlb_entry->masked_virtual_segment_id,
531 (unsigned long)EXTRACTED32(segment_tlb_entry->masked_virtual_segment_id, 31-6-24+1, 31-6),
532 (unsigned long)EXTRACTED32(ea, 4, 31)));
533 return segment_tlb_entry;
534 #endif
535
536 #if (WITH_TARGET_WORD_BITSIZE == 64)
537 if (segment_tlb_entry->is_valid
538 && (segment_tlb_entry->masked_effective_segment_id == MASKED(ea, 0, 35))) {
539 error("fixme - is there a need to update any bits\n");
540 return segment_tlb_entry;
541 }
542
543 /* drats, segment tlb missed */
544 {
545 unsigned_word segment_id_hash = ea;
546 int current_hash = 0;
547 for (current_hash = 0; current_hash < 2; current_hash += 1) {
548 unsigned_word segment_table_entry_group =
549 (map->real_address_of_segment_table
550 | (MASKED64(segment_id_hash, 31, 35) >> (56-35)));
551 unsigned_word segment_table_entry;
552 for (segment_table_entry = segment_table_entry_group;
553 segment_table_entry < (segment_table_entry_group
554 + sizeof_segment_table_entry_group);
555 segment_table_entry += sizeof_segment_table_entry) {
556 /* byte order? */
557 unsigned_word segment_table_entry_dword_0 =
558 om_read_word(map->physical, segment_table_entry, processor, cia);
559 unsigned_word segment_table_entry_dword_1 =
560 om_read_word(map->physical, segment_table_entry + 8,
561 processor, cia);
562 int is_valid = MASKED64(segment_table_entry_dword_0, 56, 56) != 0;
563 unsigned_word masked_effective_segment_id =
564 MASKED64(segment_table_entry_dword_0, 0, 35);
565 if (is_valid && masked_effective_segment_id == MASKED64(ea, 0, 35)) {
566 /* don't permit some things */
567 if (MASKED64(segment_table_entry_dword_0, 57, 57))
568 error("om_effective_to_virtual() - T=1 in STE not supported\n");
569 /* update segment tlb */
570 segment_tlb_entry->is_valid = is_valid;
571 segment_tlb_entry->masked_effective_segment_id =
572 masked_effective_segment_id;
573 segment_tlb_entry->key[om_supervisor_state] =
574 EXTRACTED64(segment_table_entry_dword_0, 58, 58);
575 segment_tlb_entry->key[om_problem_state] =
576 EXTRACTED64(segment_table_entry_dword_0, 59, 59);
577 segment_tlb_entry->invalid_access =
578 (MASKED64(segment_table_entry_dword_0, 60, 60)
579 ? om_instruction_read
580 : om_access_any);
581 segment_tlb_entry->masked_virtual_segment_id =
582 INSERTED64(EXTRACTED64(segment_table_entry_dword_1, 0, 51),
583 18-13, 63-7); /* aligned ready for pte group addr */
584 return segment_tlb_entry;
585 }
586 }
587 segment_id_hash = ~segment_id_hash;
588 }
589 }
590 return NULL;
591 #endif
592 }
593
594
595
596 STATIC_INLINE_VM\
597 (om_page_tlb_entry *)
598 om_virtual_to_real(om_map *map,
599 unsigned_word ea,
600 om_segment_tlb_entry *segment_tlb_entry,
601 om_access_types access,
602 cpu *processor,
603 unsigned_word cia)
604 {
605 om_page_tlb_entry *page_tlb_entry = (map->page_tlb->entry
606 + om_page_tlb_index(ea));
607
608 /* is it a tlb hit? */
609 if ((page_tlb_entry->masked_virtual_segment_id
610 == segment_tlb_entry->masked_virtual_segment_id)
611 && (page_tlb_entry->masked_page
612 == om_ea_masked_page(ea))) {
613 TRACE(trace_vm, ("ea=0x%lx - tlb hit - tlb=0x%lx\n",
614 (long)ea, (long)page_tlb_entry));
615 return page_tlb_entry;
616 }
617
618 /* drats, it is a tlb miss */
619 {
620 unsigned_word page_hash =
621 om_hash_page(segment_tlb_entry->masked_virtual_segment_id, ea);
622 int current_hash;
623 for (current_hash = 0; current_hash < 2; current_hash += 1) {
624 unsigned_word real_address_of_pte_group =
625 (map->real_address_of_page_table
626 | (page_hash & map->page_table_hash_mask));
627 unsigned_word real_address_of_pte_0;
628 TRACE(trace_vm,
629 ("ea=0x%lx - htab search %d - htab=0x%lx hash=0x%lx mask=0x%lx pteg=0x%lx\n",
630 (long)ea, current_hash,
631 map->real_address_of_page_table,
632 page_hash,
633 map->page_table_hash_mask,
634 (long)real_address_of_pte_group));
635 for (real_address_of_pte_0 = real_address_of_pte_group;
636 real_address_of_pte_0 < (real_address_of_pte_group
637 + sizeof_pte_group);
638 real_address_of_pte_0 += sizeof_pte) {
639 unsigned_word pte_0 = om_read_word(map,
640 real_address_of_pte_0,
641 processor, cia);
642 /* did we hit? */
643 if (om_pte_0_valid(pte_0)
644 && (current_hash == om_pte_0_hash(pte_0))
645 && (segment_tlb_entry->masked_virtual_segment_id
646 == om_pte_0_masked_vsid(pte_0))
647 && (om_ea_api(ea) == om_pte_0_api(pte_0))) {
648 unsigned_word real_address_of_pte_1 = (real_address_of_pte_0
649 + sizeof_pte / 2);
650 unsigned_word pte_1 = om_read_word(map,
651 real_address_of_pte_1,
652 processor, cia);
653 page_tlb_entry->protection = om_pte_1_pp(pte_1);
654 page_tlb_entry->changed = om_pte_1_changed(pte_1);
655 page_tlb_entry->masked_virtual_segment_id = segment_tlb_entry->masked_virtual_segment_id;
656 page_tlb_entry->masked_page = om_ea_masked_page(ea);
657 page_tlb_entry->masked_real_page_number = om_pte_1_masked_rpn(pte_1);
658 page_tlb_entry->real_address_of_pte_1 = real_address_of_pte_1;
659 if (!om_pte_1_referenced(pte_1)) {
660 om_write_word(map,
661 real_address_of_pte_1,
662 pte_1 | BIT(55),
663 processor, cia);
664 TRACE(trace_vm,
665 ("ea=0x%lx - htab hit - set ref - tlb=0x%lx &pte1=0x%lx\n",
666 (long)ea, (long)page_tlb_entry, (long)real_address_of_pte_1));
667 }
668 else {
669 TRACE(trace_vm,
670 ("ea=0x%lx - htab hit - tlb=0x%lx &pte1=0x%lx\n",
671 (long)ea, (long)page_tlb_entry, (long)real_address_of_pte_1));
672 }
673 return page_tlb_entry;
674 }
675 }
676 page_hash = ~page_hash; /*???*/
677 }
678 }
679 return NULL;
680 }
681
682
683 STATIC_INLINE_VM\
684 (void)
685 om_interrupt(cpu *processor,
686 unsigned_word cia,
687 unsigned_word ea,
688 om_access_types access,
689 storage_interrupt_reasons reason)
690 {
691 switch (access) {
692 case om_data_read:
693 data_storage_interrupt(processor, cia, ea, reason, 0/*!is_store*/);
694 break;
695 case om_data_write:
696 data_storage_interrupt(processor, cia, ea, reason, 1/*is_store*/);
697 break;
698 case om_instruction_read:
699 instruction_storage_interrupt(processor, cia, reason);
700 break;
701 default:
702 error("internal error - om_interrupt - unexpected access type %d", access);
703 }
704 }
705
706
707 STATIC_INLINE_VM\
708 (unsigned_word)
709 om_translate_effective_to_real(om_map *map,
710 unsigned_word ea,
711 om_access_types access,
712 cpu *processor,
713 unsigned_word cia,
714 int abort)
715 {
716 om_bat *bat = NULL;
717 om_segment_tlb_entry *segment_tlb_entry = NULL;
718 om_page_tlb_entry *page_tlb_entry = NULL;
719 unsigned_word ra;
720
721 if (!map->is_relocate) {
722 ra = ea;
723 TRACE(trace_vm, ("ea=0x%lx - direct map - ra=0x%lx\n",
724 (long)ea, (long)ra));
725 return ra;
726 }
727
728 /* match with BAT? */
729 bat = om_effective_to_bat(map, ea);
730 if (bat != NULL) {
731 if (!om_valid_access[1][bat->protection_bits][access]) {
732 TRACE(trace_vm, ("ea=0x%lx - bat access violation\n", (long)ea));
733 if (abort)
734 om_interrupt(processor, cia, ea, access,
735 protection_violation_storage_interrupt);
736 else
737 return MASK(0, 63);
738 }
739
740 ra = ((ea & bat->block_length_mask) | bat->block_real_page_number);
741 TRACE(trace_vm, ("ea=0x%lx - bat translation - ra=0x%lx\n",
742 (long)ea, (long)ra));
743 return ra;
744 }
745
746 /* translate ea to va using segment map */
747 segment_tlb_entry = om_effective_to_virtual(map, ea, processor, cia);
748 #if (WITH_TARGET_WORD_BITSIZE == 64)
749 if (segment_tlb_entry == NULL) {
750 TRACE(trace_vm, ("ea=0x%lx - segment tlb miss\n", (long)ea));
751 if (abort)
752 om_interrupt(processor, cia, ea, access,
753 segment_table_miss_storage_interrupt);
754 else
755 return MASK(0, 63);
756 }
757 #endif
758 /* check for invalid segment access type */
759 if (segment_tlb_entry->invalid_access == access) {
760 TRACE(trace_vm, ("ea=0x%lx - segment access invalid\n", (long)ea));
761 if (abort)
762 om_interrupt(processor, cia, ea, access,
763 protection_violation_storage_interrupt);
764 else
765 return MASK(0, 63);
766 }
767
768 /* lookup in PTE */
769 page_tlb_entry = om_virtual_to_real(map, ea, segment_tlb_entry,
770 access,
771 processor, cia);
772 if (page_tlb_entry == NULL) {
773 TRACE(trace_vm, ("ea=0x%lx - page tlb miss\n", (long)ea));
774 if (abort)
775 om_interrupt(processor, cia, ea, access,
776 hash_table_miss_storage_interrupt);
777 else
778 return MASK(0, 63);
779 }
780 if (!(om_valid_access
781 [segment_tlb_entry->key[map->is_problem_state]]
782 [page_tlb_entry->protection]
783 [access])) {
784 TRACE(trace_vm, ("ea=0x%lx - page tlb access violation\n", (long)ea));
785 if (abort)
786 om_interrupt(processor, cia, ea, access,
787 protection_violation_storage_interrupt);
788 else
789 return MASK(0, 63);
790 }
791
792 /* update change bit as needed */
793 if (access == om_data_write &&!page_tlb_entry->changed) {
794 unsigned_word pte_1 = om_read_word(map,
795 page_tlb_entry->real_address_of_pte_1,
796 processor, cia);
797 om_write_word(map,
798 page_tlb_entry->real_address_of_pte_1,
799 pte_1 | BIT(56),
800 processor, cia);
801 TRACE(trace_vm, ("ea=0x%lx - set change bit - tlb=0x%lx &pte1=0x%lx\n",
802 (long)ea, (long)page_tlb_entry,
803 (long)page_tlb_entry->real_address_of_pte_1));
804 }
805
806 ra = (page_tlb_entry->masked_real_page_number | om_ea_masked_byte(ea));
807 TRACE(trace_vm, ("ea=0x%lx - page translation - ra=0x%lx\n",
808 (long)ea, (long)ra));
809 return ra;
810 }
811
812
813 /*
814 * Definition of operations for memory management
815 */
816
817
818 /* rebuild all the relevant bat information */
819 STATIC_INLINE_VM\
820 (void)
821 om_unpack_bat(om_bat *bat,
822 spreg ubat,
823 spreg lbat)
824 {
825 /* for extracting out the offset within a page */
826 bat->block_length_mask = ((MASKED(ubat, 51, 61) << (17-2))
827 | MASK(63-17+1, 63));
828
829 /* for checking the effective page index */
830 bat->block_effective_page_index = MASKED(ubat, 0, 46);
831 bat->block_effective_page_index_mask = ~bat->block_length_mask;
832
833 /* protection information */
834 bat->protection_bits = EXTRACTED(lbat, 62, 63);
835 bat->block_real_page_number = MASKED(lbat, 0, 46);
836 }
837
838
839 /* rebuild the given bat table */
840 STATIC_INLINE_VM\
841 (void)
842 om_unpack_bats(om_bats *bats,
843 spreg *raw_bats,
844 msreg msr)
845 {
846 int i;
847 bats->nr_valid_bat_registers = 0;
848 for (i = 0; i < nr_om_bat_registers*2; i += 2) {
849 spreg ubat = raw_bats[i];
850 spreg lbat = raw_bats[i+1];
851 if ((msr & msr_problem_state)
852 ? EXTRACTED(ubat, 63, 63)
853 : EXTRACTED(ubat, 62, 62)) {
854 om_unpack_bat(&bats->bat[bats->nr_valid_bat_registers],
855 ubat, lbat);
856 bats->nr_valid_bat_registers += 1;
857 }
858 }
859 }
860
861
862 #if (WITH_TARGET_WORD_BITSIZE == 32)
863 STATIC_INLINE_VM\
864 (void)
865 om_unpack_sr(vm *virtual,
866 sreg *srs,
867 int which_sr,
868 cpu *processor,
869 unsigned_word cia)
870 {
871 om_segment_tlb_entry *segment_tlb_entry = 0;
872 sreg new_sr_value = 0;
873
874 /* check register in range */
875 ASSERT(which_sr >= 0 && which_sr < nr_om_segment_tlb_entries);
876
877 /* get the working values */
878 segment_tlb_entry = &virtual->segment_tlb.entry[which_sr];
879 new_sr_value = srs[which_sr];
880
881 /* do we support this */
882 if (MASKED32(new_sr_value, 0, 0))
883 cpu_error(processor, cia, "unsupported value of T in segment register %d",
884 which_sr);
885
886 /* update info */
887 segment_tlb_entry->key[om_supervisor_state] = EXTRACTED32(new_sr_value, 1, 1);
888 segment_tlb_entry->key[om_problem_state] = EXTRACTED32(new_sr_value, 2, 2);
889 segment_tlb_entry->invalid_access = (MASKED32(new_sr_value, 3, 3)
890 ? om_instruction_read
891 : om_access_any);
892 segment_tlb_entry->masked_virtual_segment_id =
893 INSERTED32(EXTRACTED32(new_sr_value, 8, 31),
894 31-6-24+1, 31-6); /* aligned ready for pte group addr */
895 }
896 #endif
897
898
899 #if (WITH_TARGET_WORD_BITSIZE == 32)
900 STATIC_INLINE_VM\
901 (void)
902 om_unpack_srs(vm *virtual,
903 sreg *srs,
904 cpu *processor,
905 unsigned_word cia)
906 {
907 int which_sr;
908 for (which_sr = 0; which_sr < nr_om_segment_tlb_entries; which_sr++) {
909 om_unpack_sr(virtual, srs, which_sr,
910 processor, cia);
911 }
912 }
913 #endif
914
915
916 /* Rebuild all the data structures for the new context as specifed by
917 the passed registers */
918 INLINE_VM\
919 (void)
920 vm_synchronize_context(vm *virtual,
921 spreg *sprs,
922 sreg *srs,
923 msreg msr,
924 /**/
925 cpu *processor,
926 unsigned_word cia)
927 {
928
929 /* enable/disable translation */
930 int problem_state = (msr & msr_problem_state) != 0;
931 int data_relocate = (msr & msr_data_relocate) != 0;
932 int instruction_relocate = (msr & msr_instruction_relocate) != 0;
933 int little_endian = (msr & msr_little_endian_mode) != 0;
934
935 unsigned_word page_table_hash_mask;
936 unsigned_word real_address_of_page_table;
937
938 /* update current processor mode */
939 virtual->instruction_map.translation.is_relocate = instruction_relocate;
940 virtual->instruction_map.translation.is_problem_state = problem_state;
941 virtual->data_map.translation.is_relocate = data_relocate;
942 virtual->data_map.translation.is_problem_state = problem_state;
943
944 /* update bat registers for the new context */
945 om_unpack_bats(&virtual->ibats, &sprs[spr_ibat0u], msr);
946 om_unpack_bats(&virtual->dbats, &sprs[spr_dbat0u], msr);
947
948 /* unpack SDR1 - the storage description register 1 */
949 #if (WITH_TARGET_WORD_BITSIZE == 64)
950 real_address_of_page_table = MASKED64(sprs[spr_sdr1], 0, 45);
951 page_table_hash_mask = MASK64(18+28-EXTRACTED64(sprs[spr_sdr1], 59, 63),
952 63-7);
953 #endif
954 #if (WITH_TARGET_WORD_BITSIZE == 32)
955 real_address_of_page_table = MASKED32(sprs[spr_sdr1], 0, 15);
956 page_table_hash_mask = (INSERTED32(EXTRACTED32(sprs[spr_sdr1], 23, 31),
957 7, 7+9-1)
958 | MASK32(7+9, 31-6));
959 #endif
960 virtual->instruction_map.translation.real_address_of_page_table = real_address_of_page_table;
961 virtual->instruction_map.translation.page_table_hash_mask = page_table_hash_mask;
962 virtual->data_map.translation.real_address_of_page_table = real_address_of_page_table;
963 virtual->data_map.translation.page_table_hash_mask = page_table_hash_mask;
964
965
966 /* unpack the segment tlb registers */
967 #if (WITH_TARGET_WORD_BITSIZE == 32)
968 om_unpack_srs(virtual, srs,
969 processor, cia);
970 #endif
971
972 /* set up the XOR registers if the current endian mode conflicts
973 with what is in the MSR */
974 if (WITH_XOR_ENDIAN) {
975 int i = 1;
976 unsigned mask;
977 if ((little_endian && CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
978 || (!little_endian && CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN))
979 mask = 0;
980 else
981 mask = WITH_XOR_ENDIAN - 1;
982 while (i - 1 < WITH_XOR_ENDIAN) {
983 virtual->instruction_map.translation.xor[i-1] = mask;
984 virtual->data_map.translation.xor[i-1] = mask;
985 mask = (mask << 1) & (WITH_XOR_ENDIAN - 1);
986 i = i * 2;
987 }
988 }
989 else {
990 /* don't allow the processor to change endian modes */
991 if ((little_endian && CURRENT_TARGET_BYTE_ORDER != LITTLE_ENDIAN)
992 || (!little_endian && CURRENT_TARGET_BYTE_ORDER != BIG_ENDIAN))
993 cpu_error(processor, cia, "attempt to change hardwired byte order");
994 }
995 }
996
997 /* update vm data structures due to a TLB operation */
998
999 INLINE_VM\
1000 (void)
1001 vm_page_tlb_invalidate_entry(vm *memory,
1002 unsigned_word ea)
1003 {
1004 int i = om_page_tlb_index(ea);
1005 memory->instruction_tlb.entry[i].masked_virtual_segment_id = MASK(0, 63);
1006 memory->data_tlb.entry[i].masked_virtual_segment_id = MASK(0, 63);
1007 TRACE(trace_vm, ("ea=0x%lx - tlb invalidate entry\n", (long)ea));
1008 }
1009
1010 INLINE_VM\
1011 (void)
1012 vm_page_tlb_invalidate_all(vm *memory)
1013 {
1014 int i;
1015 for (i = 0; i < nr_om_page_tlb_entries; i++) {
1016 memory->instruction_tlb.entry[i].masked_virtual_segment_id = MASK(0, 63);
1017 memory->data_tlb.entry[i].masked_virtual_segment_id = MASK(0, 63);
1018 }
1019 TRACE(trace_vm, ("tlb invalidate all\n"));
1020 }
1021
1022
1023
1024 INLINE_VM\
1025 (vm_data_map *)
1026 vm_create_data_map(vm *memory)
1027 {
1028 return &memory->data_map;
1029 }
1030
1031
1032 INLINE_VM\
1033 (vm_instruction_map *)
1034 vm_create_instruction_map(vm *memory)
1035 {
1036 return &memory->instruction_map;
1037 }
1038
1039
1040 STATIC_INLINE_VM\
1041 (unsigned_word)
1042 vm_translate(om_map *map,
1043 unsigned_word ea,
1044 om_access_types access,
1045 cpu *processor,
1046 unsigned_word cia,
1047 int abort)
1048 {
1049 switch (CURRENT_ENVIRONMENT) {
1050 case USER_ENVIRONMENT:
1051 case VIRTUAL_ENVIRONMENT:
1052 return ea;
1053 case OPERATING_ENVIRONMENT:
1054 return om_translate_effective_to_real(map, ea, access,
1055 processor, cia,
1056 abort);
1057 default:
1058 error("internal error - vm_translate - bad switch");
1059 return 0;
1060 }
1061 }
1062
1063
1064 INLINE_VM\
1065 (unsigned_word)
1066 vm_real_data_addr(vm_data_map *map,
1067 unsigned_word ea,
1068 int is_read,
1069 cpu *processor,
1070 unsigned_word cia)
1071 {
1072 return vm_translate(&map->translation,
1073 ea,
1074 is_read ? om_data_read : om_data_write,
1075 processor,
1076 cia,
1077 1); /*abort*/
1078 }
1079
1080
1081 INLINE_VM\
1082 (unsigned_word)
1083 vm_real_instruction_addr(vm_instruction_map *map,
1084 cpu *processor,
1085 unsigned_word cia)
1086 {
1087 return vm_translate(&map->translation,
1088 cia,
1089 om_instruction_read,
1090 processor,
1091 cia,
1092 1); /*abort*/
1093 }
1094
1095 INLINE_VM\
1096 (instruction_word)
1097 vm_instruction_map_read(vm_instruction_map *map,
1098 cpu *processor,
1099 unsigned_word cia)
1100 {
1101 unsigned_word ra = vm_real_instruction_addr(map, processor, cia);
1102 ASSERT((cia & 0x3) == 0); /* always aligned */
1103 if (WITH_XOR_ENDIAN)
1104 ra ^= map->translation.xor[sizeof(instruction_word) - 1];
1105 return core_map_read_4(map->code, ra, processor, cia);
1106 }
1107
1108
1109 INLINE_VM\
1110 (int)
1111 vm_data_map_read_buffer(vm_data_map *map,
1112 void *target,
1113 unsigned_word addr,
1114 unsigned nr_bytes,
1115 cpu *processor,
1116 unsigned_word cia)
1117 {
1118 unsigned count;
1119 for (count = 0; count < nr_bytes; count++) {
1120 unsigned_1 byte;
1121 unsigned_word ea = addr + count;
1122 unsigned_word ra = vm_translate(&map->translation,
1123 ea, om_data_read,
1124 processor, /*processor*/
1125 cia, /*cia*/
1126 processor != NULL); /*abort?*/
1127 if (ra == MASK(0, 63))
1128 break;
1129 if (WITH_XOR_ENDIAN)
1130 ra ^= map->translation.xor[0];
1131 if (core_map_read_buffer(map->read, &byte, ra, sizeof(byte))
1132 != sizeof(byte))
1133 break;
1134 ((unsigned_1*)target)[count] = T2H_1(byte);
1135 }
1136 return count;
1137 }
1138
1139
1140 INLINE_VM\
1141 (int)
1142 vm_data_map_write_buffer(vm_data_map *map,
1143 const void *source,
1144 unsigned_word addr,
1145 unsigned nr_bytes,
1146 int violate_read_only_section,
1147 cpu *processor,
1148 unsigned_word cia)
1149 {
1150 unsigned count;
1151 unsigned_1 byte;
1152 for (count = 0; count < nr_bytes; count++) {
1153 unsigned_word ea = addr + count;
1154 unsigned_word ra = vm_translate(&map->translation,
1155 ea, om_data_write,
1156 processor,
1157 cia,
1158 processor != NULL); /*abort?*/
1159 if (ra == MASK(0, 63))
1160 break;
1161 if (WITH_XOR_ENDIAN)
1162 ra ^= map->translation.xor[0];
1163 byte = T2H_1(((unsigned_1*)source)[count]);
1164 if (core_map_write_buffer((violate_read_only_section
1165 ? map->read
1166 : map->write),
1167 &byte, ra, sizeof(byte)) != sizeof(byte))
1168 break;
1169 }
1170 return count;
1171 }
1172
1173
1174 /* define the read/write 1/2/4/8/word functions */
1175
1176 #define N 1
1177 #include "vm_n.h"
1178 #undef N
1179
1180 #define N 2
1181 #include "vm_n.h"
1182 #undef N
1183
1184 #define N 4
1185 #include "vm_n.h"
1186 #undef N
1187
1188 #define N 8
1189 #include "vm_n.h"
1190 #undef N
1191
1192 #define N word
1193 #include "vm_n.h"
1194 #undef N
1195
1196
1197
1198 #endif /* _VM_C_ */