Nested init on i.MX31 via base_hw. Rework base_hw.

Implies support for the ARMv6 architecture through 'base-hw'.

Get rid of 'base/include/drivers' expect of 'base/include/drivers/uart'.

Merge with the support for trustzone on VEA9X4 that came from
Stefan Kalkowski.

Leave board drivers in 'base/include/platform'.

Rework structure of the other drivers that were moved to
'base_hw/src/core' and those that came with the trustzone support.

Beautify further stuff in 'base_hw'.

Test 'nested_init' with 'hw_imx31' (hardware) and 'hw_panda_a2' (hardware),
'demo' and 'signal' with 'hw_pbxa9' (qemu) and 'hw_vea9x4'
(hardware, no trustzone), and 'vmm' with 'hw_vea9x4'
(hardware, with trustzone).
This commit is contained in:
Martin Stein 2012-10-23 17:12:09 +02:00 committed by Norman Feske
parent 5b4edeb031
commit 31d57a6257
87 changed files with 3959 additions and 1391 deletions

View File

@ -21,7 +21,19 @@ void Genode::Ipc_pager::copy_regs(Thread_state *state)
{
state->ip = _regs.pc;
state->sp = _regs.sp;
Genode::memcpy(&state->r, &_regs.r, sizeof(state->r));
state->r0 = _regs.r[0];
state->r1 = _regs.r[1];
state->r2 = _regs.r[2];
state->r3 = _regs.r[3];
state->r4 = _regs.r[4];
state->r5 = _regs.r[5];
state->r6 = _regs.r[6];
state->r7 = _regs.r[7];
state->r8 = _regs.r[8];
state->r9 = _regs.r[9];
state->r10 = _regs.r[10];
state->r11 = _regs.r[11];
state->r12 = _regs.r[12];
state->lr = _regs.ulr;
state->cpsr = _regs.cpsr;
}

View File

@ -5,14 +5,21 @@
Martin Stein
The 'base-hw' repository provides an implementation of Genodes core that runs
directly on hardware, without an intermediate third-party kernel. Currently it
runs on the ARM platforms Realview PBXA9, Versatile Express A9X4 and
PandaBoard A2.
Abstract
########
This document provides brief instructions about building and booting Genode
directly on hardware.
with the 'base-hw' repository. The 'base-hw' repository provides an
implementation of the Genode core that runs directly on hardware, without an
intermediate third-party kernel. It supports a limited range of target boards.
For further target specific informations, have a look at
'<GENODE_DIR>/base-hw/doc/<TARGET>.txt' where '<TARGET>'
is one of the following:
'pbxa9' - Realview PBXA9
'vea9x4' - Versatile Express A9X4
'imx31' - Freescale i.MX31
'panda_a2' - PandaBoard A2
Prerequisites
@ -35,6 +42,7 @@ need Qemu for ARM emulations to run them on your machine:
! apt-get install qemu-kvm-extras
Building Genode to run directly on hardware
###########################################
@ -46,11 +54,22 @@ The current version of the Genode source code is available at this page:
Now, go to a directory where you want the Genode build directory to
remain. Use the helper script in the 'tool' directory of the Genode
source tree to create the initial build environment. You need to state the
build directory you want to create, and the hardware system to run
Genode on. Choose 'hw_pbxa9', 'hw_vea9x4', or 'hw_panda_a2' depending on the
hardware system you aim at.
build directory you want to create, and the hardware target to run Genode on.
! <genode-dir>/tool/create_builddir hw_pbxa9 BUILD_DIR=<build-dir>
! <genode-dir>/tool/create_builddir hw_<TARGET> BUILD_DIR=<build-dir>
Where '<TARGET>' is one of the following, depending on the hardware system
you aim at:
'pbxa9' - Realview PBXA9
'vea9x4' - Versatile Express A9X4
'imx31' - Freescale i.MX31
'panda_a2' - PandaBoard A2
Please notice that not all of these targets might be emulateable with Qemu.
To be on the safe side use 'pbxa9'. For informations about how to boot
'base-hw' images on real hardware have a look at
'<GENODE_DIR>/base-hw/doc/<TARGET>.txt'.
Now, go to the newly created build directory make a test:
@ -60,8 +79,4 @@ Now, go to the newly created build directory make a test:
This will build the Genode components that are needed to run a simple test
with 3 nested init programs, and than execute it via Qemu.
For further informations according to the specific hardware systems, have
look into the other documentations:
! base-hw/doc/<system>.txt

92
base-hw/doc/imx31.txt Normal file
View File

@ -0,0 +1,92 @@
==================================================
Getting started with 'base-hw' on Freescale i.MX31
==================================================
Martin Stein
Abstract
########
This is a short tutorial that depicts a handy way to get a Genode ELF-image,
build with 'base-hw', started on the Freescale i.MX31. For informations
about how to build Genode images with 'base-hw', have a look at
'<GENODE_DIR>/base-hw/doc/hw.txt'. This tutorial is dedicated to common
Linux systems, but all examples originate from a Ubuntu 11.10.
Tutorial
########
Connect the i.MX31 to your local Ethernet through its RJ45 connector.
Additionally connect the i.MX31 to your machine through its COM port.
We use the bootloader that is installed on the board by the manufacturer, it's
the LogicLoader by Logic Product Development, Version 2.3.5-IMX31_10 0001.
Now install the following packages to communicate with the i.MX31:
! apt-get install tftp-hpa minicom
Open '/etc/default/tftpd-hpa' with a text editor and ensure that it has
the following content:
! TFTP_USERNAME="tftp"
! TFTP_DIRECTORY="/var/lib/tftpboot"
! TFTP_ADDRESS="0.0.0.0:69"
! TFTP_OPTIONS="-l"
Tell TFTP wich image to provide:
! cd /var/lib/tftpboot/
! ln -s <GENODE_BOOT_ELF> image.elf
Where '<GENODE_BOOT_ELF>' is the absolute path of the targeted ELF image.
Start TFTP to enable the upload of the image:
! service tftp-hpa restart
Precautionary determine the inet address of your TFTP machine:
! ifconfig
Start Minicom in configuration mode:
! minicom -s
Go to 'Serial port setting' and ensure that the device is set to the
TTY of the COM port you've conntected the i.MX31 with. In my case it was
'/dev/ttyS0'. Configure the other settings for a baud rate of '115200',
8 bit char length, no parity and 1 stop bit. Quit Minicom and start
it once more in a dedicated terminal:
! minicom
Plug in the i.MX31 power connector or push the 'S1' button if the i.MX31 is
already powered. Minicom should now show the following message below some
bootloader info:
! losh>
We have to start DHCP first, so in the Minicom console type:
! ifconfig sm0 dhcp
Wait until DHCP is started:
! Starting DHCP on sm0 ...
! losh>
Then load the Genode image:
! load elf /tftp/<INET_ADDR>:/var/lib/tftpboot/image.elf
Where '<INET_ADDR>' is the inet address of your TFTP machine.
To execute the loaded image type:
! exec start
Now your Genode scenario should start and offer its debug output
in Minicom. You can boot other images by redirecting the link
'/var/lib/tftpboot/image.elf' accordingly, restarting your i.MX31
and instructing LogicLoader again as described above.

View File

@ -1,7 +1,7 @@
======================================================
Getting started with 'genode/base-hw' on PandaBoard A2
======================================================
===============================================
Getting started with 'base-hw' on PandaBoard A2
===============================================
Martin Stein
@ -9,9 +9,11 @@
Abstract
########
This is a short tutorial that depicts a handy way to get a Genode ELF image,
build with 'base-hw', started on the PandaBoard A2. It is dedicated to common
Linux systems, but all examples originate from a Ubuntu 10.10.
This is a short tutorial that depicts a handy way to get a Genode ELF-image,
build with 'base-hw', started on the PandaBoard A2. For informations
about how to build Genode images with 'base-hw', have a look at
'<GENODE_DIR>/base-hw/doc/hw.txt'. This tutorial is dedicated to common
Linux systems, but all examples originate from a Ubuntu 11.10.
Tutorial
@ -22,10 +24,10 @@ Additionally connect the PandaBoard to your machine through its COM port.
Ensure that you have installed the genode tool chain that is available at:
:[http://genode.org/download/tool-chain]:
Get the genode tool chain]
Genode tool-chain
Ensure that '<GENODE_GCC_DIR>/bin/' is in your 'PATH' variable.
Get the linaro U-Boot repository and compile U-Boot for PandaBoard:
Ensure that '<GENODE_TOOL_CHAIN_DIR>/bin/' is in your 'PATH' variable.
Get the Linaro U-Boot repository and compile U-Boot for PandaBoard:
! git clone git://git.linaro.org/boot/u-boot-linaro-stable.git
! cd <UBOOT_DIR>
@ -40,32 +42,32 @@ the array elements separately.
Now install the following packages to communicate with the PandaBoard:
! sudo apt-get install tftp-hpa minicom
! apt-get install tftp-hpa minicom
Open '/etc/default/tftpd-hpa' with a text editor and ensure that it has
the following content:
! # /etc/default/tftpd-hpa
! TFTP_USERNAME="tftp"
! TFTP_DIRECTORY="/var/lib/tftpboot"
! TFTP_ADDRESS="0.0.0.0:69"
! TFTP_OPTIONS="-l"
Tell U-Boot wich image to load on boot command:
Tell TFTP wich image to provide:
! cd /var/lib/tftpboot/
! ln -s <GENODE_BOOT_ELF> image.elf
Where '<GENODE_BOOT_ELF>' is the absolute path of the targeted ELF image.
Start TFTP to enable the upload of the image:
! sudo service tftp-hpa restart
! service tftp-hpa restart
Start Minicom in configuration mode:
! minicom -s
Go to 'Serial port setting' and ensure that the device is set the
TTY of the COM port you've conntected PandaBoard with, in my case it was
Go to 'Serial port setting' and ensure that the device is set to the
TTY of the COM port you've conntected PandaBoard with. In my case it was
'/dev/ttyS0'. Configure the other settings for a baud rate of '115200',
8 bit char length, no parity and 1 stop bit. Quit Minicom and start
it once more:
@ -78,9 +80,8 @@ Mount your SD-card and copy the U-Boot files to its boot partition:
Unmount the SD card and insert it into the appropriate PandaBoard slot.
Plug in the power connector or push the 'S1' button if the PandaBoard is
already powered.
Minicom should now show the following message:
already powered. Minicom should now show the following message below some
bootloader info:
! Hit any key to stop autoboot:
@ -89,8 +90,8 @@ image via ethernet:
! usb start; dhcp; bootelf 0x82000000
Now the ELF image should start correctly and offer some debug output in
minicom. You can now boot further images by redirecting the link
'/var/lib/tftpboot/image.elf' accordingly, restarting your pandaboard
and instructing 'uboot' again as described above.
Now your Genode scenario should start and offer its debug output
in Minicom. You can boot other images by redirecting the link
'/var/lib/tftpboot/image.elf' accordingly, restarting your PandaBoard
and instructing U-boot again as described above.

View File

@ -0,0 +1,27 @@
/*
* \brief Syscall declarations specific for ARM V7A systems
* \author Martin Stein
* \date 2011-11-30
*/
/*
* Copyright (C) 2011-2012 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 _INCLUDE__ARM__BASE__SYSCALL_H_
#define _INCLUDE__ARM__BASE__SYSCALL_H_
/* Genode includes */
#include <base/stdint.h>
namespace Kernel
{
typedef Genode::uint32_t Syscall_arg;
typedef Genode::uint32_t Syscall_ret;
}
#endif /* _INCLUDE__ARM__BASE__SYSCALL_H_ */

View File

@ -1,62 +0,0 @@
/*
* \brief Syscall declarations specific for ARM V7A systems
* \author Martin Stein
* \date 2011-11-30
*/
/*
* Copyright (C) 2011-2012 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 _INCLUDE__ARM_V7A__BASE__SYSCALL_H_
#define _INCLUDE__ARM_V7A__BASE__SYSCALL_H_
/* Genode includes */
#include <base/stdint.h>
namespace Kernel
{
typedef Genode::uint32_t Syscall_arg;
typedef Genode::uint32_t Syscall_ret;
/*****************************************************************
** Syscall with 1 to 6 arguments **
** **
** These functions must not be inline to ensure that objects, **
** wich are referenced by arguments, are tagged as "used" even **
** though only the pointer gets handled in here. **
*****************************************************************/
Syscall_ret syscall(Syscall_arg arg_0);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4,
Syscall_arg arg_5);
}
#endif /* _INCLUDE__ARM_V7A__BASE__SYSCALL_H_ */

View File

@ -0,0 +1,43 @@
/*
* \brief Connection to CPU service
* \author Martin Stein
* \date 2008-08-22
*/
/*
* Copyright (C) 2008-2012 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 _INCLUDE__CPU_SESSION__CONNECTION_H_
#define _INCLUDE__CPU_SESSION__CONNECTION_H_
/* Genode includes */
#include <cpu_session/client.h>
#include <base/connection.h>
namespace Genode {
struct Cpu_connection : Connection<Cpu_session>, Cpu_session_client
{
enum { RAM_QUOTA = 128*1024 };
/**
* Constructor
*
* \param label initial session label
* \param priority designated priority of all threads created
* with this CPU session
*/
Cpu_connection(const char *label = "", long priority = DEFAULT_PRIORITY)
:
Connection<Cpu_session>(
session("priority=0x%lx, ram_quota=128K, label=\"%s\"",
priority, label)),
Cpu_session_client(cap()) { }
};
}
#endif /* _INCLUDE__CPU_SESSION__CONNECTION_H_ */

View File

@ -15,7 +15,7 @@
#define _INCLUDE__KERNEL__SYSCALLS_H_
/* Genode includes */
#include <base/syscall.h>
#include <base/syscall_types.h>
class Software_tlb;
@ -35,7 +35,7 @@ namespace Kernel
/* execution control */
NEW_THREAD = 1,
DELETE_THREAD = 24,
DELETE_THREAD = 26,
START_THREAD = 2,
PAUSE_THREAD = 3,
RESUME_THREAD = 4,
@ -70,10 +70,45 @@ namespace Kernel
SUBMIT_SIGNAL = 23,
/* vm specific */
NEW_VM = 25,
RUN_VM = 26,
NEW_VM = 24,
RUN_VM = 25,
};
/*****************************************************************
** Syscall with 1 to 6 arguments **
** **
** These functions must not be inline to ensure that objects, **
** wich are referenced by arguments, are tagged as "used" even **
** though only the pointer gets handled in here. **
*****************************************************************/
Syscall_ret syscall(Syscall_arg arg_0);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4);
Syscall_ret syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4,
Syscall_arg arg_5);
/**
* Virtual range of the mode transition region in every PD
*/
@ -107,8 +142,8 @@ namespace Kernel
* Restricted to core threads. Regaining of the supplied memory is not
* supported by now.
*/
inline int new_pd(void * const dst)
{ return syscall(NEW_PD, (Syscall_arg)dst); }
inline int new_pd(void * const dst) {
return syscall(NEW_PD, (Syscall_arg)dst); }
/**

View File

@ -0,0 +1,38 @@
/*
* \brief Serial output driver specific for the i.MX31
* \author Norman Feske
* \date 2012-08-30
*/
/*
* Copyright (C) 2012 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 _INCLUDE__PLATFORM__IMX31__DRIVERS__SERIAL_LOG_H_
#define _INCLUDE__PLATFORM__IMX31__DRIVERS__SERIAL_LOG_H_
/* Genode includes */
#include <drivers/board.h>
#include <drivers/uart/imx31_uart_base.h>
namespace Genode
{
struct Serial_log : Imx31_uart_base
{
/**
* Constructor
*
* \param baud_rate targeted transfer baud-rate
*
* XXX: The 'baud_rate' argument is ignored for now.
*/
Serial_log(unsigned const baud_rate)
: Imx31_uart_base(Board::UART_1_MMIO_BASE) { }
};
}
#endif /* _INCLUDE__PLATFORM__IMX31__DRIVERS__SERIAL_LOG_H_ */

View File

@ -14,6 +14,7 @@
#ifndef _INCLUDE__VM_SESSION__CAPABILITY_H_
#define _INCLUDE__VM_SESSION__CAPABILITY_H_
/* Genode includes */
#include <base/capability.h>
#include <vm_session/vm_session.h>

View File

@ -1,5 +1,5 @@
/*
* \brief Client-side vm session interface
* \brief Client-side VM session interface
* \author Stefan Kalkowski
* \date 2012-10-02
*/
@ -14,16 +14,27 @@
#ifndef _INCLUDE__VM_SESSION__CLIENT_H_
#define _INCLUDE__VM_SESSION__CLIENT_H_
/* Genode includes */
#include <vm_session/capability.h>
#include <base/rpc_client.h>
namespace Genode {
namespace Genode
{
/**
* Client-side VM session interface
*/
struct Vm_session_client : Rpc_client<Vm_session>
{
/**
* Constructor
*/
explicit Vm_session_client(Vm_session_capability session)
: Rpc_client<Vm_session>(session) { }
/**************************
** Vm_session interface **
**************************/
Dataspace_capability cpu_state() {
return call<Rpc_cpu_state>(); }

View File

@ -1,5 +1,5 @@
/*
* \brief Connection to VM service
* \brief Connection to VM a service
* \author Stefan Kalkowski
* \date 2012-10-02
*/
@ -18,8 +18,11 @@
#include <cpu_session/cpu_session.h>
#include <base/connection.h>
namespace Genode {
namespace Genode
{
/**
* Connection to a VM service
*/
struct Vm_connection : Connection<Vm_session>, Vm_session_client
{
/**

View File

@ -1,5 +1,5 @@
/*
* \brief Vm session interface
* \brief VM-session interface
* \author Stefan Kalkowski
* \date 2012-10-02
*/
@ -14,6 +14,7 @@
#ifndef _INCLUDE__VM_SESSION__VM_SESSION_H_
#define _INCLUDE__VM_SESSION__VM_SESSION_H_
/* Genode includes */
#include <base/rpc_args.h>
#include <base/signal.h>
#include <session/session.h>
@ -25,6 +26,9 @@ namespace Genode {
{
static const char *service_name() { return "VM"; }
/**
* Destructor
*/
virtual ~Vm_session() { }
/**

View File

@ -0,0 +1,27 @@
#
# \brief Parts of core that depend on ARM
# \author Martin Stein
# \date 2012-04-16
#
# add C++ sources
SRC_CC += syscall.cc
# add assembly sources
SRC_S += crt0.s boot_modules.s
#
# Check if there are other images wich shall be linked to core.
# If not use a dummy boot-modules file wich includes only the symbols.
#
ifeq ($(wildcard $(BUILD_BASE_DIR)/boot_modules.s),)
vpath boot_modules.s $(REP_DIR)/src/core/arm
else
INC_DIR += $(BUILD_BASE_DIR)
vpath boot_modules.s $(BUILD_BASE_DIR)
endif
# declare source paths
vpath syscall.cc $(REP_DIR)/src/base/arm
vpath % $(REP_DIR)/src/core/arm

View File

@ -0,0 +1,15 @@
#
# \brief Parts of core that depend on ARMv6
# \author Martin Stein
# \date 2012-04-16
#
# add assembly sources
SRC_S += mode_transition.s
# declare source paths
vpath % $(REP_DIR)/src/core/arm_v6
# include less specific parts
include $(REP_DIR)/lib/mk/arm/core_support.inc

View File

@ -0,0 +1,25 @@
#
# \brief Essential platform specific sources for common programs
# \author Martin Stein
# \date 2012-04-16
#
# FIXME: This is an almost verbatim copy of 'armv7a/startup.mk'. We should move
# the common parts to a separate file.
#
# add libraries
LIBS += cxx lock
# add C++ sources
SRC_CC += _main.cc
# add assembly sources
SRC_S += crt0.s syscall.cc
# add include paths
INC_DIR += $(REP_DIR)/src/platform $(BASE_DIR)/src/platform
# declare source paths
vpath crt0.s $(REP_DIR)/src/platform
vpath _main.cc $(BASE_DIR)/src/platform
vpath syscall.cc $(REP_DIR)/src/base/arm

View File

@ -0,0 +1,15 @@
#
# \brief Parts of core that depend on ARMv7
# \author Martin Stein
# \date 2012-04-16
#
# add assembly sources
SRC_S += mode_transition.s
# declare source paths
vpath % $(REP_DIR)/src/core/arm_v7
# include less specific parts
include $(REP_DIR)/lib/mk/arm/core_support.inc

View File

@ -19,4 +19,4 @@ INC_DIR += $(REP_DIR)/src/platform $(BASE_DIR)/src/platform
# declare source paths
vpath crt0.s $(REP_DIR)/src/platform
vpath _main.cc $(BASE_DIR)/src/platform
vpath syscall.cc $(REP_DIR)/src/base/arm_v7a
vpath syscall.cc $(REP_DIR)/src/base/arm

View File

@ -14,6 +14,7 @@ CC_OPT += -DCORE_MAIN=_main
# add C++ sources
SRC_CC += kernel.cc rm_session_support.cc kernel_support.cc trustzone.cc
# add library dependencies
LIBS += platform_support
# declare source paths

View File

@ -0,0 +1,17 @@
#
# \brief Parts of core that depend on i.MX31
# \author Norman Feske
# \author Martin Stein
# \date 2012-08-30
#
# declare location of core files that are board specific
BOARD_DIR = $(REP_DIR)/src/core/imx31
# add includes to search path
INC_DIR += $(REP_DIR)/src/core/include/imx31
# include less specific parts
include $(REP_DIR)/lib/mk/arm_v6/core_support.inc
include $(REP_DIR)/lib/mk/core_support.inc

View File

@ -0,0 +1,18 @@
#
# \brief Platform implementations specific for base-hw and i.MX31
# \author Martin Stein
# \date 2012-05-10
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include \
$(REP_DIR)/src/core/include/imx31 \
$(BASE_DIR)/src/core/include
# add C++ sources
SRC_CC += platform_support.cc platform_services.cc
# declare source paths
vpath % $(REP_DIR)/src/core/imx31
vpath platform_services.cc $(BASE_DIR)/src/core

View File

@ -7,8 +7,7 @@
# declare location of core files that are board specific
BOARD_DIR = $(REP_DIR)/src/core/panda_a2
SRC_CC = trustzone.cc
# include generic parts of core support
include $(REP_DIR)/lib/mk/arm_v7/core_support.inc
include $(REP_DIR)/lib/mk/core_support.inc

View File

@ -7,8 +7,7 @@
# declare location of core files that are board specific
BOARD_DIR = $(REP_DIR)/src/core/pbxa9
SRC_CC = trustzone.cc
# include generic part of core support
include $(REP_DIR)/lib/mk/arm_v7/core_support.inc
include $(REP_DIR)/lib/mk/core_support.inc

View File

@ -13,5 +13,6 @@ vpath kernel_support.cc $(BOARD_DIR)/trustzone
vpath trustzone.cc $(BOARD_DIR)/trustzone
# include generic part of core support
include $(REP_DIR)/lib/mk/arm_v7/core_support.inc
include $(REP_DIR)/lib/mk/core_support.inc

View File

@ -7,4 +7,5 @@
BOARD_DIR = $(REP_DIR)/src/core/vea9x4
# include generic part of core support
include $(REP_DIR)/lib/mk/arm_v7/core_support.inc
include $(REP_DIR)/lib/mk/core_support.inc

View File

@ -0,0 +1,15 @@
#
# \brief Build configurations for 'base-hw' on Freescale i.MX31
# \author Martin Stein
# \date 2011-12-20
#
# denote wich specs are also fullfilled by this spec
SPECS += hw platform_imx31
# set address where to link the text segment at
LD_TEXT_ADDR ?= 0x82000000
# include implied specs
include $(call select_from_repositories,mk/spec-hw.mk)
include $(call select_from_repositories,mk/spec-platform_imx31.mk)

View File

@ -21,7 +21,7 @@
# 'binaries', minus 'core' if given, plus 'config' if available. It also
# provides a simple file system that enables Genode to access these BLOBs.
#
proc boot_modules_arm_v7a {{file} {binaries}} {
proc boot_modules_arm {{file} {binaries}} {
set load_store_alignm 0x3
set min_page_alignm 12
@ -30,7 +30,7 @@ proc boot_modules_arm_v7a {{file} {binaries}} {
exec echo -e \
"/**" \
"\n * This file was automatically generated by the procedure" \
"\n * 'boot_modules_arm_v7a' in 'run/env'." \
"\n * 'boot_modules_arm' in 'run/env'." \
"\n */" \
"\n" \
"\n.section .data" \
@ -194,8 +194,8 @@ proc build_boot_image {binaries} {
# create scenario-specific 'boot_modules.s' of all given binaries
set boot_modules "[run_dir]/boot_modules.s"
if { [have_spec {arm_v7a}] } {
boot_modules_arm_v7a $boot_modules $binaries
if { [have_spec {arm}] } {
boot_modules_arm $boot_modules $binaries
}
# preserve stand-alone core for debugging

View File

@ -0,0 +1,163 @@
/*
* \brief Syscall-framework implementation for ARM
* \author Martin stein
* \date 2011-11-30
*
* The code in this file is compliant to the general ARM instruction- and
* register-set but the semantics are tested only on ARMv6 and ARMv7 by now.
*/
/*
* Copyright (C) 2011-2012 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.
*/
/* Genode includes */
#include <kernel/syscalls.h>
using namespace Kernel;
/******************************************************************
** Inline assembly templates for syscalls with 1 to 6 arguments **
******************************************************************/
#define SYSCALL_6_ASM_OPS \
"mov r5, #0 \n" \
"add r5, %[arg_5] \n" \
SYSCALL_5_ASM_OPS
#define SYSCALL_5_ASM_OPS \
"mov r4, #0 \n" \
"add r4, %[arg_4] \n" \
SYSCALL_4_ASM_OPS
#define SYSCALL_4_ASM_OPS \
"mov r3, #0 \n" \
"add r3, %[arg_3] \n" \
SYSCALL_3_ASM_OPS
#define SYSCALL_3_ASM_OPS \
"mov r2, #0 \n" \
"add r2, %[arg_2] \n" \
SYSCALL_2_ASM_OPS
#define SYSCALL_2_ASM_OPS \
"mov r1, #0 \n" \
"add r1, %[arg_1] \n" \
SYSCALL_1_ASM_OPS
#define SYSCALL_1_ASM_OPS \
"mov r0, #0 \n" \
"add r0, %[arg_0] \n" \
"swi 0 \n" \
"mov %[result], #0 \n" \
"add %[result], r0 "
/*****************************************************************************
** Inline assembly "writeable" template-args for syscalls with 1 to 6 args **
*****************************************************************************/
#define SYSCALL_6_ASM_WRITE [arg_5] "+r" (arg_5), SYSCALL_5_ASM_WRITE
#define SYSCALL_5_ASM_WRITE [arg_4] "+r" (arg_4), SYSCALL_4_ASM_WRITE
#define SYSCALL_4_ASM_WRITE [arg_3] "+r" (arg_3), SYSCALL_3_ASM_WRITE
#define SYSCALL_3_ASM_WRITE [arg_2] "+r" (arg_2), SYSCALL_2_ASM_WRITE
#define SYSCALL_2_ASM_WRITE [arg_1] "+r" (arg_1), SYSCALL_1_ASM_WRITE
#define SYSCALL_1_ASM_WRITE \
[arg_0] "+r" (arg_0), \
[result] "+r" (result)
/**********************************************************************
** Inline assembly clobber lists for syscalls with 1 to 6 arguments **
**********************************************************************/
#define SYSCALL_6_ASM_CLOBBER "r5", SYSCALL_5_ASM_CLOBBER
#define SYSCALL_5_ASM_CLOBBER "r4", SYSCALL_4_ASM_CLOBBER
#define SYSCALL_4_ASM_CLOBBER "r3", SYSCALL_3_ASM_CLOBBER
#define SYSCALL_3_ASM_CLOBBER "r2", SYSCALL_2_ASM_CLOBBER
#define SYSCALL_2_ASM_CLOBBER "r1", SYSCALL_1_ASM_CLOBBER
#define SYSCALL_1_ASM_CLOBBER "r0"
/************************************
** Syscalls with 1 to 6 arguments **
************************************/
Syscall_ret Kernel::syscall(Syscall_arg arg_0)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_1_ASM_OPS
: SYSCALL_1_ASM_WRITE
:: SYSCALL_1_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_2_ASM_OPS
: SYSCALL_2_ASM_WRITE
:: SYSCALL_2_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_3_ASM_OPS
: SYSCALL_3_ASM_WRITE
:: SYSCALL_3_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_4_ASM_OPS
: SYSCALL_4_ASM_WRITE
:: SYSCALL_4_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_5_ASM_OPS
: SYSCALL_5_ASM_WRITE
:: SYSCALL_5_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4,
Syscall_arg arg_5)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_6_ASM_OPS
: SYSCALL_6_ASM_WRITE
:: SYSCALL_6_ASM_CLOBBER);
return result;
}

View File

@ -1,5 +1,5 @@
/*
* \brief Dummy version of a boot modules file to enable a 'core' standalone image
* \brief Dummy boot-modules-file to enable a 'core' standalone image
* \author Martin Stein
* \date 2011-12-16
*/
@ -31,3 +31,4 @@ _boot_module_headers_end:
.global _boot_modules_end
_boot_modules_end:

View File

@ -1,8 +1,11 @@
/*
* \brief Startup code for the Genode Kernel on ARM
* \brief Startup code for core on ARM
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-01
*
* The code in this file is compliant to the general ARM instruction- and
* register-set but the semantics are tested only on ARMv6 and ARMv7 by now.
*/
/*
@ -12,6 +15,15 @@
* under the terms of the GNU General Public License version 2.
*/
/**
* Do no operation for 'count' cycles
*/
.macro _nop count
.rept \count
mov r8, r8
.endr
.endm
.section .text
/* ELF entry symbol */
@ -19,9 +31,7 @@
_start:
/* idle a little initially because 'u-boot' likes it this way */
.rept 8
nop
.endr
_nop 8
/* zero-fill BSS segment */
.extern _bss_start
@ -36,12 +46,19 @@
cmp r0, r1
bne 1b
/* enable C++ to prepare the first kernel run */
ldr sp, =_kernel_stack_high
bl init_phys_kernel
/* call kernel routine */
.extern kernel
_start_kernel:
ldr sp, =_kernel_stack_high
bl kernel
/* catch erroneous kernel return */
2: b 2b
/* handle for dynamic symbol objects */
.align 3
.global __dso_handle
@ -55,7 +72,7 @@
.global _kernel_stack_high
_kernel_stack_high:
/* main thread UTCB pointer for the Genode thread API */
/* main-thread UTCB-pointer for the Genode thread-API */
.align 3
.global _main_utcb
_main_utcb: .long 0

View File

@ -0,0 +1,234 @@
/*
* \brief Transition between kernel and userland
* \author Martin stein
* \date 2011-11-15
*/
/*
* Copyright (C) 2011-2012 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.
*/
/**
* Invalidate all entries of the branch prediction cache
*
* FIXME branch prediction shall not be activated for now because we have no
* support for instruction barriers. The manual says that one should
* implement this via 'swi 0xf00000', but when we do this in SVC mode it
* pollutes our SP and this is not acceptable with the current mode
* transition implementation
*/
.macro _flush_branch_predictor
mcr p15, 0, sp, c7, c5, 6
/* swi 0xf00000 */
.endm
/**
* Switch from an interrupted user context to a kernel context
*
* \param exception_type immediate exception type ID
* \param pc_adjust immediate value that gets subtracted from the
* user PC before it gets saved
*/
.macro _user_to_kernel_pic exception_type, pc_adjust
/*
* We expect that privileged modes are never interrupted by an
* exception. Thus we can assume that we always come from
* user mode at this point.
*/
/************************************************
** We're still in the user protection domain, **
** so we must avoid access to kernel memory **
************************************************/
/* load kernel cidr */
adr sp, _mt_master_context_begin
ldr sp, [sp, #18*4]
mcr p15, 0, sp, c13, c0, 1
_flush_branch_predictor
/* load kernel section table */
adr sp, _mt_master_context_begin
ldr sp, [sp, #19*4]
mcr p15, 0, sp, c2, c0, 0
_flush_branch_predictor
/*******************************************
** Now it's save to access kernel memory **
*******************************************/
/* get user context pointer */
ldr sp, _mt_client_context_ptr
/*
* Save user r0 ... r12. We explicitely target user registers
* via '^' because we might be in FIQ exception-mode where
* some of them are banked. Doesn't affect other modes.
*/
stmia sp, {r0-r12}^
/* save user lr and sp */
add r0, sp, #13*4
stmia r0, {sp,lr}^
/* adjust and save user pc */
.if \pc_adjust != 0
sub lr, lr, #\pc_adjust
.endif
str lr, [sp, #15*4]
/* save user psr */
mrs r0, spsr
str r0, [sp, #16*4]
/* save type of exception that interrupted the user */
mov r0, #\exception_type
str r0, [sp, #17*4]
/*
* Switch to supervisor mode
*
* FIXME This is done due to incorrect behavior when running the kernel
* high-level-code in FIQ-exception mode. Please debug this behavior
* and remove this switch.
*/
cps #19
/* get kernel context pointer */
adr r0, _mt_master_context_begin
/* load kernel context */
add r0, r0, #13*4
ldmia r0, {sp, lr, pc}
.endm
.section .text
/*
* The mode transition PIC switches between a kernel context and a user
* context and thereby between their address spaces. Due to the latter
* it must be mapped executable to the same region in every address space.
* To enable such switching, the kernel context must be stored within this
* region, thus one should map it solely accessable for privileged modes.
*/
.p2align 12
.global _mode_transition_begin
_mode_transition_begin:
/*
* On user exceptions the CPU has to jump to one of the following
* 7 entry vectors to switch to a kernel context.
*/
.global _mt_kernel_entry_pic
_mt_kernel_entry_pic:
b _rst_entry /* 0x00: reset */
b _und_entry /* 0x04: undefined instruction */
b _swi_entry /* 0x08: software interrupt */
b _pab_entry /* 0x0c: prefetch abort */
b _dab_entry /* 0x10: data abort */
nop /* 0x14: reserved */
b _irq_entry /* 0x18: interrupt request */
b _fiq_entry /* 0x1c: fast interrupt request */
/* PICs that switch from an user exception to the kernel */
_rst_entry: _user_to_kernel_pic 1, 0
_und_entry: _user_to_kernel_pic 2, 4
_swi_entry:
/*
* FIXME fast SWI routines pollute the SVC SP but we have
* to call them especially in SVC mode
*/
/* check if SWI requests a fast service routine */
/* ldr sp, [r14, #-0x4]
and sp, sp, #0xffffff
*/
/* fast "instruction barrier" service routine */
/* cmp sp, #0xf00000
bne _mt_slow_swi
movs pc, r14
*/
/* slow high level service routine */
_mt_slow_swi:
_user_to_kernel_pic 3, 0
_pab_entry: _user_to_kernel_pic 4, 4
_dab_entry: _user_to_kernel_pic 5, 8
_irq_entry: _user_to_kernel_pic 6, 4
_fiq_entry: _user_to_kernel_pic 7, 4
/* kernel must jump to this point to switch to a user context */
.p2align 2
.global _mt_user_entry_pic
_mt_user_entry_pic:
/* get user context pointer */
ldr lr, _mt_client_context_ptr
/* buffer user pc */
ldr r0, [lr, #15*4]
adr r1, _mt_buffer
str r0, [r1]
/* buffer user psr */
ldr r0, [lr, #16*4]
msr spsr, r0
/* load user r0 ... r12 */
ldmia lr, {r0-r12}
/* load user sp and lr */
add sp, lr, #13*4
ldmia sp, {sp,lr}^
/* get user cidr and section table */
ldr sp, [lr, #18*4]
ldr lr, [lr, #19*4]
/********************************************************
** From now on, until we leave kernel mode, we must **
** avoid access to memory that is not mapped globally **
********************************************************/
/* apply user contextidr and section table */
mcr p15, 0, sp, c13, c0, 1
mcr p15, 0, lr, c2, c0, 0
_flush_branch_predictor
/* load user pc (implies application of the user psr) */
adr lr, _mt_buffer
ldmia lr, {pc}^
/* leave some space for 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:
/* pointer to the context backup space */
.p2align 2
.global _mt_client_context_ptr
_mt_client_context_ptr: .long 0
/* a local word-sized buffer */
.p2align 2
.global _mt_buffer
_mt_buffer: .long 0
.p2align 2
.global _mode_transition_end
_mode_transition_end:
/* FIXME this exists only because _vm_mon_entry pollutes kernel.cc */
.global _mon_vm_entry
_mon_vm_entry:
1: b 1b

View File

@ -12,6 +12,7 @@
* under the terms of the GNU General Public License version 2.
*/
/**
* Switch from an interrupted user context to a kernel context
*
@ -37,13 +38,14 @@
** so we must avoid access to kernel memory **
************************************************/
/* load kernel contextidr */
adr sp, _mt_kernel_context_begin
/* load kernel cidr */
adr sp, _mt_master_context_begin
ldr sp, [sp, #18*4]
mcr p15, 0, sp, c13, c0, 1
isb
/* load kernel section table */
adr sp, _mt_kernel_context_begin
adr sp, _mt_master_context_begin
ldr sp, [sp, #19*4]
mcr p15, 0, sp, c2, c0, 0
isb
@ -54,7 +56,7 @@
*******************************************/
/* get user context pointer */
ldr sp, _mt_context_ptr
ldr sp, _mt_client_context_ptr
/*
* Save user r0 ... r12. We explicitely target user registers
@ -90,7 +92,7 @@
cps #19
/* get kernel context pointer */
adr r0, _mt_kernel_context_begin
adr r0, _mt_master_context_begin
/* load kernel context */
add r0, r0, #13*4
@ -105,7 +107,7 @@
.macro _kernel_to_user_pic
/* get user context pointer */
ldr lr, _mt_context_ptr
ldr lr, _mt_client_context_ptr
/* buffer user pc */
ldr r0, [lr, #15*4]
@ -154,7 +156,7 @@
orr r8, #64
msr spsr, r8
subs pc, lr, #4 /* resume previous exception */
1:
1:
.endm /* _fiq_check_prior_mode */
/**
@ -168,14 +170,14 @@
/**
* Switch from an interrupted vm to the kernel context
* Switch from an interrupted VM to the kernel context
*
* \param exception_type immediate exception type ID
* \param pc_adjust immediate value that gets subtracted from the
* vm's PC before it gets saved
*/
.macro _vm_to_kernel exception_type, pc_adjust
ldr sp, _mt_context_ptr /* load context pointer */
ldr sp, _mt_client_context_ptr /* load context pointer */
stmia sp, {r0-lr}^ /* save user regs r0-r12,sp,lr */
add r0, sp, #15*4
.if \pc_adjust != 0 /* adjust pc if necessary */
@ -194,7 +196,7 @@
_save_bank 17 /* save fiq banks */
stmia r0!, {r8-r12} /* save fiq r8-r12 */
cps #19 /* switch to supervisor mode */
adr r0, _mt_kernel_context_begin /* get kernel context pointer */
adr r0, _mt_master_context_begin /* get kernel context pointer */
add r0, r0, #13*4 /* load kernel context */
ldmia r0, {sp,lr,pc}
.endm /* _vm_to_kernel */
@ -211,10 +213,10 @@
/**
* Switch from kernel context to a vm
* Switch from kernel context to a VM
*/
.macro _kernel_to_vm
ldr r0, _mt_context_ptr /* get vm context pointer */
ldr r0, _mt_client_context_ptr /* get vm context pointer */
add r0, r0, #18*4 /* add offset of banked modes */
_restore_bank 27 /* load undefined banks */
_restore_bank 19 /* load supervisor banks */
@ -223,7 +225,7 @@
_restore_bank 17 /* load fiq banks */
ldmia r0!, {r8 - r12} /* load fiq r8-r12 */
cps #22 /* switch to monitor mode */
ldr sp, _mt_context_ptr /* get vm context pointer */
ldr sp, _mt_client_context_ptr /* get vm context pointer */
ldmia sp, {r0-lr}^ /* load user r0-r12,sp,lr */
ldr lr, [sp, #16*4] /* load vm's cpsr to lr */
msr spsr_cxfs, lr /* save cpsr to be load when switching */
@ -254,23 +256,23 @@
.global _mt_kernel_entry_pic
_mt_kernel_entry_pic:
b _rst_entry /* reset */
b _und_entry /* undefined instruction */
b _svc_entry /* supervisor call */
b _pab_entry /* prefetch abort */
b _dab_entry /* data abort */
nop /* reserved */
b _irq_entry /* interrupt request */
_fiq_check_prior_mode /* fast interrupt request */
_user_to_kernel_pic 6, 4
b _rst_entry /* 0x00: reset */
b _und_entry /* 0x04: undefined instruction */
b _svc_entry /* 0x08: supervisor call */
b _pab_entry /* 0x0c: prefetch abort */
b _dab_entry /* 0x10: data abort */
nop /* 0x14: reserved */
b _irq_entry /* 0x18: interrupt request */
_fiq_check_prior_mode /* 0x1c: fast interrupt request */
_user_to_kernel_pic 7, 4
/* PICs that switch from an user exception to the kernel */
_rst_entry: _user_to_kernel_pic 0, 0
_und_entry: _user_to_kernel_pic 1, 4
_svc_entry: _user_to_kernel_pic 2, 0
_pab_entry: _user_to_kernel_pic 3, 4
_dab_entry: _user_to_kernel_pic 4, 8
_irq_entry: _user_to_kernel_pic 5, 4
_rst_entry: _user_to_kernel_pic 1, 0
_und_entry: _user_to_kernel_pic 2, 4
_svc_entry: _user_to_kernel_pic 3, 0
_pab_entry: _user_to_kernel_pic 4, 4
_dab_entry: _user_to_kernel_pic 5, 8
_irq_entry: _user_to_kernel_pic 6, 4
/* kernel must jump to this point to switch to a user context */
.p2align 2
@ -280,15 +282,15 @@
/* leave some space for the kernel context */
.p2align 2
.global _mt_kernel_context_begin
_mt_kernel_context_begin: .space 32*4
.global _mt_kernel_context_end
_mt_kernel_context_end:
.global _mt_master_context_begin
_mt_master_context_begin: .space 32*4
.global _mt_master_context_end
_mt_master_context_end:
/* pointer to the context backup space */
.p2align 2
.global _mt_context_ptr
_mt_context_ptr: .long 0
.global _mt_client_context_ptr
_mt_client_context_ptr: .long 0
/* a local word-sized buffer */
.p2align 2
@ -302,7 +304,7 @@
* On vm exceptions the CPU has to jump to one of the following
* 7 entry vectors to switch to a kernel context.
*/
.p2align 2
.p2align 4
.global _mon_kernel_entry
_mon_kernel_entry:
b _mon_rst_entry /* reset */
@ -312,15 +314,15 @@
b _mon_dab_entry /* data abort */
nop /* reserved */
b _mon_irq_entry /* interrupt request */
_vm_to_kernel 6, 4 /* fast interrupt request */
_vm_to_kernel 7, 4 /* fast interrupt request */
/* PICs that switch from a vm exception to the kernel */
_mon_rst_entry: _vm_to_kernel 0, 0
_mon_und_entry: _vm_to_kernel 1, 4
_mon_svc_entry: _vm_to_kernel 2, 0
_mon_pab_entry: _vm_to_kernel 3, 4
_mon_dab_entry: _vm_to_kernel 4, 8
_mon_irq_entry: _vm_to_kernel 5, 4
_mon_rst_entry: _vm_to_kernel 1, 0
_mon_und_entry: _vm_to_kernel 2, 4
_mon_svc_entry: _vm_to_kernel 3, 0
_mon_pab_entry: _vm_to_kernel 4, 4
_mon_dab_entry: _vm_to_kernel 5, 8
_mon_irq_entry: _vm_to_kernel 6, 4
/* kernel must jump to this point to switch to a vm */
.p2align 2

View File

@ -0,0 +1,21 @@
/*
* \brief Platform specific parts of kernel
* \author Martin Stein
* \date 2012-04-23
*/
/*
* Copyright (C) 2012 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 _SRC__CORE__KERNEL_SUPPORT_H_
#define _SRC__CORE__KERNEL_SUPPORT_H_
/* local includes */
#include <arm1136/kernel_support.h>
#endif /* _SRC__CORE__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,96 @@
/*
* \brief Platform implementations specific for base-hw and i.MX31
* \author Norman Feske
* \date 2012-08-30
*/
/*
* Copyright (C) 2012 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.
*/
/* Genode includes */
#include <drivers/board.h>
#include <imx31/pic.h>
/* core includes */
#include <platform.h>
using namespace Genode;
Native_region * Platform::_ram_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Board::CSD0_SDRAM_BASE, Board::CSD0_SDRAM_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Imx31::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core timer */
{ Board::EPIT_1_IRQ, 1 },
/* core UART */
{ Board::UART_1_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
/*
* The address range below 0x30000000 is used for secure ROM, ROM, and
* internal RAM.
*/
{ 0x30000000, 0x50000000 },
/*
* The address range between 0x8000000 and 0x9fffffff is designated for
* SDRAM. The remaining address range is populated with peripherals.
*/
{ 0xa0000000, 0x24000000 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core UART */
{ Board::UART_1_MMIO_BASE, Board::UART_1_MMIO_SIZE },
/* core timer */
{ Board::EPIT_1_MMIO_BASE, Board::EPIT_1_MMIO_SIZE },
/* interrupt controller */
{ Board::AVIC_MMIO_BASE, Board::AVIC_MMIO_SIZE },
/* bus interface controller */
{ Board::AIPS_1_MMIO_BASE, Board::AIPS_1_MMIO_SIZE },
{ Board::AIPS_2_MMIO_BASE, Board::AIPS_2_MMIO_SIZE },
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

@ -0,0 +1,26 @@
/*
* \brief Software TLB controls specific for the i.MX31
* \author Norman Feske
* \date 2012-08-30
*/
/*
* Copyright (C) 2012 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 _SRC__CORE__IMX31__SOFTWARE_TLB_H_
#define _SRC__CORE__IMX31__SOFTWARE_TLB_H_
/* Genode includes */
#include <arm/v6/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Arm_v6::Section_table { };
#endif /* _SRC__CORE__IMX31__SOFTWARE_TLB_H_ */

View File

@ -0,0 +1,11 @@
#
# \brief Makefile for core
# \author Martin Stein
# \date 2012-10-04
#
# declare wich specs must be given to build this target
REQUIRES = platform_imx31
# include less specific target parts
include $(REP_DIR)/src/core/target.inc

View File

@ -0,0 +1,660 @@
/*
* \brief Simple driver for the ARM core
* \author Martin stein
* \date 2012-09-11
*/
/*
* Copyright (C) 2012 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 _INCLUDE__ARM__CPU_H_
#define _INCLUDE__ARM__CPU_H_
/* Genode includes */
#include <util/register.h>
#include <cpu/cpu_state.h>
namespace Arm
{
using namespace Genode;
/**
* ARM core
*/
struct Cpu
{
enum {
TTBCR_N = 0,
EXCEPTION_ENTRY = 0xffff0000,
DATA_ACCESS_ALIGNM = 4,
};
/**
* Cache type register
*/
struct Ctr : Register<32>
{
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c0, c0, 1" : [v]"=r"(v) :: );
return v;
}
};
/**
* System control register
*/
struct Sctlr : Register<32>
{
struct M : Bitfield<0,1> { }; /* enable MMU */
struct A : Bitfield<1,1> { }; /* strict data addr. alignment on */
struct C : Bitfield<2,1> { }; /* enable L1 data cache */
struct Z : Bitfield<11,1> { }; /* enable program flow prediction */
struct I : Bitfield<12,1> { }; /* enable L1 instruction-cache */
struct V : Bitfield<13,1> /* select exception-entry base */
{
enum { XFFFF0000 = 1 };
};
struct Rr : Bitfield<14,1> /* replacement strategy */
{
enum { RANDOM = 0 };
};
struct Fi : Bitfield<21,1> { }; /* enable fast IRQ config */
struct Ve : Bitfield<24,1> /* interrupt vector config */
{
enum { FIXED = 0 };
};
struct Ee : Bitfield<25,1> { }; /* raise CPSR.E on exceptions */
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return M::bits(1) |
A::bits(0) |
C::bits(0) |
Z::bits(0) |
I::bits(0) |
V::bits(V::XFFFF0000) |
Rr::bits(Rr::RANDOM) |
Fi::bits(0) |
Ve::bits(Ve::FIXED) |
Ee::bits(0);
}
/**
* Value for the initial kernel entry
*/
static access_t init_phys_kernel()
{
return M::bits(0) |
A::bits(0) |
C::bits(0) |
Z::bits(0) |
I::bits(0) |
V::bits(V::XFFFF0000) |
Rr::bits(Rr::RANDOM) |
Fi::bits(0) |
Ve::bits(Ve::FIXED) |
Ee::bits(0);
}
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c1, c0, 0" : [v]"=r"(v) :: );
return v;
}
/**
* Write register value
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c1, c0, 0" :: [v]"r"(v) : );
}
};
/**
* Translation table base control register
*/
struct Ttbcr : Register<32>
{
struct N : Bitfield<0, 3> { }; /* base address width */
/**
* Write register, only in privileged CPU mode
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %[v], c2, c0, 2" :: [v]"r"(v) : ); }
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c2, c0, 2" : [v]"=r"(v) :: );
return v;
}
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel() { return N::bits(TTBCR_N); }
};
/**
* Translation table base register 0
*/
struct Ttbr0 : Register<32>
{
struct Irgn_1 : Bitfield<0,1> /* inner cachable mode */
{
enum { NON_CACHEABLE = 0 };
};
struct S : Bitfield<1,1> { }; /* shareable */
struct Rgn : Bitfield<3, 2> /* outer cachable attributes */
{
enum { NON_CACHEABLE = 0 };
};
struct Ba : Bitfield<14-TTBCR_N, 18+TTBCR_N> { }; /* translation
* table base */
/**
* Write register, only in privileged CPU mode
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %[v], c2, c0, 0" :: [v]"r"(v) : ); }
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c2, c0, 0" : [v]"=r"(v) :: );
return v;
}
/**
* Value for the switch to virtual mode in kernel
*
* \param sect_table pointer to initial section table
*/
static access_t init_virt_kernel(addr_t const sect_table)
{
return S::bits(0) |
Irgn_1::bits(Irgn_1::NON_CACHEABLE) |
Rgn::bits(Rgn::NON_CACHEABLE) |
Ba::masked((addr_t)sect_table);
}
};
/**
* Domain access control register
*/
struct Dacr : Register<32>
{
enum Dx_values { NO_ACCESS = 0, CLIENT = 1 };
/**
* Access values for the 16 available domains
*/
struct D0 : Bitfield<0,2> { };
struct D1 : Bitfield<2,2> { };
struct D2 : Bitfield<4,2> { };
struct D3 : Bitfield<6,2> { };
struct D4 : Bitfield<8,2> { };
struct D5 : Bitfield<10,2> { };
struct D6 : Bitfield<12,2> { };
struct D7 : Bitfield<14,2> { };
struct D8 : Bitfield<16,2> { };
struct D9 : Bitfield<18,2> { };
struct D10 : Bitfield<20,2> { };
struct D11 : Bitfield<22,2> { };
struct D12 : Bitfield<24,2> { };
struct D13 : Bitfield<26,2> { };
struct D14 : Bitfield<28,2> { };
struct D15 : Bitfield<30,2> { };
/**
* Write register, only in privileged CPU mode
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %[v], c3, c0, 0" :: [v]"r"(v) : ); }
/**
* Initialize for Genodes operational mode
*/
static access_t init_virt_kernel()
{
return D0::bits(CLIENT) | D1::bits(NO_ACCESS) |
D2::bits(NO_ACCESS) | D3::bits(NO_ACCESS) |
D4::bits(NO_ACCESS) | D5::bits(NO_ACCESS) |
D6::bits(NO_ACCESS) | D7::bits(NO_ACCESS) |
D8::bits(NO_ACCESS) | D9::bits(NO_ACCESS) |
D10::bits(NO_ACCESS) | D11::bits(NO_ACCESS) |
D12::bits(NO_ACCESS) | D13::bits(NO_ACCESS) |
D14::bits(NO_ACCESS) | D15::bits(NO_ACCESS);
}
};
/**
* Context identification register
*/
struct Cidr : Register<32>
{
/**
* Write register value
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c13, c0, 1" :: [v]"r"(v) : );
}
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c13, c0, 1" : [v]"=r"(v) :: );
return v;
}
};
/**
* Program status register
*/
struct Psr : Register<32>
{
struct M : Bitfield<0,5> /* processor mode */
{
enum { USER = 0b10000, SUPERVISOR = 0b10011 };
};
struct T : Bitfield<5,1> /* instruction state */
{
enum { ARM = 0 };
};
struct F : Bitfield<6,1> { }; /* FIQ disable */
struct I : Bitfield<7,1> { }; /* IRQ disable */
struct A : Bitfield<8,1> { }; /* asynchronous abort disable */
struct E : Bitfield<9,1> /* load/store endianess */
{
enum { LITTLE = 0 };
};
struct J : Bitfield<24,1> /* instruction state */
{
enum { ARM = 0 };
};
/**
* Read register
*/
static access_t read()
{
access_t v;
asm volatile ("mrs %[v], cpsr" : [v] "=r" (v) : : );
return v;
}
/**
* Write register
*/
static void write(access_t const v) {
asm volatile ("msr cpsr, %[v]" : : [v] "r" (v) : ); }
/**
* Initial value for a user execution context with trustzone
*
* FIXME: This function should not be declared in 'Arm' but in
* 'Arm_v7', but for now the declaration is necessary
* because of 'User_context::User_context()'.
*/
inline static access_t init_user_with_trustzone();
/**
* Initial value for an userland execution context
*/
static access_t init_user()
{
return M::bits(M::USER) |
T::bits(T::ARM) |
F::bits(1) |
I::bits(0) |
A::bits(1) |
E::bits(E::LITTLE) |
J::bits(J::ARM);
}
/**
* Initial value for the kernel execution context
*/
static access_t init_kernel()
{
return M::bits(M::SUPERVISOR) |
T::bits(T::ARM) |
F::bits(1) |
I::bits(1) |
A::bits(1) |
E::bits(E::LITTLE) |
J::bits(J::ARM);
}
};
/**
* Common parts of fault status registers
*/
struct Fsr : Register<32>
{
/**
* Fault status encoding
*/
enum Fault_status
{
SECTION_TRANSLATION = 5,
PAGE_TRANSLATION = 7,
};
struct Fs_3_0 : Bitfield<0, 4> { }; /* fault status */
struct Fs_4 : Bitfield<10, 1> { }; /* fault status */
};
/**
* Instruction fault status register
*/
struct Ifsr : Fsr
{
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 1" : [v]"=r"(v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status()
{
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) |
(Fs_4::get(v) << Fs_3_0::WIDTH));
}
};
/**
* Data fault status register
*/
struct Dfsr : Fsr
{
struct Wnr : Bitfield<11, 1> { }; /* write not read bit */
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 0" : [v]"=r"(v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status() {
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) |
(Fs_4::get(v) << Fs_3_0::WIDTH));
}
};
/**
* Data fault address register
*/
struct Dfar : Register<32>
{
/**
* Read register value
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c6, c0, 0" : [v]"=r"(v) :: );
return v;
}
};
/**
* Extend basic CPU state by members relevant for 'base-hw' only
*/
struct Context : Cpu_state
{
/**********************************************************
** The offset and width of any of these classmembers is **
** silently expected to be this way by several assembly **
** files. So take care if you attempt to change them. **
**********************************************************/
uint32_t cidr; /* context ID register backup */
uint32_t section_table; /* base address of applied section table */
/***************
** Accessors **
***************/
void software_tlb(addr_t const st) { section_table = st; }
addr_t software_tlb() const { return section_table; }
void protection_domain(unsigned const id) { cidr = id; }
};
/**
* An usermode execution state
*/
struct User_context : Context
{
/**
* Constructor
*/
User_context();
/***************************************************
** Communication between user and context holder **
***************************************************/
void user_arg_0(unsigned const arg) { r0 = arg; }
void user_arg_1(unsigned const arg) { r1 = arg; }
void user_arg_2(unsigned const arg) { r2 = arg; }
void user_arg_3(unsigned const arg) { r3 = arg; }
void user_arg_4(unsigned const arg) { r4 = arg; }
void user_arg_5(unsigned const arg) { r5 = arg; }
void user_arg_6(unsigned const arg) { r6 = arg; }
void user_arg_7(unsigned const arg) { r7 = arg; }
unsigned user_arg_0() const { return r0; }
unsigned user_arg_1() const { return r1; }
unsigned user_arg_2() const { return r2; }
unsigned user_arg_3() const { return r3; }
unsigned user_arg_4() const { return r4; }
unsigned user_arg_5() const { return r5; }
unsigned user_arg_6() const { return r6; }
unsigned user_arg_7() const { return r7; }
/**
* Read a general purpose register
*
* \param id ID of the targeted register
* \param v Holds register value if this returns 1
*/
bool get_gpr(unsigned id, unsigned & v) const
{
switch(id)
{
case 0: v = r0; return 1;
case 1: v = r1; return 1;
case 2: v = r2; return 1;
case 3: v = r3; return 1;
case 4: v = r4; return 1;
case 5: v = r5; return 1;
case 6: v = r6; return 1;
case 7: v = r7; return 1;
case 8: v = r8; return 1;
case 9: v = r9; return 1;
case 10: v = r10; return 1;
case 11: v = r11; return 1;
case 12: v = r12; return 1;
case 13: v = sp; return 1;
case 14: v = lr; return 1;
case 15: v = ip; return 1;
}
return 0;
}
/**
* Override a general purpose register
*
* \param id ID of the targeted register
* \param v Has been written to register if this returns 1
*/
bool set_gpr(unsigned id, unsigned const v)
{
switch(id)
{
case 0: r0 = v; return 1;
case 1: r1 = v; return 1;
case 2: r2 = v; return 1;
case 3: r3 = v; return 1;
case 4: r4 = v; return 1;
case 5: r5 = v; return 1;
case 6: r6 = v; return 1;
case 7: r7 = v; return 1;
case 8: r8 = v; return 1;
case 9: r9 = v; return 1;
case 10: r10 = v; return 1;
case 11: r11 = v; return 1;
case 12: r12 = v; return 1;
case 13: sp = v; return 1;
case 14: lr = v; return 1;
case 15: ip = v; return 1;
}
return 0;
}
/**
* Check if a pagefault has occured due to a translation miss
*
* \param va holds the virtual fault-address if this returns 1
* \param w wether it is a write fault if this returns 1
*/
bool translation_miss(addr_t & va, bool & w) const
{
/* determine fault type */
switch (cpu_exception) {
case PREFETCH_ABORT: {
/* check if fault was caused by a translation miss */
Ifsr::Fault_status const fs = Ifsr::fault_status();
if (fs == Ifsr::SECTION_TRANSLATION ||
fs == Ifsr::PAGE_TRANSLATION)
{
/* fetch fault data */
w = 0;
va = ip;
return 1;
}
return 0; }
case DATA_ABORT: {
/* check if fault was caused by translation miss */
Dfsr::Fault_status const fs = Dfsr::fault_status();
if(fs == Dfsr::SECTION_TRANSLATION ||
fs == Dfsr::PAGE_TRANSLATION)
{
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return 1;
}
return 0; }
default: return 0;
}
}
};
/**
* Flush all instruction caches
*/
__attribute__((always_inline)) static void flush_instr_caches() {
asm volatile ("mcr p15, 0, %[rd], c7, c5, 0" :: [rd]"r"(0) : ); }
/**
* Flush all data caches
*/
inline static void flush_data_caches();
/**
* Flush all caches
*/
static void flush_caches()
{
flush_data_caches();
flush_instr_caches();
}
/**
* Invalidate all TLB entries of one address space
*
* \param pid ID of the targeted address space
*/
static void flush_tlb_by_pid(unsigned const pid)
{
asm volatile ("mcr p15, 0, %[pid], c8, c7, 2" :: [pid]"r"(pid) : );
flush_caches();
}
/**
* Invalidate all TLB entries
*/
static void flush_tlb()
{
asm volatile ("mcr p15, 0, %[rd], c8, c7, 0" :: [rd]"r"(0) : );
flush_caches();
}
};
}
#endif /* _INCLUDE__ARM__CPU_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief Driver for Cortex A9 section tables as software TLB
* \brief Driver for ARM section tables
* \author Martin Stein
* \date 2012-02-22
*/
@ -11,20 +11,21 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__DRIVERS__CPU__CORTEX_A9__SECTION_TABLE_H_
#define _INCLUDE__DRIVERS__CPU__CORTEX_A9__SECTION_TABLE_H_
#ifndef _INCLUDE__ARM__SECTION_TABLE_H_
#define _INCLUDE__ARM__SECTION_TABLE_H_
/* Genode includes */
#include <util/register.h>
#include <base/printf.h>
#include <cortex_a9/cpu/core.h>
namespace Genode
namespace Arm
{
using namespace Genode;
/**
* Check if 'p' is aligned to 1 << 'alignm_log2'
*/
bool inline aligned(addr_t const a, unsigned long const alignm_log2)
inline bool aligned(addr_t const a, unsigned long const alignm_log2)
{
return a == ((a >> alignm_log2) << alignm_log2);
}
@ -53,7 +54,6 @@ namespace Genode
};
};
/**
* Permission configuration according to given access rights
*
@ -77,7 +77,7 @@ namespace Genode
Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS),
Ap_1_0::bits(Ap_1_0::USER_NO_ACCESS) | /* -k */
Ap_2::bits(Ap_2::KERNEL_RO_ACCESS) }, {
Ap_2::bits(Ap_2::KERNEL_RO_ACCESS) }, {
Ap_1_0::bits(Ap_1_0::KERNEL_AND_USER_SAME_ACCESS) | /* w- */
Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS),
@ -91,11 +91,11 @@ namespace Genode
}
/**
* Cortex A9 second level translation table
* Second level translation table
*
* A table is dedicated to either secure or non-secure mode. All
* translations done by this table apply domain 0. They are not shareable
* and have zero-filled memory region attributes.
* translations done by this table apply to domain 0. They are not
* shareable and have zero-filled memory region attributes.
*/
class Page_table
{
@ -197,32 +197,6 @@ namespace Genode
};
};
/**
* Large page descriptor structure
*
* Must always occur as group of 16 consecutive copies, this groups
* must be aligned on a 16 word boundary (Represents 64KB = 16 *
* Small page size)
*/
struct Large_page : Descriptor
{
enum { VIRT_SIZE_LOG2 = _64KB_LOG2,
VIRT_SIZE = 1 << VIRT_SIZE_LOG2,
VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1) };
struct B : Bitfield<2, 1> { }; /* part of the memory region attributes */
struct C : Bitfield<3, 1> { }; /* part of the memory region attributes */
struct Ap_1_0 : Bitfield<4, 2>, /* access permission bits [1:0] */
Ap_1_0_bitfield { };
struct Ap_2 : Bitfield<9, 1>, /* access permission bits [2] */
Ap_2_bitfield { };
struct S : Bitfield<10, 1> { }; /* shareable bit */
struct Ng : Bitfield<11, 1> { }; /* not global bit */
struct Tex : Bitfield<12, 3> { }; /* part of the memory region attributes */
struct Xn : Bitfield<15, 1> { }; /* execute never bit */
struct Pa_31_16 : Bitfield<16, 16> { }; /* physical address bits [31:16] */
};
/**
* Small page descriptor structure
*/
@ -234,17 +208,17 @@ namespace Genode
VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1)
};
struct Xn : Bitfield<0, 1> { }; /* execute never bit */
struct B : Bitfield<2, 1> { }; /* part of the memory region attributes */
struct C : Bitfield<3, 1> { }; /* part of the memory region attributes */
struct Ap_1_0 : Bitfield<4, 2>, /* access permission bits [1:0] */
struct Xn : Bitfield<0, 1> { }; /* execute never */
struct B : Bitfield<2, 1> { }; /* mem region attr. */
struct C : Bitfield<3, 1> { }; /* mem region attr. */
struct Ap_1_0 : Bitfield<4, 2>, /* access permission */
Ap_1_0_bitfield { };
struct Tex : Bitfield<6, 3> { }; /* part of the memory region attributes */
struct Ap_2 : Bitfield<9, 1>, /* access permission bits [2] */
struct Tex : Bitfield<6, 3> { }; /* mem region attr. */
struct Ap_2 : Bitfield<9, 1>, /* access permission */
Ap_2_bitfield { };
struct S : Bitfield<10, 1> { }; /* shareable bit */
struct Ng : Bitfield<11, 1> { }; /* not global bit */
struct Pa_31_12 : Bitfield<12, 20> { }; /* physical address bits [31:12] */
struct Pa_31_12 : Bitfield<12, 20> { }; /* physical base */
};
/*
@ -259,12 +233,11 @@ namespace Genode
/**
* Get entry index by virtual offset
*
* \param i is overridden with the resulting index
* \param i is overridden with the index if call returns 0
* \param vo virtual offset relative to the virtual table base
*
* \retval 0 on success
* \retval <0 If virtual offset couldn't be resolved.
* In this case 'i' reside invalid
* \retval <0 translation failed
*/
int _index_by_vo (unsigned long & i, addr_t const vo) const
{
@ -286,13 +259,12 @@ namespace Genode
Page_table()
{
/* check table alignment */
if (!aligned((addr_t)this, ALIGNM_LOG2)
|| (addr_t)this != (addr_t)_entries)
if (!aligned((addr_t)this, ALIGNM_LOG2) ||
(addr_t)this != (addr_t)_entries)
{
PDBG("Insufficient table alignment");
while (1) ;
}
/* start with an empty table */
for (unsigned i = 0; i <= MAX_INDEX; i++)
Descriptor::invalidate(_entries[i]);
@ -341,9 +313,9 @@ namespace Genode
{
/* compose new descriptor value */
Descriptor::access_t entry =
access_permission_bits<Small_page>(w, x, k)
| Small_page::Ng::bits(!g)
| Small_page::Pa_31_12::masked(pa);
access_permission_bits<Small_page>(w, x, k) |
Small_page::Ng::bits(!g) |
Small_page::Pa_31_12::masked(pa);
Descriptor::type(entry, Descriptor::SMALL_PAGE);
/* check if we can we write to the targeted entry */
@ -375,7 +347,7 @@ namespace Genode
* represented by this table
* \param size region size
*/
void remove_region (addr_t const vo, size_t const size)
void remove_region(addr_t const vo, size_t const size)
{
/* traverse all possibly affected entries */
addr_t residual_vo = vo;
@ -389,30 +361,28 @@ namespace Genode
if (_index_by_vo(i, residual_vo)) return;
/* update current entry and recalculate residual region */
switch (Descriptor::type(_entries[i]))
{
case Descriptor::FAULT:
{
switch (Descriptor::type(_entries[i])) {
case Descriptor::FAULT: {
residual_vo = (residual_vo & Fault::VIRT_BASE_MASK)
+ Fault::VIRT_SIZE;
break;
}
case Descriptor::SMALL_PAGE:
{
break; }
case Descriptor::SMALL_PAGE: {
residual_vo = (residual_vo & Small_page::VIRT_BASE_MASK)
+ Small_page::VIRT_SIZE;
Descriptor::invalidate(_entries[i]);
break;
}
case Descriptor::LARGE_PAGE:
{
break; }
case Descriptor::LARGE_PAGE: {
PDBG("Removal of large pages not implemented");
while (1) ;
break;
}
break; }
}
}
return;
}
/**
@ -429,13 +399,13 @@ namespace Genode
} __attribute__((aligned(1<<Page_table::ALIGNM_LOG2)));
/**
* Cortex A9 first level translation table
* First level translation table
*
* A table is dedicated to either secure or non-secure mode. All
* translations done by this table apply domain 0. They are not shareable
* and have zero-filled memory region attributes. The size of this table is
* fixed to such a value that this table translates a space wich is
* addressable by 32 bit.
* translations done by this table apply to domain 0. They are not
* shareable and have zero-filled memory region attributes. The size
* of this table is fixed to such a value that this table translates
* a space wich is addressable by 32 bit.
*/
class Section_table
{
@ -443,6 +413,8 @@ namespace Genode
_16KB_LOG2 = 14,
_1MB_LOG2 = 20,
_16MB_LOG2 = 24,
DOMAIN = 0,
};
public:
@ -458,12 +430,10 @@ namespace Genode
MAX_COSTS_PER_TRANSLATION = sizeof(Page_table),
MAX_TRANSL_SIZE_LOG2 = 20,
MIN_TRANSL_SIZE_LOG2 = 12,
MAX_PAGE_SIZE_LOG2 = 20,
MIN_PAGE_SIZE_LOG2 = 12,
};
protected:
/**
* A first level translation descriptor
*/
@ -474,8 +444,8 @@ namespace Genode
*/
enum Type { FAULT, PAGE_TABLE, SECTION, SUPERSECTION };
struct Type_1 : Bitfield<0, 2> { }; /* entry type encoding 1 */
struct Type_2 : Bitfield<18, 1> { }; /* entry type encoding 2 */
struct Type_1 : Bitfield<0, 2> { }; /* entry type code 1 */
struct Type_2 : Bitfield<18, 1> { }; /* entry type code 2 */
/**
* Get descriptor type of 'v'
@ -538,43 +508,23 @@ namespace Genode
*/
struct Page_table_descriptor : Descriptor
{
struct Ns : Bitfield<3, 1> { }; /* non-secure bit */
struct Domain : Bitfield<5, 4> { }; /* domain field */
struct Pa_31_10 : Bitfield<10, 22> { }; /* physical address bits [31:10] */
struct Domain : Bitfield<5, 4> { }; /* domain */
struct Pa_31_10 : Bitfield<10, 22> { }; /* physical base */
/**
* Compose descriptor value
*/
static access_t create(Page_table * const pt)
{
access_t v = Domain::bits(DOMAIN) |
Pa_31_10::masked((addr_t)pt);
Descriptor::type(v, Descriptor::PAGE_TABLE);
return v;
}
};
/**
* Supersection-descriptor structure
*
* Must always occur as group of 16 consecutive copies, this groups
* must be aligned on a 16 word boundary.
*/
struct Supersection : Descriptor
{
enum {
VIRT_SIZE_LOG2 = _16MB_LOG2,
VIRT_SIZE = 1 << VIRT_SIZE_LOG2,
VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1)
};
struct B : Bitfield<2, 1> { }; /* part of the memory region attributes */
struct C : Bitfield<3, 1> { }; /* part of the memory region attributes */
struct Xn : Bitfield<4, 1> { }; /* execute never bit */
struct Pa_39_36 : Bitfield<5, 4> { }; /* extendend physical address bits [39:36] */
struct Ap_1_0 : Bitfield<10, 2>, /* access permission bits [1:0] */
Ap_1_0_bitfield { };
struct Tex : Bitfield<12, 3> { }; /* part of the memory region attributes */
struct Ap_2 : Bitfield<15, 1>, /* access permission bits [2] */
Ap_2_bitfield { };
struct S : Bitfield<16, 1> { }; /* shareable bit */
struct Ng : Bitfield<17, 1> { }; /* not global bit */
struct Ns : Bitfield<19, 1> { }; /* non-secure bit */
struct Pa_35_32 : Bitfield<20, 4> { }; /* extendend physical address bits [35:32] */
struct Pa_31_24 : Bitfield<24, 8> { }; /* physical address bits [31:24] */
};
/**
* Section-descriptor structure
* Section translation descriptor
*/
struct Section : Descriptor
{
@ -584,29 +534,42 @@ namespace Genode
VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1)
};
struct B : Bitfield<2, 1> { }; /* part of the memory region attributes */
struct C : Bitfield<3, 1> { }; /* part of the memory region attributes */
struct Xn : Bitfield<4, 1> { }; /* execute never bit */
struct Domain : Bitfield<5, 4> { }; /* domain field */
struct Ap_1_0 : Bitfield<10, 2>, /* access permission bits [1:0] */
struct B : Bitfield<2, 1> { }; /* mem. region attr. */
struct C : Bitfield<3, 1> { }; /* mem. region attr. */
struct Xn : Bitfield<4, 1> { }; /* execute never bit */
struct Domain : Bitfield<5, 4> { }; /* domain */
struct Ap_1_0 : Bitfield<10, 2>, /* access permission */
Ap_1_0_bitfield { };
struct Tex : Bitfield<12, 3> { }; /* part of the memory region attributes */
struct Ap_2 : Bitfield<15, 1>, /* access permission bits [2] */
struct Tex : Bitfield<12, 3> { }; /* mem. region attr. */
struct Ap_2 : Bitfield<15, 1>, /* access permission */
Ap_2_bitfield { };
struct S : Bitfield<16, 1> { }; /* shareable bit */
struct Ng : Bitfield<17, 1> { }; /* not global bit */
struct Ns : Bitfield<19, 1> { }; /* non-secure bit */
struct Pa_31_20 : Bitfield<20, 12> { }; /* physical address bits [31:20] */
struct S : Bitfield<16, 1> { }; /* shared */
struct Ng : Bitfield<17, 1> { }; /* not global */
struct Pa_31_20 : Bitfield<20, 12> { }; /* physical base */
/**
* Compose descriptor value
*/
static access_t create(bool const w, bool const x,
bool const k, bool const g,
addr_t const pa)
{
access_t v = access_permission_bits<Section>(w, x, k) |
Domain::bits(DOMAIN) |
Ng::bits(!g) |
Pa_31_20::masked(pa);
Descriptor::type(v, Descriptor::SECTION);
return v;
}
};
protected:
/* table payload, must be the first member of this class */
Descriptor::access_t _entries[SIZE/sizeof(Descriptor::access_t)];
enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 };
/* if this table dedicated to secure mode or to non-secure mode */
bool _secure;
/**
* Get entry index by virtual offset
*
@ -628,18 +591,17 @@ namespace Genode
public:
/**
* Constructor for a table that adopts current secure mode status
* Constructor
*/
Section_table() : _secure(Cortex_a9::secure_mode_active())
Section_table()
{
/* check table alignment */
/* check for appropriate positioning of the table */
if (!aligned((addr_t)this, ALIGNM_LOG2)
|| (addr_t)this != (addr_t)_entries)
{
PDBG("Insufficient table alignment");
while (1) ;
}
/* start with an empty table */
for (unsigned i = 0; i <= MAX_INDEX; i++)
Descriptor::invalidate(_entries[i]);
@ -657,6 +619,8 @@ namespace Genode
/**
* Insert one atomic translation into this table
*
* \param ST platform specific section-table type
* \param st platform specific section table
* \param vo offset of the virtual region represented
* by the translation within the virtual
* region represented by this table
@ -691,19 +655,23 @@ namespace Genode
* spans the the same virtual range and is not a link to another
* table level.
*/
template <typename ST>
unsigned long insert_translation(addr_t const vo, addr_t const pa,
unsigned long const size_log2,
bool const w, bool const x,
bool const k, bool const g,
ST * const st,
void * const extra_space = 0)
{
typedef typename ST::Section Section;
typedef typename ST::Page_table_descriptor Page_table_descriptor;
/* validate virtual address */
unsigned long i;
if (_index_by_vo (i, vo)) {
PDBG("Invalid virtual offset");
while (1) ;
}
/* select descriptor type by translation size */
if (size_log2 < Section::VIRT_SIZE_LOG2)
{
@ -723,11 +691,9 @@ namespace Genode
}
/* create and link page table */
pt = new (extra_space) Page_table();
_entries[i] = Page_table_descriptor::Ns::bits(!_secure)
| Page_table_descriptor::Pa_31_10::masked((addr_t)pt);
Descriptor::type(_entries[i], Descriptor::PAGE_TABLE);
_entries[i] = Page_table_descriptor::create(pt, st);
}
/* Request additional memory to create a page table */
/* request additional memory to create a page table */
else return Page_table::SIZE_LOG2;
/* insert translation */
@ -738,12 +704,8 @@ namespace Genode
if (size_log2 == Section::VIRT_SIZE_LOG2)
{
/* compose section descriptor */
Descriptor::access_t entry =
access_permission_bits<Section>(w, x, k)
| Section::Ns::bits(!_secure)
| Section::Ng::bits(!g)
| Section::Pa_31_20::masked(pa);
Descriptor::type(entry, Descriptor::SECTION);
Descriptor::access_t entry = Section::create(w, x, k,
g, pa, st);
/* check if we can we write to the targeted entry */
if (Descriptor::valid(_entries[i]))
@ -774,7 +736,7 @@ namespace Genode
* represented by this table
* \param size region size
*/
void remove_region (addr_t const vo, size_t const size)
void remove_region(addr_t const vo, size_t const size)
{
/* traverse all possibly affected entries */
addr_t residual_vo = vo;
@ -806,7 +768,7 @@ namespace Genode
- Section::Pa_31_20::masked(residual_vo);
pt->remove_region(pt_vo, residual_size);
/* Recalculate residual region */
/* recalculate residual region */
residual_vo = (residual_vo & Page_table::VIRT_BASE_MASK)
+ Page_table::VIRT_SIZE;
break;
@ -834,6 +796,7 @@ namespace Genode
* \param base base of regained mem portion if method returns 1
* \param s size of regained mem portion if method returns 1
*
* \retval 1 successfully regained memory
* \retval 0 no more memory to regain
*/
bool regain_memory (void * & base, size_t & s)
@ -860,5 +823,5 @@ namespace Genode
} __attribute__((aligned(1<<Section_table::ALIGNM_LOG2)));
}
#endif /* _INCLUDE__DRIVERS__CPU__CORTEX_A9__SECTION_TABLE_H_ */
#endif /* _INCLUDE__ARM__SECTION_TABLE_H_ */

View File

@ -0,0 +1,174 @@
/*
* \brief Simple driver for the ARMv6 CPU core
* \author Norman Feske
* \date 2012-08-30
*/
/*
* Copyright (C) 2012 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 _INCLUDE__ARM_V6__CPU_H_
#define _INCLUDE__ARM_V6__CPU_H_
/* Genode includes */
#include <drivers/board.h>
#include <base/printf.h>
/* core includes */
#include <arm/cpu.h>
namespace Arm_v6
{
using namespace Genode;
/**
* ARMv6 core
*/
struct Cpu : Arm::Cpu
{
/**
* Cache type register
*/
struct Ctr : Arm::Cpu::Ctr
{
struct P : Bitfield<23, 1> { }; /* page mapping restriction on */
};
/**
* System control register
*/
struct Sctlr : Arm::Cpu::Sctlr
{
struct W : Bitfield<3,1> { }; /* enable write buffer */
struct Unused_0 : Bitfield<4,3> { }; /* shall be ones */
struct B : Bitfield<7,1> /* Memory system endianess */
{
enum { LITTLE = 0 };
};
struct S : Bitfield<8,1> { }; /* enbale MMU protection */
struct R : Bitfield<9,1> { }; /* enbale ROM protection */
struct L4 : Bitfield<15,1> { }; /* raise T bit on LOAD-to-PC */
struct Dt : Bitfield<16,1> { }; /* global data TCM enable */
struct It : Bitfield<18,1> { }; /* global instruction TCM enable */
struct U : Bitfield<22,1> { }; /* enable unaligned data access */
struct Xp : Bitfield<23,1> { }; /* disable subpage AP bits */
struct Unused_1 : Bitfield<26,6> { }; /* shall not be modified */
/**
* Get static base value for writes
*/
static access_t base_value() {
return Unused_0::reg_mask() | Unused_1::masked(read()); }
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return base_value() |
Arm::Cpu::Sctlr::init_virt_kernel() |
W::bits(0) |
B::bits(B::LITTLE) |
S::bits(0) |
R::bits(0) |
L4::bits(0) |
Dt::bits(0) |
It::bits(0) |
U::bits(0) |
Xp::bits(1);
}
/**
* Value for the initial kernel entry
*/
static access_t init_phys_kernel()
{
return base_value() |
Arm::Cpu::Sctlr::init_phys_kernel() |
W::bits(0) |
B::bits(B::LITTLE) |
S::bits(0) |
R::bits(0) |
L4::bits(0) |
Dt::bits(1) |
It::bits(1) |
U::bits(0) |
Xp::bits(1);
}
};
/**
* Translation table base control register 0
*/
struct Ttbr0 : Arm::Cpu::Ttbr0
{
struct P : Bitfield<2,1> { }; /* memory controller ECC enabled */
/**
* Value for the switch to virtual mode in kernel
*
* \param section_table initial section table
*/
static access_t init_virt_kernel(addr_t const sect_table)
{
return Arm::Cpu::Ttbr0::init_virt_kernel(sect_table) |
P::bits(0);
}
};
/**
* If page descriptor bits [13:12] are restricted
*/
static bool restricted_page_mappings() {
return Ctr::P::get(Ctr::read()); }
/**
* Configure this module appropriately for the first kernel run
*/
static void init_phys_kernel()
{
::Board::prepare_kernel();
Sctlr::write(Sctlr::init_phys_kernel());
flush_tlb();
/* check for mapping restrictions */
if (restricted_page_mappings()) {
PDBG("Insufficient driver for page tables");
while (1) ;
}
}
/**
* Switch to the virtual mode in kernel
*
* \param section_table section translation table of the initial
* address space this function switches to
* \param process_id process ID of the initial address space
*/
static void init_virt_kernel(addr_t const section_table,
unsigned long const process_id)
{
Cidr::write(process_id);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init_virt_kernel(section_table));
Ttbcr::write(Ttbcr::init_virt_kernel());
Sctlr::write(Sctlr::init_virt_kernel());
}
};
}
void Arm::Cpu::flush_data_caches() {
asm volatile ("mcr p15, 0, %[rd], c7, c14, 0" :: [rd]"r"(0) : ); }
#endif /* _INCLUDE__ARM_V6__CPU_H_ */

View File

@ -0,0 +1,85 @@
/*
* \brief Driver for ARMv6 section tables
* \author Martin Stein
* \date 2012-02-22
*/
/*
* Copyright (C) 2012 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 _INCLUDE__ARM_V6__SECTION_TABLE_H_
#define _INCLUDE__ARM_V6__SECTION_TABLE_H_
/* core includes */
#include <arm/section_table.h>
namespace Arm_v6
{
using namespace Genode;
/**
* First level translation table
*/
class Section_table : public Arm::Section_table
{
public:
/**
* Link to second level translation-table
*/
struct Page_table_descriptor : Arm::Section_table::Page_table_descriptor
{
/**
* Compose descriptor value
*/
static access_t create(Arm::Page_table * const pt,
Section_table *)
{
return Arm::Section_table::Page_table_descriptor::create(pt);
}
};
/**
* Section translation descriptor
*/
struct Section : Arm::Section_table::Section
{
struct P : Bitfield<9, 1> { }; /* enable ECC */
/**
* Compose descriptor value
*/
static access_t create(bool const w, bool const x,
bool const k, bool const g,
addr_t const pa,
Section_table *)
{
return Arm::Section_table::Section::create(w, x, k, g, pa) |
P::bits(0);
}
};
/**
* Insert one atomic translation into this table
*
* For details see 'Arm::Section_table::insert_translation'
*/
unsigned long insert_translation(addr_t const vo, addr_t const pa,
unsigned long const size_log2,
bool const w, bool const x,
bool const k, bool const g,
void * const extra_space = 0)
{
return Arm::Section_table::
insert_translation<Section_table>(vo, pa, size_log2, w,
x, k, g, this, extra_space);
}
};
}
#endif /* _INCLUDE__ARM_V6__SECTION_TABLE_H_ */

View File

@ -0,0 +1,309 @@
/*
* \brief Simple driver for the ARMv7 core
* \author Martin stein
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-2012 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 _INCLUDE__ARM_V7__CPU_H_
#define _INCLUDE__ARM_V7__CPU_H_
/* Genode includes */
#include <drivers/board.h>
/* core includes */
#include <arm/cpu.h>
namespace Arm_v7
{
using namespace Genode;
/**
* ARMv7 core
*/
struct Cpu : Arm::Cpu
{
/**
* Secure configuration register
*/
struct Scr : Register<32>
{
struct Ns : Bitfield<0, 1> { }; /* not secure */
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c1, c1, 0" : [v]"=r"(v) ::);
return v;
}
};
/**
* Non-secure access control register
*/
struct Nsacr : Register<32>
{
/************************************************
** Coprocessor 0-13 non-secure acccess enable **
************************************************/
struct Cpnsae10 : Bitfield<10, 1> { };
struct Cpnsae11 : Bitfield<11, 1> { };
};
/**
* System control register
*/
struct Sctlr : Arm::Cpu::Sctlr
{
struct Unused_0 : Bitfield<3,4> { }; /* shall be ~0 */
struct Sw : Bitfield<10,1> { }; /* support SWP and SWPB */
struct Unused_1 : Bitfield<16,1> { }; /* shall be ~0 */
struct Ha : Bitfield<17,1> { }; /* enable HW access flag */
struct Unused_2 : Bitfield<18,1> { }; /* shall be ~0 */
struct Unused_3 : Bitfield<22,2> { }; /* shall be ~0 */
struct Nmfi : Bitfield<27,1> { }; /* FIQs are non-maskable */
struct Tre : Bitfield<28,1> { }; /* remap TEX[2:1] for OS */
struct Afe : Bitfield<29,1> /* translation access perm. mode */
{
enum { FULL_RANGE_OF_PERMISSIONS = 0 };
};
struct Te : Bitfield<30,1> { }; /* do exceptions in Thumb state */
/**
* Static base value
*/
static access_t base_value()
{
return Unused_0::bits(~0) |
Unused_1::bits(~0) |
Unused_2::bits(~0) |
Unused_3::bits(~0);
}
/**
* Value for the first kernel run
*/
static access_t init_phys_kernel()
{
return base_value() |
Arm::Cpu::Sctlr::init_virt_kernel() |
Sw::bits(0) |
Ha::bits(0) |
Nmfi::bits(0) |
Tre::bits(0);
}
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return base_value() |
Arm::Cpu::Sctlr::init_virt_kernel() |
Sw::bits(0) |
Ha::bits(0) |
Nmfi::bits(0) |
Tre::bits(0);
}
};
/**
* Translation table base register 0
*/
struct Ttbr0 : Arm::Cpu::Ttbr0
{
struct Nos : Bitfield<6,1> { }; /* not outer shareable */
struct Irgn_0 : Bitfield<6,1> /* inner cachable mode */
{
enum { NON_CACHEABLE = 0 };
};
/**
* Value for the switch to virtual mode in kernel
*
* \param sect_table pointer to initial section table
*/
static access_t init_virt_kernel(addr_t const sect_table)
{
return Arm::Cpu::Ttbr0::init_virt_kernel(sect_table) |
Nos::bits(0) |
Irgn_0::bits(Irgn_0::NON_CACHEABLE);
}
};
/**
* Translation table base control register
*/
struct Ttbcr : Arm::Cpu::Ttbcr
{
struct Pd0 : Bitfield<4,1> { }; /* disable walk for TTBR0 */
struct Pd1 : Bitfield<5,1> { }; /* disable walk for TTBR1 */
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return Arm::Cpu::Ttbcr::init_virt_kernel() |
Pd0::bits(0) |
Pd1::bits(0);
}
};
/**
* Switch to the virtual mode in kernel
*
* \param section_table section translation table of the initial
* address space this function switches to
* \param process_id process ID of the initial address space
*/
static void init_virt_kernel(addr_t const section_table,
unsigned long const process_id)
{
Cidr::write(process_id);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init_virt_kernel(section_table));
Ttbcr::write(Ttbcr::init_virt_kernel());
Sctlr::write(Sctlr::init_virt_kernel());
}
/**
* Configure this module appropriately for the first kernel run
*/
static void init_phys_kernel()
{
Psr::write(Psr::init_kernel());
flush_tlb();
}
/**
* Wether we are in secure mode
*/
static bool secure_mode()
{
if (!Board::SECURITY_EXTENSION) return 0;
return !Cpu::Scr::Ns::get(Cpu::Scr::read());
}
/******************************
** Trustzone specific API **
******************************/
/**
* Set the exception-vector's base-address for the monitor mode
* software stack.
*
* \param addr address of the exception vector's base
*/
static inline void mon_exception_entry_at(addr_t const addr)
{
asm volatile ("mcr p15, 0, %[rd], c12, c0, 1" : : [rd] "r" (addr));
}
/**
* Enable access of co-processors cp10 and cp11 from non-secure mode.
*/
static inline void allow_coprocessor_nonsecure()
{
Nsacr::access_t rd = Nsacr::Cpnsae10::bits(1) |
Nsacr::Cpnsae11::bits(1);
asm volatile ("mcr p15, 0, %[rd], c1, c1, 2" : : [rd] "r" (rd));
}
};
}
/**************
** Arm::Cpu **
**************/
void Arm::Cpu::flush_data_caches()
{
/*
* FIXME This routine is taken from the ARMv7 reference manual by
* applying the inline-assembly framework and replacing 'Loop1'
* with '1:', 'Loop2' with '2:', 'Loop3' with '3:', 'Skip'
* with '4:' and 'Finished' with '5:'. It might get implemented
* with more beauty.
*/
asm volatile (
"mrc p15, 1, r0, c0, c0, 1\n" /* read CLIDR into R0 */
"ands r3, r0, #0x7000000\n"
"mov r3, r3, lsr #23\n" /* cache level value (naturally aligned) */
"beq 5f\n"
"mov r10, #0\n"
"1:\n"
"add r2, r10, r10, lsr #1\n" /* work out 3 x cachelevel */
"mov r1, r0, lsr r2\n" /* bottom 3 bits are the Cache type for this level */
"and r1, r1, #7\n" /* get those 3 bits alone */
"cmp r1, #2\n"
"blt 4f\n" /* no cache or only instruction cache at this level */
"mcr p15, 2, r10, c0, c0, 0\n" /* write CSSELR from R10 */
"isb\n" /* ISB to sync the change to the CCSIDR */
"mrc p15, 1, r1, c0, c0, 0\n" /* read current CCSIDR to R1 */
"and r2, r1, #0x7\n" /* extract the line length field */
"add r2, r2, #4\n" /* add 4 for the line length offset (log2 16 bytes) */
"ldr r4, =0x3ff\n"
"ands r4, r4, r1, lsr #3\n" /* R4 is the max number on the way size (right aligned) */
"clz r5, r4\n" /* R5 is the bit position of the way size increment */
"mov r9, r4\n" /* R9 working copy of the max way size (right aligned) */
"2:\n"
"ldr r7, =0x00007fff\n"
"ands r7, r7, r1, lsr #13\n" /* R7 is the max number of the index size (right aligned) */
"3:\n"
"orr r11, r10, r9, lsl r5\n" /* factor in the way number and cache number into R11 */
"orr r11, r11, r7, lsl r2\n" /* factor in the index number */
"mcr p15, 0, r11, c7, c10, 2\n" /* DCCSW, clean by set/way */
"subs r7, r7, #1\n" /* decrement the index */
"bge 3b\n"
"subs r9, r9, #1\n" /* decrement the way number */
"bge 2b\n"
"4:\n"
"add r10, r10, #2\n" /* increment the cache number */
"cmp r3, r10\n"
"bgt 1b\n"
"dsb\n"
"5:\n"
::: "r0", "r1", "r2", "r3", "r4",
"r5", "r7", "r9", "r10", "r11");
}
Arm::Cpu::Psr::access_t Arm::Cpu::Psr::init_user_with_trustzone()
{
return M::bits(M::USER) |
T::bits(T::ARM) |
F::bits(0) |
I::bits(1) |
A::bits(1) |
E::bits(E::LITTLE) |
J::bits(J::ARM);
}
#endif /* _INCLUDE__ARM_V7__CPU_H_ */

View File

@ -0,0 +1,107 @@
/*
* \brief Driver for ARMv7 section tables
* \author Martin Stein
* \date 2012-02-22
*/
/*
* Copyright (C) 2012 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 _INCLUDE__ARM_V7__SECTION_TABLE_H_
#define _INCLUDE__ARM_V7__SECTION_TABLE_H_
/* core includes */
#include <arm/section_table.h>
#include <arm/v7/cpu.h>
namespace Arm_v7
{
using namespace Genode;
/**
* ARMv7 first level translation table
*/
class Section_table : public Arm::Section_table
{
public:
/**
* Link to second level translation-table
*/
struct Page_table_descriptor : Arm::Section_table::Page_table_descriptor
{
struct Ns : Bitfield<3, 1> { }; /* non-secure bit */
/**
* Compose descriptor value
*/
static access_t create(Arm::Page_table * const pt,
Section_table * const st)
{
return Arm::Section_table::Page_table_descriptor::create(pt) |
Ns::bits(!st->secure());
}
};
/**
* Section translation descriptor
*/
struct Section : Arm::Section_table::Section
{
struct Ns : Bitfield<19, 1> { }; /* non-secure bit */
/**
* Compose descriptor value
*/
static access_t create(bool const w, bool const x,
bool const k, bool const g,
addr_t const pa,
Section_table * const st)
{
return Arm::Section_table::Section::create(w, x, k, g, pa) |
Ns::bits(!st->secure());
}
};
protected:
/* if this table is dedicated to secure mode or to non-secure mode */
bool _secure;
public:
/**
* Constructor
*/
Section_table() : _secure(Arm_v7::Cpu::secure_mode()) { }
/**
* Insert one atomic translation into this table
*
* For details see 'Arm::Section_table::insert_translation'
*/
unsigned long insert_translation(addr_t const vo, addr_t const pa,
unsigned long const size_log2,
bool const w, bool const x,
bool const k, bool const g,
void * const extra_space = 0)
{
return Arm::Section_table::
insert_translation<Section_table>(vo, pa, size_log2, w,
x, k, g, this, extra_space);
}
/***************
** Accessors **
***************/
bool secure() { return _secure; }
};
}
#endif /* _INCLUDE__ARM_V7__SECTION_TABLE_H_ */

View File

@ -0,0 +1,54 @@
/*
* \brief Simple driver for the Cortex A9
* \author Martin stein
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-2012 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 _INCLUDE__CORTEX_A9__CPU_H_
#define _INCLUDE__CORTEX_A9__CPU_H_
/* Genode includes */
#include <drivers/board.h>
/* core includes */
#include <arm/v7/cpu.h>
namespace Cortex_a9
{
using namespace Genode;
/**
* Cortex A9 CPU
*/
struct Cpu : Arm_v7::Cpu
{
enum
{
/* common */
CLK = Board::CORTEX_A9_CLOCK, /* CPU interface clock */
PERIPH_CLK = CLK, /* clock for CPU internal components */
/* interrupt controller */
PL390_DISTRIBUTOR_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x1000,
PL390_DISTRIBUTOR_MMIO_SIZE = 0x1000,
PL390_CPU_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x100,
PL390_CPU_MMIO_SIZE = 0x100,
/* timer */
PRIVATE_TIMER_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x600,
PRIVATE_TIMER_MMIO_SIZE = 0x10,
PRIVATE_TIMER_IRQ = 29,
PRIVATE_TIMER_CLK = PERIPH_CLK
};
};
}
#endif /* _INCLUDE__CORTEX_A9__CPU_H_ */

View File

@ -1,683 +0,0 @@
/*
* \brief Simple Driver for the ARM Cortex A9
* \author Martin stein
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-2012 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 _INCLUDE__CORTEX_A9__CPU__CORE_H_
#define _INCLUDE__CORTEX_A9__CPU__CORE_H_
/* Genode includes */
#include <util/register.h>
#include <util/mmio.h>
#include <drivers/board.h>
#include <cpu/cpu_state.h>
#include <cortex_a9/cpu/timer.h>
namespace Genode
{
class Section_table;
/**
* Cortex A9 driver
*/
struct Cortex_a9
{
enum
{
/* common */
DATA_ACCESS_ALIGNM = 4,
CLK = Board::CORTEX_A9_CLOCK, /* CPU interface clock */
PERIPH_CLK = CLK, /* clock for CPU internal components */
MIN_PAGE_SIZE_LOG2 = 12,
MAX_PAGE_SIZE_LOG2 = 20,
HIGHEST_EXCEPTION_ENTRY = 0xffff0000,
/* interrupt controller */
PL390_DISTRIBUTOR_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x1000,
PL390_DISTRIBUTOR_MMIO_SIZE = 0x1000,
PL390_CPU_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x100,
PL390_CPU_MMIO_SIZE = 0x100,
/* timer */
PRIVATE_TIMER_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x600,
PRIVATE_TIMER_MMIO_SIZE = 0x10,
PRIVATE_TIMER_IRQ = 29,
PRIVATE_TIMER_CLK = PERIPH_CLK
};
/**
* CPU local timer module
*/
class Private_timer : public Cortex_a9_timer<PRIVATE_TIMER_CLK>
{
public:
enum { IRQ = PRIVATE_TIMER_IRQ };
/**
* Constructor
*/
Private_timer() :
Cortex_a9_timer<PRIVATE_TIMER_CLK>(PRIVATE_TIMER_MMIO_BASE)
{ }
};
typedef Cortex_a9_timer<PERIPH_CLK> Timer;
/**
* Common parts of fault status registers
*/
struct Fsr : Register<32>
{
/**
* Fault status encoding
*/
enum Fault_status {
SECTION_TRANSLATION_FAULT = 5,
PAGE_TRANSLATION_FAULT = 7,
};
struct Fs_3_0 : Bitfield<0, 4> { }; /* fault status bits [3:0] */
struct Fs_4 : Bitfield<10, 1> { }; /* fault status bits [4] */
};
/**
* Instruction fault status register
*/
struct Ifsr : Fsr
{
/**
* Read register
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 1\n" : [v]"=r"(v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status() {
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) |
(Fs_4::get(v) << Fs_3_0::WIDTH));
}
};
/**
* Instruction fault address register
*/
struct Ifar : Register<32>
{
/**
* Read register
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c6, c0, 2\n" : [v]"=r"(v) :: );
return v;
}
};
/**
* Data fault status register
*/
struct Dfsr : Fsr
{
struct Wnr : Bitfield<11, 1> { }; /* write not read bit */
/**
* Read register
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 0\n" : [v]"=r"(v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status() {
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) | (4<<Fs_4::get(v)));
}
};
/**
* Data fault address register
*/
struct Dfar : Register<32>
{
/**
* Read register
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c6, c0, 0\n" : [v]"=r"(v) :: );
return v;
}
};
/**
* Process identification register
*/
struct Contextidr : Register<32>
{
struct Asid : Bitfield<0,8> { }; /* ID part used by MMU */
struct Procid : Bitfield<8,24> { }; /* ID part used by debug/trace */
/**
* Write whole register
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c13, c0, 1\n" :: [v]"r"(v) : );
}
};
/**
* A system control register
*/
struct Sctlr : Register<32>
{
struct M : Bitfield<0,1> { }; /* MMU enable bit */
struct C : Bitfield<2,1> { }; /* cache enable bit */
struct I : Bitfield<12,1> { }; /* instruction cache enable bit */
struct V : Bitfield<13,1> { }; /* exception vectors bit */
/**
* Read whole register
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c1, c0, 0\n" : [v]"=r"(v) :: );
return v;
};
/**
* Write whole register
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c1, c0, 0\n" :: [v]"r"(v) : );
}
};
/**
* The translation table base control register
*/
struct Ttbcr : Register<32>
{
/**********************
** Always available **
**********************/
struct N : Bitfield<0,3> /* base address width */
{ };
/********************************************
** Only available with security extension **
********************************************/
struct Pd0 : Bitfield<4,1> { }; /* translation table walk disable bit for TTBR0 */
struct Pd1 : Bitfield<5,1> { }; /* translation table walk disable bit for TTBR1 */
/**
* Read whole register, only in privileged CPU mode
*/
static access_t read();
/**
* Write whole register, only in privileged CPU mode
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c2, c0, 2" :: [v]"r"(v) : );
}
};
/**
* The domain access control register
*/
struct Dacr : Register<32>
{
enum Dx_values { NO_ACCESS = 0, CLIENT = 1, MANAGER = 3 };
/**
* Access values for the 16 available domains
*/
struct D0 : Bitfield<0,2> { };
struct D1 : Bitfield<2,2> { };
struct D2 : Bitfield<4,2> { };
struct D3 : Bitfield<6,2> { };
struct D4 : Bitfield<8,2> { };
struct D5 : Bitfield<10,2> { };
struct D6 : Bitfield<12,2> { };
struct D7 : Bitfield<14,2> { };
struct D8 : Bitfield<16,2> { };
struct D9 : Bitfield<18,2> { };
struct D10 : Bitfield<20,2> { };
struct D11 : Bitfield<22,2> { };
struct D12 : Bitfield<24,2> { };
struct D13 : Bitfield<26,2> { };
struct D14 : Bitfield<28,2> { };
struct D15 : Bitfield<30,2> { };
/**
* Write whole register, only in privileged CPU mode
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c3, c0, 0" :: [v]"r"(v) : );
}
};
/**
* Translation table base register 0
*
* Typically for process specific spaces, references first level
* table with a size between 128B and 16KB according to 'Ttbcr::N'.
*/
struct Ttbr0 : Register<32>
{
/**********************
** Always available **
**********************/
struct S : Bitfield<1,1> { }; /* shareable bit */
struct Rgn : Bitfield<3,2> /* region bits */
{
enum { OUTER_NON_CACHEABLE = 0b00,
OUTER_WBACK_WALLOCATE_CACHEABLE = 0b01,
OUTER_WTHROUGH_CACHEABLE = 0b10,
OUTER_WBACK_NO_WALLCOATE_CACHEABLE = 0b11,
};
};
struct Nos : Bitfield<5,1> { }; /* not outer shareable bit */
struct Base_address : Bitfield<14,18> { }; /* translation table base address
(Driver supports only 16KB alignment) */
/***********************************************
** Only available without security extension **
***********************************************/
struct C : Bitfield<0,1> { }; /* cacheable bit */
/********************************************
** Only available with security extension **
********************************************/
struct Irgn_1 : Bitfield<0,1> /* inner region bit 0 */
{
enum { INNER_NON_CACHEABLE = 0b0,
INNER_WBACK_WALLOCATE_CACHEABLE = 0b0,
INNER_WTHROUGH_CACHEABLE = 0b1,
INNER_WBACK_NO_WALLCOATE_CACHEABLE = 0b1,
};
};
struct Irgn_0 : Bitfield<6,1> /* inner region bit 1 */
{
enum { INNER_NON_CACHEABLE = 0b0,
INNER_WBACK_WALLOCATE_CACHEABLE = 0b1,
INNER_WTHROUGH_CACHEABLE = 0b0,
INNER_WBACK_NO_WALLCOATE_CACHEABLE = 0b1,
};
};
/**
* Read whole register, only in privileged CPU mode
*/
static access_t read();
/**
* Write whole register, only in privileged CPU mode
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c2, c0, 0" :: [v]"r"(v) : );
}
};
/**
* A current program status register
*/
struct Cpsr : Register<32>
{
struct M : Bitfield<0,5> /* processor mode */
{
enum { /* <Privileged>, <Description> */
USER = 0b10000, /* 0, application code */
FIQ = 0b10001, /* 1, entered at fast interrupt */
IRQ = 0b10010, /* 1, entered at normal interrupt */
SUPERVISOR = 0b10011, /* 1, most kernel code */
MONITOR = 0b10110, /* 1, a secure mode, switch sec./non-sec. */
ABORT = 0b10111, /* 1, entered at aborts */
UNDEFINED = 0b11011, /* 1, entered at instruction-related error */
SYSTEM = 0b11111, /* 1, applications that require privileged */
};
};
struct F : Bitfield<6,1> { }; /* fast interrupt request disable */
struct I : Bitfield<7,1> { }; /* interrupt request disable */
struct A : Bitfield<8,1> { }; /* asynchronous abort disable */
/**
* Read whole register
*/
static access_t read()
{
access_t v;
asm volatile ("mrs %[v], cpsr\n" : [v] "=r" (v) : : );
return v;
}
/**
* Write whole register
*/
static void write(access_t & v)
{
asm volatile ("msr cpsr, %[v]\n" : : [v] "r" (v) : );
}
};
/**
* Secure configuration register
*/
struct Scr : Register<32>
{
struct Ns : Bitfield<0, 1> { }; /* non secure bit */
/**
* Read whole register
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c1, c1, 0" : [v]"=r"(v) ::);
return v;
}
};
struct Context : Cpu_state
{
uint32_t contextidr; /* contextidr register backup, offset 18*4 */
uint32_t section_table; /* base address of applied section table,
* offset 19*4 */
/***************
** Accessors **
***************/
void software_tlb(Section_table * const st) {
section_table = (addr_t)st; }
Section_table * software_tlb() const {
return (Section_table *)section_table; }
void instruction_ptr(addr_t const p) { ip = p; }
addr_t instruction_ptr() const { return ip; }
void return_ptr(addr_t const p) { lr = p; }
void stack_ptr(addr_t const p) { sp = p; }
void protection_domain(unsigned const id) { contextidr = id; }
/**
* Read a general purpose register
*
* \param id ID of the targeted register
* \param v Holds register value if this returns 1
*/
bool get_gpr(unsigned id, unsigned & v) const
{
if (id >= MAX_GPR) return 0;
v = r[id];
return 1;
}
/**
* Override a general purpose register
*
* \param id ID of the targeted register
* \param v Has been written to register if this returns 1
*/
bool set_gpr(unsigned id, unsigned const v)
{
if (id >= MAX_GPR) return 0;
r[id] = v;
return 1;
}
};
/**
* An usermode execution state
*/
struct User_context : Context
{
/**
* Constructor
*/
User_context(void);
/***************************************************
** Communication between user and context holder **
***************************************************/
void user_arg_0(unsigned const arg) { r[0] = arg; }
void user_arg_1(unsigned const arg) { r[1] = arg; }
void user_arg_2(unsigned const arg) { r[2] = arg; }
void user_arg_3(unsigned const arg) { r[3] = arg; }
void user_arg_4(unsigned const arg) { r[4] = arg; }
void user_arg_5(unsigned const arg) { r[5] = arg; }
void user_arg_6(unsigned const arg) { r[6] = arg; }
void user_arg_7(unsigned const arg) { r[7] = arg; }
unsigned user_arg_0() const { return r[0]; }
unsigned user_arg_1() const { return r[1]; }
unsigned user_arg_2() const { return r[2]; }
unsigned user_arg_3() const { return r[3]; }
unsigned user_arg_4() const { return r[4]; }
unsigned user_arg_5() const { return r[5]; }
unsigned user_arg_6() const { return r[6]; }
unsigned user_arg_7() const { return r[7]; }
/**
* Does a pagefault exist and originate from a lack of translation?
*
* \param va Holds the virtual fault-address if this
* function returns 1
* \param w Indicates wether the fault was caused by a write
* access if this function returns 1
*/
bool translation_miss(addr_t & va, bool & w) const
{
/* determine fault type */
switch (cpu_exception)
{
case PREFETCH_ABORT: {
/* check if fault was caused by a translation miss */
Ifsr::Fault_status const fs = Ifsr::fault_status();
if(fs == Ifsr::SECTION_TRANSLATION_FAULT ||
fs == Ifsr::PAGE_TRANSLATION_FAULT)
{
/* fetch fault data */
w = 0;
va = Ifar::read();
return 1;
}
return 0; }
case DATA_ABORT: {
/* check if fault was caused by translation miss */
Dfsr::Fault_status const fs = Dfsr::fault_status();
if(fs == Dfsr::SECTION_TRANSLATION_FAULT ||
fs == Dfsr::PAGE_TRANSLATION_FAULT)
{
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return 1;
}
return 0; }
default: return 0;
}
}
};
/**
* Enable interrupt requests
*/
static void enable_irqs()
{
Cpsr::access_t cpsr = Cpsr::read();
Cpsr::I::clear(cpsr);
Cpsr::write(cpsr);
}
/**
* Set CPU exception entry to a given address
*
* \return 0 exception entry set to the given address
* <0 otherwise
*/
static int exception_entry_at(addr_t a)
{
Sctlr::access_t sctlr = Sctlr::read();
switch (a) {
case 0x0:
Sctlr::V::clear(sctlr);
break;
case 0xffff0000:
Sctlr::V::set(sctlr);
break;
default:
return -1;
}
Sctlr::write(sctlr);
return 0;
}
/**
* Are we in secure mode?
*/
static bool secure_mode_active()
{
if (!Board::CORTEX_A9_SECURITY_EXTENSION) return 0;
return !Scr::Ns::get(Scr::read());
}
/**
* Enable the MMU
*
* \param section_table section translation table of the initial
* address space this function switches to
* \param process_id process ID of the initial address space
*/
static void enable_mmu (Section_table * const section_table,
unsigned long const process_id)
{
/* initialize domains */
Dacr::write (Dacr::D0::bits (Dacr::CLIENT)
| Dacr::D1::bits (Dacr::NO_ACCESS)
| Dacr::D2::bits (Dacr::NO_ACCESS)
| Dacr::D3::bits (Dacr::NO_ACCESS)
| Dacr::D4::bits (Dacr::NO_ACCESS)
| Dacr::D5::bits (Dacr::NO_ACCESS)
| Dacr::D6::bits (Dacr::NO_ACCESS)
| Dacr::D7::bits (Dacr::NO_ACCESS)
| Dacr::D8::bits (Dacr::NO_ACCESS)
| Dacr::D9::bits (Dacr::NO_ACCESS)
| Dacr::D10::bits (Dacr::NO_ACCESS)
| Dacr::D11::bits (Dacr::NO_ACCESS)
| Dacr::D12::bits (Dacr::NO_ACCESS)
| Dacr::D13::bits (Dacr::NO_ACCESS)
| Dacr::D14::bits (Dacr::NO_ACCESS)
| Dacr::D15::bits (Dacr::NO_ACCESS));
/* switch process ID */
Contextidr::write(process_id);
/* install section table */
Ttbr0::write (Ttbr0::Base_address::masked ((addr_t)section_table));
Ttbcr::write (Ttbcr::N::bits(0)
| Ttbcr::Pd0::bits(0)
| Ttbcr::Pd1::bits(0) );
/* enable MMU without instruction-, data-, or unified caches */
Sctlr::access_t sctlr = Sctlr::read();
Sctlr::M::set(sctlr);
Sctlr::I::clear(sctlr);
Sctlr::C::clear(sctlr);
Sctlr::write(sctlr);
flush_branch_prediction();
}
/**
* Invalidate all entries of the branch predictor array
*
* Must be inline to avoid dependence on the branch predictor.
*/
__attribute__((always_inline)) inline static void flush_branch_prediction()
{
asm volatile ("mcr p15, 0, r0, c7, c5, 6\n"
"isb");
}
/**
* Invalidate at least all TLB entries regarding a specific process
*
* \param process_id ID of the targeted process
*/
static void flush_tlb_by_pid (unsigned const process_id)
{
asm volatile ("mcr p15, 0, %[asid], c8, c7, 2 \n"
:: [asid]"r"(Contextidr::Asid::masked(process_id)) : );
flush_branch_prediction();
}
/******************************
** Trustzone specific API **
******************************/
/**
* Set the exception-vector's base-address for the monitor mode
* software stack.
*
* \param addr address of the exception vector's base
*/
static inline void mon_exception_entry_at(addr_t addr)
{
asm volatile ("mcr p15, 0, %0, c12, c0, 1" : : "r" (addr));
}
/**
* Enable access of co-processors cp10 and cp11 from non-secure mode.
*/
static inline void allow_coprocessor_nonsecure(void)
{
uint32_t val = (1 << 10) | (1 << 11);
asm volatile ("mcr p15, 0, %0, c1, c1, 2" : : "r" (val));
}
};
}
#endif /* _INCLUDE__DRIVERS__CPU__CORTEX_A9__CORE_H_ */

View File

@ -1,112 +0,0 @@
/*
* \brief Driver base for the private timer of the ARM Cortex-A9
* \author Martin stein
* \date 2011-12-13
*/
/*
* Copyright (C) 2011-2012 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 _INCLUDE__DRIVERS__CPU__CORTEX_A9__TIMER_H_
#define _INCLUDE__DRIVERS__CPU__CORTEX_A9__TIMER_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode
{
/**
* Driver base for the private timer of the ARM Cortex-A9
*/
template <unsigned long CLK>
struct Cortex_a9_timer : public Mmio
{
enum { TICS_PER_MS = CLK / 1000, };
/**
* Load value register
*/
struct Load : Register<0x0, 32> { };
/**
* Timer counter value register
*/
struct Counter : Register<0x4, 32> { };
/**
* Timer control register
*/
struct Control : Register<0x8, 32>
{
struct Timer_enable : Bitfield<0,1> { }; /* 1: 'Counter' decrements, 0: 'Counter' stays 0 */
struct Auto_reload : Bitfield<1,1> { }; /* 1: Auto reload mode, 0: One shot mode */
struct Irq_enable : Bitfield<2,1> { }; /* 1: IRQ = 'Interrupt_status::Event' 0: IRQ = 0 */
struct Prescaler : Bitfield<8,8> { }; /* modifies the clock period for the decrementing */
};
/**
* Timer interrupt status register
*/
struct Interrupt_status : Register<0xc, 32>
{
struct Event : Bitfield<0,1> { }; /* 'Event' = !'Counter' */
};
/**
* Constructor, clears the interrupt output
*/
Cortex_a9_timer(addr_t const mmio_base) : Mmio(mmio_base) {
clear_interrupt(); }
/**
* Start a one-shot run
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
*/
inline void start_one_shot(uint32_t const tics);
/**
* Translate milliseconds to a native timer value
*/
static uint32_t ms_to_tics(unsigned long const ms) {
return ms * TICS_PER_MS; }
/**
* Stop the timer and return last timer value
*/
unsigned long stop()
{
unsigned long const v = read<Counter>();
write<typename Control::Timer_enable>(0);
return v;
}
/**
* Clear interrupt output line
*/
void clear_interrupt() { write<typename Interrupt_status::Event>(1); }
};
}
template <unsigned long CLOCK>
void Genode::Cortex_a9_timer<CLOCK>::start_one_shot(uint32_t const tics)
{
/* reset timer */
clear_interrupt();
write<Control>(Control::Timer_enable::bits(0) |
Control::Auto_reload::bits(0) |
Control::Irq_enable::bits(1) |
Control::Prescaler::bits(0));
/* load timer and start decrementing */
write<Load>(tics);
write<typename Control::Timer_enable>(1);
}
#endif /* _INCLUDE__DRIVERS__CPU__CORTEX_A9__TIMER_H_ */

View File

@ -14,68 +14,27 @@
#ifndef _CORE__INCLUDE__CORTEX_A9__KERNEL_SUPPORT_H_
#define _CORE__INCLUDE__CORTEX_A9__KERNEL_SUPPORT_H_
/* Core includes */
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
/* core includes */
#include <cortex_a9/cpu.h>
#include <cortex_a9/timer.h>
#include <cortex_a9/no_trustzone/pic.h>
/**
* CPU driver
*/
class Cpu : public Genode::Cortex_a9 { };
class Cpu : public Cortex_a9::Cpu { };
namespace Kernel
{
/* import Genode types */
typedef Genode::Cortex_a9 Cortex_a9;
typedef Genode::Pl390_base Pl390_base;
/**
* Kernel interrupt-controller
* Programmable interrupt controller
*/
class Pic : public Pl390_base
{
public:
/**
* Constructor
*/
Pic() : Pl390_base(Cortex_a9::PL390_DISTRIBUTOR_MMIO_BASE,
Cortex_a9::PL390_CPU_MMIO_BASE)
{
/* disable device */
_distr.write<Distr::Icddcr::Enable>(0);
_cpu.write<Cpu::Iccicr::Enable>(0);
mask();
/* supported priority range */
unsigned const min_prio = _distr.min_priority();
unsigned const max_prio = _distr.max_priority();
/* configure every shared peripheral interrupt */
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++)
{
_distr.write<Distr::Icdicr::Edge_triggered>(0, i);
_distr.write<Distr::Icdipr::Priority>(max_prio, i);
_distr.write<Distr::Icdiptr::Cpu_targets>(Distr::Icdiptr::Cpu_targets::ALL, i);
}
/* disable the priority filter */
_cpu.write<Cpu::Iccpmr::Priority>(min_prio);
/* disable preemption of interrupt handling by interrupts */
_cpu.write<Cpu::Iccbpr::Binary_point>(
Cpu::Iccbpr::Binary_point::NO_PREEMPTION);
/* enable device */
_distr.write<Distr::Icddcr::Enable>(1);
_cpu.write<Cpu::Iccicr::Enable>(1);
}
};
class Pic : public Cortex_a9_no_trustzone::Pic { };
/**
* Kernel timer
*/
class Timer : public Cortex_a9::Private_timer { };
class Timer : public Cortex_a9::Timer { };
}
#endif /* _CORE__INCLUDE__CORTEX_A9__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,70 @@
/*
* \brief Programmable interrupt controller for core
* \author Martin Stein
* \date 2012-10-11
*/
/*
* Copyright (C) 2012 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 _INCLUDE__CORTEX_A9__NO_TRUSTZONE__PIC_H_
#define _INCLUDE__CORTEX_A9__NO_TRUSTZONE__PIC_H_
/* core includes */
#include <cortex_a9/cpu.h>
#include <cortex_a9/pic.h>
namespace Cortex_a9_no_trustzone
{
using namespace Genode;
/**
* Programmable interrupt controller for core
*/
class Pic : public Cortex_a9::Pic
{
public:
/**
* Constructor
*/
Pic()
{
/* disable device */
_distr.write<Distr::Icddcr::Enable>(0);
_cpu.write<Cpu::Iccicr::Enable>(0);
mask();
/* supported priority range */
unsigned const min_prio = _distr.min_priority();
unsigned const max_prio = _distr.max_priority();
/* configure every shared peripheral interrupt */
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++)
{
_distr.write<Distr::Icdicr::Edge_triggered>(0, i);
_distr.write<Distr::Icdipr::Priority>(max_prio, i);
_distr.write<Distr::Icdiptr::Cpu_targets>(
Distr::Icdiptr::Cpu_targets::ALL, i);
}
/* disable the priority filter */
_cpu.write<Cpu::Iccpmr::Priority>(min_prio);
/* disable preemption of interrupt handling by interrupts */
_cpu.write<Cpu::Iccbpr::Binary_point>(
Cpu::Iccbpr::Binary_point::NO_PREEMPTION);
/* enable device */
_distr.write<Distr::Icddcr::Enable>(1);
_cpu.write<Cpu::Iccicr::Enable>(1);
}
};
}
#endif /* _INCLUDE__CORTEX_A9__NO_TRUSTZONE__PIC_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief Base driver for the ARM PL390 interrupt controller
* \brief Programmable interrupt controller for core
* \author Martin stein
* \date 2011-10-26
*/
@ -11,19 +11,20 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__DRIVERS__PIC__PL390_BASE_H_
#define _INCLUDE__DRIVERS__PIC__PL390_BASE_H_
#ifndef _INCLUDE__CORTEX_A9__PIC_H_
#define _INCLUDE__CORTEX_A9__PIC_H_
/* Genode includes */
#include <util/mmio.h>
#include <base/printf.h>
namespace Genode
namespace Cortex_a9
{
using namespace Genode;
/**
* Base driver for the ARM PL390 interrupt controller
* Programmable interrupt controller for core
*/
class Pl390_base
class Pic
{
public:
@ -41,7 +42,7 @@ namespace Genode
*/
struct Distr : public Mmio
{
Distr(addr_t const base) : Mmio(base) { }
Distr() : Mmio(Cortex_a9::Cpu::PL390_DISTRIBUTOR_MMIO_BASE) { }
/**
* Distributor control register
@ -145,7 +146,7 @@ namespace Genode
*/
struct Cpu : public Mmio
{
Cpu(addr_t const base) : Mmio(base) { }
Cpu() : Mmio(Cortex_a9::Cpu::PL390_CPU_MMIO_BASE) { }
/**
* CPU interface control register
@ -160,7 +161,7 @@ namespace Genode
struct Enable_ns : Bitfield<1,1> { };
struct Ack_ctl : Bitfield<2,1> { };
struct Fiq_en : Bitfield<3,1> { };
struct Cbpr : Bitfield<4,1> { };
struct Sbpr : Bitfield<4,1> { };
};
/**
@ -221,11 +222,8 @@ namespace Genode
/**
* Constructor, all interrupts get masked
*/
Pl390_base(addr_t const distributor, addr_t const cpu_interface) :
_distr(distributor),
_cpu(cpu_interface),
_max_interrupt(_distr.max_interrupt()),
_last_taken_request(SPURIOUS_ID) { }
Pic() : _max_interrupt(_distr.max_interrupt()),
_last_taken_request(SPURIOUS_ID) { }
/**
* Get the ID of the last interrupt request
@ -270,10 +268,8 @@ namespace Genode
/**
* Unmask interrupt 'i'
*/
void unmask(unsigned const i)
{
_distr.write<Distr::Icdiser::Set_enable>(1, i);
}
void unmask(unsigned const i) {
_distr.write<Distr::Icdiser::Set_enable>(1, i); }
/**
* Mask all interrupts
@ -287,12 +283,10 @@ namespace Genode
/**
* Mask interrupt 'i'
*/
void mask(unsigned const i)
{
_distr.write<Distr::Icdicer::Clear_enable>(1, i);
}
void mask(unsigned const i) {
_distr.write<Distr::Icdicer::Clear_enable>(1, i); }
};
}
#endif /* _INCLUDE__DRIVERS__PIC__PL390_BASE_H_ */
#endif /* _INCLUDE__CORTEX_A9__PIC_H_ */

View File

@ -0,0 +1,131 @@
/*
* \brief Timer for core
* \author Martin stein
* \date 2011-12-13
*/
/*
* Copyright (C) 2011-2012 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 _INCLUDE__CORTEX_A9__TIMER_H_
#define _INCLUDE__CORTEX_A9__TIMER_H_
/* Genode includes */
#include <util/mmio.h>
/* core includes */
#include <cortex_a9/cpu.h>
namespace Cortex_a9
{
/**
* Timer for core
*/
class Timer : public Mmio
{
enum { TICS_PER_MS = Cortex_a9::Cpu::PRIVATE_TIMER_CLK / 1000, };
/**
* Load value register
*/
struct Load : Register<0x0, 32> { };
/**
* Timer counter value register
*/
struct Counter : Register<0x4, 32> { };
/**
* Timer control register
*/
struct Control : Register<0x8, 32>
{
struct Timer_enable : Bitfield<0,1> { }; /* enable counting */
struct Auto_reload : Bitfield<1,1> { }; /* reload at zero */
struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */
struct Prescaler : Bitfield<8,8> { }; /* modify frequency */
/**
* Configure for a one-shot
*/
static access_t init_one_shot()
{
return Timer_enable::bits(0) |
Auto_reload::bits(0) |
Irq_enable::bits(1) |
Prescaler::bits(0);
}
};
/**
* Timer interrupt status register
*/
struct Interrupt_status : Register<0xc, 32>
{
struct Event : Bitfield<0,1> { }; /* if counter hit zero */
};
/**
* Stop counting
*/
void _disable() { write<Control::Timer_enable>(0); }
public:
enum { IRQ = Cortex_a9::Cpu::PRIVATE_TIMER_IRQ };
/**
* Constructor, clears the interrupt output
*/
Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE)
{
_disable();
clear_interrupt();
}
/**
* Start a one-shot run
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
*/
inline void start_one_shot(uint32_t const tics)
{
/* reset timer */
clear_interrupt();
write<Control>(Control::init_one_shot());
/* load timer and start decrementing */
write<Load>(tics);
write<Control::Timer_enable>(1);
}
/**
* Translate milliseconds to a native timer value
*/
static uint32_t ms_to_tics(unsigned long const ms) {
return ms * TICS_PER_MS; }
/**
* Stop the timer and return last timer value
*/
unsigned long stop_one_shot()
{
unsigned long const v = read<Counter>();
_disable();
return v;
}
/**
* Clear interrupt output line
*/
void clear_interrupt() {
write<Interrupt_status::Event>(1); }
};
}
#endif /* _INCLUDE__CORTEX_A9__TIMER_H_ */

View File

@ -0,0 +1,99 @@
/*
* \brief Board definitions for core
* \author Martin Stein
* \date 2012-11-01
*/
#ifndef _INCLUDE__IMX31__DRIVERS__BOARD_H_
#define _INCLUDE__IMX31__DRIVERS__BOARD_H_
/* Genode includes */
#include <platform/imx31/drivers/board.h>
namespace Imx31
{
using namespace Genode;
/**
* AHB-lite 2v6 to IP bus interface
*/
class Aips : public Mmio
{
/**
* Configuration of the masters
*/
struct Mpr { enum { ALL_UNBUFFERED_AND_FULLY_TRUSTED = 0x77777777 }; };
struct Mpr1 : Register<0x0, 32>, Mpr { };
struct Mpr2 : Register<0x4, 32>, Mpr { };
/**
* Configuration of the platform peripherals
*/
struct Pacr { enum { ALL_UNBUFFERED_AND_FULLY_UNPROTECTED = 0 }; };
struct Pacr1 : Register<0x20, 32>, Pacr { };
struct Pacr2 : Register<0x24, 32>, Pacr { };
struct Pacr3 : Register<0x28, 32>, Pacr { };
struct Pacr4 : Register<0x2c, 32>, Pacr { };
/**
* Configuration of the off-platform peripherals
*/
struct Opacr1 : Register<0x40, 32>, Pacr { };
struct Opacr2 : Register<0x44, 32>, Pacr { };
struct Opacr3 : Register<0x48, 32>, Pacr { };
struct Opacr4 : Register<0x4c, 32>, Pacr { };
struct Opacr5 : Register<0x50, 32>, Pacr { };
public:
/**
* Constructor
*/
Aips(addr_t const base) : Mmio(base) { }
/**
* Configure this module appropriately for the first kernel run
*/
void prepare_kernel()
{
/* avoid AIPS intervention at any memory access */
write<Mpr1>(Mpr::ALL_UNBUFFERED_AND_FULLY_TRUSTED);
write<Mpr2>(Mpr::ALL_UNBUFFERED_AND_FULLY_TRUSTED);
write<Pacr1>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Pacr2>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Pacr3>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Pacr4>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr1>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr2>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr3>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr4>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr5>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
}
};
struct Board : Genode::Board
{
/**
* static AIPS 1 instance
*/
static Aips * aips_1() { static Aips a(AIPS_1_MMIO_BASE); return &a; }
/**
* Static AIPS 2 instance
*/
static Aips * aips_2() { static Aips a(AIPS_2_MMIO_BASE); return &a; }
/**
* Configure this module appropriately for the first kernel run
*/
static void prepare_kernel()
{
aips_1()->prepare_kernel();
aips_2()->prepare_kernel();
}
};
}
typedef Imx31::Board Board;
#endif /* _INCLUDE__IMX31__DRIVERS__BOARD_H_ */

View File

@ -0,0 +1,39 @@
/*
* \brief Kernel support for i.MX31
* \author Norman Feske
* \author Martin Stein
* \date 2012-08-30
*/
/*
* Copyright (C) 2012 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 _CORE__INCLUDE__IMX31__KERNEL_SUPPORT_H_
#define _CORE__INCLUDE__IMX31__KERNEL_SUPPORT_H_
/* Genode includes */
#include <arm/v6/cpu.h>
#include <imx31/timer.h>
#include <imx31/pic.h>
struct Cpu : Arm_v6::Cpu { };
namespace Kernel
{
/**
* Programmable interrupt controller
*/
class Pic : public Imx31::Pic { };
/**
* Timer
*/
class Timer : public Imx31::Timer { };
}
#endif /* _CORE__INCLUDE__IMX31__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,197 @@
/*
* \brief Programmable interrupt controller for core
* \author Norman Feske
* \author Martin Stein
* \date 2012-08-30
*/
/*
* Copyright (C) 2012 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 _INCLUDE__IMX31__PIC_H_
#define _INCLUDE__IMX31__PIC_H_
/* Genode includes */
#include <util/mmio.h>
#include <drivers/board.h>
namespace Imx31
{
using namespace Genode;
/**
* Programmable interrupt controller for core
*/
class Pic : public Mmio
{
/**
* Interrupt control register
*/
struct Intcntl : Register<0x0, 32>
{
struct Nm : Bitfield<18,1> /* IRQ mode */
{
enum { SW_CONTROL = 0 };
};
struct Fiad : Bitfield<19,1> { }; /* FIQ rises prio in arbiter */
struct Niad : Bitfield<20,1> { }; /* IRQ rises prio in arbiter */
struct Fidis : Bitfield<21,1> { }; /* FIQ disable */
struct Nidis : Bitfield<22,1> { }; /* IRQ disable */
struct Abfen : Bitfield<24,1> { }; /* if ABFLAG is sticky */
struct Abflag : Bitfield<25,1> { }; /* rise prio in bus arbiter */
static access_t init_value()
{
return Nm::bits(Nm::SW_CONTROL) |
Fiad::bits(0) |
Niad::bits(0) |
Fidis::bits(0) |
Nidis::bits(0) |
Abfen::bits(0) |
Abflag::bits(0);
}
};
/**
* Normal interrupt mask register
*/
struct Nimask : Register<0x4, 32>
{
enum { NONE_MASKED = ~0 };
};
/**
* Interrupt enable number register
*/
struct Intennum : Register<0x8, 32>
{
struct Enable : Bitfield<0,6> { };
};
/**
* Interrupt disable number register
*/
struct Intdisnum : Register<0xc, 32>
{
struct Disable : Bitfield<0,6> { };
};
/**
* Interrupt enable register
*/
struct Intenableh : Register<0x10, 32> { };
struct Intenablel : Register<0x14, 32> { };
/**
* Interrupt type register
*/
struct Inttype { enum { ALL_IRQS = 0 }; };
struct Inttypeh : Register<0x18, 32> { };
struct Inttypel : Register<0x1c, 32> { };
/**
* Normal interrupt priority registers
*/
struct Nipriority : Register_array<0x20, 32, 8, 32>
{
enum { ALL_LOWEST = 0 };
};
/**
* Interrupt source registers
*/
struct Intsrch : Register<0x48, 32> { };
struct Intsrcl : Register<0x4c, 32> { };
/**
* Normal interrupt pending registers
*/
struct Nipndh : Register<0x58, 32> { };
struct Nipndl : Register<0x5c, 32> { };
/**
* Normal interrupt vector and status register
*/
struct Nivecsr : Register<0x40, 32>
{
struct Nvector : Bitfield<16, 16> { };
};
public:
enum { MAX_INTERRUPT_ID = 63 };
/**
* Constructor, enables all interrupts
*/
Pic() : Mmio(Board::AVIC_MMIO_BASE)
{
mask();
write<Nimask>(Nimask::NONE_MASKED);
write<Intcntl>(Intcntl::init_value());
write<Inttypeh>(Inttype::ALL_IRQS);
write<Inttypel>(Inttype::ALL_IRQS);
for (unsigned i = 0; i < Nipriority::ITEMS; i++)
write<Nipriority>(Nipriority::ALL_LOWEST, i);
}
/**
* Receive a pending request number 'i'
*/
bool take_request(unsigned & i)
{
i = read<Nivecsr::Nvector>();
return valid(i) ? true : false;
}
/**
* Finish the last taken request
*/
void finish_request() {
/* requests disappear by source retraction or masking */ }
/**
* Validate request number 'i'
*/
bool valid(unsigned const i) const {
return i <= MAX_INTERRUPT_ID; }
/**
* Unmask all interrupts
*/
void unmask()
{
write<Intenablel>(~0);
write<Intenableh>(~0);
}
/**
* Mask all interrupts
*/
void mask()
{
write<Intenablel>(0);
write<Intenableh>(0);
}
/**
* Unmask interrupt 'i'
*/
void unmask(unsigned const i) {
if (i <= MAX_INTERRUPT_ID) write<Intennum>(i); }
/**
* Mask interrupt 'i'
*/
void mask(unsigned const i) {
if (i <= MAX_INTERRUPT_ID) write<Intdisnum>(i); }
};
}
#endif /* _INCLUDE__IMX31__PIC_H_ */

View File

@ -0,0 +1,176 @@
/*
* \brief Core timer
* \author Martin Stein
* \author Norman Feske
* \date 2012-08-30
*/
/*
* Copyright (C) 2012 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 _INCLUDE__IMX31__TIMER_H_
#define _INCLUDE__IMX31__TIMER_H_
/* Genode includes */
#include <util/mmio.h>
namespace Imx31
{
using namespace Genode;
/**
* Core timer
*/
class Timer : public Mmio
{
enum { TICS_PER_MS = 32 };
/**
* Control register
*/
struct Cr : Register<0x0, 32>
{
struct En : Bitfield<0, 1> { }; /* enable timer */
struct En_mod : Bitfield<1, 1> /* reload or continue on enable */
{
enum { RELOAD = 1 };
};
struct Oci_en : Bitfield<2, 1> { }; /* interrupt on compare */
struct Rld : Bitfield<3, 1> /* reload or roll-over */
{
enum { RELOAD_FROM_LR = 1 };
};
struct Prescaler : Bitfield<4, 12> /* clock input divisor */
{
enum { DIVIDE_BY_1 = 0 };
};
struct Swr : Bitfield<16, 1> { }; /* software reset bit */
struct Iovw : Bitfield<17, 1> { }; /* enable overwrite */
struct Dbg_en : Bitfield<18, 1> { }; /* enable in debug mode */
struct Wait_en : Bitfield<19, 1> { }; /* enable in wait mode */
struct Doz_en : Bitfield<20, 1> { }; /* enable in doze mode */
struct Stop_en : Bitfield<21, 1> { }; /* enable in stop mode */
struct Om : Bitfield<22, 2> /* mode of the output pin */
{
enum { DISCONNECTED = 0 };
};
struct Clk_src : Bitfield<24, 2> /* select clock input */
{
enum { IPG_CLK_32K = 3 };
};
/**
* Register value that configures the timer for a one-shot run
*/
static access_t prepare_one_shot()
{
return En::bits(0) |
En_mod::bits(En_mod::RELOAD) |
Oci_en::bits(1) |
Rld::bits(Rld::RELOAD_FROM_LR) |
Prescaler::bits(Prescaler::DIVIDE_BY_1) |
Swr::bits(0) |
Iovw::bits(0) |
Dbg_en::bits(0) |
Wait_en::bits(0) |
Doz_en::bits(0) |
Stop_en::bits(0) |
Om::bits(Om::DISCONNECTED) |
Clk_src::bits(Clk_src::IPG_CLK_32K);
}
};
/**
* Status register
*/
struct Sr : Register<0x4, 32>
{
struct Ocif : Bitfield<0, 1> { }; /* IRQ status, write 1 clears */
};
struct Lr : Register<0x8, 32> { }; /* load value register */
struct Cmpr : Register<0xc, 32> { }; /* compare value register */
struct Cnt : Register<0x10, 32> { }; /* counter register */
/**
* Disable timer and clear its interrupt output
*/
void _reset()
{
/* wait until ongoing reset operations are finished */
while (read<Cr::Swr>()) ;
/* disable timer */
write<Cr::En>(0);
clear_interrupt();
}
public:
enum { IRQ = Board::EPIT_1_IRQ };
/**
* Constructor
*/
Timer() : Mmio(Board::EPIT_1_MMIO_BASE) { _reset(); }
/**
* Start a one-shot run
*
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
*/
void start_one_shot(unsigned const tics)
{
/* stop timer */
_reset();
/* configure timer for a one-shot */
write<Cr>(Cr::prepare_one_shot());
write<Lr>(tics);
write<Cmpr>(0);
/* start timer */
write<Cr::En>(1);
}
/**
* Stop the timer from a one-shot run
*
* \return last native timer value of the one-shot run
*/
unsigned long stop_one_shot()
{
/* disable timer */
write<Cr::En>(0);
/* if the timer has hit zero already return 0 */
return read<Sr::Ocif>() ? 0 : read<Cnt>();
}
/**
* Clear interrupt output line
*/
void clear_interrupt() { write<Sr::Ocif>(1); }
/**
* Translate milliseconds to a native timer value
*/
static unsigned ms_to_tics(unsigned const ms) {
return TICS_PER_MS * ms; }
};
}
#endif /* _INCLUDE__IMX31__TIMER_H_ */

View File

@ -0,0 +1,68 @@
/*
* \brief Programmable interrupt controller for core
* \author Stefan Kalkowski
* \date 2012-10-11
*/
/*
* Copyright (C) 2012 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 _INCLUDE__VEA9X4_TRUSTZONE__PIC_H_
#define _INCLUDE__VEA9X4_TRUSTZONE__PIC_H_
/* core includes */
#include <cortex_a9/cpu.h>
#include <cortex_a9/pic.h>
namespace Vea9x4_trustzone
{
using namespace Genode;
/**
* Programmable interrupt controller for core
*/
class Pic : public Cortex_a9::Pic
{
public:
/**
* Constructor
*/
Pic()
{
/* configure every shared peripheral interrupt */
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++) {
_distr.write<Distr::Icdicr::Edge_triggered>(0, i);
_distr.write<Distr::Icdipr::Priority>(0, i);
_distr.write<Distr::Icdiptr::Cpu_targets>(Distr::Icdiptr::Cpu_targets::ALL, i);
}
/* disable the priority filter */
_cpu.write<Cpu::Iccpmr::Priority>(0xff);
/* signal secure IRQ via FIQ interface */
_cpu.write<Cpu::Iccicr>(Cpu::Iccicr::Enable_s::bits(1) |
Cpu::Iccicr::Enable_ns::bits(1) |
Cpu::Iccicr::Fiq_en::bits(1));
/* use whole band of prios */
_cpu.write<Cpu::Iccbpr::Binary_point>(Cpu::Iccbpr::Binary_point::NO_PREEMPTION);
/* enable device */
_distr.write<Distr::Icddcr>(Distr::Icddcr::Enable::bits(1));
}
/**
* Mark interrupt 'i' unsecure
*/
void unsecure(unsigned const i) {
_distr.write<Distr::Icdisr::Nonsecure>(1, i); }
};
}
#endif /* _INCLUDE__VEA9X4_TRUSTZONE__PIC_H_ */

View File

@ -47,9 +47,9 @@ extern int _mode_transition_begin;
extern int _mode_transition_end;
extern int _mt_user_entry_pic;
extern int _mon_vm_entry;
extern Genode::addr_t _mt_context_ptr;
extern Genode::addr_t _mt_kernel_context_begin;
extern Genode::addr_t _mt_kernel_context_end;
extern Genode::addr_t _mt_client_context_ptr;
extern Genode::addr_t _mt_master_context_begin;
extern Genode::addr_t _mt_master_context_end;
namespace Kernel
{
@ -68,7 +68,7 @@ namespace Kernel
/* kernel configuration */
enum {
DEFAULT_STACK_SIZE = 1*1024*1024,
USER_TIME_SLICE_MS = 10,
USER_TIME_SLICE_MS = 100,
MAX_PDS = 256,
MAX_THREADS = 256,
MAX_SIGNAL_RECEIVERS = 256,
@ -720,17 +720,17 @@ namespace Kernel
*
* The code that switches between kernel/user mode must not exceed the
* smallest page size supported by the MMU. The Code must be position
* independent. This code has to be mapped to in every PD, to ensure
* independent. This code has to be mapped in every PD, to ensure
* appropriate kernel invokation on CPU interrupts.
* This class controls the settings like kernel, user, and vm states
* that are handled by the PIC mode transition code.
* This class controls the settings like kernel, user, and VM states
* that are handled by the mode transition PIC.
*/
struct Mode_transition_control
{
enum {
SIZE_LOG2 = Cpu::MIN_PAGE_SIZE_LOG2,
SIZE_LOG2 = Software_tlb::MIN_PAGE_SIZE_LOG2,
SIZE = 1 << SIZE_LOG2,
VIRT_BASE = Cpu::HIGHEST_EXCEPTION_ENTRY,
VIRT_BASE = Cpu::EXCEPTION_ENTRY,
VIRT_END = VIRT_BASE + SIZE,
ALIGNM_LOG2 = SIZE_LOG2,
};
@ -751,20 +751,17 @@ namespace Kernel
assert(pic_size <= SIZE);
/* check if kernel context fits into the mode transition */
addr_t const kc_begin = (addr_t)&_mt_kernel_context_begin;
addr_t const kc_end = (addr_t)&_mt_kernel_context_end;
addr_t const kc_begin = (addr_t)&_mt_master_context_begin;
addr_t const kc_end = (addr_t)&_mt_master_context_end;
size_t const kc_size = kc_end - kc_begin;
assert(sizeof(Cpu::Context) <= kc_size);
/* try to set CPU exception entry accordingly */
assert(!Cpu::exception_entry_at(VIRT_BASE));
}
/**
* Fetch next kernelmode context
*/
void fetch_kernel_context(Cpu::Context * const c) {
memcpy(&_mt_kernel_context_begin, c, sizeof(Cpu::Context)); }
void fetch_master_context(Cpu::Context * const c) {
memcpy(&_mt_master_context_begin, c, sizeof(Cpu::Context)); }
/**
* Page aligned physical base of the mode transition PIC
@ -836,7 +833,7 @@ namespace Kernel
void append_context(Cpu::Context * const c)
{
c->protection_domain(id());
c->software_tlb((Software_tlb *)this);
c->software_tlb((addr_t)static_cast<Software_tlb *>(this));
}
};
@ -1125,6 +1122,11 @@ namespace Kernel
Platform_thread * const _platform_thread; /* userland object wich
* addresses this thread */
State _state; /* thread state, description given at the beginning */
Pagefault _pagefault; /* last pagefault triggered by this thread */
Thread * _pager; /* gets informed if thread throws a pagefault */
unsigned _pd_id; /* ID of the PD this thread runs on */
Native_utcb * _phys_utcb; /* physical UTCB base */
Native_utcb * _virt_utcb; /* virtual UTCB base */
/**
* Resume execution
@ -1135,12 +1137,6 @@ namespace Kernel
_state = ACTIVE;
}
Pagefault _pagefault; /* last pagefault triggered by this thread */
Thread * _pager; /* gets informed if thread throws a pagefault */
unsigned _pd_id; /* ID of the PD this thread runs on */
Native_utcb * _phys_utcb; /* physical UTCB base */
Native_utcb * _virt_utcb; /* virtual UTCB base */
public:
void * operator new (size_t, void * p) { return p; }
@ -1288,9 +1284,10 @@ namespace Kernel
}
}
void scheduled_next() {
void scheduled_next()
{
/* set context pointer for mode switch */
_mt_context_ptr = (addr_t)static_cast<Genode::Cpu_state*>(this);
_mt_client_context_ptr = (addr_t)static_cast<Genode::Cpu_state*>(this);
/* jump to user entry assembler path */
mtc()->virt_user_entry();
@ -1344,7 +1341,6 @@ namespace Kernel
class Signal_receiver;
/**
* Specific signal type, owned by a receiver, can be triggered asynchr.
*/
@ -1472,9 +1468,10 @@ namespace Kernel
}
}
void scheduled_next() {
void scheduled_next()
{
/* set context pointer for mode switch */
_mt_context_ptr = (addr_t)_state;
_mt_client_context_ptr = (addr_t)_state;
/* jump to assembler path */
((void(*)(void))&_mon_vm_entry)();
@ -1959,7 +1956,7 @@ namespace Kernel
assert(c);
/* trigger signal at context */
c->trigger_signal(1);
c->trigger_signal(user->user_arg_2());
}
@ -2041,9 +2038,9 @@ namespace Kernel
/* 21 */ do_new_signal_context,
/* 22 */ do_await_signal,
/* 23 */ do_submit_signal,
/* 24 */ do_delete_thread,
/* 25 */ do_new_vm,
/* 26 */ do_run_vm,
/* 24 */ do_new_vm,
/* 25 */ do_run_vm,
/* 26 */ do_delete_thread,
};
enum { MAX_SYSCALL = sizeof(handle_sysc)/sizeof(handle_sysc[0]) - 1 };
@ -2054,13 +2051,17 @@ namespace Kernel
}
}
/**
* Prepare the system for the first run of 'kernel'
*/
extern "C" void init_phys_kernel() {
Cpu::init_phys_kernel(); }
/**
* Kernel main routine
*/
extern "C" void kernel()
{
unsigned const timer_value = timer()->stop();
static unsigned user_time = 0;
static bool initial_call = true;
@ -2068,6 +2069,7 @@ extern "C" void kernel()
if (!initial_call)
{
/* update how much time the last user has consumed */
unsigned const timer_value = timer()->stop_one_shot();
user_time = timer_value < user_time ? user_time - timer_value : 0;
/* handle exception that interrupted the last user */
@ -2082,7 +2084,7 @@ extern "C" void kernel()
{
/* map everything except the mode transition region */
enum {
SIZE_LOG2 = Software_tlb::MAX_TRANSL_SIZE_LOG2,
SIZE_LOG2 = Software_tlb::MAX_PAGE_SIZE_LOG2,
SIZE = 1 << SIZE_LOG2,
};
if (mtc()->VIRT_END <= a || mtc()->VIRT_BASE > (a + SIZE - 1))
@ -2098,20 +2100,20 @@ extern "C" void kernel()
}
/* compose kernel CPU context */
static Cpu::Context kernel_context;
kernel_context.instruction_ptr((addr_t)kernel);
kernel_context.stack_ptr((addr_t)&_kernel_stack_high);
kernel_context.ip = (addr_t)kernel;
kernel_context.sp = (addr_t)&_kernel_stack_high;
/* add kernel to the core PD */
core()->append_context(&kernel_context);
/* offer the final kernel context to the mode transition page */
mtc()->fetch_kernel_context(&kernel_context);
mtc()->fetch_master_context(&kernel_context);
/* TrustZone initialization code */
trustzone_initialization(pic());
/* switch to core address space */
Cpu::enable_mmu(core(), core_id());
Cpu::init_virt_kernel((addr_t)static_cast<Software_tlb *>(core()), core_id());
/* create the core main thread */
static Native_utcb cm_utcb;
@ -2120,7 +2122,7 @@ extern "C" void kernel()
static Thread core_main((Platform_thread *)0);
_main_utcb = &cm_utcb;
enum { CM_STACK_SIZE = sizeof(cm_stack)/sizeof(cm_stack[0]) + 1 };
core_main.start((void *)&CORE_MAIN,
core_main.start((void *)CORE_MAIN,
(void *)&cm_stack[CM_STACK_SIZE - 1],
0, core_id(), &cm_utcb, &cm_utcb);
@ -2128,7 +2130,7 @@ extern "C" void kernel()
initial_call = false;
}
/* offer next user context to the mode transition PIC */
Schedule_context* const next = cpu_scheduler()->next_entry(user_time);
Schedule_context * const next = cpu_scheduler()->next_entry(user_time);
/* limit user mode execution in time */
timer()->start_one_shot(user_time);
@ -2167,19 +2169,19 @@ int Thread::start(void *ip, void *sp, unsigned cpu_no,
}
void Thread::init_context(void * const ip, void * const sp,
void Thread::init_context(void * const instr_p, void * const stack_p,
unsigned const pd_id)
{
/* basic thread state */
stack_ptr((addr_t)sp);
instruction_ptr((addr_t)ip);
sp = (addr_t)stack_p;
ip = (addr_t)instr_p;
/* join a pd */
_pd_id = pd_id;
Pd * const pd = Pd::pool()->object(_pd_id);
assert(pd)
protection_domain(pd_id);
software_tlb(pd);
software_tlb((addr_t)static_cast<Software_tlb *>(pd));
}
@ -2191,10 +2193,8 @@ void Thread::pagefault(addr_t const va, bool const w)
/* inform pager through IPC */
assert(_pager);
Software_tlb * const tlb =
static_cast<Software_tlb *>(software_tlb());
_pagefault =
Pagefault(id(), tlb, instruction_ptr(), va, w);
Software_tlb * const tlb = (Software_tlb *)software_tlb();
_pagefault = Pagefault(id(), tlb, ip, va, w);
Ipc_node::send_note(_pager, &_pagefault, sizeof(_pagefault));
}

View File

@ -11,13 +11,8 @@
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel_support.h>
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }
Cpu::User_context::User_context()
{
/* Execute in usermode with IRQ's enabled and FIQ's and
* asynchronous aborts disabled */
cpsr = Cpsr::M::bits(Cpsr::M::USER) | Cpsr::F::bits(1) |
Cpsr::I::bits(0) | Cpsr::A::bits(1);
}

View File

@ -15,9 +15,9 @@
#include <drivers/board.h>
/* core includes */
#include <cortex_a9/cpu.h>
#include <cortex_a9/no_trustzone/pic.h>
#include <platform.h>
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
using namespace Genode;
@ -37,7 +37,7 @@ Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Pl390_base::MAX_INTERRUPT_ID + 1 }
{ 0, Cortex_a9_no_trustzone::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
@ -48,7 +48,7 @@ Native_region * Platform::_core_only_irq_regions(unsigned const i)
static Native_region _regions[] =
{
/* core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* core UART */
{ Board::TL16C750_3_IRQ, 1 }

View File

@ -15,12 +15,12 @@
#define _SRC__CORE__PANDA_A2__SOFTWARE_TLB_H_
/* Genode includes */
#include <cortex_a9/cpu/section_table.h>
#include <arm/v7/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Genode::Section_table { };
class Software_tlb : public Arm_v7::Section_table { };
#endif /* _SRC__CORE__PANDA_A2__SOFTWARE_TLB_H_ */

View File

@ -1,9 +1,12 @@
#
# \brief Pandaboard-specific makefile for core
# \brief Makefile for core
# \author Stefan Kalkowski
# \date 2012-10-04
#
REQUIRES = platform_panda_a2
# declare wich specs must be given to build this target
REQUIRES += platform_panda_a2
# include less specific target parts
include $(REP_DIR)/src/core/target.inc

View File

@ -16,8 +16,9 @@
/* core includes */
#include <platform.h>
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
#include <cortex_a9/cpu.h>
#include <cortex_a9/no_trustzone/pic.h>
using namespace Genode;
@ -36,7 +37,7 @@ Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Pl390_base::MAX_INTERRUPT_ID + 1 }
{ 0, Cortex_a9_no_trustzone::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
@ -47,7 +48,7 @@ Native_region * Platform::_core_only_irq_regions(unsigned const i)
static Native_region _regions[] =
{
/* core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* core UART */
{ Board::PL011_0_IRQ, 1 }

View File

@ -14,13 +14,13 @@
#ifndef _SRC__CORE__PBXA9__SOFTWARE_TLB_H_
#define _SRC__CORE__PBXA9__SOFTWARE_TLB_H_
/* Genode includes */
#include <cortex_a9/cpu/section_table.h>
/* core includes */
#include <arm/v7/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Genode::Section_table { };
class Software_tlb : public Arm_v7::Section_table { };
#endif /* _SRC__CORE__PBXA9__SOFTWARE_TLB_H_ */

View File

@ -1,9 +1,12 @@
#
# \brief PBXA9-specific makefile for core
# \brief Makefile for core
# \author Stefan Kalkowski
# \date 2012-10-04
#
# declare wich specs must be given to build this target
REQUIRES = platform_pbxa9
# include less specific target parts
include $(REP_DIR)/src/core/target.inc

View File

@ -142,6 +142,10 @@ Platform::Platform() :
printf("-------------------\n");
_io_mem_alloc.raw()->dump_addr_tree();
printf("\n");
printf("IRQ allocator\n");
printf("-------------------\n");
_irq_alloc.raw()->dump_addr_tree();
printf("\n");
printf("ROM filesystem\n");
printf("--------------\n");
_rom_fs.print_fs();

View File

@ -8,11 +8,11 @@
TARGET = core
# use core specific startup library
STARTUP_LIB = startup_core
STARTUP_LIB = core_support
# add library dependencies
LIBS += cxx raw_ipc heap child pager lock console signal raw_server \
syscall startup_core core_support
LIBS += cxx raw_ipc heap child process pager lock console signal raw_server \
syscall core_support
# add include paths
GEN_CORE_DIR = $(BASE_DIR)/src/core

View File

@ -16,8 +16,8 @@
/* Core includes */
#include <platform.h>
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
#include <cortex_a9/cpu.h>
#include <cortex_a9/no_trustzone/pic.h>
using namespace Genode;
@ -36,7 +36,7 @@ Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Pl390_base::MAX_INTERRUPT_ID + 1 }
{ 0, Cortex_a9_no_trustzone::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
@ -47,7 +47,7 @@ Native_region * Platform::_core_only_irq_regions(unsigned const i)
static Native_region _regions[] =
{
/* Core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* Core UART */
{ Board::PL011_0_IRQ, 1 }

View File

@ -15,12 +15,12 @@
#define _SRC__CORE__VEA9X4__SOFTWARE_TLB_H_
/* Genode includes */
#include <cortex_a9/cpu/section_table.h>
#include <arm/v7/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Genode::Section_table { };
class Software_tlb : public Arm_v7::Section_table { };
#endif /* _SRC__CORE__VEA9X4__SOFTWARE_TLB_H_ */

View File

@ -1,13 +1,16 @@
#
# \brief VEA9x4-specific makefile for core
# \brief Makefile for core
# \author Stefan Kalkowski
# \date 2012-10-04
#
# declare wich specs must be given to build this target
REQUIRES = platform_vea9x4
# adjust link address of a trustzone text segment
ifeq ($(filter-out $(SPECS),trustzone),)
LD_TEXT_ADDR = 0x48000000
endif
# include less specific target parts
include $(REP_DIR)/src/core/target.inc

View File

@ -14,11 +14,6 @@
/* Core includes */
#include <kernel_support.h>
Cpu::User_context::User_context() {
cpsr = Psr::init_user_with_trustzone(); }
Genode::Cortex_a9::User_context::User_context()
{
/* Execute in usermode with FIQ's enabled and IRQ's and
* asynchronous aborts disabled */
cpsr = Cpsr::M::bits(Cpsr::M::USER) | Cpsr::F::bits(0) |
Cpsr::I::bits(1) | Cpsr::A::bits(1);
}

View File

@ -15,66 +15,26 @@
#define _SRC__CORE__VEA9X4__TRUSTZONE__KERNEL_SUPPORT_H_
/* Core includes */
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
#include <cortex_a9/cpu.h>
#include <cortex_a9/timer.h>
#include <vea9x4_trustzone/pic.h>
/**
* CPU driver
*/
class Cpu : public Genode::Cortex_a9 { };
class Cpu : public Cortex_a9::Cpu { };
namespace Kernel
{
/* import Genode types */
typedef Genode::Cortex_a9 Cortex_a9;
typedef Genode::Pl390_base Pl390_base;
/**
* Kernel interrupt-controller
* Programmable interrupt controller
*/
class Pic : public Pl390_base
{
public:
/**
* Constructor
*/
Pic() : Pl390_base(Cortex_a9::PL390_DISTRIBUTOR_MMIO_BASE,
Cortex_a9::PL390_CPU_MMIO_BASE)
{
/* configure every shared peripheral interrupt */
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++) {
_distr.write<Distr::Icdicr::Edge_triggered>(0, i);
_distr.write<Distr::Icdipr::Priority>(0, i);
_distr.write<Distr::Icdiptr::Cpu_targets>(Distr::Icdiptr::Cpu_targets::ALL, i);
}
/* disable the priority filter */
_cpu.write<Cpu::Iccpmr::Priority>(0xff);
/* signal secure IRQ via FIQ interface */
_cpu.write<Cpu::Iccicr>(Cpu::Iccicr::Enable_s::bits(1) |
Cpu::Iccicr::Enable_ns::bits(1) |
Cpu::Iccicr::Fiq_en::bits(1));
/* use whole band of prios */
_cpu.write<Cpu::Iccbpr::Binary_point>(Cpu::Iccbpr::Binary_point::NO_PREEMPTION);
/* enable device */
_distr.write<Distr::Icddcr>(Distr::Icddcr::Enable::bits(1));
}
/**
* Mark interrupt i unsecure
*/
void unsecure(unsigned i) {
_distr.write<Distr::Icdisr::Nonsecure>(1, i); }
};
class Pic : public Vea9x4_trustzone::Pic { };
/**
* Kernel timer
*/
class Timer : public Cortex_a9::Private_timer { };
class Timer : public Cortex_a9::Timer { };
}

View File

@ -16,8 +16,8 @@
/* Core includes */
#include <platform.h>
#include <pic/pl390_base.h>
#include <cortex_a9/cpu/core.h>
#include <vea9x4_trustzone/pic.h>
#include <cortex_a9/cpu.h>
using namespace Genode;
@ -39,7 +39,7 @@ Native_region * Platform::_irq_regions(unsigned const i)
{ 0, 34 },
{ 37, 3 },
{ 46, 1 },
{ 49, Pl390_base::MAX_INTERRUPT_ID - 49 }
{ 49, Vea9x4_trustzone::Pic::MAX_INTERRUPT_ID - 49 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
@ -50,7 +50,7 @@ Native_region * Platform::_core_only_irq_regions(unsigned const i)
static Native_region _regions[] =
{
/* Core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* Core UART */
{ Board::PL011_0_IRQ, 1 }

View File

@ -14,6 +14,7 @@
/* Core includes */
#include <trustzone.h>
#include <kernel_support.h>
#include <base/printf.h>
/* monitor exception vector address */
extern int _mon_kernel_entry;

View File

@ -1,5 +1,5 @@
/*
* \brief Vm_session_component for base-hw
* \brief VM session component for 'base-hw'
* \author Stefan Kalkowski
* \date 2012-10-08
*/
@ -17,7 +17,7 @@
#include <root/root.h>
#include <cpu/cpu_state.h>
/* Core includes */
/* core includes */
#include <vm_session_component.h>
using namespace Genode;

View File

@ -17,19 +17,6 @@
.global _start
_start:
/* zero-fill BSS segment but don't pollute thread-entry arguments */
.extern _bss_start
ldr r4, =_bss_start
.extern _bss_end
ldr r3, =_bss_end
mov r2, #0
sub r3, r3, #4
1:
str r2, [r4]
add r4, r4, #4
cmp r4, r3
bne 1b
/* fetch thread-entry arguments to their destinations in BSS */
ldr r1, =_main_utcb
str r0, [r1]
@ -38,8 +25,7 @@
ldr sp, =_main_stack_high
.extern _main
bl _main
1:
b 1b
1: b 1b
/* dynamic symbol object handle */
.align 3

View File

@ -2,6 +2,7 @@
* \brief CPU state
* \author Norman Feske
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2011-05-06
*/
@ -15,37 +16,44 @@
#ifndef _INCLUDE__ARM__CPU__CPU_STATE_H_
#define _INCLUDE__ARM__CPU__CPU_STATE_H_
/* Genode includes */
#include <base/stdint.h>
namespace Genode {
/**
* Basic CPU state
*/
struct Cpu_state
{
/**
* Native exception types
*/
enum Cpu_exception {
RESET,
UNDEFINED_INSTRUCTION,
SUPERVISOR_CALL,
PREFETCH_ABORT,
DATA_ABORT,
INTERRUPT_REQUEST,
FAST_INTERRUPT_REQUEST,
MAX_CPU_EXCEPTION,
RESET = 1,
UNDEFINED_INSTRUCTION = 2,
SUPERVISOR_CALL = 3,
PREFETCH_ABORT = 4,
DATA_ABORT = 5,
INTERRUPT_REQUEST = 6,
FAST_INTERRUPT_REQUEST = 7,
};
enum { MAX_GPR = 13 };
addr_t r[MAX_GPR]; /* r0-r12 - general purpose */
addr_t sp; /* r13 - stack pointer */
addr_t lr; /* r14 - link register */
addr_t ip; /* r15 - instruction pointer */
addr_t cpsr; /* current program status register */
Cpu_exception cpu_exception; /* last exception */
/**
* Registers
*/
addr_t r0, r1, r2, r3, r4, r5, r6,
r7, r8, r9, r10, r11, r12; /* general purpose register 0..12 */
addr_t sp; /* stack pointer */
addr_t lr; /* link register */
addr_t ip; /* instruction pointer */
addr_t cpsr; /* current program status register */
addr_t cpu_exception; /* last hardware exception */
};
/**
* Extend CPU state by banked registers
*/
struct Cpu_state_modes : Cpu_state
{
/**

View File

@ -0,0 +1,274 @@
/*
* \brief Driver base for i.MX31 UART-module
* \author Norman Feske
* \author Martin Stein
* \date 2012-08-30
*/
/*
* Copyright (C) 2012 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 _INCLUDE__DRIVERS__UART__IMX31_UART_BASE_H_
#define _INCLUDE__DRIVERS__UART__IMX31_UART_BASE_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode
{
/**
* Driver base for i.MX31 UART-module
*/
class Imx31_uart_base : Mmio
{
/**
* Control register 1
*/
struct Cr1 : Register<0x80, 32>
{
struct Uart_en : Bitfield<0, 1> { }; /* enable UART */
struct Doze : Bitfield<1, 1> { }; /* disable on doze */
struct At_dma_en : Bitfield<2, 1> { }; /* aging DMA
* timer on */
struct Tx_dma_en : Bitfield<3, 1> { }; /* TX ready DMA on */
struct Snd_brk : Bitfield<4, 1> { }; /* send breaks */
struct Rtsd_en : Bitfield<5, 1> { }; /* RTS delta IRQ on */
struct Tx_mpty_en : Bitfield<6, 1> { }; /* TX empty IRQ on */
struct Ir_en : Bitfield<7, 1> { }; /* enable infrared */
struct Rx_dma_en : Bitfield<8, 1> { }; /* RX ready DMA on */
struct R_rdy_en : Bitfield<9, 1> { }; /* RX ready IRQ on */
struct Icd : Bitfield<10, 2> /* idle IRQ condition */
{
enum { IDLE_4_FRAMES = 0 };
};
struct Id_en : Bitfield<12, 1> { }; /* enable idle IRQ */
struct T_rdy_en : Bitfield<13, 1> { }; /* TX ready IRQ on */
struct Adbr : Bitfield<14, 1> { }; /* enable baud-rate
* auto detect */
struct Ad_en : Bitfield<15, 1> { }; /* enable ADBR IRQ */
/**
* Initialization value
*/
static access_t init_value()
{
return Uart_en::bits(1) |
Doze::bits(0) |
At_dma_en::bits(0) |
Tx_dma_en::bits(0) |
Snd_brk::bits(0) |
Rtsd_en::bits(0) |
Tx_mpty_en::bits(0) |
Ir_en::bits(0) |
Rx_dma_en::bits(0) |
R_rdy_en::bits(0) |
Id_en::bits(0) |
T_rdy_en::bits(0) |
Adbr::bits(0) |
Ad_en::bits(0);
}
};
/**
* Control register 2
*/
struct Cr2 : Register<0x84, 32>
{
struct S_rst : Bitfield<0, 1> /* SW reset bit */
{
enum { NO_RESET = 1 };
};
struct Rx_en : Bitfield<1, 1> { }; /* enable receiver */
struct Tx_en : Bitfield<2, 1> { }; /* enable transmitter */
struct At_en : Bitfield<3, 1> { }; /* enable aging timer */
struct Rts_en : Bitfield<4, 1> { }; /* send request IRQ on */
struct Ws : Bitfield<5, 1> /* select word size */
{
enum { _8_BITS = 1 };
};
struct Stpb : Bitfield<6, 1> /* number of stop bits */
{
enum { _1_BIT = 0 };
};
struct Pr_en : Bitfield<8, 1> { }; /* enable parity */
struct Esc_en : Bitfield<11, 1> { }; /* escape detection on */
struct Ctsc : Bitfield<13, 1> /* select CTS control */
{
enum { BY_RECEIVER = 1 };
};
struct Irts : Bitfield<14, 1> { }; /* ignore RTS pin */
struct Esci : Bitfield<15, 1> { }; /* enable escape IRQ */
/**
* Initialization value
*/
static access_t init_value()
{
return S_rst::bits(S_rst::NO_RESET) |
Rx_en::bits(0) |
Tx_en::bits(1) |
At_en::bits(0) |
Rts_en::bits(0) |
Ws::bits(Ws::_8_BITS) |
Stpb::bits(Stpb::_1_BIT) |
Pr_en::bits(0) |
Esc_en::bits(0) |
Ctsc::bits(Ctsc::BY_RECEIVER) |
Irts::bits(1) |
Esci::bits(0);
}
};
/**
* Control register 3
*/
struct Cr3 : Register<0x88, 32>
{
struct Rxdmux_sel : Bitfield<2, 1> { }; /* use muxed RXD */
struct Aci_en : Bitfield<0, 1> { }; /* autobaud count IRQ on */
struct Dtrd_en : Bitfield<3, 1> { }; /* data terminal ready
* delta IRQ on */
struct Awak_en : Bitfield<4, 1> { }; /* wake IRQ on */
struct Air_int_en : Bitfield<5, 1> { }; /* IR wake IRQ on */
struct Rx_ds_en : Bitfield<6, 1> { }; /* RX status IRQ on */
struct Ad_nimp : Bitfield<7, 1> { }; /* autobaud detect off */
struct Ri_en : Bitfield<8, 1> { }; /* ring indicator IRQ on */
struct Dcd_en : Bitfield<9, 1> { }; /* data carrier detect
* IRQ on */
struct Dsr : Bitfield<10,1> { }; /* DSR/DTR output */
struct Frame_en : Bitfield<11,1> { }; /* frame error IRQ on */
struct Parity_en : Bitfield<12,1> { }; /* parity error IRQ on */
struct Dtr_en : Bitfield<13,1> { }; /* data terminal ready
* IRQ on */
struct Dpec_ctrl : Bitfield<14,2> { }; /* DTR/DSR IRQ edge
* control */
/**
* Initialization value
*/
static access_t init_value()
{
return Aci_en::bits(0) |
Rxdmux_sel::bits(0) |
Dtrd_en::bits(0) |
Awak_en::bits(0) |
Air_int_en::bits(0) |
Rx_ds_en::bits(0) |
Ad_nimp::bits(1) |
Ri_en::bits(0) |
Dcd_en::bits(0) |
Dsr::bits(0) |
Frame_en::bits(0) |
Parity_en::bits(0) |
Dtr_en::bits(0) |
Dpec_ctrl::bits(0);
}
};
/**
* Control register 4
*/
struct Cr4 : Register<0x8c, 32>
{
struct Dr_en : Bitfield<0, 1> { }; /* RX data ready IRQ on */
struct Or_en : Bitfield<1, 1> { }; /* RX overrun IRQ on */
struct Bk_en : Bitfield<2, 1> { }; /* BREAK IRQ on */
struct Tc_en : Bitfield<3, 1> { }; /* TX complete IRQ on */
struct Lp_dis : Bitfield<4, 1> { }; /* low power off */
struct IR_sc : Bitfield<5, 1> { }; /* use UART ref clock
* for vote logic */
struct Id_dma_en : Bitfield<6, 1> { }; /* idle DMA IRQ on */
struct Wake_en : Bitfield<7, 1> { }; /* WAKE IRQ on */
struct IR_en : Bitfield<8, 1> { }; /* serial IR IRQ on */
struct Cts_level : Bitfield<10,6> { }; /* CTS trigger level*/
/**
* Initialization value
*/
static access_t init_value()
{
return Dr_en::bits(0) |
Or_en::bits(0) |
Bk_en::bits(0) |
Tc_en::bits(0) |
Lp_dis::bits(0) |
IR_sc::bits(0) |
Id_dma_en::bits(0) |
Wake_en::bits(0) |
IR_en::bits(0) |
Cts_level::bits(0);
}
};
/**
* Status register 2
*/
struct Sr2 : Register<0x98, 32>
{
struct Txdc : Bitfield<3, 1> { }; /* transmission complete */
};
/**
* Transmitter register
*/
struct Txd : Register<0x40, 32>
{
struct Tx_data : Bitfield<0, 8> { }; /* transmit data */
};
/**
* Transmit character 'c' without care about its type
*/
inline void _put_char(char const c)
{
while (!read<Sr2::Txdc>()) ;
write<Txd::Tx_data>(c);
}
public:
/**
* Constructor
*
* \param base device MMIO base
*/
explicit Imx31_uart_base(addr_t const base) : Mmio(base)
{
write<Cr1>(Cr1::init_value());
write<Cr2>(Cr2::init_value());
write<Cr3>(Cr3::init_value());
write<Cr4>(Cr4::init_value());
}
/**
* Print character 'c' through the UART
*/
inline void put_char(char const c)
{
enum { ASCII_LINE_FEED = 10,
ASCII_CARRIAGE_RETURN = 13 };
/* prepend line feed with carriage return */
if (c == ASCII_LINE_FEED) _put_char(ASCII_CARRIAGE_RETURN);
/* transmit character */
_put_char(c);
}
};
}
#endif /* _INCLUDE__DRIVERS__UART__IMX31_UART_BASE_H_ */

View File

@ -0,0 +1,53 @@
/*
* \brief Board definitions for the i.MX31
* \author Martin Stein
* \author Norman Feske
* \date 2011-11-03
*/
/*
* Copyright (C) 2012 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 _INCLUDE__PLATFORM__BOARD_H_
#define _INCLUDE__PLATFORM__BOARD_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode
{
/**
* i.MX31 motherboard
*/
struct Board
{
enum {
CSD0_SDRAM_BASE = 0x80000000,
CSD0_SDRAM_SIZE = 0x10000000,
UART_1_IRQ = 45,
UART_1_MMIO_BASE = 0x43f90000,
UART_1_MMIO_SIZE = 0x00004000,
EPIT_1_IRQ = 28,
EPIT_1_MMIO_BASE = 0x53f94000,
EPIT_1_MMIO_SIZE = 0x00004000,
AVIC_MMIO_BASE = 0x68000000,
AVIC_MMIO_SIZE = 0x04000000,
AIPS_1_MMIO_BASE = 0x43F00000,
AIPS_1_MMIO_SIZE = 0x00004000,
AIPS_2_MMIO_BASE = 0x53F00000,
AIPS_2_MMIO_SIZE = 0x00004000,
};
};
}
#endif /* _INCLUDE__PLATFORM__BOARD_H_ */

View File

@ -42,11 +42,12 @@ namespace Genode
CORTEX_A9_PRIVATE_MEM_BASE = L4_PER_BASE + 0x240000,
CORTEX_A9_PRIVATE_MEM_SIZE = 0x2000,
CORTEX_A9_CLOCK = MPU_DPLL_CLOCK,
CORTEX_A9_SECURITY_EXTENSION = 0,
/* RAM */
EMIF1_EMIF2_CS0_SDRAM_BASE = 0x80000000,
EMIF1_EMIF2_CS0_SDRAM_SIZE = 0x40000000,
SECURITY_EXTENSION = 0,
};
};
}

View File

@ -42,7 +42,6 @@ namespace Genode
CORTEX_A9_CLOCK = OSC_7_CLOCK * 5,
CORTEX_A9_PRIVATE_MEM_BASE = 0x1f000000,
CORTEX_A9_PRIVATE_MEM_SIZE = 0x01000000,
CORTEX_A9_SECURITY_EXTENSION = 0,
/* UART */
PL011_0_MMIO_BASE = SOUTHBRIDGE_APB_BASE + 0x9000,
@ -54,7 +53,9 @@ namespace Genode
SP804_0_1_MMIO_BASE = SOUTHBRIDGE_APB_BASE + 0x11000,
SP804_0_1_MMIO_SIZE = 4*1024,
SP804_0_1_IRQ = 36,
SP804_0_1_CLOCK = 1*1000*1000,
SP804_0_1_CLOCK = 1000*1000,
SECURITY_EXTENSION = 0,
};
};
}

View File

@ -59,7 +59,6 @@ namespace Genode
CORTEX_A9_PRIVATE_MEM_BASE = 0x1e000000,
CORTEX_A9_PRIVATE_MEM_SIZE = 0x2000,
CORTEX_A9_CLOCK = TCREF_CLOCK,
CORTEX_A9_SECURITY_EXTENSION = 1,
/* RAM */
LOCAL_DDR2_BASE = 0x60000000,
@ -68,6 +67,8 @@ namespace Genode
/* SRAM */
SRAM_BASE = SMB_CS2_BASE,
SRAM_SIZE = 0x01ffffff,
SECURITY_EXTENSION = 1,
};
};
}

18
base/mk/spec-arm_v6.mk Normal file
View File

@ -0,0 +1,18 @@
#
# \brief Build-system configurations for ARMv6
# \author Martin Stein
# \date 2012-09-26
#
# denote wich specs are also fullfilled by this spec
SPECS += arm
# configure compiler
CC_MARCH += -march=armv6
# add repository relative include paths
REP_INC_DIR += include/arm_v6
# include implied specs
include $(call select_from_repositories,mk/spec-arm.mk)

15
base/mk/spec-arm_v7.mk Normal file
View File

@ -0,0 +1,15 @@
#
# \brief Build-system configurations for ARMv7
# \author Martin Stein
# \date 2012-09-26
#
# denote wich specs are also fullfilled by this spec
SPECS += arm
# add repository relative include paths
REP_INC_DIR += include/arm_v7
# include implied specs
include $(call select_from_repositories,mk/spec-arm.mk)

View File

@ -1,10 +1,18 @@
SPECS += arm
#
# \brief Build-system configurations for ARMv7a
# \author Martin Stein
# \date 2012-09-26
#
#
# Configure target CPU
#
# denote wich specs are also fullfilled by this spec
SPECS += arm_v7
# configure compiler
CC_MARCH += -march=armv7-a
# add repository relative include paths
REP_INC_DIR += include/arm_v7a
include $(call select_from_repositories,mk/spec-arm.mk)
# include implied specs
include $(call select_from_repositories,mk/spec-arm_v7.mk)

View File

@ -0,0 +1,15 @@
#
# \brief Build-system configurations for Freescale i.MX31
# \author Martin Stein
# \date 2012-09-26
#
# denote wich specs are also fullfilled by this spec
SPECS += arm_v6
# add repository relative include paths
REP_INC_DIR += include/platform/imx31
# include implied specs
include $(call select_from_repositories,mk/spec-arm_v6.mk)

View File

@ -21,8 +21,6 @@ namespace Genode
{
/**
* Basic driver for the ARM SP804 timer
*
* Uses only timer module 0.
*/
template <unsigned long CLK>
class Sp804_base : public Mmio

View File

@ -152,8 +152,8 @@ namespace Genode {
_load_initrd();
_prepare_atag();
_state->cpsr = 0x93; /* SVC mode and IRQs disabled */
_state->r[1] = 2272; /* MACH_TYPE vexpress board */
_state->r[2] = _ram.base() + ATAG_OFFSET; /* ATAG addr */
_state->r1 = 2272; /* MACH_TYPE vexpress board */
_state->r2 = _ram.base() + ATAG_OFFSET; /* ATAG addr */
_vm_con.exception_handler(sig_cap);
}
@ -168,8 +168,19 @@ namespace Genode {
"data_abort", "irq", "fiq" };
printf("Cpu state:\n");
for (unsigned i = 0; i<13; i++)
printf(" r%x = %08lx\n", i, _state->r[i]);
printf(" r0 = %08lx\n", _state->r0);
printf(" r1 = %08lx\n", _state->r1);
printf(" r2 = %08lx\n", _state->r2);
printf(" r3 = %08lx\n", _state->r3);
printf(" r4 = %08lx\n", _state->r4);
printf(" r5 = %08lx\n", _state->r5);
printf(" r6 = %08lx\n", _state->r6);
printf(" r7 = %08lx\n", _state->r7);
printf(" r8 = %08lx\n", _state->r8);
printf(" r9 = %08lx\n", _state->r9);
printf(" r10 = %08lx\n", _state->r10);
printf(" r11 = %08lx\n", _state->r11);
printf(" r12 = %08lx\n", _state->r12);
printf(" sp = %08lx\n", _state->sp);
printf(" lr = %08lx\n", _state->lr);
printf(" ip = %08lx\n", _state->ip);
@ -220,8 +231,8 @@ namespace Genode {
DVI_MODE = 0xc0b00000
};
uint32_t ctrl = _vm->state()->r[2];
uint32_t data = _vm->state()->r[0];
uint32_t ctrl = _vm->state()->r2;
uint32_t data = _vm->state()->r0;
switch(ctrl) {
case OSC1:
@ -241,25 +252,25 @@ namespace Genode {
void _handle_hypervisor_call()
{
switch (_vm->state()->r[1]) {
switch (_vm->state()->r1) {
case SP810_ENABLE:
_sp810.enable_timer0();
_sp810.enable_timer1();
break;
case CPU_ID:
_vm->state()->r[0] = 0x0c000191; // Coretile A9 ID
_vm->state()->r0 = 0x0c000191; // Coretile A9 ID
break;
case SYS_COUNTER:
_vm->state()->r[0] = _sys.counter();
_vm->state()->r0 = _sys.counter();
break;
case MISC_FLAGS:
_vm->state()->r[0] = _sys.misc_flags();
_vm->state()->r0 = _sys.misc_flags();
break;
case SYS_CTRL:
_sys_ctrl();
break;
case MCI_STATUS:
_vm->state()->r[0] = _sys.mci_status();
_vm->state()->r0 = _sys.mci_status();
break;
default:
PERR("Unknown hypervisor call!");

View File

@ -89,19 +89,19 @@ extern "C" int genode_fetch_register(int regno, unsigned long *reg_content)
} else {
switch((enum reg_index)regno)
{
case R0: *reg_content = thread_state.r[0]; PDBG("R0 = %8lx", *reg_content); return 0;
case R1: *reg_content = thread_state.r[1]; PDBG("R1 = %8lx", *reg_content); return 0;
case R2: *reg_content = thread_state.r[2]; PDBG("R2 = %8lx", *reg_content); return 0;
case R3: *reg_content = thread_state.r[3]; PDBG("R3 = %8lx", *reg_content); return 0;
case R4: *reg_content = thread_state.r[4]; PDBG("R4 = %8lx", *reg_content); return 0;
case R5: *reg_content = thread_state.r[5]; PDBG("R5 = %8lx", *reg_content); return 0;
case R6: *reg_content = thread_state.r[6]; PDBG("R6 = %8lx", *reg_content); return 0;
case R7: *reg_content = thread_state.r[7]; PDBG("R7 = %8lx", *reg_content); return 0;
case R8: *reg_content = thread_state.r[8]; PDBG("R8 = %8lx", *reg_content); return 0;
case R9: *reg_content = thread_state.r[9]; PDBG("R9 = %8lx", *reg_content); return 0;
case R10: *reg_content = thread_state.r[10]; PDBG("R10 = %8lx", *reg_content); return 0;
case R11: *reg_content = thread_state.r[11]; PDBG("FP = %8lx", *reg_content); return 0;
case R12: *reg_content = thread_state.r[12]; PDBG("R12 = %8lx", *reg_content); return 0;
case R0: *reg_content = thread_state.r0; PDBG("R0 = %8lx", *reg_content); return 0;
case R1: *reg_content = thread_state.r1; PDBG("R1 = %8lx", *reg_content); return 0;
case R2: *reg_content = thread_state.r2; PDBG("R2 = %8lx", *reg_content); return 0;
case R3: *reg_content = thread_state.r3; PDBG("R3 = %8lx", *reg_content); return 0;
case R4: *reg_content = thread_state.r4; PDBG("R4 = %8lx", *reg_content); return 0;
case R5: *reg_content = thread_state.r5; PDBG("R5 = %8lx", *reg_content); return 0;
case R6: *reg_content = thread_state.r6; PDBG("R6 = %8lx", *reg_content); return 0;
case R7: *reg_content = thread_state.r7; PDBG("R7 = %8lx", *reg_content); return 0;
case R8: *reg_content = thread_state.r8; PDBG("R8 = %8lx", *reg_content); return 0;
case R9: *reg_content = thread_state.r9; PDBG("R9 = %8lx", *reg_content); return 0;
case R10: *reg_content = thread_state.r10; PDBG("R10 = %8lx", *reg_content); return 0;
case R11: *reg_content = thread_state.r11; PDBG("FP = %8lx", *reg_content); return 0;
case R12: *reg_content = thread_state.r12; PDBG("R12 = %8lx", *reg_content); return 0;
case SP: *reg_content = thread_state.sp; PDBG("SP = %8lx", *reg_content); return 0;
case LR: *reg_content = thread_state.lr; PDBG("LR = %8lx", *reg_content); return 0;
case PC: *reg_content = thread_state.ip; PDBG("PC = %8lx", *reg_content); return 0;