hw: LPAE for Cortex a15 (fix #1387)

This commit is contained in:
Stefan Kalkowski 2015-02-06 11:26:39 +01:00 committed by Christian Helmuth
parent 21fd2fc582
commit 322be1b4fb
27 changed files with 487 additions and 212 deletions

View File

@ -8,7 +8,7 @@
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_v6
# add C++ sources
SRC_CC += cpu.cc
SRC_CC += spec/arm/cpu.cc
# add assembly sources
SRC_S += spec/arm_v6/mode_transition.s

View File

@ -0,0 +1,11 @@
#
# \brief Build config for Genodes core process
# \author Stefan Kalkowski
# \date 2014-09-02
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a15
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc

View File

@ -0,0 +1,14 @@
#
# \brief Build config for Genodes core process
# \author Stefan Kalkowski
# \date 2014-09-02
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a8
# add C++ sources
SRC_CC += spec/arm/cpu.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc

View File

@ -0,0 +1,14 @@
#
# \brief Build config for Genodes core process
# \author Stefan Kalkowski
# \date 2014-09-02
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a9
# add C++ sources
SRC_CC += spec/arm/cpu.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc

View File

@ -16,4 +16,4 @@ SRC_CC += platform_services.cc
SRC_CC += spec/arm_gic/pic.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc
include $(REP_DIR)/lib/mk/cortex_a15/core.inc

View File

@ -13,8 +13,5 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/imx53
INC_DIR += $(REP_DIR)/src/core/include/spec/imx
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a8
# add C++ sources
SRC_CC += cpu.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc
include $(REP_DIR)/lib/mk/cortex_a8/core.inc

View File

@ -15,7 +15,6 @@ SRC_CC += platform_services.cc
SRC_CC += spec/panda/platform_support.cc
SRC_CC += spec/cortex_a9/pic.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += cpu.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc
include $(REP_DIR)/lib/mk/cortex_a9/core.inc

View File

@ -15,7 +15,6 @@ SRC_CC += platform_services.cc
SRC_CC += spec/pbxa9/platform_support.cc
SRC_CC += spec/cortex_a9/pic.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += cpu.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc
include $(REP_DIR)/lib/mk/cortex_a9/core.inc

View File

@ -11,11 +11,10 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a9
INC_DIR += $(REP_DIR)/src/core/include/spec/pl011
# add C++ sources
SRC_CC += cpu.cc
SRC_CC += platform_services.cc
SRC_CC += spec/vea9x4/platform_support.cc
SRC_CC += spec/cortex_a9/pic.cc
SRC_CC += spec/arm_gic/pic.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc
include $(REP_DIR)/lib/mk/cortex_a9/core.inc

View File

@ -1,21 +0,0 @@
/*
* \brief CPU driver for core
* \author Martin stein
* \date 2014-07-14
*/
/*
* Copyright (C) 2011-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <cpu.h>
using namespace Genode;
unsigned Cpu::primary_id() { return 0; }
unsigned Cpu::executing_id() { return primary_id(); }

View File

@ -16,6 +16,7 @@
#define _KERNEL__EARLY_TRANSLATIONS_H_
/* core includes */
#include <assert.h>
#include <page_slab.h>
#include <translation_table.h>

View File

@ -18,6 +18,7 @@
/* Genode includes */
#include <base/printf.h>
#include <root/root.h>
#include <util/construct_at.h>
/* Core includes */
#include <translation_table.h>
@ -80,7 +81,7 @@ namespace Genode
throw Root::Quota_exceeded();
}
_tt = new (tt) Translation_table();
_tt = construct_at<Translation_table>(tt);
_tt_phys = (Translation_table*) cma->phys_addr(_tt);
_pslab = new (cma) Page_slab(cma);
Kernel::mtc()->map(_tt, _pslab);

View File

@ -336,20 +336,27 @@ class Genode::Arm
*/
struct Context : Cpu_state
{
Cidr::access_t cidr;
Ttbr0::access_t ttbr0;
/**
* TODO: currently all non-Cortex A15 platforms use the
* short translation table format and thereby the Context ID
* register to store the ASID, and the TTBR0 for the table
* address. Cortex A15 uses the long translation format and
* a 64-bit wide TTBR0 that holds all information.
* The current Cortex A15 implementation stores TTBR0 in both
* members stated below.
*/
uint32_t cidr;
uint32_t ttbr0;
/**
* Return base of assigned translation table
*/
addr_t translation_table() const {
return Ttbr0::Ba::masked(ttbr0); }
addr_t translation_table() const;
/**
* Assign translation-table base 'table'
*/
void translation_table(addr_t const table) {
ttbr0 = Arm::Ttbr0::init(table); }
void translation_table(addr_t const table);
/**
* Assign protection domain
@ -405,35 +412,7 @@ class Genode::Arm
* \param va holds the virtual fault-address if call returns 1
* \param w holds wether it's a write fault if call returns 1
*/
bool in_fault(addr_t & va, addr_t & w) const
{
switch (cpu_exception) {
case PREFETCH_ABORT: {
/* check if fault was caused by a translation miss */
Ifsr::access_t const fs = Ifsr::Fs::get(Ifsr::read());
if (fs != Ifsr::section && fs != Ifsr::page) { return 0; }
/* fetch fault data */
w = 0;
va = ip;
return 1; }
case DATA_ABORT: {
/* check if fault was caused by translation miss */
Dfsr::access_t const fs = Dfsr::Fs::get(Dfsr::read());
if (fs != Dfsr::section && fs != Dfsr::page) { return 0; }
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return 1; }
default: return 0; }
}
bool in_fault(addr_t & va, addr_t & w) const;
};
/**

View File

@ -53,3 +53,72 @@
/* alignment constraints */
.set MIN_PAGE_SIZE_LOG2, 12
.set DATA_ACCESS_ALIGNM_LOG2, 2
/***************************************************
** Constant values that the mode transition uses **
***************************************************/
/* kernel names of exceptions that can interrupt a user */
.set RST_TYPE, 1
.set UND_TYPE, 2
.set SVC_TYPE, 3
.set PAB_TYPE, 4
.set DAB_TYPE, 5
.set IRQ_TYPE, 6
.set FIQ_TYPE, 7
.set RST_PC_ADJUST, 0
.set UND_PC_ADJUST, 4
.set SVC_PC_ADJUST, 0
.set PAB_PC_ADJUST, 4
.set DAB_PC_ADJUST, 8
.set IRQ_PC_ADJUST, 4
.set FIQ_PC_ADJUST, 4
/* offsets of the member variables in a CPU context */
.set R12_OFFSET, 12 * 4
.set SP_OFFSET, 13 * 4
.set LR_OFFSET, 14 * 4
.set PC_OFFSET, 15 * 4
.set PSR_OFFSET, 16 * 4
.set EXCEPTION_TYPE_OFFSET, 17 * 4
.set TRANSIT_TTBR0_OFFSET, 17 * 4
.set CIDR_OFFSET, 18 * 4
.set TTBR0_OFFSET, 19 * 4
/* size of local variables */
.set CONTEXT_PTR_SIZE, 1 * 4
/*********************************************************
** Local data structures that the mode transition uses **
*********************************************************/
.macro _mt_local_variables
/* space for a copy of the kernel context */
.p2align 2
.global _mt_master_context_begin
_mt_master_context_begin:
.space 32 * 4
.global _mt_master_context_end
_mt_master_context_end:
/* space for a client context-pointer per CPU */
.p2align 2
.global _mt_client_context_ptr
_mt_client_context_ptr:
.rept NR_OF_CPUS
.space CONTEXT_PTR_SIZE
.endr
/* a globally mapped buffer per CPU */
.p2align 2
.global _mt_buffer
_mt_buffer:
.rept NR_OF_CPUS
.space BUFFER_SIZE
.endr
.endm /* _mt_local_variables */

View File

@ -1,80 +0,0 @@
/*
* \brief Mode transition definitions used by all ARM architectures
* \author Stefan Kalkowski
* \date 2014-06-12
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/***************************************************
** Constant values that the mode transition uses **
***************************************************/
/* kernel names of exceptions that can interrupt a user */
.set RST_TYPE, 1
.set UND_TYPE, 2
.set SVC_TYPE, 3
.set PAB_TYPE, 4
.set DAB_TYPE, 5
.set IRQ_TYPE, 6
.set FIQ_TYPE, 7
.set RST_PC_ADJUST, 0
.set UND_PC_ADJUST, 4
.set SVC_PC_ADJUST, 0
.set PAB_PC_ADJUST, 4
.set DAB_PC_ADJUST, 8
.set IRQ_PC_ADJUST, 4
.set FIQ_PC_ADJUST, 4
/* offsets of the member variables in a CPU context */
.set R12_OFFSET, 12 * 4
.set SP_OFFSET, 13 * 4
.set LR_OFFSET, 14 * 4
.set PC_OFFSET, 15 * 4
.set PSR_OFFSET, 16 * 4
.set EXCEPTION_TYPE_OFFSET, 17 * 4
.set TRANSIT_TTBR0_OFFSET, 17 * 4
.set CIDR_OFFSET, 18 * 4
.set TTBR0_OFFSET, 19 * 4
/* size of local variables */
.set CONTEXT_PTR_SIZE, 1 * 4
/*********************************************************
** Local data structures that the mode transition uses **
*********************************************************/
.macro _mt_local_variables
/* space for a copy of the kernel context */
.p2align 2
.global _mt_master_context_begin
_mt_master_context_begin:
.space 32 * 4
.global _mt_master_context_end
_mt_master_context_end:
/* space for a client context-pointer per CPU */
.p2align 2
.global _mt_client_context_ptr
_mt_client_context_ptr:
.rept NR_OF_CPUS
.space CONTEXT_PTR_SIZE
.endr
/* a globally mapped buffer per CPU */
.p2align 2
.global _mt_buffer
_mt_buffer:
.rept NR_OF_CPUS
.space BUFFER_SIZE
.endr
.endm /* _mt_local_variables */

View File

@ -34,8 +34,82 @@ namespace Kernel { using Genode::Cpu_lazy_state; }
class Genode::Cpu : public Arm_v7
{
protected:
/**
* Translation table base control register
*/
struct Ttbcr : Arm::Ttbcr
{
struct Irgn0 : Bitfield<8, 2> { };
struct Orgn0 : Bitfield<10, 2> { };
struct Sh0 : Bitfield<12, 2> { };
struct Eae : Bitfield<31, 1> { }; /* extended address enable */
static access_t init_virt_kernel()
{
access_t v = 0;
Irgn0::set(v, 1);
Orgn0::set(v, 1);
Sh0::set(v, 0b10);
Eae::set(v, 1);
return v;
}
};
struct Mair0 : Register<32>
{
static void init()
{
access_t v = 0xff0044;
asm volatile ("mcr p15, 0, %[v], c10, c2, 0" :: [v]"r"(v) : );
}
};
public:
/**
* Translation table base register 0 (64-bit format)
*/
struct Ttbr0 : Register<64>
{
enum Memory_region { NON_CACHEABLE = 0, CACHEABLE = 1 };
struct Ba : Bitfield<5, 34> { }; /* translation table base */
struct Asid : Bitfield<48,8> { };
static void write(access_t const v)
{
asm volatile ("mcrr p15, 0, %[v0], %[v1], c2"
:: [v0]"r"(v), [v1]"r"(v >> 32) : );
}
static access_t read()
{
uint32_t v0, v1;
asm volatile ("mrrc p15, 0, %[v0], %[v1], c2"
: [v0]"=r"(v0), [v1]"=r"(v1) :: );
return (access_t) v0 | ((access_t)v1 << 32);
}
/**
* Return initialized value
*
* \param table base of targeted translation table
*/
static access_t init(addr_t const table, unsigned const id)
{
access_t v = Ba::masked((access_t)table);
Asid::set(v, id);
return v;
}
static Genode::uint32_t init(addr_t const table) {
return table; }
};
/**
* Return wether to retry an undefined user instruction after this call
*/
@ -51,6 +125,24 @@ class Genode::Cpu : public Arm_v7
*/
static unsigned primary_id();
/**
* Switch to the virtual mode in kernel
*
* \param table base of targeted translation table
* \param process_id process ID of the kernel address-space
*/
static void
init_virt_kernel(addr_t const table, unsigned const process_id)
{
Mair0::init();
Cidr::write(process_id);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init(table, 1));
Ttbcr::write(Ttbcr::init_virt_kernel());
Sctlr::write(Sctlr::init_virt_kernel());
inval_branch_predicts();
}
/*************
** Dummies **
*************/

View File

@ -0,0 +1,38 @@
/*
* \brief Macros that are used by multiple assembly files
* \author Stefan Kalkowski
* \date 2015-01-30
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
.include "spec/arm_v7/macros_support.s"
/**
* Switch to a given protection domain
*
* There is no atomicity problem when setting the ASID and translation table
* base address in the one 64-bit TTBR0 register, like in Armv7 cpus without
* LPAE extensions. Therefore, we don't have to use a transition table.
*
* \param transit_ttbr0 ignored parameter
* \param new_cidr new CIDR value, read reg
* \param new_ttbr0 new TTBR0 value, read/write reg
*/
.macro _switch_protection_domain transit_ttbr0, new_cidr, new_ttbr0
/* write translation-table-base register 0 */
lsl \new_cidr, \new_cidr, #16
mcrr p15, 0, \new_ttbr0, \new_cidr, c2
/* instruction and data synchronization barrier */
isb
dsb
.endm

View File

@ -0,0 +1,18 @@
/*
* \brief Translation table definitions for core
* \author Stefan Kalkowski
* \date 2015-01-30
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _TRANSLATION_TABLE_H_
#define _TRANSLATION_TABLE_H_
/* core includes */
#include <long_translation_table.h>
#endif /* _TRANSLATION_TABLE_H_ */

View File

@ -0,0 +1,31 @@
/*
* \brief Macros that are used by multiple assembly files
* \author Stefan Kalkowski
* \date 2015-01-30
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
.include "spec/arm_v7/macros_support.s"
/**
* Switch to a given protection domain
*
* \param transit_ttbr0 transitional TTBR0 value, read/write reg
* \param new_cidr new CIDR value, read reg
* \param new_ttbr0 new TTBR0 value, read/write reg
*/
.macro _switch_protection_domain transit_ttbr0, new_cidr, new_ttbr0
mcr p15, 0, \transit_ttbr0, c2, c0, 0
isb
mcr p15, 0, \new_cidr, c13, c0, 1
isb
mcr p15, 0, \new_ttbr0, c2, c0, 0
isb
.endm

View File

@ -1,22 +1,20 @@
/*
* \brief Armv7 translation table definitions for core
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2012-02-22
* \brief Translation table definitions for core
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2012-02-22
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _TRANSLATION_TABLE_H_
#define _TRANSLATION_TABLE_H_
/* core includes */
#include <spec/arm/short_translation_table.h>
#include <short_translation_table.h>
constexpr unsigned Genode::Translation::_device_tex() { return 2; }

View File

@ -0,0 +1,40 @@
/*
* \brief Macros that are used by multiple assembly files
* \author Stefan Kalkowski
* \date 2015-01-30
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
.include "spec/arm_v7/macros_support.s"
/**
* Switch to a given protection domain
*
* \param transit_ttbr0 transitional TTBR0 value, read/write reg
* \param new_cidr new CIDR value, read reg
* \param new_ttbr0 new TTBR0 value, read/write reg
*/
.macro _switch_protection_domain transit_ttbr0, new_cidr, new_ttbr0
/*
* FIXME: Fixes instability problems that were observed on the
* PandaBoard only. We neither know why invalidating predictions
* at PD switches is a fix nor wether not doing so is the real
* cause of this instability.
*/
mcr p15, 0, r0, c7, c5, 6
mcr p15, 0, \transit_ttbr0, c2, c0, 0
isb
mcr p15, 0, \new_cidr, c13, c0, 1
isb
mcr p15, 0, \new_ttbr0, c2, c0, 0
isb
.endm

View File

@ -0,0 +1,21 @@
/*
* \brief Translation table definitions for core
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2012-02-22
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _TRANSLATION_TABLE_H_
#define _TRANSLATION_TABLE_H_
/* core includes */
#include <short_translation_table.h>
constexpr unsigned Genode::Translation::_device_tex() { return 2; }
#endif /* _TRANSLATION_TABLE_H_ */

View File

@ -0,0 +1,66 @@
/*
* \brief CPU driver for core
* \author Martin stein
* \date 2014-07-14
*/
/*
* Copyright (C) 2011-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <cpu.h>
using namespace Genode;
unsigned Cpu::primary_id() { return 0; }
unsigned Cpu::executing_id() { return primary_id(); }
addr_t Cpu::Context::translation_table() const {
return Ttbr0::Ba::masked(ttbr0); }
void Cpu::Context::translation_table(addr_t const t) {
ttbr0 = Arm::Ttbr0::init(t); }
bool Cpu::User_context::in_fault(addr_t & va, addr_t & w) const
{
switch (cpu_exception) {
case PREFETCH_ABORT:
{
/* check if fault was caused by a translation miss */
Ifsr::access_t const fs = Ifsr::Fs::get(Ifsr::read());
if (fs != Ifsr::section && fs != Ifsr::page)
return false;
/* fetch fault data */
w = 0;
va = ip;
return true;
}
case DATA_ABORT:
{
/* check if fault was caused by translation miss */
Dfsr::access_t const fs = Dfsr::Fs::get(Dfsr::read());
if (fs != Dfsr::section && fs != Dfsr::page)
return false;
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return true;
}
default:
return false;
};
}

View File

@ -12,7 +12,6 @@
*/
/* core includes */
.include "mode_transition.s"
.include "macros.s"

View File

@ -13,7 +13,6 @@
*/
/* core includes */
.include "mode_transition.s"
.include "macros.s"
@ -84,60 +83,6 @@
.endm
/**
* Override the TTBR0 register
*
* \param val new value, read reg
*/
.macro _write_ttbr0 val
mcr p15, 0, \val, c2, c0, 0
.endm
/**
* Override the CIDR register
*
* \param val new value, read reg
*/
.macro _write_cidr val
mcr p15, 0, \val, c13, c0, 1
.endm
/*
* Invalidate all branch predictors
*/
.macro _bpiall
mcr p15, 0, r0, c7, c5, 6
.endm
/**
* Switch to a given protection domain
*
* \param transit_ttbr0 transitional TTBR0 value, read/write reg
* \param new_cidr new CIDR value, read reg
* \param new_ttbr0 new TTBR0 value, read/write reg
*/
.macro _switch_protection_domain transit_ttbr0, new_cidr, new_ttbr0
/*
* FIXME: Fixes instability problems that were observed on the
* PandaBoard only. We neither know why invalidating predictions
* at PD switches is a fix nor wether not doing so is the real
* cause of this instability.
*/
_bpiall
_write_ttbr0 \transit_ttbr0
isb
_write_cidr \new_cidr
isb
_write_ttbr0 \new_ttbr0
isb
.endm
/**
* Save an interrupted user context and switch to the kernel context
*

View File

@ -1,6 +1,7 @@
/*
* \brief CPU driver for core
* \author Martin stein
* \author Stefan Kalkowski
* \date 2011-11-03
*/
@ -19,4 +20,48 @@ using namespace Genode;
unsigned Cpu::executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); }
unsigned Cpu::primary_id() { return Board::PRIMARY_MPIDR_AFF_0; }
addr_t Cpu::Context::translation_table() const { return ttbr0; }
void Cpu::Context::translation_table(addr_t const t) { ttbr0 = t; }
bool Cpu::User_context::in_fault(addr_t & va, addr_t & w) const
{
switch (cpu_exception) {
case PREFETCH_ABORT:
{
/* check if fault was caused by a translation miss */
Ifsr::access_t const fs = Ifsr::Fs::get(Ifsr::read());
if ((fs & 0b11100) != 0b100)
return false;
/* fetch fault data */
w = 0;
va = ip;
return true;
}
case DATA_ABORT:
{
/* check if fault was caused by translation miss */
Dfsr::access_t const fs = Dfsr::Fs::get(Dfsr::read());
if ((fs & 0b11100) != 0b100)
return false;
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return true;
}
default:
return false;
};
}