kernel: add support for Raspberry Pi 2 and 3

Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr>
Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
This commit is contained in:
Jean-Baptiste Boric
2016-05-29 13:02:32 +02:00
parent c5e7db6fac
commit 61569864b0
25 changed files with 1191 additions and 4 deletions

1
.gitignore vendored
View File

@@ -9,6 +9,7 @@ cscope.*
*.rej
*.[1-9].gz
*.o
*.elf
*.[psS]o
*.pico
lib*.so*

View File

@@ -3,7 +3,7 @@ set -e
exec >/dev/log
exec 2>/dev/log
exec </dev/null
exec </dev/console
FSCK=/bin/fsck_mfs
ACPI=/service/acpi
@@ -45,6 +45,12 @@ then if [ -e $ACPI -a -n "`sysenv acpi`" ]
/bin/umount /proc >/dev/null
fi
# XXX: We don't have anything better to do on Raspberry Pi yet
if [ "$(/bin/sysenv board_name)" = "RPI_2_B" ] || [ "$(/bin/sysenv board_name)" = "RPI_3_B" ]
then
exec /bin/sh < /dev/console
fi
if [ X`/bin/sysenv arch` = Xearm ]
then echo Starting the mmc driver
/bin/service -c up /service/mmc -dev /dev/c0d0
@@ -88,7 +94,7 @@ fi
echo "Root device name is $rootdevname"
if ! sysenv cdproberoot >/dev/null
if (! sysenv cdproberoot) && (! sysenv bootramdisk) >/dev/null
then
if [ -e $FSCK ]
then $FSCK -p $rootdevname

View File

@@ -3,6 +3,6 @@
#ifndef _INTERRUPT_H
#define _INTERRUPT_H
#define NR_IRQ_VECTORS 125
#define NR_IRQ_VECTORS 128
#endif /* _INTERRUPT_H */

View File

@@ -67,12 +67,15 @@
#define MINIX_BOARD_VENDOR_INTEL MINIX_MK_BOARD_VENDOR(1<<0)
#define MINIX_BOARD_VENDOR_TI MINIX_MK_BOARD_VENDOR(1<<1)
#define MINIX_BOARD_VENDOR_RPI MINIX_MK_BOARD_VENDOR(1<<2)
#define MINIX_BOARD_GENERIC MINIX_MK_BOARD(1<<0)
/* BeagleBoard XM */
#define MINIX_BOARD_BBXM MINIX_MK_BOARD(1<<1)
/* BeagleBone (Black and* white) */
#define MINIX_BOARD_BB MINIX_MK_BOARD(1<<2)
/* Raspberry Pi */
#define MINIX_BOARD_RPI MINIX_MK_BOARD(1<<3)
/* Only one of a kind */
#define MINIX_BOARD_VARIANT_GENERIC MINIX_MK_BOARD_VARIANT(1<<0)
@@ -81,6 +84,10 @@
/* BeagleBone Black */
#define MINIX_BOARD_VARIANT_BBB MINIX_MK_BOARD_VARIANT(1<<2)
/* Rasberry Pi */
#define MINIX_BOARD_VARIANT_RPI_2_B MINIX_MK_BOARD_VARIANT(1<<1)
#define MINIX_BOARD_VARIANT_RPI_3_B MINIX_MK_BOARD_VARIANT(1<<2)
#define BOARD_ID_INTEL \
( MINIX_BOARD_ARCH_X86 \
| MINIX_BOARD_ARCH_VARIANT_X86_GENERIC \
@@ -113,6 +120,22 @@
| MINIX_BOARD_VARIANT_BBB\
)
#define BOARD_ID_RPI_2_B \
( MINIX_BOARD_ARCH_ARM \
| MINIX_BOARD_ARCH_VARIANT_ARM_ARMV7 \
| MINIX_BOARD_VENDOR_RPI \
| MINIX_BOARD_RPI \
| MINIX_BOARD_VARIANT_RPI_2_B \
)
#define BOARD_ID_RPI_3_B \
( MINIX_BOARD_ARCH_ARM \
| MINIX_BOARD_ARCH_VARIANT_ARM_ARMV7 \
| MINIX_BOARD_VENDOR_RPI \
| MINIX_BOARD_RPI \
| MINIX_BOARD_VARIANT_RPI_3_B \
)
#define BOARD_IS_BBXM(v) \
( (BOARD_ID_BBXM & ~MINIX_BOARD_VARIANT_MASK) == (v & ~MINIX_BOARD_VARIANT_MASK))
/* Either one of the known BeagleBones */
@@ -121,6 +144,9 @@
#define BOARD_IS_BBW(v) ( v == BOARD_ID_BBW)
#define BOARD_IS_BBB(v) ( v == BOARD_ID_BBB)
#define BOARD_IS_RPI_2_B(v) ( v == BOARD_ID_RPI_2_B)
#define BOARD_IS_RPI_3_B(v) ( v == BOARD_ID_RPI_3_B)
#define BOARD_FILTER_BBXM_VALUE (BOARD_ID_BBXM)
#define BOARD_FILTER_BBXM_MASK \
(MINIX_BOARD_ARCH_MASK \
@@ -148,6 +174,8 @@ static struct shortname2id shortname2id[] = {
{.name = "BBXM",.id = BOARD_ID_BBXM},
{.name = "A335BONE",.id = BOARD_ID_BBW},
{.name = "A335BNLT",.id = BOARD_ID_BBB},
{.name = "RPI_2_B",.id = BOARD_ID_RPI_2_B},
{.name = "RPI_3_B",.id = BOARD_ID_RPI_3_B},
};
struct board_id2name
@@ -162,6 +190,8 @@ static struct board_id2name board_id2name[] = {
{.id = BOARD_ID_BBXM,.name = "ARM-ARMV7-TI-BBXM-GENERIC"},
{.id = BOARD_ID_BBW,.name = "ARM-ARMV7-TI-BB-WHITE"},
{.id = BOARD_ID_BBB,.name = "ARM-ARMV7-TI-BB-BLACK"},
{.id = BOARD_ID_RPI_2_B,.name = "ARM-ARMV7-RPI-RPI_2_B"},
{.id = BOARD_ID_RPI_3_B,.name = "ARM-ARMV7-RPI-RPI_3_B"},
};
struct board_arch2arch

View File

@@ -319,4 +319,9 @@
#define CONTROL_CONF_PUDEN (1<<3)
#define CONTROL_CONF_MUXMODE(X) (X&0x7)
/* Raspberry Pi specific registers */
#define PADCONF_RPI2_REGISTERS_BASE 0x3F200000
#define PADCONF_RPI2_REGISTERS_OFFSET 0x0000
#define PADCONF_RPI2_REGISTERS_SIZE 0x1000
#endif /* __MINIX_PADCONF_H */

View File

@@ -24,6 +24,7 @@
#include "bsp_timer.h"
#include "bsp_intr.h"
#include "cpufunc_timer.h"
static unsigned tsc_per_ms[CONFIG_MAX_CPUS];
static unsigned tsc_per_tick[CONFIG_MAX_CPUS];
@@ -37,7 +38,11 @@ int init_local_timer(unsigned freq)
tsc_per_ms[0] = 16250;
} else if (BOARD_IS_BB(machine.board_id)) {
tsc_per_ms[0] = 15000;
} else {
} else if (BOARD_IS_RPI_2_B(machine.board_id) ||
BOARD_IS_RPI_3_B(machine.board_id)) {
tsc_per_ms[0] = read_cntfrq() / 1000;
}
else {
panic("Can not do the clock setup. machine (0x%08x) is unknown\n",machine.board_id);
};

View File

@@ -0,0 +1,12 @@
#
# BSP for RPI hardware
#
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/bsp/${BSP_NAME}
.for unpaged_obj in rpi_serial.o rpi_reset.o
BSP_OBJS_UNPAGED += ${unpaged_obj}
.endfor
SRCS+= rpi_init.c rpi_serial.c rpi_timer.c rpi_padconf.c rpi_intr.c \
rpi_reset.c

View File

@@ -0,0 +1,17 @@
#include <sys/types.h>
#include "bsp_init.h"
#include "bsp_padconf.h"
#include "bsp_reset.h"
void
bsp_init()
{
/* map memory for padconf */
bsp_padconf_init();
/* map memory for reset control */
bsp_reset_init();
/* disable watchdog */
bsp_disable_watchdog();
}

View File

@@ -0,0 +1,140 @@
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/type.h>
#include <minix/board.h>
#include <io.h>
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include "kernel/proto.h"
#include "arch_proto.h"
#include "hw_intr.h"
#include "rpi_intr_registers.h"
#include "rpi_timer_registers.h"
static struct rpi2_intr
{
vir_bytes base;
vir_bytes core_base;
int size;
} rpi2_intr;
static kern_phys_map intr_phys_map;
static kern_phys_map timer_phys_map;
static irq_hook_t dummy8_irq_hook;
static irq_hook_t dummy41_irq_hook;
static irq_hook_t dummy51_irq_hook;
int
dummy_irq_handler()
{
/*
* The Raspberry Pi has a bunch of cascaded interrupts that are useless
* for MINIX. This handler catches them so as not to pollute the console
* with spurious interrupts messages.
*/
return 0;
}
int
intr_init(const int auto_eoi)
{
if (BOARD_IS_RPI_2_B(machine.board_id) ||
BOARD_IS_RPI_3_B(machine.board_id)) {
rpi2_intr.base = RPI2_INTR_BASE;
rpi2_intr.core_base = RPI2_QA7_BASE;
} else {
panic
("Can not do the interrupt setup. machine (0x%08x) is unknown\n",
machine.board_id);
}
rpi2_intr.size = 0x1000; /* 4K */
kern_phys_map_ptr(rpi2_intr.base, rpi2_intr.size,
VMMF_UNCACHED | VMMF_WRITE,
&intr_phys_map, (vir_bytes) & rpi2_intr.base);
kern_phys_map_ptr(rpi2_intr.core_base, rpi2_intr.size,
VMMF_UNCACHED | VMMF_WRITE,
&timer_phys_map, (vir_bytes) & rpi2_intr.core_base);
/* Disable FIQ and all interrupts */
mmio_write(rpi2_intr.base + RPI2_INTR_FIQ_CTRL, 0);
mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE_BASIC, 0xFFFFFFFF);
mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE1, 0xFFFFFFFF);
mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE2, 0xFFFFFFFF);
/* Enable ARM timer routing to IRQ here */
mmio_write(rpi2_intr.core_base + QA7_CORE0TIMER, 0x8);
/* Register dummy irq handlers */
put_irq_handler(&dummy8_irq_hook, 8, (irq_handler_t)dummy_irq_handler);
put_irq_handler(&dummy41_irq_hook, 41, (irq_handler_t)dummy_irq_handler);
put_irq_handler(&dummy51_irq_hook, 51, (irq_handler_t)dummy_irq_handler);
return 0;
}
void
bsp_irq_handle(void)
{
/* Function called from assembly to handle interrupts */
uint32_t irq_0_31 = mmio_read(rpi2_intr.core_base + QA7_CORE0INT);
uint32_t irq_32_63 = mmio_read(rpi2_intr.base + RPI2_INTR_BASIC_PENDING);
uint32_t irq_64_95 = mmio_read(rpi2_intr.base + RPI2_INTR_PENDING1);
uint64_t irq_96_128 = mmio_read(rpi2_intr.base + RPI2_INTR_PENDING2);
int irq = 0;
/* Scan all interrupts bits */
for (irq = 0; irq < 128; irq++) {
int is_pending = 0;
if (irq < 32)
is_pending = irq_0_31 & (1 << irq);
else if (irq < 64)
is_pending = irq_32_63 & (1 << (irq-32));
else if (irq < 96)
is_pending = irq_64_95 & (1 << (irq-64));
else
is_pending = irq_96_128 & (1 << (irq-96));
if (is_pending)
irq_handle(irq);
}
/* Clear all pending interrupts */
mmio_write(rpi2_intr.base + RPI2_INTR_BASIC_PENDING, irq_32_63);
mmio_write(rpi2_intr.base + RPI2_INTR_PENDING1, irq_64_95);
mmio_write(rpi2_intr.base + RPI2_INTR_PENDING2, irq_96_128);
}
void
bsp_irq_unmask(int irq)
{
if (irq < 32)
/* Nothing to do */
;
else if (irq < 64)
mmio_write(rpi2_intr.base + RPI2_INTR_ENABLE_BASIC, 1 << (irq-32));
else if (irq < 96)
mmio_write(rpi2_intr.base + RPI2_INTR_ENABLE1, 1 << (irq-64));
else if (irq < 128)
mmio_write(rpi2_intr.base + RPI2_INTR_ENABLE2, 1 << (irq-96));
}
void
bsp_irq_mask(const int irq)
{
if (irq < 32)
/* Nothing to do */
;
else if (irq < 64)
mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE_BASIC, 1 << (irq-32));
else if (irq < 96)
mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE1, 1 << (irq-64));
else if (irq < 128)
mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE2, 1 << (irq-96));
}

View File

@@ -0,0 +1,17 @@
#ifndef _RPI_INTR_H
#define _RPI_INTR_H
#define RPI2_INTR_BASE 0x3f00B000
#define RPI2_INTR_BASIC_PENDING 0x200
#define RPI2_INTR_PENDING1 0x204
#define RPI2_INTR_PENDING2 0x208
#define RPI2_INTR_FIQ_CTRL 0x20c
#define RPI2_INTR_ENABLE1 0x210
#define RPI2_INTR_ENABLE2 0x214
#define RPI2_INTR_ENABLE_BASIC 0x218
#define RPI2_INTR_DISABLE1 0x21c
#define RPI2_INTR_DISABLE2 0x220
#define RPI2_INTR_DISABLE_BASIC 0x224
#endif /* _RPI_INTR_H */

View File

@@ -0,0 +1,58 @@
/* Implements sys_padconf() for the Raspberry Pi. */
#include "kernel/kernel.h"
#include "arch_proto.h"
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/mmio.h>
#include <minix/padconf.h>
#include <minix/board.h>
#include <minix/com.h>
#include <assert.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include "bsp_padconf.h"
struct rpi2_padconf
{
vir_bytes base;
vir_bytes offset;
vir_bytes size;
};
static struct rpi2_padconf rpi2_padconf;
static kern_phys_map padconf_phys_map;
int
bsp_padconf_set(u32_t padconf, u32_t mask, u32_t value)
{
/* check that the value will be inside the padconf memory range */
if (padconf >= (rpi2_padconf.size - rpi2_padconf.offset)) {
return EINVAL; /* outside of valid range */
}
set32(padconf + rpi2_padconf.base + rpi2_padconf.offset, mask,
value);
return OK;
}
void
bsp_padconf_init(void)
{
if (BOARD_IS_RPI_2_B(machine.board_id) ||
BOARD_IS_RPI_3_B(machine.board_id)) {
rpi2_padconf.base = PADCONF_RPI2_REGISTERS_BASE;
rpi2_padconf.offset = PADCONF_RPI2_REGISTERS_OFFSET;
rpi2_padconf.size = PADCONF_RPI2_REGISTERS_SIZE;
}
kern_phys_map_ptr(rpi2_padconf.base, rpi2_padconf.size,
VMMF_UNCACHED | VMMF_WRITE,
&padconf_phys_map, (vir_bytes) & rpi2_padconf.base);
return;
}

View File

@@ -0,0 +1,33 @@
#include <assert.h>
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/type.h>
#include <minix/board.h>
#include <io.h>
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include "kernel/proto.h"
#include "arch_proto.h"
#include "bsp_reset.h"
void
bsp_reset_init(void)
{
}
void
bsp_reset(void)
{
}
void
bsp_poweroff(void)
{
}
void bsp_disable_watchdog(void)
{
}

View File

@@ -0,0 +1,95 @@
#include <assert.h>
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/type.h>
#include <minix/board.h>
#include <io.h>
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include "kernel/proto.h"
#include "arch_proto.h"
#include "rpi_serial.h"
struct pl011_serial
{
vir_bytes base;
vir_bytes size;
};
static struct pl011_serial pl011_serial = {
.base = 0,
};
static kern_phys_map serial_phys_map;
/*
* In kernel serial for the RPi. The serial driver like most other
* drivers needs to be started early and even before the MMU is turned on.
* We start by directly accessing the hardware memory address. Later on
* when the MMU is turned on we still use a 1:1 mapping for these addresses.
*
* Pretty soon we are going to remap these addresses at later stage. And this
* requires us to use a dynamic base address. The idea is to receive a callback
* from VM with the new address to use.
*
* The serial driver also gets used in the "pre_init" stage before the kernel is loaded
* in high memory so keep in mind there are two copies of this code in the kernel.
*/
void
bsp_ser_init()
{
if (BOARD_IS_RPI_2_B(machine.board_id) ||
BOARD_IS_RPI_3_B(machine.board_id)) {
pl011_serial.base = RPI2_PL011_DEBUG_UART_BASE;
}
pl011_serial.size = 0x1000; /* 4k */
kern_phys_map_ptr(pl011_serial.base, pl011_serial.size,
VMMF_UNCACHED | VMMF_WRITE, &serial_phys_map,
(vir_bytes) & pl011_serial.base);
assert(pl011_serial.base);
/* Set UART to 115200 bauds */
if (BOARD_IS_RPI_2_B(machine.board_id)) {
/* UARTCLK=48MHz */
mmio_write(pl011_serial.base + PL011_IBRD, 1);
mmio_write(pl011_serial.base + PL011_FBRD, 40);
}
else if (BOARD_IS_RPI_3_B(machine.board_id)) {
/* UARTCLK=3MHz */
mmio_write(pl011_serial.base + PL011_IBRD, 26);
mmio_write(pl011_serial.base + PL011_FBRD, 3);
}
mmio_write(pl011_serial.base + PL011_LCRH, 0x70);
mmio_write(pl011_serial.base + PL011_CR, 0x301);
}
void
bsp_ser_putc(char c)
{
int i;
assert(pl011_serial.base);
/* Wait until FIFO's not full */
for (i = 0; i < 100000; i++) {
if ((mmio_read(pl011_serial.base + PL011_FR) & PL011_FR_TXFF) == 0) {
break;
}
}
/* Write character */
mmio_write(pl011_serial.base + PL011_DR, c);
/* And wait again until FIFO's empty to prevent TTY from overwriting */
for (i = 0; i < 100000; i++) {
if (mmio_read(pl011_serial.base + PL011_FR) & PL011_FR_TXFE) {
break;
}
}
}

View File

@@ -0,0 +1,23 @@
#ifndef _RPI_SERIAL_H
#define _RPI_SERIAL_H
#define RPI2_PL011_DEBUG_UART_BASE 0x3f201000
#define PL011_DR 0x0
#define PL011_FR 0x18
#define PL011_IBRD 0x24
#define PL011_FBRD 0x28
#define PL011_LCRH 0x2c
#define PL011_CR 0x30
#define PL011_FR_TXFF (1<<5)
#define PL011_FR_TXFE (1<<7)
#ifndef __ASSEMBLY__
void bsp_ser_init();
void bsp_ser_putc(char c);
#endif /* __ASSEMBLY__ */
#endif /* _RPI_SERIAL_H */

View File

@@ -0,0 +1,85 @@
#include "kernel/kernel.h"
#include "kernel/clock.h"
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/board.h>
#include <minix/mmio.h>
#include <assert.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include "arch_proto.h"
#include "bsp_timer.h"
#include "rpi_timer_registers.h"
#include "rpi_intr_registers.h"
#include "bsp_intr.h"
#include "cpufunc_timer.h"
static irq_hook_t arm_timer_hook;
struct arm_timer
{
int irq_nr;
u32_t freq;
};
static struct arm_timer arm_timer = {
.irq_nr = RPI2_IRQ_ARMTIMER,
.freq = 0,
};
static kern_phys_map stc_timer_phys_map;
int
bsp_register_timer_handler(const irq_handler_t handler)
{
/* Initialize the CLOCK's interrupt hook. */
arm_timer_hook.proc_nr_e = NONE;
arm_timer_hook.irq = arm_timer.irq_nr;
put_irq_handler(&arm_timer_hook, arm_timer.irq_nr, handler);
/* Prepare next firing of timer */
bsp_timer_int_handler();
/* only unmask interrupts after registering */
bsp_irq_unmask(arm_timer.irq_nr);
return 0;
}
/* callback for when the free running clock gets mapped */
int
kern_phys_fr_user_mapped(vir_bytes id, phys_bytes address)
{
return 0;
}
void
bsp_timer_init(unsigned freq)
{
arm_timer.freq = freq;
}
void
bsp_timer_stop()
{
bsp_irq_mask(arm_timer.irq_nr);
}
void
bsp_timer_int_handler()
{
/* Arm next timer countdown and enable timer */
write_cntv_cval(-1);
write_cntv_tval(read_cntfrq() / arm_timer.freq);
write_cntv_ctl(ARMTIMER_ENABLE);
}
/* Use the free running clock as TSC */
void
read_tsc_64(u64_t * t)
{
*t = read_cntv_cval();
}

View File

@@ -0,0 +1,11 @@
#ifndef _RPI_TIMER_REGISTERS_H
#define _RPI_TIMER_REGISTERS_H
#define RPI2_QA7_BASE 0x40000000
#define QA7_CORE0TIMER 0x40
#define QA7_CORE0INT 0x60
#define RPI2_IRQ_ARMTIMER 3
#endif /* _RPI_TIMER_REGISTERS_H */

View File

@@ -0,0 +1,67 @@
#ifndef _ARM_CPUFUNC_TIMER_H
#define _ARM_CPUFUNC_TIMER_H
/* Read CNTFRQ */
static inline u32_t read_cntfrq() {
u32_t cntfrq;
asm volatile("mrc p15, 0, %[cntfrq], c14, c0 , 0 @ READ CNTFRQ\n\t"
: [cntfrq] "=r" (cntfrq));
return cntfrq;
}
/* Read CNTV_TVAL, virtual timer value register */
static inline i32_t read_cntv_tval() {
i32_t cntv_tval;
asm volatile("mrc p15, 0, %[cntv_tval], c14, c3 , 0 @ READ CNTV_TVAL\n\t"
: [cntv_tval] "=r" (cntv_tval));
return cntv_tval;
}
/* write CNTV_TVAL, virtual timer control register */
static inline void write_cntv_tval(i32_t val) {
asm volatile("mcr p15, 0, %[val], c14, c3 , 0 @ WRITE CNTV_CTL\n\t"
: : [val] "r" (val));
}
/* Read CNTV_CTL, virtual timer control register */
static inline u32_t read_cntv_ctl() {
u32_t cntv_ctl;
asm volatile("mrc p15, 0, %[cntv_ctl], c14, c3 , 1 @ READ CNTV_CTL\n\t"
: [cntv_ctl] "=r" (cntv_ctl));
return cntv_ctl;
}
/* write CNTV_CTL, virtual timer control register */
static inline void write_cntv_ctl(u32_t val) {
asm volatile("mcr p15, 0, %[val], c14, c3 , 1 @ WRITE CNTV_CTL\n\t"
: : [val] "r" (val));
}
/* Read CNTV_CVAL, virtual timer compare value register */
static inline u64_t read_cntv_cval() {
u32_t cntv_cval_lo, cntv_cval_hi;
asm volatile("mrrc p15, 3, %[cntv_cval_lo], %[cntv_cval_hi], c14 @ READ CNTV_CVAL\n\t"
: [cntv_cval_lo] "=r" (cntv_cval_lo), [cntv_cval_hi] "=r" (cntv_cval_hi));
return ((u64_t)cntv_cval_hi) << 32 | cntv_cval_lo;
}
/* Write CNTV_CVAL, virtual timer compare value register */
static inline void write_cntv_cval(u64_t val) {
u32_t cntv_cval_lo = val & 0xFFFFFFFF, cntv_cval_hi = val >> 32;
asm volatile("mcrr p15, 3, %[cntv_cval_lo], %[cntv_cval_hi], c14 @ WRITE CNTV_CVAL\n\t"
: : [cntv_cval_lo] "r" (cntv_cval_lo), [cntv_cval_hi] "r" (cntv_cval_hi));
}
/* Read CNTVCT, virtual count register */
static inline u64_t read_cntvct() {
u32_t cntvct_lo, cntvct_hi;
asm volatile("mrrc p15, 1, %[cntvct_lo], %[cntvct_hi], c14 @ READ CNTVCT\n\t"
: [cntvct_lo] "=r" (cntvct_lo), [cntvct_hi] "=r" (cntvct_hi));
return ((u64_t)cntvct_hi) << 32 | cntvct_lo;
}
#define ARMTIMER_ENABLE 0x1
#define ARMTIMER_IMASK 0x2
#define ARMTIMER_ISTATUS 0x4
#endif /* _ARM_CPUFUNC_TIMER_H */

View File

@@ -0,0 +1,50 @@
OUTPUT_ARCH("arm")
ENTRY(__k_unpaged_MINIX)
_kern_phys_base = 0x00200000; /* phys 4MB aligned for convenient remapping */
_kern_vir_base = 0xF0400000; /* map kernel high for max. user vir space */
_kern_offset = (_kern_vir_base - _kern_phys_base);
__k_unpaged__kern_offset = _kern_offset;
__k_unpaged__kern_vir_base = _kern_vir_base;
__k_unpaged__kern_phys_base = _kern_phys_base;
SECTIONS
{
. = _kern_phys_base;
__k_unpaged__kern_unpaged_start = .;
.unpaged_text ALIGN(4096) : { unpaged_*.o(.startup); unpaged_*.o(.text) }
.unpaged_data ALIGN(4096) : { unpaged_*.o(.data .rodata*) }
__k_unpaged__kern_unpaged_edata = .;
.unpaged_bss ALIGN(4096) : { unpaged_*.o(.bss COMMON) }
__k_unpaged__kern_unpaged_end = .;
. += _kern_offset;
. = ALIGN(4096); usermapped_start = .;
.usermapped_glo : AT(ADDR(.usermapped_glo) - _kern_offset) { *(.usermapped_glo) }
. = ALIGN(4096); usermapped_nonglo_start = .;
.usermapped : AT(ADDR(.usermapped) - _kern_offset) { *(.usermapped) }
. = ALIGN(4096); usermapped_end = .;
.text : AT(ADDR(.text) - _kern_offset) { *(.text*) }
_etext = .;
.data ALIGN(4096) : AT(ADDR(.data) - _kern_offset) { *(.data .rodata* ) }
. = ALIGN(4096);
_edata = .;
__k_unpaged__edata = . - _kern_offset;
.bss ALIGN(4096) : AT(ADDR(.bss) - _kern_offset) { *(.bss* COMMON)
__k_unpaged__kern_size = . - _kern_vir_base;
_kern_size = __k_unpaged__kern_size;
. += 4096;
}
_end = .;
__k_unpaged__end = . - _kern_offset;
/DISCARD/ :
{
*(.ARM.exidx*)
}
}

View File

@@ -31,6 +31,10 @@ void get_phys_mem_map(phys_bytes *start, phys_bytes *end)
*start = 0x80000000;
*end = 0xbfffffff;
}
else if (BOARD_IS_RPI_2_B(machine.board_id) || BOARD_IS_RPI_3_B(machine.board_id)) {
*start = 0x00000000;
*end = 0x3effffff;
}
}
void print_memmap(kinfo_t *cbi)

View File

@@ -211,6 +211,11 @@ void setup_mbi(multiboot_info_t *mbi, char *bootargs)
mb_mmap_start = 0x80000000;
mb_mmap_size = 0x10000000; /* 256 MB */
}
else if (BOARD_IS_RPI_2_B(machine.board_id) || BOARD_IS_RPI_3_B(machine.board_id)) {
mb_mods_base = 0x02000000;
mb_mmap_start = 0x00008000; /* Don't overwrite bootcode for secondary CPUs */
mb_mmap_size = 0x3C000000 - 0x00008000; /* 960 MB */
}
else
POORMANS_FAILURE_NOTIFICATION;

151
releasetools/arm_sdimage_rpi.sh Executable file
View File

@@ -0,0 +1,151 @@
#!/usr/bin/env bash
set -e
#
# This script creates a bootable image and should at some point in the future
# be replaced by the proper NetBSD infrastructure.
#
#
# Source settings if present
#
: ${SETTINGS_MINIX=.settings}
if [ -f "${SETTINGS_MINIX}" ]
then
echo "Sourcing settings from ${SETTINGS_MINIX}"
# Display the content (so we can check in the build logs
# what the settings contain.
cat ${SETTINGS_MINIX} | sed "s,^,CONTENT ,g"
. ${SETTINGS_MINIX}
fi
BSP_NAME=rpi
: ${ARCH=evbearm-el}
: ${TOOLCHAIN_TRIPLET=arm-elf32-minix-}
: ${BUILDSH=build.sh}
: ${SETS="minix-base"}
: ${IMG=minix_arm_sd_rpi.img}
# ARM definitions:
: ${BUILDVARS=-V MKGCCCMDS=yes -V MKLLVM=no}
# These BUILDVARS are for building with LLVM:
#: ${BUILDVARS=-V MKLIBCXX=no -V MKKYUA=no -V MKATF=no -V MKLLVMCMDS=no}
if [ ! -f ${BUILDSH} ]
then
echo "Please invoke me from the root source dir, where ${BUILDSH} is."
exit 1
fi
# we create a disk image of about 2 gig's
# for alignment reasons, prefer sizes which are multiples of 4096 bytes
: ${FAT_START=4096}
: ${FAT_SIZE=$(( 64*(2**20) - ${FAT_START} ))}
: ${ROOT_SIZE=$(( 64*(2**20) ))}
: ${HOME_SIZE=$(( 128*(2**20) ))}
: ${USR_SIZE=$(( 1792*(2**20) ))}
#: ${IMG_SIZE=$(( 2*(2**30) ))} # no need to build an image that big for now
: ${IMG_SIZE=$(( 64*(2**20) ))}
# set up disk creation environment
. releasetools/image.defaults
. releasetools/image.functions
${RELEASETOOLSDIR}/checkout_repo.sh -o ${RELEASETOOLSDIR}/rpi-firmware -b ${RPI_FIRMWARE_BRANCH} -n ${RPI_FIRMWARE_REVISION} ${RPI_FIRMWARE_URL}
# where the kernel & boot modules will be
MODDIR=${DESTDIR}/boot/minix/.temp
echo "Building work directory..."
build_workdir "$SETS"
# IMG might be a block device
if [ -f ${IMG} ]
then
rm -f ${IMG}
fi
dd if=/dev/zero of=${IMG} bs=512 count=1 seek=$((($IMG_SIZE / 512) -1)) 2>/dev/null
#
# Generate /root, /usr and /home partition images.
#
echo "Writing disk image..."
#
# Write FAT bootloader partition
#
echo " * BOOT"
rm -rf ${ROOT_DIR}/*
# copy over all modules
for i in ${MODDIR}/*
do
cp $i ${ROOT_DIR}/$(basename $i).elf
done
${CROSS_PREFIX}objcopy ${OBJ}/minix/kernel/kernel -O binary ${ROOT_DIR}/kernel.bin
# create packer
${CROSS_PREFIX}as ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.S -o ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.o
${CROSS_PREFIX}as ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.S -o ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.o
${CROSS_PREFIX}ld ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.o -o ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.elf -Ttext=0x8000 2> /dev/null
${CROSS_PREFIX}ld ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.o -o ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.elf -Ttext=0x8000 2> /dev/null
${CROSS_PREFIX}objcopy -O binary ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.elf ${ROOT_DIR}/minix_rpi2.bin
${CROSS_PREFIX}objcopy -O binary ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.elf ${ROOT_DIR}/minix_rpi3.bin
# pack modules
(cd ${ROOT_DIR} && cat <<EOF | cpio -o --format=newc >> ${ROOT_DIR}/minix_rpi2.bin 2>/dev/null
kernel.bin
mod01_ds.elf
mod02_rs.elf
mod03_pm.elf
mod04_sched.elf
mod05_vfs.elf
mod06_memory.elf
mod07_tty.elf
mod08_mib.elf
mod09_vm.elf
mod10_pfs.elf
mod11_mfs.elf
mod12_init.elf
EOF
)
(cd ${ROOT_DIR} && cat <<EOF | cpio -o --format=newc >> ${ROOT_DIR}/minix_rpi3.bin 2>/dev/null
kernel.bin
mod01_ds.elf
mod02_rs.elf
mod03_pm.elf
mod04_sched.elf
mod05_vfs.elf
mod06_memory.elf
mod07_tty.elf
mod08_mib.elf
mod09_vm.elf
mod10_pfs.elf
mod11_mfs.elf
mod12_init.elf
EOF
)
cp -r releasetools/rpi-firmware/* ${ROOT_DIR}
# Write GPU config file
cat <<EOF >${ROOT_DIR}/config.txt
[pi3]
kernel=minix_rpi3.bin
enable_uart=1
dtoverlay=pi3-disable-bt
[pi2]
kernel=minix_rpi2.bin
EOF
${CROSS_TOOLS}/nbmakefs -t msdos -s $FAT_SIZE -O $FAT_START -o "F=32,c=1" ${IMG} ${ROOT_DIR} >/dev/null
#
# Write the partition table using the natively compiled
# minix partition utility
#
${CROSS_TOOLS}/nbpartition -f -m ${IMG} $((${FAT_START}/512)) "c:$((${FAT_SIZE}/512))*"
echo ""
echo "Disk image at `pwd`/${IMG}"
echo ""
echo "To boot this image on kvm:"
echo "qemu-system-arm -M raspi2 -drive if=sd,cache=writeback,format=raw,file=$(pwd)/${IMG} -bios ${ROOT_DIR}/minix_rpi2.bin"

View File

@@ -33,3 +33,7 @@ MODDIR=${DESTDIR}/boot/minix/.temp
: ${U_BOOT_URL=git://git.minix3.org/u-boot}
: ${U_BOOT_BRANCH=minix}
: ${U_BOOT_REVISION=cb5178f12787c690cb1c888d88733137e5a47b15}
: ${RPI_FIRMWARE_URL=https://github.com/boricj/rpi-firmware.git}
: ${RPI_FIRMWARE_BRANCH=master}
: ${RPI_FIRMWARE_REVISION=ccbca2eadd09dc550968839f227ecd0323cdbf22}

View File

@@ -0,0 +1,18 @@
.text
.include "releasetools/rpi-bootloader/bootloader_common.S"
.align 4
argv:
.word argv0
.word argv1
.word 0x0
argv0:
.asciz "0x00200000"
argv1:
.asciz "board_name=RPI_2_B console=tty00"
.data
.align 4
.space 256
stack_top:

View File

@@ -0,0 +1,18 @@
.text
.include "releasetools/rpi-bootloader/bootloader_common.S"
.align 4
argv:
.word argv0
.word argv1
.word 0x0
argv0:
.asciz "0x00200000"
argv1:
.asciz "board_name=RPI_3_B console=tty00"
.data
.align 4
.space 256
stack_top:

View File

@@ -0,0 +1,332 @@
_start:
ldr sp, =stack_top
/* Print banner */
ldr r0, =msg_empty
bl puts
ldr r0, =msg_empty
bl puts
ldr r0, =msg_banner
bl puts
/* Check if in hypervisor mode */
mrs r0, cpsr
and r1, r0, #0x1f
cmp r1, #0x1a
bne mode_svc
mode_hyp:
/* In hypervisor mode */
ldr r0, =msg_hypmode
bl puts
movw r0, #0x1d3
ldr r1, =mode_svc
msr ELR_hyp, r1
msr SPSR_hyp, r0
eret
nop
mode_svc:
nop
ldr sp, =stack_top
/* In supervisor mode */
ldr r0, =msg_svcmode
bl puts
/* Move CPIO archive out of the way */
ldr r0, =0xA000000
ldr r1, =stack_top
mov r2, #0x2000000
bl memcpy
load_files:
ldr r0, =msg_extract
bl puts
/* Load kernel */
ldr r0, =0x0A000000
ldr r1, =0x00200000
bl load_file
/* Load module */
ldr r4, =0x02000000
ldr r5, =0x00800000
load_files_loop:
mov r1, r4
bl load_file
cmp r0, #0
beq final_preparations
add r4, r4, r5
b load_files_loop
final_preparations:
/* Set up args and jump */
ldr r0, =msg_launch
bl print
mov r0, #0x22
bl putc
ldr r0, =argv1
bl print
mov r0, #0x22
bl putc
ldr r0, =msg_empty
bl puts
mov r0, #2
ldr r1, =argv
b 0x00200000
/*
* Load a file from CPIO archive.
* r0: address of CPIO archive
* r1: address to copy the file to
* Return: address of next entry, or 0 if loading failed
*/
load_file:
push {r4-r8,lr}
mov r4, r0
mov r5, r1
mov r6, r2
/* Check header : either 070701 or 070702 */
ldr r0, [r4]
ldr r1, =0x37303730
cmp r0, r1
bne load_file_failed
ldr r0, [r4, #4]
ldr r1, =0xFFFF
and r1, r1, r0
ldr r2, =0x3130
cmp r1, r2
beq load_file_header_ok
ldr r2, =0x3230
cmp r1, r2
bne load_file_failed
load_file_header_ok:
/* Check for trailer */
ldrh r0, [r4, #0x6e]
ldr r1, =0x5254
cmp r1, r0
beq load_file_failed
ldrh r0, [r4, #0x6e]
ldr r1, =0x4941
cmp r1, r0
beq load_file_failed
/* Get data size */
add r0, r4, #0x36
bl hex2bin
mov r7, r0
/* Get filename size */
add r0, r4, #0x5e
bl hex2bin
mov r8, r0
/* Print file, size and offset */
add r0, r4, #0x6e
bl print
mov r0, r8
load_file_name_padding_loop:
cmp r0, #24
bgt load_file_name_padding_loop_end
push {r0}
mov r0, #0x20
bl putc
pop {r0}
add r0, r0, #1
b load_file_name_padding_loop
load_file_name_padding_loop_end:
ldr r0, =msg_size
bl print
mov r0, r7
bl print_hex
ldr r0, =msg_addr
bl print
mov r0, r5
bl print_hex
/* Add CR/LF */
mov r0, #0xd
bl putc
mov r0, #0xa
bl putc
/* Get pointer to data source */
add r1, r4, #0x6e
add r1, r1, r8
/* Align to 4 bytes */
and r2, r1, #0x3
cmp r2, #0
mov r0, #4
subne r2, r0, r2
addne r1, r1, r2
mov r0, r5
mov r2, r7
push {r1}
bl memcpy
pop {r0}
add r0, r7
/* Align to 4 bytes */
and r2, r0, #0x3
cmp r2, #0
mov r1, #4
subne r2, r1, r2
addne r0, r0, r2
pop {r4-r8,lr}
bx lr
load_file_failed:
mov r0, #0
pop {r4-r8,lr}
bx lr
/*
* Send one character to the PL011 UART.
* r0: character to send
*/
putc:
/* Loop as long as FIFO isn't empty */
ldr r1, =0x3f201018
ldr r1, [r1]
and r1, #0x80
tst r1, #0x80
beq putc
# Write character
ldr r1, =0x3f201000
str r0, [r1]
bx lr
/*
* Print an ASCIIZ string to the PL011 UART.
* r0: address of string to print
*/
print:
push {lr}
/* If end of string, add newline */
print_loop:
ldrb r1, [r0]
cmp r1, #0
beq print_end
/* Send character */
push {r0}
mov r0, r1
bl putc
pop {r0}
/* Advance to next character */
add r0, r0, #1
b print_loop
print_end:
pop {lr}
bx lr
/*
* Print an ASCIIZ string to the PL011 UART, followed by CR/LF.
* r0: address of string to print
*/
puts:
push {lr}
bl print
/* Add CR/LF */
mov r0, #0xd
bl putc
mov r0, #0xa
bl putc
pop {lr}
bx lr
/*
* Convert 8 hexadecimal characters to binary.
* r0: address of string to convert
* Return: the converted value
*/
hex2bin:
mov r1, #0
mov r2, #0
hex2bin_loop:
ldrb r3, [r0, r2]
cmp r3, #0x40
sublt r3, r3, #0x30
blt hex2bin_add_digit
cmp r3, #0x60
sublt r3, r3, #0x37
blt hex2bin_add_digit
sub r3, r3, #0x57
hex2bin_add_digit:
lsl r1, r1, #4
add r1, r1, r3
add r2, r2, #1
cmp r2, #8
blt hex2bin_loop
mov r0, r1
bx lr
/*
* Print a value as hexadecimal.
* r0: value to print
*/
print_hex:
push {lr}
mov r1, #8
print_hex_loop:
cmp r1, #0
ble print_hex_end
lsr r2, r0, #28
cmp r2, #10
addlt r2, r2, #0x30
addge r2, r2, #0x37
push {r0-r2}
mov r0, r2
bl putc
pop {r0-r2}
sub r1, r1, #1
lsl r0, r0, #4
b print_hex_loop
print_hex_end:
pop {lr}
bx lr
/*
* Quickly copy a memory area to another.
* r0: destination
* r1: source
* r2: length
*/
memcpy:
push {r5-r11}
add r2, r0, r2
memcpy_loop:
cmp r0, r2
bge memcpy_done
ldm r1!, {r3-r11}
stm r0!, {r3-r11}
b memcpy_loop
memcpy_done:
pop {r5-r11}
bx lr
msg_empty:
.asciz ""
msg_banner:
.asciz "MINIX 3 unpacker for Raspberry Pi"
msg_svcmode:
.asciz "Current mode: supervisor"
msg_hypmode:
.asciz "Current mode: hypervisor. Switching to supervisor mode..."
msg_extract:
.asciz "Extracting modules..."
msg_launch:
.asciz "Jumping into kernel, argv[1]="
msg_size:
.asciz " size:0x"
msg_addr:
.asciz " address:0x"