blob: 5cc77dd40e95a854cab6130bcdb868ad10415ef9 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "page_table_arrays.h"
#include "macros.h"
#include "registers.h"
std::unique_ptr<PageTableArrays> PageTableArrays::Create(magma::PlatformBusMapper* bus_mapper)
{
auto address_manager = std::make_unique<PageTableArrays>();
if (!address_manager->Init(bus_mapper))
return DRETP(nullptr, "Failed to initialize");
return address_manager;
}
bool PageTableArrays::Init(magma::PlatformBusMapper* bus_mapper)
{
page_table_array_ =
magma::PlatformBuffer::Create(kPageTableArraySizeInPages * PAGE_SIZE, "page_table_array");
if (!page_table_array_)
return DRETF(false, "Failed to allocate page_table_array");
if (!page_table_array_->SetCachePolicy(MAGMA_CACHE_POLICY_UNCACHED))
return DRETF(false, "Failed to set cache policy");
if (!page_table_array_->MapCpu(reinterpret_cast<void**>(&master_tlb_bus_addr_)))
return DRETF(false, "Failed to map page table array");
bus_mapping_ =
bus_mapper->MapPageRangeBus(page_table_array_.get(), 0, kPageTableArraySizeInPages);
if (!bus_mapping_)
return DRETF(false, "Failed to bus map page table array");
security_safe_page_ = magma::PlatformBuffer::Create(PAGE_SIZE, "security safe page");
if (!security_safe_page_)
return DRETF(false, "Failed to allocated security safe page");
security_safe_page_bus_mapping_ = bus_mapper->MapPageRangeBus(security_safe_page_.get(), 0, 1);
if (!security_safe_page_bus_mapping_)
return DRETF(false, "Failed to bus map security safe page");
non_security_safe_page_ = magma::PlatformBuffer::Create(PAGE_SIZE, "security safe page");
if (!non_security_safe_page_)
return DRETF(false, "Failed to allocated non security safe page");
non_security_safe_page_bus_mapping_ =
bus_mapper->MapPageRangeBus(non_security_safe_page_.get(), 0, 1);
if (!non_security_safe_page_bus_mapping_)
return DRETF(false, "Failed to bus map non security safe page");
return true;
}
void PageTableArrays::HardwareInit(magma::RegisterIo* register_io)
{
uint64_t security_safe_page_bus_addr = security_safe_page_bus_mapping_->Get()[0];
uint64_t non_security_safe_page_bus_addr = non_security_safe_page_bus_mapping_->Get()[0];
DASSERT(fits_in_40_bits(security_safe_page_bus_addr));
DASSERT(fits_in_40_bits(non_security_safe_page_bus_addr));
Enable(register_io, false);
{
auto reg = registers::PageTableArrayAddressLow::Get().FromValue(0);
reg.set_reg_value(magma::lower_32_bits(bus_addr()));
reg.WriteTo(register_io);
}
{
auto reg = registers::PageTableArrayAddressHigh::Get().FromValue(0);
reg.set_reg_value(magma::upper_32_bits(bus_addr()));
reg.WriteTo(register_io);
}
{
auto reg = registers::PageTableArrayControl::Get().FromValue(0);
reg.enable().set(1);
reg.WriteTo(register_io);
}
{
auto reg = registers::MmuNonSecuritySafeAddressLow::Get().FromValue(0);
reg.set_reg_value(magma::lower_32_bits(non_security_safe_page_bus_addr));
reg.WriteTo(register_io);
}
{
auto reg = registers::MmuSecuritySafeAddressLow::Get().FromValue(0);
reg.set_reg_value(magma::lower_32_bits(security_safe_page_bus_addr));
reg.WriteTo(register_io);
}
{
auto reg = registers::MmuSafeAddressConfig::Get().FromValue(0);
reg.non_security_safe_address_high().set(non_security_safe_page_bus_addr & 0xFF);
reg.security_safe_address_high().set(security_safe_page_bus_addr & 0xFF);
reg.WriteTo(register_io);
}
}
void PageTableArrays::Enable(magma::RegisterIo* register_io, bool enable)
{
auto reg_mmu_sec_ctrl = registers::MmuSecureControl::Get().ReadFrom(register_io);
reg_mmu_sec_ctrl.enable().set(enable ? 1 : 0);
reg_mmu_sec_ctrl.WriteTo(register_io);
}
void PageTableArrays::AssignAddressSpace(uint32_t index, AddressSpace* address_space)
{
DASSERT(index <= kPageTableArrayEntries);
master_tlb_bus_addr_[index] = address_space->bus_addr();
}