base-hw: Add basic Zynq-7000 support (QEMU)

Ref #1599
This commit is contained in:
Johannes Schlatow 2015-09-02 13:59:31 +02:00 committed by Christian Helmuth
parent 458b4d6fc4
commit 40b31876d2
18 changed files with 655 additions and 90 deletions

View File

@ -0,0 +1,8 @@
#
# \brief Build config for Genodes core process
# \author Johannes Schlatow
# \date 2014-12-15
#
# include less specific configuration
include $(REP_DIR)/lib/mk/zynq/core.inc

View File

@ -0,0 +1,12 @@
#
# \brief Build config for a core that prints hardware information
# \author Johannes Schlatow
# \author Martin Stein
# \date 2011-12-16
#
# add C++ sources
SRC_CC += spec/arm_v7/info.cc
# decrlare source directories
vpath % $(REP_DIR)/src/test/hw_info

View File

@ -0,0 +1,16 @@
#
# \brief Build config for Genodes core process
# \author Johannes Schlatow
# \date 2014-12-15
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/zynq
INC_DIR += $(REP_DIR)/src/core/include/spec/xilinx
# add C++ sources
SRC_CC += platform_services.cc
SRC_CC += spec/zynq/platform_support.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/cortex_a9/core.inc

View File

@ -0,0 +1,18 @@
#
# \brief Offer build configurations that are specific to base-hw and Zynq
# \author Johannes Schlatow
# \date 2014-12-15
#
# denote which specs are also fulfilled by this spec
SPECS += hw platform_zynq
# configure multiprocessor mode
NR_OF_CPUS = 1
# set address where to link the text segment at
LD_TEXT_ADDR ?= 0x00100000
# include implied specs
include $(call select_from_repositories,mk/spec-hw.mk)
include $(call select_from_repositories,mk/spec-platform_zynq.mk)

View File

@ -0,0 +1,100 @@
/*
* \brief L2 outer cache controller ARM PL310
* \author Johannes Schlatow
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2014-06-02
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SPEC__ARM__PL310_H_
#define _SPEC__ARM__PL310_H_
/* Genode includes */
#include <util/mmio.h>
namespace Arm
{
using Genode::addr_t;
class Pl310;
}
/**
* L2 outer cache controller
*/
class Arm::Pl310 : Genode::Mmio
{
protected:
struct Control : Register <0x100, 32>
{
struct Enable : Bitfield<0,1> { };
};
struct Aux : Register<0x104, 32>
{
struct Associativity : Bitfield<16,1> { };
struct Way_size : Bitfield<17,3> { };
struct Share_override : Bitfield<22,1> { };
struct Reserved : Bitfield<25,1> { };
struct Ns_lockdown : Bitfield<26,1> { };
struct Ns_irq_ctrl : Bitfield<27,1> { };
struct Data_prefetch : Bitfield<28,1> { };
struct Inst_prefetch : Bitfield<29,1> { };
struct Early_bresp : Bitfield<30,1> { };
static access_t init_value()
{
access_t v = 0;
Associativity::set(v, 1);
Way_size::set(v, 3);
Share_override::set(v, 1);
Reserved::set(v, 1);
Ns_lockdown::set(v, 1);
Ns_irq_ctrl::set(v, 1);
Data_prefetch::set(v, 1);
Inst_prefetch::set(v, 1);
Early_bresp::set(v, 1);
return v;
}
};
struct Irq_mask : Register <0x214, 32> { };
struct Irq_clear : Register <0x220, 32> { };
struct Cache_sync : Register <0x730, 32> { };
struct Invalidate_by_way : Register <0x77c, 32> { };
struct Clean_invalidate_by_way : Register <0x7fc, 32> { };
inline void _sync() { while (read<Cache_sync>()) ; }
void _init()
{
write<Irq_mask>(0);
write<Irq_clear>(~0);
}
public:
Pl310(addr_t const base) : Mmio(base) { }
void flush()
{
write<Clean_invalidate_by_way>((1 << 16) - 1);
_sync();
}
void invalidate()
{
write<Invalidate_by_way>((1 << 16) - 1);
_sync();
}
};
#endif /* _SPEC__ARM__PL310_H_ */

View File

@ -1,11 +1,12 @@
/*
* \brief Board driver for core on pandaboard
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2014-06-02
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -15,105 +16,69 @@
#define _BOARD_H_
/* core includes */
#include <util/mmio.h>
#include <spec/cortex_a9/board_support.h>
#include <spec/arm/pl310.h>
namespace Genode
{
struct Board : Cortex_a9::Board
{
/**
* L2 outer cache controller
*/
struct Pl310 : Mmio {
class Pl310;
class Board;
}
enum Trustzone_hypervisor_syscalls {
L2_CACHE_SET_DEBUG_REG = 0x100,
L2_CACHE_ENABLE_REG = 0x102,
L2_CACHE_AUX_REG = 0x109,
};
/**
* L2 outer cache controller
*/
class Genode::Pl310 : public Arm::Pl310
{
private:
static inline void
trustzone_hypervisor_call(addr_t func, addr_t val)
{
register addr_t _func asm("r12") = func;
register addr_t _val asm("r0") = val;
asm volatile("dsb; smc #0" :: "r" (_func), "r" (_val)
: "memory", "cc", "r1", "r2", "r3", "r4", "r5",
"r6", "r7", "r8", "r9", "r10", "r11");
}
struct Control : Register <0x100, 32>
{
struct Enable : Bitfield<0,1> {};
};
struct Aux : Register<0x104, 32>
{
struct Associativity : Bitfield<16,1> { };
struct Way_size : Bitfield<17,3> { };
struct Share_override : Bitfield<22,1> { };
struct Reserved : Bitfield<25,1> { };
struct Ns_lockdown : Bitfield<26,1> { };
struct Ns_irq_ctrl : Bitfield<27,1> { };
struct Data_prefetch : Bitfield<28,1> { };
struct Inst_prefetch : Bitfield<29,1> { };
struct Early_bresp : Bitfield<30,1> { };
static access_t init_value()
{
access_t v = 0;
Associativity::set(v, 1);
Way_size::set(v, 3);
Share_override::set(v, 1);
Reserved::set(v, 1);
Ns_lockdown::set(v, 1);
Ns_irq_ctrl::set(v, 1);
Data_prefetch::set(v, 1);
Inst_prefetch::set(v, 1);
Early_bresp::set(v, 1);
return v;
}
};
struct Irq_mask : Register <0x214, 32> {};
struct Irq_clear : Register <0x220, 32> {};
struct Cache_sync : Register <0x730, 32> {};
struct Invalidate_by_way : Register <0x77c, 32> {};
struct Clean_invalidate_by_way : Register <0x7fc, 32> {};
inline void sync() { while (read<Cache_sync>()) ; }
void invalidate()
{
write<Invalidate_by_way>((1 << 16) - 1);
sync();
}
void flush()
{
trustzone_hypervisor_call(L2_CACHE_SET_DEBUG_REG, 0x3);
write<Clean_invalidate_by_way>((1 << 16) - 1);
sync();
trustzone_hypervisor_call(L2_CACHE_SET_DEBUG_REG, 0x0);
}
Pl310(addr_t const base) : Mmio(base)
{
trustzone_hypervisor_call(L2_CACHE_AUX_REG,
Pl310::Aux::init_value());
trustzone_hypervisor_call(L2_CACHE_ENABLE_REG, 1);
write<Irq_mask>(0);
write<Irq_clear>(0xffffffff);
}
enum Secure_monitor_syscalls
{
L2_CACHE_SET_DEBUG_REG = 0x100,
L2_CACHE_ENABLE_REG = 0x102,
L2_CACHE_AUX_REG = 0x109,
};
static inline void _secure_monitor_call(addr_t func, addr_t val)
{
register addr_t _func asm("r12") = func;
register addr_t _val asm("r0") = val;
asm volatile(
"dsb; smc #0" ::
"r" (_func), "r" (_val) :
"memory", "cc", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11");
}
public:
void flush()
{
_secure_monitor_call(L2_CACHE_SET_DEBUG_REG, 0x3);
Arm::Pl310::flush();
_secure_monitor_call(L2_CACHE_SET_DEBUG_REG, 0x0);
}
Pl310(addr_t const base) : Arm::Pl310(base)
{
_secure_monitor_call(L2_CACHE_AUX_REG, Aux::init_value());
_secure_monitor_call(L2_CACHE_ENABLE_REG, 1);
_init();
}
};
/**
* Board driver for core
*/
class Genode::Board : public Cortex_a9::Board
{
public:
static void outer_cache_invalidate();
static void outer_cache_flush();
static void prepare_kernel();
static void secondary_cpus_ip(void * const ip) { }
static bool is_smp() { return true; }
};
}
};
#endif /* _BOARD_H_ */

View File

@ -0,0 +1,44 @@
/*
* \brief Serial output driver for core
* \author Johannes Schlatow
* \date 2014-12-15
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SERIAL_H_
#define _SERIAL_H_
/* core includes */
#include <board.h>
/* Genode includes */
#include <drivers/uart/xilinx_uartps_base.h>
namespace Genode { class Serial; }
/**
* Serial output driver for core
*/
class Genode::Serial : public Xilinx_uartps_base
{
public:
/**
* Constructor
*
* \param baud_rate targeted transfer baud-rate
*/
Serial(unsigned const baud_rate)
:
Xilinx_uartps_base(Board::UART_0_MMIO_BASE,
Board::UART_CLOCK, baud_rate)
{ }
};
#endif /* _SERIAL_H_ */

View File

@ -0,0 +1,53 @@
/*
* \brief Board driver for core on Zynq
* \author Johannes Schlatow
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2014-06-02
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _BOARD_H_
#define _BOARD_H_
/* core includes */
#include <spec/cortex_a9/board_support.h>
#include <spec/arm/pl310.h>
namespace Genode
{
class Pl310;
class Board;
}
/**
* L2 outer cache controller
*/
class Genode::Pl310 : public Arm::Pl310
{
public:
Pl310(addr_t const base) : Arm::Pl310(base) { _init(); }
};
/**
* Board driver for core
*/
class Genode::Board : public Cortex_a9::Board
{
public:
static void outer_cache_invalidate();
static void outer_cache_flush();
static void prepare_kernel();
static void secondary_cpus_ip(void * const ip) { }
static bool is_smp() { return true; }
};
#endif /* _BOARD_H_ */

View File

@ -62,8 +62,8 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
}
static Board::Pl310 * l2_cache() {
return unmanaged_singleton<Board::Pl310>(Board::PL310_MMIO_BASE); }
static Genode::Pl310 * l2_cache() {
return unmanaged_singleton<Genode::Pl310>(Board::PL310_MMIO_BASE); }
void Board::outer_cache_invalidate() { l2_cache()->invalidate(); }

View File

@ -0,0 +1,75 @@
/*
* \brief Platform implementations specific for base-hw and Zynq
* \author Johannes Schlatow
* \date 2014-12-15
*/
/*
* Copyright (C) 2012-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <platform.h>
#include <board.h>
#include <cpu.h>
#include <pic.h>
#include <unmanaged_singleton.h>
using namespace Genode;
Native_region * Platform::_ram_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Board::RAM_0_BASE, Board::RAM_0_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Board::MMIO_0_BASE, Board::MMIO_0_SIZE },
{ Board::MMIO_1_BASE, Board::MMIO_1_SIZE },
{ Board::QSPI_MMIO_BASE, Board::QSPI_MMIO_SIZE },
{ Board::OCM_MMIO_BASE, Board::OCM_MMIO_SIZE },
{ Board::AXI_0_MMIO_BASE, Board::AXI_0_MMIO_SIZE },
{ Board::AXI_1_MMIO_BASE, Board::AXI_1_MMIO_SIZE }
};
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 timer and PIC */
{ Board::CORTEX_A9_PRIVATE_MEM_BASE,
Board::CORTEX_A9_PRIVATE_MEM_SIZE },
/* core UART */
{ Board::UART_0_MMIO_BASE, Board::UART_SIZE },
/* L2 cache controller */
{ Board::PL310_MMIO_BASE, Board::PL310_MMIO_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }
static Genode::Pl310 * l2_cache() {
return unmanaged_singleton<Genode::Pl310>(Board::PL310_MMIO_BASE); }
void Genode::Board::outer_cache_invalidate() { l2_cache()->invalidate(); }
void Genode::Board::outer_cache_flush() { l2_cache()->flush(); }
void Genode::Board::prepare_kernel() { l2_cache()->invalidate(); }

View File

@ -0,0 +1,129 @@
/*
* \brief Base UART driver for the Xilinx UART PS used on Zynq devices
* \author Johannes Schlatow
* \date 2014-12-15
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__DRIVERS__UART__XILINX_UARTPS_BASE_H_
#define _INCLUDE__DRIVERS__UART__XILINX_UARTPS_BASE_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode { class Xilinx_uartps_base; }
/**
* Base driver Xilinx UART PS module
*/
class Genode::Xilinx_uartps_base : public Mmio
{
protected:
/**
* Control register
*/
struct Uart_cr : Register<0x00, 32>
{
struct Rx_reset : Bitfield<0, 1> { };
struct Tx_reset : Bitfield<1, 1> { };
struct Rx_enable : Bitfield<2, 1> { };
struct Tx_enable : Bitfield<4, 1> { };
};
/**
* Mode register
*/
struct Uart_mr : Register<0x04, 32>
{
struct Clock_sel : Bitfield<0, 1> { };
struct Parity : Bitfield<3, 3> { enum { NO_PARITY = 4 }; };
};
/**
* Baudgen register
*/
struct Uart_baudgen : Register<0x18, 32>
{
struct Clock_div : Bitfield<0, 16> { };
};
/**
* Status register
*/
struct Uart_sr : Register<0x2C, 32>
{
struct Tx_full : Bitfield<4, 1> { };
};
/**
* FIFO register
*/
struct Uart_fifo : Register<0x30, 32>
{
struct Data : Bitfield<0, 8> { };
};
/**
* Bauddiv register
*/
struct Uart_bauddiv : Register<0x34, 32>
{
struct Bdiv : Bitfield<0,8> { };
};
public:
/**
* Constructor
*
* \param base MMIO base address
* \param clock reference clock
* \param baud_rate targeted baud rate
*/
Xilinx_uartps_base(addr_t const base, unsigned long const clock,
unsigned long const baud_rate) : Mmio(base)
{
/* reset UART */
Uart_cr::access_t uart_cr = 0;
Uart_cr::Tx_reset::set(uart_cr, 1);
Uart_cr::Rx_reset::set(uart_cr, 1);
write<Uart_cr>(uart_cr);
/* set baud rate */
constexpr unsigned div = 4;
write<Uart_bauddiv::Bdiv>(div);
write<Uart_baudgen::Clock_div>(clock / baud_rate / (div + 1));
/* set 8N1 */
Uart_mr::access_t uart_mr = 0;
Uart_mr::Parity::set(uart_mr, Uart_mr::Parity::NO_PARITY);
write<Uart_mr>(uart_mr);
/* enable */
uart_cr = 0;
Uart_cr::Rx_enable::set(uart_cr, 1);
Uart_cr::Tx_enable::set(uart_cr, 1);
write<Uart_cr>(uart_cr);
}
/**
* Transmit ASCII char 'c'
*/
void put_char(char const c)
{
/* wait as long as the transmission buffer is full */
while (read<Uart_sr::Tx_full>()) ;
/* transmit character */
write<Uart_fifo::Data>(c);
}
};
#endif /* _INCLUDE__DRIVERS__UART__XILINX_UARTPS_BASE_H_ */

View File

@ -0,0 +1,38 @@
/*
* \brief Base driver for the Zynq (QEMU)
* \author Johannes Schlatow
* \date 2015-06-30
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__PLATFORM__DRIVERS__BOARD_BASE_H_
#define _INCLUDE__PLATFORM__DRIVERS__BOARD_BASE_H_
#include <zynq/drivers/board_base.h>
namespace Genode { struct Board_base; }
/**
* Base driver for the Zynq platform
*/
struct Genode::Board_base : Zynq::Board_base
{
enum
{
/* clocks (assuming 6:2:1 mode) */
CPU_1X_CLOCK = 111111115,
CPU_6X4X_CLOCK = 6 * CPU_1X_CLOCK,
/* CPU */
CORTEX_A9_CLOCK = CPU_6X4X_CLOCK,
CORTEX_A9_PRIVATE_TIMER_CLK = CORTEX_A9_CLOCK,
};
};
#endif /* _INCLUDE__PLATFORM__DRIVERS__BOARD_BASE_H_ */

View File

@ -0,0 +1,77 @@
/*
* \brief Base driver for Xilinx Zynq platforms
* \author Mark Albers
* \author Timo Wischer
* \author Johannes Schlatow
* \date 2014-12-15
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__DRIVERS__BOARD_BASE_H_
#define _INCLUDE__DRIVERS__BOARD_BASE_H_
namespace Zynq { struct Board_base; }
/**
* Base driver for the Zynq platform
*/
struct Zynq::Board_base
{
enum
{
/* device IO memory */
MMIO_0_BASE = 0xe0000000, /* IOP devices */
MMIO_0_SIZE = 0x10000000,
MMIO_1_BASE = 0xF8000000, /* Programmable register via APB */
MMIO_1_SIZE = 0x02000000,
QSPI_MMIO_BASE = 0xFC000000, /* Quad-SPI */
QSPI_MMIO_SIZE = 0x01000000,
OCM_MMIO_BASE = 0xFFFC0000, /* OCM upper address range */
OCM_MMIO_SIZE = 0x00040000,
/* normal RAM */
RAM_0_BASE = 0x00000000,
RAM_0_SIZE = 0x40000000, /* 1GiB */
/* AXI */
AXI_0_MMIO_BASE = 0x40000000, /* PL AXI Slave port #0 */
AXI_0_MMIO_SIZE = 0x40000000,
AXI_1_MMIO_BASE = 0x80000000, /* PL AXI Slave port #1 */
AXI_1_MMIO_SIZE = 0x40000000,
/* UART controllers */
UART_0_MMIO_BASE = MMIO_0_BASE,
UART_SIZE = 0x1000,
UART_CLOCK = 50*1000*1000,
/* CPU */
CORTEX_A9_PRIVATE_MEM_BASE = 0xf8f00000,
CORTEX_A9_PRIVATE_MEM_SIZE = 0x00002000,
/* CPU cache */
PL310_MMIO_BASE = MMIO_1_BASE + 0xF02000,
PL310_MMIO_SIZE = 0x1000,
CACHE_LINE_SIZE_LOG2 = 2, /* FIXME get correct value from board spec */
/* TTC (triple timer counter) */
TTC0_MMIO_BASE = MMIO_1_BASE + 0x1000,
TTC0_MMIO_SIZE = 0xfff,
TTC0_IRQ_0 = 42,
/* Ethernet MAC PS */
EMAC_0_MMIO_BASE = 0xE000B000,
EMAC_0_MMIO_SIZE = 0x1000,
EMAC_0_IRQ = 54,
/* wether board provides security extension */
SECURITY_EXTENSION = 0,
};
};
#endif /* _INCLUDE__DRIVERS__BOARD_BASE_H_ */

View File

@ -0,0 +1,9 @@
#
# Pull in CPU specifics
#
SPECS += zynq cadence_gem
REP_INC_DIR += include/platform/zynq_qemu
include $(call select_from_repositories,mk/spec-zynq.mk)

View File

@ -0,0 +1,6 @@
#
# Pull in CPU specifics
#
SPECS += cortex_a9 arm_v7a
include $(call select_from_repositories,mk/spec-cortex_a9.mk)

View File

@ -0,0 +1,7 @@
REPOSITORIES += $(GENODE_DIR)/repos/base-hw
##
## Kernel-specific run tool configuration
##
RUN_OPT = --include boot_dir/hw --include power_on/qemu --include log/qemu

View File

@ -36,6 +36,7 @@ usage:
@echo " 'hw_arndale'"
@echo " 'hw_odroid_xu'"
@echo " 'hw_rpi'"
@echo " 'hw_zynq'"
@echo " 'hw_x86_64'"
@echo " 'hw_x86_64_muen'"
@echo " 'foc_x86_32'"
@ -252,6 +253,9 @@ hw_rpi::
@echo "SPECS = genode hw_rpi" > $(BUILD_DIR)/etc/specs.conf
@echo "SPECS += perf_counter" >> $(BUILD_DIR)/etc/specs.conf
hw_zynq::
@echo "SPECS = genode hw_zynq" > $(BUILD_DIR)/etc/specs.conf
hw_odroid_xu::
@echo "SPECS = genode hw_odroid_xu" > $(BUILD_DIR)/etc/specs.conf
@echo "SPECS += perf_counter" >> $(BUILD_DIR)/etc/specs.conf

View File

@ -50,11 +50,15 @@ proc run_power_on { } {
append qemu_args " -M realview-pbx-a9"
}
if {[have_spec platform_vpb926]} { append qemu_args " -M versatilepb -m 128 " }
if {[have_spec platform_zynq]} { append qemu_args " -M xilinx-zynq-a9 -cpu cortex-a9 -m 256 " }
if {[have_spec hw_x86_64]} {
regsub -all {\-m ([0-9])+} $qemu_args "" qemu_args
append qemu_args " -m 512 "
}
# add devices for specific platforms
if {[have_spec platform_zynq] && [have_spec cadence_gem]} { append qemu_args " -net nic,model=cadence_gem" }
# on x86, we support booting via pxe or iso/disk image
if {[have_spec x86]} {
if {[have_include "load/tftp"]} {