summaryrefslogtreecommitdiffstats
path: root/sim/ppc/vm.c
diff options
context:
space:
mode:
authorMichael Meissner <gnu@the-meissners.org>1995-11-02 14:27:18 +0000
committerMichael Meissner <gnu@the-meissners.org>1995-11-02 14:27:18 +0000
commita983c8f080912c4c99c68812b22a795c9b7f1f0d (patch)
treeee47ad45eb2e3529b02852066947955a4d8de5a1 /sim/ppc/vm.c
parentf2cd34413022d50dd8ae94db69324938fd63ea2d (diff)
downloadppe42-binutils-a983c8f080912c4c99c68812b22a795c9b7f1f0d.tar.gz
ppe42-binutils-a983c8f080912c4c99c68812b22a795c9b7f1f0d.zip
Andrew's latest changes & print all instruction counts if -I
Diffstat (limited to 'sim/ppc/vm.c')
-rw-r--r--sim/ppc/vm.c938
1 files changed, 938 insertions, 0 deletions
diff --git a/sim/ppc/vm.c b/sim/ppc/vm.c
new file mode 100644
index 0000000000..f15e0bf8ea
--- /dev/null
+++ b/sim/ppc/vm.c
@@ -0,0 +1,938 @@
+/* This file is part of the program psim.
+
+ Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ */
+
+
+#ifndef _VM_C_
+#define _VM_C_
+
+#ifndef STATIC_INLINE_VM
+#define STATIC_INLINE_VM STATIC_INLINE
+#endif
+
+
+#include "basics.h"
+
+#include "registers.h"
+
+#include "device_tree.h"
+#include "core.h"
+
+#include "vm.h"
+
+#include "interrupts.h"
+
+#include "mon.h"
+
+/* OEA vs VEA
+
+ For the VEA model, the VM layer is almost transparent. It's only
+ purpose is to maintain separate core_map's for the instruction
+ and data address spaces. This being so that writes to instruction
+ space or execution of a data space is prevented.
+
+ For the OEA model things are more complex. The reason for separate
+ instruction and data models becomes crucial. The OEA model is
+ built out of three parts. An instruction map, a data map and an
+ underlying structure that provides access to the VM data kept in
+ main memory. */
+
+
+/* OEA data structures:
+
+ The OEA model maintains internal data structures that shadow the
+ semantics of the various OEA VM registers (BAT, SR, etc). This
+ allows a simple efficient model of the VM to be implemented.
+
+ Consistency between OEA registers and this model's internal data
+ structures is maintained by updating the structures at
+ `synchronization' points. Of particular note is that (at the time
+ of writing) the memory data types for BAT registers are rebuilt
+ when ever the processor moves between problem and system states */
+
+
+/* Protection table:
+
+ Matrix of processor state, type of access and validity */
+
+typedef enum {
+ om_supervisor_state,
+ om_problem_state,
+ nr_om_modes
+} om_processor_modes;
+
+typedef enum {
+ om_data_read, om_data_write,
+ om_instruction_read, om_access_any,
+ nr_om_access_types
+} om_access_types;
+
+static int om_valid_access[2][4][nr_om_access_types] = {
+ /* read, write, instruction, any */
+ /* K bit == 0 */
+ { /*r w i a pp */
+ { 1, 1, 1, 1 }, /* 00 */
+ { 1, 1, 1, 1 }, /* 01 */
+ { 1, 1, 1, 1 }, /* 10 */
+ { 1, 0, 1, 1 }, /* 11 */
+ },
+ /* K bit == 1 or P bit valid */
+ { /*r w i a pp */
+ { 0, 0, 0, 0 }, /* 00 */
+ { 1, 0, 1, 1 }, /* 01 */
+ { 1, 1, 1, 1 }, /* 10 */
+ { 1, 0, 1, 1 }, /* 11 */
+ }
+};
+
+
+/* Bat translation:
+
+ The bat data structure only contains information on valid BAT
+ translations for the current processor mode and type of access. */
+
+typedef struct _om_bat {
+ unsigned_word block_effective_page_index;
+ unsigned_word block_effective_page_index_mask;
+ unsigned_word block_length_mask;
+ unsigned_word block_real_page_number;
+ int protection_bits;
+} om_bat;
+
+enum _nr_om_bat_registers {
+ nr_om_bat_registers = 4
+};
+
+typedef struct _om_bats {
+ int nr_valid_bat_registers;
+ om_bat bat[nr_om_bat_registers];
+} om_bats;
+
+
+/* Segment TLB:
+
+ In this model the 32 and 64 bit segment tables are treated in very
+ similar ways. The 32bit segment registers are treated as a
+ simplification of the 64bit segment tlb */
+
+enum _om_segment_tlb_constants {
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+ sizeof_segment_table_entry_group = 128,
+ sizeof_segment_table_entry = 16,
+#endif
+ om_segment_tlb_index_start_bit = 32,
+ om_segment_tlb_index_stop_bit = 35,
+ nr_om_segment_tlb_entries = 16,
+ nr_om_segment_tlb_constants
+};
+
+typedef struct _om_segment_tlb_entry {
+ int key[nr_om_modes];
+ om_access_types invalid_access; /* set to instruction if no_execute bit */
+ unsigned_word masked_virtual_segment_id;
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+ int is_valid;
+ unsigned_word masked_effective_segment_id;
+#endif
+} om_segment_tlb_entry;
+
+typedef struct _om_segment_tlb {
+ om_segment_tlb_entry entry[nr_om_segment_tlb_entries];
+} om_segment_tlb;
+
+
+/* Page TLB:
+
+ This OEA model includes a small direct map Page TLB. The tlb is to
+ cut down on the need for the OEA to perform walks of the page hash
+ table. */
+
+enum _om_page_tlb_constants {
+ om_page_tlb_index_start_bit = 46,
+ om_page_tlb_index_stop_bit = 51,
+ nr_om_page_tlb_entries = 64,
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+ sizeof_pte_group = 128,
+ sizeof_pte = 16,
+#endif
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+ sizeof_pte_group = 64,
+ sizeof_pte = 8,
+#endif
+ nr_om_page_tlb_constants
+};
+
+typedef struct _om_page_tlb_entry {
+ int valid;
+ int protection;
+ unsigned_word masked_virtual_segment_id;
+ unsigned_word masked_page;
+ unsigned_word masked_real_page_number;
+} om_page_tlb_entry;
+
+typedef struct _om_page_tlb {
+ om_page_tlb_entry entry[nr_om_page_tlb_entries];
+} om_page_tlb;
+
+
+/* memory translation:
+
+ OEA memory translation possibly involves BAT, SR, TLB and HTAB
+ information*/
+
+typedef struct _om_map {
+
+ /* local cache of register values */
+ int is_relocate;
+ int is_problem_state;
+
+ /* block address translation */
+ om_bats *bat_registers;
+
+ /* failing that, translate ea to va using segment tlb */
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+ unsigned_word real_address_of_segment_table;
+#endif
+ om_segment_tlb *segment_tlb;
+
+ /* then va to ra using hashed page table and tlb */
+ unsigned_word real_address_of_page_table;
+ unsigned_word page_table_hash_mask;
+ om_page_tlb *page_tlb;
+
+ /* physical memory for fetching page table entries */
+ core_map *physical;
+
+} om_map;
+
+
+/* VM objects:
+
+ External objects defined by vm.h */
+
+struct _vm_instruction_map {
+ /* real memory for last part */
+ core_map *code;
+ /* translate effective to real */
+ om_map translation;
+};
+
+struct _vm_data_map {
+ /* translate effective to real */
+ om_map translation;
+ /* real memory for translated address */
+ core_map *read;
+ core_map *write;
+};
+
+
+/* VM:
+
+ Underlying memory object. For the VEA this is just the
+ core_map. For OEA it is the instruction and data memory
+ translation's */
+
+struct _vm {
+
+ /* OEA: base address registers */
+ om_bats ibats;
+ om_bats dbats;
+
+ /* OEA: segment registers */
+ om_segment_tlb segment_tlb;
+
+ /* OEA: translation lookaside buffers */
+ om_page_tlb instruction_tlb;
+ om_page_tlb data_tlb;
+
+ /* real memory */
+ core *physical;
+
+ /* memory maps */
+ vm_instruction_map instruction_map;
+ vm_data_map data_map;
+
+};
+
+
+/* OEA Support procedures */
+
+
+STATIC_INLINE_VM unsigned_word
+om_segment_tlb_index(unsigned_word ea)
+{
+ unsigned_word index = EXTRACTED(ea,
+ om_segment_tlb_index_start_bit,
+ om_segment_tlb_index_stop_bit);
+ return index;
+}
+
+STATIC_INLINE_VM unsigned_word
+om_page_tlb_index(unsigned_word ea)
+{
+ unsigned_word index = EXTRACTED(ea,
+ om_page_tlb_index_start_bit,
+ om_page_tlb_index_stop_bit);
+ return index;
+}
+
+STATIC_INLINE_VM unsigned_word
+om_masked_page(unsigned_word ea)
+{
+ unsigned_word masked_page = MASKED(ea, 36, 51);
+ return masked_page;
+}
+
+STATIC_INLINE_VM unsigned_word
+om_masked_byte(unsigned_word ea)
+{
+ unsigned_word masked_byte = MASKED(ea, 52, 63);
+ return masked_byte;
+}
+
+
+
+INLINE_VM vm *
+vm_create(core *physical)
+{
+ vm *virtual;
+
+ /* internal checks */
+ if (nr_om_segment_tlb_entries
+ != (1 << (om_segment_tlb_index_stop_bit
+ - om_segment_tlb_index_start_bit + 1)))
+ error("new_vm() - internal error with om_segment constants\n");
+ if (nr_om_page_tlb_entries
+ != (1 << (om_page_tlb_index_stop_bit
+ - om_page_tlb_index_start_bit + 1)))
+ error("new_vm() - internal error with om_page constants\n");
+
+ /* create the new vm register file */
+ virtual = ZALLOC(vm);
+
+ /* set up core */
+ virtual->physical = physical;
+
+ /* set up the address decoders */
+ virtual->instruction_map.translation.bat_registers = &virtual->ibats;
+ virtual->instruction_map.translation.segment_tlb = &virtual->segment_tlb;
+ virtual->instruction_map.translation.page_tlb = &virtual->instruction_tlb;
+ virtual->instruction_map.translation.is_relocate = 0;
+ virtual->instruction_map.translation.is_problem_state = 0;
+ virtual->instruction_map.translation.physical = core_readable(physical);
+ virtual->instruction_map.code = core_readable(physical);
+
+ virtual->data_map.translation.bat_registers = &virtual->dbats;
+ virtual->data_map.translation.segment_tlb = &virtual->segment_tlb;
+ virtual->data_map.translation.page_tlb = &virtual->data_tlb;
+ virtual->data_map.translation.is_relocate = 0;
+ virtual->data_map.translation.is_problem_state = 0;
+ virtual->data_map.translation.physical = core_readable(physical);
+ virtual->data_map.read = core_readable(physical);
+ virtual->data_map.write = core_writeable(physical);
+
+ return virtual;
+}
+
+
+STATIC_INLINE_VM om_bat *
+om_effective_to_bat(om_map *map,
+ unsigned_word ea)
+{
+ int curr_bat = 0;
+ om_bats *bats = map->bat_registers;
+ int nr_bats = bats->nr_valid_bat_registers;
+
+ for (curr_bat = 0; curr_bat < nr_bats; curr_bat++) {
+ om_bat *bat = bats->bat + curr_bat;
+ if ((ea & bat->block_effective_page_index_mask)
+ != bat->block_effective_page_index)
+ continue;
+ return bat;
+ }
+
+ return NULL;
+}
+
+
+STATIC_INLINE_VM om_segment_tlb_entry *
+om_effective_to_virtual(om_map *map,
+ unsigned_word ea,
+ cpu *processor,
+ unsigned_word cia)
+{
+ /* first try the segment tlb */
+ om_segment_tlb_entry *segment_tlb_entry = (map->segment_tlb->entry
+ + om_segment_tlb_index(ea));
+
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+ return segment_tlb_entry;
+#endif
+
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+ if (segment_tlb_entry->is_valid
+ && (segment_tlb_entry->masked_effective_segment_id == MASKED(ea, 0, 35))) {
+ error("fixme - is there a need to update any bits\n");
+ return segment_tlb_entry;
+ }
+
+ /* drats, segment tlb missed */
+ {
+ unsigned_word segment_id_hash = ea;
+ int current_hash = 0;
+ for (current_hash = 0; current_hash < 2; current_hash += 1) {
+ unsigned_word segment_table_entry_group =
+ (map->real_address_of_segment_table
+ | (MASKED64(segment_id_hash, 31, 35) >> (56-35)));
+ unsigned_word segment_table_entry;
+ for (segment_table_entry = segment_table_entry_group;
+ segment_table_entry < (segment_table_entry_group
+ + sizeof_segment_table_entry_group);
+ segment_table_entry += sizeof_segment_table_entry) {
+ /* byte order? */
+ unsigned_word segment_table_entry_dword_0 =
+ core_map_read_8(map->physical, segment_table_entry, processor, cia);
+ unsigned_word segment_table_entry_dword_1 =
+ core_map_read_8(map->physical, segment_table_entry + 8, processor, cia);
+ int is_valid = MASKED64(segment_table_entry_dword_0, 56, 56) != 0;
+ unsigned_word masked_effective_segment_id =
+ MASKED64(segment_table_entry_dword_0, 0, 35);
+ if (is_valid && masked_effective_segment_id == MASKED64(ea, 0, 35)) {
+ /* don't permit some things */
+ if (MASKED64(segment_table_entry_dword_0, 57, 57))
+ error("om_effective_to_virtual() - T=1 in STE not supported\n");
+ /* update segment tlb */
+ segment_tlb_entry->is_valid = is_valid;
+ segment_tlb_entry->masked_effective_segment_id =
+ masked_effective_segment_id;
+ segment_tlb_entry->key[om_supervisor_state] =
+ EXTRACTED64(segment_table_entry_dword_0, 58, 58);
+ segment_tlb_entry->key[om_problem_state] =
+ EXTRACTED64(segment_table_entry_dword_0, 59, 59);
+ segment_tlb_entry->invalid_access =
+ (MASKED64(segment_table_entry_dword_0, 60, 60)
+ ? om_instruction_read
+ : om_access_any);
+ segment_tlb_entry->masked_virtual_segment_id =
+ MASKED(segment_table_entry_dword_1, 0, 51);
+ return segment_tlb_entry;
+ }
+ }
+ segment_id_hash = ~segment_id_hash;
+ }
+ }
+ return NULL;
+#endif
+}
+
+
+
+STATIC_INLINE_VM 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)
+{
+ om_page_tlb_entry *page_tlb_entry = (map->page_tlb->entry
+ + om_page_tlb_index(ea));
+
+ /* is it a tlb hit? */
+ if (page_tlb_entry->valid
+ && (page_tlb_entry->masked_virtual_segment_id ==
+ segment_tlb_entry->masked_virtual_segment_id)
+ && (page_tlb_entry->masked_page == om_masked_page(ea))) {
+ error("fixme - it is not a hit if direction/update bits do not match\n");
+ return page_tlb_entry;
+ }
+
+ /* drats, it is a tlb miss */
+ {
+ unsigned_word page_hash = (segment_tlb_entry->masked_virtual_segment_id
+ ^ om_masked_page(ea));
+ int current_hash;
+ for (current_hash = 0; current_hash < 2; current_hash += 1) {
+ unsigned_word real_address_of_pte_group =
+ (map->real_address_of_page_table
+ | (page_hash & map->page_table_hash_mask));
+ unsigned_word real_address_of_pte;
+ for (real_address_of_pte = real_address_of_pte_group;
+ real_address_of_pte < (real_address_of_pte_group
+ + sizeof_pte_group);
+ real_address_of_pte += sizeof_pte) {
+ unsigned_word pte_word_0 =
+ core_map_read_word(map->physical,
+ real_address_of_pte,
+ processor, cia);
+ unsigned_word pte_word_1 =
+ core_map_read_word(map->physical,
+ real_address_of_pte + sizeof_pte / 2,
+ processor, cia);
+ error("fixme - check pte hit\n");
+ if (1) {
+ error("fixme - update the page_tlb\n");
+ page_tlb_entry->valid = 1;
+ page_tlb_entry->protection = 0;
+ page_tlb_entry->masked_virtual_segment_id = 0;
+ page_tlb_entry->masked_page = 0;
+ page_tlb_entry->masked_real_page_number = 0;
+ return page_tlb_entry;
+ }
+ }
+ page_hash = ~page_hash; /*???*/
+ }
+ }
+ return NULL;
+}
+
+
+static void
+om_interrupt(cpu *processor,
+ unsigned_word cia,
+ unsigned_word ea,
+ om_access_types access,
+ storage_interrupt_reasons reason)
+{
+ switch (access) {
+ case om_data_read:
+ data_storage_interrupt(processor, cia, ea, reason, 0/*!is_store*/);
+ break;
+ case om_data_write:
+ data_storage_interrupt(processor, cia, ea, reason, 1/*is_store*/);
+ break;
+ case om_instruction_read:
+ instruction_storage_interrupt(processor, cia, reason);
+ break;
+ default:
+ error("om_interrupt - unexpected access type %d, cia=0x%x, ea=0x%x\n",
+ access, cia, ea);
+ }
+}
+
+
+STATIC_INLINE_VM unsigned_word
+om_translate_effective_to_real(om_map *map,
+ unsigned_word ea,
+ om_access_types access,
+ cpu *processor,
+ unsigned_word cia,
+ int abort)
+{
+ om_bat *bat = NULL;
+ om_segment_tlb_entry *segment_tlb_entry = NULL;
+ om_page_tlb_entry *page_tlb_entry = NULL;
+ unsigned_word ra;
+
+ if (!map->is_relocate) {
+ ra = ea;
+ TRACE(trace_vm, ("%s, direct map, ea=0x%x\n",
+ "om_translate_effective_to_real",
+ ea));
+ return ra;
+ }
+
+ /* match with BAT? */
+ bat = om_effective_to_bat(map, ea);
+ if (bat != NULL) {
+ if (!om_valid_access[1][bat->protection_bits][access]) {
+ TRACE(trace_vm, ("%s, bat protection violation, ea=0x%x\n",
+ "om_translate_effective_to_real",
+ ea));
+ if (abort)
+ om_interrupt(processor, cia, ea, access,
+ protection_violation_storage_interrupt);
+ else
+ return MASK(0, 63);
+ }
+
+ ra = ((ea & bat->block_length_mask) | bat->block_real_page_number);
+ TRACE(trace_vm, ("%s, bat translation, ea=0x%x, ra=0x%x\n",
+ "om_translate_effective_to_real",
+ ea, ra));
+ return ra;
+ }
+
+ /* translate ea to va using segment map */
+ segment_tlb_entry = om_effective_to_virtual(map, ea, processor, cia);
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+ if (segment_tlb_entry == NULL) {
+ TRACE(trace_vm, ("%s, segment tlb lookup failed - ea=0x%x\n",
+ "om_translate_effective_to_real",
+ ea));
+ if (abort)
+ om_interrupt(processor, cia, ea, access,
+ segment_table_miss_storage_interrupt);
+ else
+ return MASK(0, 63);
+ }
+#endif
+ /* check for invalid segment access type */
+ if (segment_tlb_entry->invalid_access == access) {
+ TRACE(trace_vm, ("%s, segment tlb access invalid - ea=0x%x\n",
+ "om_translate_effective_to_real",
+ ea));
+ if (abort)
+ om_interrupt(processor, cia, ea, access,
+ protection_violation_storage_interrupt);
+ else
+ return MASK(0, 63);
+ }
+
+ /* lookup in PTE */
+ page_tlb_entry = om_virtual_to_real(map, ea, segment_tlb_entry,
+ access,
+ processor, cia);
+ if (page_tlb_entry == NULL) {
+ TRACE(trace_vm, ("%s, page tlb lookup failed - ea=0x%x\n",
+ "om_translate_effective_to_real",
+ ea));
+ if (abort)
+ om_interrupt(processor, cia, ea, access,
+ hash_table_miss_storage_interrupt);
+ else
+ return MASK(0, 63);
+ }
+ if (!(om_valid_access
+ [segment_tlb_entry->key[map->is_problem_state]]
+ [page_tlb_entry->protection]
+ [access])) {
+ TRACE(trace_vm, ("%s, page tlb access invalid - ea=0x%x\n",
+ "om_translate_effective_to_real",
+ ea));
+ if (abort)
+ om_interrupt(processor, cia, ea, access,
+ protection_violation_storage_interrupt);
+ else
+ return MASK(0, 63);
+ }
+
+ ra = (page_tlb_entry->masked_real_page_number
+ | om_masked_byte(ea));
+ TRACE(trace_vm, ("%s, page - ea=0x%x, ra=0x%x\n",
+ "om_translate_effective_to_real",
+ ea, ra));
+ return ra;
+}
+
+
+/*
+ * Definition of operations for memory management
+ */
+
+
+/* rebuild all the relevant bat information */
+STATIC_INLINE_VM void
+om_unpack_bat(om_bat *bat,
+ spreg ubat,
+ spreg lbat)
+{
+ /* for extracting out the offset within a page */
+ bat->block_length_mask = ((MASKED(ubat, 51, 61) << (17-2))
+ | MASK(63-17+1, 63));
+
+ /* for checking the effective page index */
+ bat->block_effective_page_index = MASKED(ubat, 0, 46);
+ bat->block_effective_page_index_mask = ~bat->block_length_mask;
+
+ /* protection information */
+ bat->protection_bits = EXTRACTED(lbat, 62, 63);
+ bat->block_real_page_number = MASKED(lbat, 0, 46);
+}
+
+
+/* rebuild the given bat table */
+STATIC_INLINE_VM void
+om_unpack_bats(om_bats *bats,
+ spreg *raw_bats,
+ msreg msr)
+{
+ int i;
+ bats->nr_valid_bat_registers = 0;
+ for (i = 0; i < nr_om_bat_registers*2; i += 2) {
+ spreg ubat = raw_bats[i];
+ spreg lbat = raw_bats[i+1];
+ if ((msr & msr_problem_state)
+ ? EXTRACTED(ubat, 62, 62)
+ : EXTRACTED(ubat, 63, 63)) {
+ om_unpack_bat(&bats->bat[bats->nr_valid_bat_registers],
+ ubat, lbat);
+ bats->nr_valid_bat_registers += 1;
+ }
+ }
+}
+
+
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+STATIC_INLINE_VM void
+om_unpack_sr(vm *virtual,
+ sreg *srs,
+ int which_sr)
+{
+ om_segment_tlb_entry *segment_tlb_entry = 0;
+ sreg new_sr_value = 0;
+
+ /* check register in range */
+ if (which_sr < 0 || which_sr > nr_om_segment_tlb_entries)
+ error("om_set_sr: segment register out of bounds\n");
+
+ /* get the working values */
+ segment_tlb_entry = &virtual->segment_tlb.entry[which_sr];
+ new_sr_value = srs[which_sr];
+
+ /* do we support this */
+ if (MASKED32(new_sr_value, 0, 0))
+ error("om_ser_sr(): unsupported value of T in segment register %d\n",
+ which_sr);
+
+ /* update info */
+ segment_tlb_entry->key[om_supervisor_state] = EXTRACTED32(new_sr_value, 1, 1);
+ segment_tlb_entry->key[om_problem_state] = EXTRACTED32(new_sr_value, 2, 2);
+ segment_tlb_entry->invalid_access = (MASKED32(new_sr_value, 3, 3)
+ ? om_instruction_read
+ : om_access_any);
+ segment_tlb_entry->masked_virtual_segment_id = MASKED32(new_sr_value, 8, 31);
+}
+#endif
+
+
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+STATIC_INLINE_VM void
+om_unpack_srs(vm *virtual,
+ sreg *srs)
+{
+ int which_sr;
+ for (which_sr = 0; which_sr < nr_om_segment_tlb_entries; which_sr++) {
+ om_unpack_sr(virtual, srs, which_sr);
+ }
+}
+#endif
+
+
+/* Rebuild all the data structures for the new context as specifed by
+ the passed registers */
+INLINE_VM void
+vm_synchronize_context(vm *virtual,
+ spreg *sprs,
+ sreg *srs,
+ msreg msr)
+{
+
+ /* enable/disable translation */
+ int problem_state = (msr & msr_problem_state) != 0;
+ int data_relocate = (msr & msr_data_relocate) != 0;
+ int instruction_relocate = (msr & msr_instruction_relocate) != 0;
+
+ unsigned_word page_table_hash_mask;
+ unsigned_word real_address_of_page_table;
+
+
+ /* update current processor mode */
+ virtual->instruction_map.translation.is_relocate = instruction_relocate;
+ virtual->instruction_map.translation.is_problem_state = problem_state;
+ virtual->data_map.translation.is_relocate = data_relocate;
+ virtual->data_map.translation.is_problem_state = problem_state;
+
+
+ /* update bat registers for the new context */
+ om_unpack_bats(&virtual->ibats, &sprs[spr_ibat0u], msr);
+ om_unpack_bats(&virtual->dbats, &sprs[spr_dbat0u], msr);
+
+
+ /* unpack SDR1 - the storage description register 1 */
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+ real_address_of_page_table = EXTRACTED64(sprs[spr_sdr1], 0, 45);
+ page_table_hash_mask = MASK64(47-EXTRACTED64(sprs[spr_sdr1], 59, 63),
+ 57);
+#endif
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+ real_address_of_page_table = EXTRACTED32(sprs[spr_sdr1], 0, 15);
+ page_table_hash_mask = ((EXTRACTED32(sprs[spr_sdr1], 23, 31) << (10+6))
+ | MASK32(16, 25));
+#endif
+ virtual->instruction_map.translation.real_address_of_page_table = real_address_of_page_table;
+ virtual->instruction_map.translation.page_table_hash_mask = page_table_hash_mask;
+ virtual->data_map.translation.real_address_of_page_table = real_address_of_page_table;
+ virtual->data_map.translation.page_table_hash_mask = page_table_hash_mask;
+
+
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+ /* unpack the segment tlb registers */
+ om_unpack_srs(virtual, srs);
+#endif
+}
+
+
+INLINE_VM vm_data_map *
+vm_create_data_map(vm *memory)
+{
+ return &memory->data_map;
+}
+
+
+INLINE_VM vm_instruction_map *
+vm_create_instruction_map(vm *memory)
+{
+ return &memory->instruction_map;
+}
+
+
+STATIC_INLINE_VM unsigned_word
+vm_translate(om_map *map,
+ unsigned_word ea,
+ om_access_types access,
+ cpu *processor,
+ unsigned_word cia,
+ int abort)
+{
+ switch (CURRENT_ENVIRONMENT) {
+ case USER_ENVIRONMENT:
+ case VIRTUAL_ENVIRONMENT:
+ return ea;
+ case OPERATING_ENVIRONMENT:
+ return om_translate_effective_to_real(map, ea, access,
+ processor, cia,
+ abort);
+ default:
+ error("vm_translate() - unknown environment\n");
+ return 0;
+ }
+}
+
+
+INLINE_VM unsigned_word
+vm_real_data_addr(vm_data_map *map,
+ unsigned_word ea,
+ int is_read,
+ cpu *processor,
+ unsigned_word cia)
+{
+ return vm_translate(&map->translation,
+ ea,
+ is_read ? om_data_read : om_data_write,
+ processor,
+ cia,
+ 1); /*abort*/
+}
+
+
+INLINE_VM unsigned_word
+vm_real_instruction_addr(vm_instruction_map *map,
+ cpu *processor,
+ unsigned_word cia)
+{
+ return vm_translate(&map->translation,
+ cia,
+ om_instruction_read,
+ processor,
+ cia,
+ 1); /*abort*/
+}
+
+INLINE_VM instruction_word
+vm_instruction_map_read(vm_instruction_map *map,
+ cpu *processor,
+ unsigned_word cia)
+{
+ unsigned_word ra = vm_real_instruction_addr(map, processor, cia);
+ ASSERT((cia & 0x3) == 0); /* always aligned */
+ return core_map_read_4(map->code, ra, processor, cia);
+}
+
+
+INLINE_VM int
+vm_data_map_read_buffer(vm_data_map *map,
+ void *target,
+ unsigned_word addr,
+ unsigned nr_bytes)
+{
+ unsigned count;
+ for (count = 0; count < nr_bytes; count++) {
+ unsigned_1 byte;
+ unsigned_word ea = addr + count;
+ unsigned_word ra = vm_translate(&map->translation,
+ ea, om_data_read,
+ NULL, /*processor*/
+ 0, /*cia*/
+ 0); /*dont-abort*/
+ if (ra == MASK(0, 63))
+ break;
+ if (core_map_read_buffer(map->read, &byte, ea, sizeof(byte))
+ != sizeof(byte))
+ break;
+ ((unsigned_1*)target)[count] = T2H_1(byte);
+ }
+ return count;
+}
+
+
+INLINE_VM int
+vm_data_map_write_buffer(vm_data_map *map,
+ const void *source,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section)
+{
+ unsigned count;
+ unsigned_1 byte;
+ for (count = 0; count < nr_bytes; count++) {
+ unsigned_word ea = addr + count;
+ unsigned_word ra = vm_translate(&map->translation,
+ ea, om_data_write,
+ NULL/*processor*/,
+ 0, /*cia*/
+ 0); /*dont-abort*/
+ if (ra == MASK(0, 63))
+ break;
+ byte = T2H_1(((unsigned_1*)source)[count]);
+ if (core_map_write_buffer((violate_read_only_section
+ ? map->read
+ : map->write),
+ &byte, ra, sizeof(byte)) != sizeof(byte))
+ break;
+ }
+ return count;
+}
+
+
+/* define the read/write 1/2/4/8/word functions */
+
+#undef N
+#define N 1
+#include "vm_n.h"
+
+#undef N
+#define N 2
+#include "vm_n.h"
+
+#undef N
+#define N 4
+#include "vm_n.h"
+
+#undef N
+#define N 8
+#include "vm_n.h"
+
+#undef N
+#define N word
+#include "vm_n.h"
+
+
+
+#endif /* _VM_C_ */
OpenPOWER on IntegriCloud