* Copyright (c) 2015-2023 Google, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Google, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#include "tlb.h"
#include <assert.h>
#include <stddef.h>
#include "memref.h"
#include "caching_device.h"
#include "caching_device_block.h"
#include "tlb_entry.h"
#include "trace_entry.h"
namespace dynamorio {
namespace drmemtrace {
void
tlb_t::init_blocks()
{
for (int i = 0; i < num_blocks_; i++) {
blocks_[i] = new tlb_entry_t;
}
}
void
tlb_t::request(const memref_t &memref_in)
{
memref_t memref;
addr_t final_addr = memref_in.data.addr + memref_in.data.size - 1 ;
addr_t final_tag = compute_tag(final_addr);
addr_t tag = compute_tag(memref_in.data.addr);
memref_pid_t pid = memref_in.data.pid;
if (tag == final_tag && tag == last_tag_ && pid == last_pid_) {
caching_device_block_t *tlb_entry =
&get_caching_device_block(last_block_idx_, last_way_);
assert(tag != TAG_INVALID && tag == tlb_entry->tag_ &&
pid == ((tlb_entry_t *)tlb_entry)->pid_);
record_access_stats(memref_in, true , tlb_entry);
access_update(last_block_idx_, last_way_);
return;
}
memref = memref_in;
for (; tag <= final_tag; ++tag) {
int way;
int block_idx = compute_block_idx(tag);
if (tag + 1 <= final_tag)
memref.data.size = ((tag + 1) << block_size_bits_) - memref.data.addr;
for (way = 0; way < associativity_; ++way) {
caching_device_block_t *tlb_entry = &get_caching_device_block(block_idx, way);
if (tlb_entry->tag_ == tag && ((tlb_entry_t *)tlb_entry)->pid_ == pid) {
record_access_stats(memref, true , tlb_entry);
break;
}
}
if (way == associativity_) {
way = replace_which_way(block_idx);
caching_device_block_t *tlb_entry = &get_caching_device_block(block_idx, way);
record_access_stats(memref, false , tlb_entry);
if (parent_ != NULL)
parent_->request(memref);
tlb_entry->tag_ = tag;
((tlb_entry_t *)tlb_entry)->pid_ = pid;
}
access_update(block_idx, way);
if (tag + 1 <= final_tag) {
addr_t next_addr = (tag + 1) << block_size_bits_;
memref.data.addr = next_addr;
memref.data.size = final_addr - next_addr + 1 ;
}
last_tag_ = tag;
last_way_ = way;
last_block_idx_ = block_idx;
last_pid_ = pid;
}
}
}
}