xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/vm.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
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 3 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, see <http://www.gnu.org/licenses/>.
17 
18     */
19 
20 
21 #ifndef _VM_C_
22 #define _VM_C_
23 
24 #if 0
25 #include "basics.h"
26 #include "registers.h"
27 #include "device.h"
28 #include "corefile.h"
29 #include "vm.h"
30 #include "interrupts.h"
31 #include "mon.h"
32 #endif
33 
34 #include "cpu.h"
35 #include "symcat.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)
om_segment_tlb_index(unsigned_word ea)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)
om_page_tlb_index(unsigned_word ea)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)
om_hash_page(unsigned_word masked_vsid,unsigned_word ea)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)
om_pte_0_api(unsigned_word pte_0)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)
om_pte_0_hash(unsigned_word pte_0)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)
om_pte_0_valid(unsigned_word pte_0)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)
om_ea_masked_page(unsigned_word ea)358 om_ea_masked_page(unsigned_word ea)
359 {
360   return MASKED(ea, 36, 51);
361 }
362 
363 STATIC_INLINE_VM\
364 (unsigned_word)
om_ea_masked_byte(unsigned_word ea)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)
om_pte_0_masked_vsid(unsigned_word pte_0)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)
om_pte_1_pp(unsigned_word pte_1)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)
om_pte_1_referenced(unsigned_word pte_1)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)
om_pte_1_changed(unsigned_word pte_1)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)
om_pte_1_masked_rpn(unsigned_word pte_1)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)
om_ea_api(unsigned_word ea)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)
om_read_word(om_map * map,unsigned_word ra,cpu * processor,unsigned_word cia)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)
om_write_word(om_map * map,unsigned_word ra,unsigned_word val,cpu * processor,unsigned_word cia)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 *)
vm_create(core * physical)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 *)
om_effective_to_bat(om_map * map,unsigned_word ea)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 *)
om_effective_to_virtual(om_map * map,unsigned_word ea,cpu * processor,unsigned_word cia)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 *)
om_virtual_to_real(om_map * map,unsigned_word ea,om_segment_tlb_entry * segment_tlb_entry,om_access_types access,cpu * processor,unsigned_word cia)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=%p\n",
614 		     (long)ea, 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 	     (long)map->real_address_of_page_table,
632 	     (long)page_hash,
633 	     (long)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=%p &pte1=0x%lx\n",
666 		   (long)ea, page_tlb_entry, (long)real_address_of_pte_1));
667 	  }
668 	  else {
669 	    TRACE(trace_vm,
670 		  ("ea=0x%lx - htab hit - tlb=%p &pte1=0x%lx\n",
671 		   (long)ea, 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)
om_interrupt(cpu * processor,unsigned_word cia,unsigned_word ea,om_access_types access,storage_interrupt_reasons reason)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)
om_translate_effective_to_real(om_map * map,unsigned_word ea,om_access_types access,cpu * processor,unsigned_word cia,int abort)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=%p &pte1=0x%lx\n",
802 		     (long)ea, 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)
om_unpack_bat(om_bat * bat,spreg ubat,spreg lbat)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)
om_unpack_bats(om_bats * bats,spreg * raw_bats,msreg msr)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)
om_unpack_sr(vm * virtual,sreg * srs,int which_sr,cpu * processor,unsigned_word cia)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)
om_unpack_srs(vm * virtual,sreg * srs,cpu * processor,unsigned_word cia)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 specified by
917    the passed registers */
918 INLINE_VM\
919 (void)
vm_synchronize_context(vm * virtual,spreg * sprs,sreg * srs,msreg msr,cpu * processor,unsigned_word cia)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 == BFD_ENDIAN_LITTLE)
978 	|| (!little_endian && CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG))
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 != BFD_ENDIAN_LITTLE)
992 	|| (!little_endian && CURRENT_TARGET_BYTE_ORDER != BFD_ENDIAN_BIG))
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)
vm_page_tlb_invalidate_entry(vm * memory,unsigned_word ea)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)
vm_page_tlb_invalidate_all(vm * memory)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 *)
vm_create_data_map(vm * memory)1026 vm_create_data_map(vm *memory)
1027 {
1028   return &memory->data_map;
1029 }
1030 
1031 
1032 INLINE_VM\
1033 (vm_instruction_map *)
vm_create_instruction_map(vm * memory)1034 vm_create_instruction_map(vm *memory)
1035 {
1036   return &memory->instruction_map;
1037 }
1038 
1039 
1040 STATIC_INLINE_VM\
1041 (unsigned_word)
vm_translate(om_map * map,unsigned_word ea,om_access_types access,cpu * processor,unsigned_word cia,int abort)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)
vm_real_data_addr(vm_data_map * map,unsigned_word ea,int is_read,cpu * processor,unsigned_word cia)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)
vm_real_instruction_addr(vm_instruction_map * map,cpu * processor,unsigned_word cia)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)
vm_instruction_map_read(vm_instruction_map * map,cpu * processor,unsigned_word cia)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)
vm_data_map_read_buffer(vm_data_map * map,void * target,unsigned_word addr,unsigned nr_bytes,cpu * processor,unsigned_word cia)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)
vm_data_map_write_buffer(vm_data_map * map,const void * source,unsigned_word addr,unsigned nr_bytes,int violate_read_only_section,cpu * processor,unsigned_word cia)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_ */
1199