Merge branch 'lagarto-ox' into 'master'

Lagarto OX support

See merge request rarias/nixos-riscv!1
This commit is contained in:
Rodrigo Arias 2024-10-11 14:14:29 +02:00
commit ccf41b441d
74 changed files with 11826 additions and 151 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
*result*
nixos-riscv.qcow2
misc/
gcroots/

6
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,6 @@
build:lagarto-ox:
stage: build
tags:
- nix
script:
- nix develop -L .#lagarto-ox --command fpga/run-remotely.sh fpgalogin1:ci

5307
JOURNAL.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -2,45 +2,49 @@
This repository contains NixOS configurations for different RISC-V machines.
## QEMU
## Lagarto Ox on FPGA Alveo U55C
To boot the system in QEMU, first enter the development shell:
To build the system and boot it on an FPGA of the MEEP cluster, you can run the
following:
```
$ nix develop
$ nix develop -L '.#lagarto-ox' --command fpga/run-remotely.sh fpgalogin1:ci
```
Then run the boot script:
To do it manually, you can first enter the development shell:
```
$ ./boot.sh
$ nix develop -L '.#lagarto-ox'
```
To prevent the GC from erasing the system:
```
$ nix build .#devShells.x86_64-linux.default --out-link result-env
```
## Lagarto Hun on FPGA Alveo U55C
First build required dependencies:
```
$ nix develop '.#lagarto-hun'
```
Then upload to destination:
Then upload the files to the target machine (fpgalogin1 by default):
```
$ fpga/upload.sh
```
And then boot the system there:
Then connect to the fpgalogin1 machine, allocate a FPGA node and load the
environment there:
```
cucu$ ./boot.sh
...
$ cd nixos
$ . env.sh
```
In the U-Boot prompt, paste the commands of the `uboot.env` file.
Flash the images to the FPGA:
```
$ ./fpgactl -w bitstream.bit -b opensbi.bin -k kernel.bin -i initrd.bin -r rootfs.img
```
And monitor the serial line:
```
$ picocom -q -b 115200 $FPGACTL_UART
```
It should boot without any user interaction.
## Lagarto Hun
WIP

3
bootrom/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.o
*.elf
*.bin

23
bootrom/Makefile Normal file
View File

@ -0,0 +1,23 @@
CC ?= riscv64-unknown-elf-gcc
OBJCOPY ?= riscv64-unknown-elf-objcopy
ROM_BASE ?= 0x00100
LDFLAGS=-Tlinker.ld -nostdlib -nostartfiles -nodefaultlibs -static -Wl,--no-gc-sections -Wl,--defsym=ROM_BASE=$(ROM_BASE)
b=rbootrom
all: $b.elf $b.bin
$b.o: $b.S
$(CC) $(CFLAGS) -c -o $@ $<
$b.elf: $b.o linker.ld
$(CC) $(LDFLAGS) -o $@ $<
$b.bin: $b.elf
$(OBJCOPY) -O binary $b.elf $b.bin
clean:
rm -f $b.elf $b.bin $b.o
.PHONY: clean all

19
bootrom/linker.ld Normal file
View File

@ -0,0 +1,19 @@
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
SECTIONS
{
ROM_BASE = DEFINED(ROM_BASE) ? ROM_BASE : 0x00100; /* Default to 0x00100 if ROM_BASE is not defined */
. = ROM_BASE;
.text.start : { *(.text.start) }
. = ROM_BASE + 0x80;
.text.hang : { *(.text.hang) }
/*
. = ROM_BASE + 0xC0;
.rodata.dtb : { *(.rodata.dtb) }
*/
. = ALIGN(0x100);
.text : { *(.text) }
}

189
bootrom/rbootrom.S Normal file
View File

@ -0,0 +1,189 @@
/*
* Copyright (c) 2024, Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: MIT
*
* RBOOTROM v1.0
* Modified by Rodrigo Arias Mallo <rodrigo.arias@bsc.es>
*
* This is a custom bootrom that prints some information to the UART when
* starting, as well as when it hangs. It assumes the UART is at UART_BASE and
* it will jump to DRAM_BASE to continue the boot.
*/
#define DRAM_BASE 0x80000000
#define UART_BASE 0x40001000
#define UART_BAUDRATE 115200
#define UART_CLOCK 50000000
#define UART_BDIV ((UART_CLOCK + 8 * UART_BAUDRATE) / (16 * UART_BAUDRATE))
#define UART_SHIFT 2
#define UART_RBR_OFFSET (0<<UART_SHIFT) /* In: Recieve Buffer Register */
#define UART_THR_OFFSET (0<<UART_SHIFT) /* Out: Transmitter Holding Register */
#define UART_DLL_OFFSET (0<<UART_SHIFT) /* Out: Divisor Latch Low */
#define UART_IER_OFFSET (1<<UART_SHIFT) /* I/O: Interrupt Enable Register */
#define UART_DLM_OFFSET (1<<UART_SHIFT) /* Out: Divisor Latch High */
#define UART_FCR_OFFSET (2<<UART_SHIFT) /* Out: FIFO Control Register */
#define UART_IIR_OFFSET (2<<UART_SHIFT) /* I/O: Interrupt Identification Register */
#define UART_LCR_OFFSET (3<<UART_SHIFT) /* Out: Line Control Register */
#define UART_MCR_OFFSET (4<<UART_SHIFT) /* Out: Modem Control Register */
#define UART_LSR_OFFSET (5<<UART_SHIFT) /* In: Line Status Register */
#define UART_MSR_OFFSET (6<<UART_SHIFT) /* In: Modem Status Register */
#define UART_SCR_OFFSET (7<<UART_SHIFT) /* I/O: Scratch Register */
#define UART_MDR1_OFFSET (8<<UART_SHIFT) /* I/O: Mode Register */
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
#define UART_LSR_DR 0x01 /* Receiver data ready */
.macro PUTC, ch
li a0, \ch
jal putchar
.endm
.section .text.start, "ax", @progbits
.globl _start
_start:
jal uart_init // Initialize console
jal print_hello // Print initial message on HART 0 only
la t0, _hang
csrw mtvec, t0 // Set the machine trap vector
csrr a0, mhartid // Load HART ID into a0
li s0, DRAM_BASE // Load next address into s0
jr s0 // Jump to s0
.section .text.hang, "ax", @progbits
.globl _hang
_hang:
PUTC '\n'
PUTC '\r'
PUTC 'R'
PUTC 'B'
PUTC 'O'
PUTC 'O'
PUTC 'T'
PUTC 'R'
PUTC 'O'
PUTC 'M'
PUTC ' '
PUTC 'H'
PUTC 'A'
PUTC 'N'
PUTC 'G'
PUTC '\n'
PUTC '\r'
/* Hang */
csrr a0, mhartid
1:
wfi
j 1b
.section .text, "ax", @progbits
putchar:
/* Wait until ready to transmit */
la t0, UART_BASE // Load UART base address
1:
lb t1, UART_LSR_OFFSET(t0) // Read Line Status Register
andi t1, t1, UART_LSR_THRE // Transmitter Holding Register Empty
beqz t1, 1b // Repeat if zero (not empty)
/* Write the character now */
sb a0, UART_THR_OFFSET(t0) // Transmit character
ret
uart_init:
/* Assume reg_shift = 2 and reg_width = 2 */
la t0, UART_BASE // Load UART base address
/* From OpenSBI v1.5 lib/utils/serial/uart8250.c */
la t1, 0x00 // Disable all interrupts
sb t1, UART_IER_OFFSET(t0)
la t1, 0x80 // Enable DLAB
sb t1, UART_LCR_OFFSET(t0)
la t1, UART_BDIV & 0xff // Set divisor low byte
sb t1, UART_DLL_OFFSET(t0)
la t1, (UART_BDIV >> 8) & 0xff // Set divisor high byte
sb t1, UART_DLM_OFFSET(t0)
la t1, 0x03 // 8 bits, no parity, one stop bit
sb t1, UART_LCR_OFFSET(t0)
la t1, 0x01 // Enable FIFO
sb t1, UART_FCR_OFFSET(t0)
la t1, 0x00 // No modem control DTR RTS
sb t1, UART_MCR_OFFSET(t0)
/* TODO: Clear line status */
/* TODO: Read receive buffer */
la t1, 0x00 // Set scratchpad to 0
sb t1, UART_SCR_OFFSET(t0)
ret
print_hello:
csrr t0, mhartid // Load HART ID into a0
beq t0, zero, 1f // Print message on HART 0 only
ret
1:
mv s0, ra // Save return address
PUTC '\n' // Identify bootroom
PUTC '\r'
PUTC 'R'
PUTC 'B'
PUTC 'O'
PUTC 'O'
PUTC 'T'
PUTC 'R'
PUTC 'O'
PUTC 'M'
PUTC ' '
PUTC 'v'
PUTC '1'
PUTC '.'
PUTC '0'
PUTC ' '
PUTC ':'
PUTC '^'
PUTC ')'
PUTC '\n'
PUTC '\r'
// Print jumping address
PUTC 'J'
PUTC 'u'
PUTC 'm'
PUTC 'p'
PUTC 'i'
PUTC 'n'
PUTC 'g'
PUTC ' '
PUTC 't'
PUTC 'o'
PUTC ' '
PUTC '0' // TODO: Compute from DRAM_BASE
PUTC 'x'
PUTC '8'
PUTC '0'
PUTC '0'
PUTC '0'
PUTC '_'
PUTC '0'
PUTC '0'
PUTC '0'
PUTC '0'
PUTC '.'
PUTC '.'
PUTC '.'
PUTC '\n'
PUTC '\r'
mv ra, s0 // Restore return address
ret

View File

@ -1,13 +1,22 @@
{ config, lib, pkgs, modulesPath, ... }:
{ config, lib, pkgs, modulesPath, self, ... }:
{
imports = [
#"${modulesPath}/profiles/base.nix"
#"${modulesPath}/profiles/minimal.nix"
"${modulesPath}/profiles/minimal.nix"
];
nixpkgs.crossSystem = {
system = "riscv64-linux";
nixpkgs = {
crossSystem = {
system = "riscv64-linux";
};
overlays = [
self.inputs.bscpkgs.bscOverlay
(import ./overlay.nix)
];
config.allowUnsupportedSystem = true;
};
networking.hostName = "nixos-riscv";
@ -26,5 +35,33 @@
};
};
systemd.oomd.enable = false;
networking.firewall.enable = false;
networking.dhcpcd.enable = false;
services.timesyncd.enable = false;
#environment.systemPackages = with pkgs; [ vim gdb neofetch gcc bintools ];
environment.systemPackages = with pkgs; [
rvb riscv-tools stream spec-cpu-mini
config.boot.kernelPackages.perf
];
services.getty.helpLine = ''
__________________
< Welcome to NixOS >
------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
If you can read this message then then you have
successfully booted NixOS into the login shell.
'';
}

2
dts/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.pp.dts
*.dtb

18
dts/Makefile Normal file
View File

@ -0,0 +1,18 @@
CC?=gcc
DTC?=dtc
CPPFLAGS=-E -C -P -nostdinc -undef -x assembler-with-cpp
all: lagarto_ox.dtb
clean:
rm -f *.pp.dts *.dtb
%.pp.dts: %.dts *.h
$(CC) $(CPPFLAGS) $< -o $@
sed -i 's/@0x0*/@/' $@
%.dtb: %.pp.dts
dtc -O dtb -o $@ $^
.PRECIOUS: %.pp.dts

255
dts/lagarto_ox.dts Normal file
View File

@ -0,0 +1,255 @@
#include "lagarto_ox.h"
/dts-v1/;
/ {
#address-cells = <2>;
#size-cells = <2>; /* 64 bits memory addresses */
compatible = "riscv,rv64i";
model = "Barcelona Supercomputing Center - Lagarto Ox (NixOS)";
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <RTC_FREQ>;
CPU0: cpu@0 {
clock-frequency = <CPU_FREQ>;
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafd";
mmu-type = "riscv,sv39";
tlb-split;
i-cache-block-size = <64>; // Guess
i-cache-sets = <4>;
i-cache-size = <16384>;
i-tlb-sets = <1>; // Guess
i-tlb-size = <32>; // Guess
d-cache-block-size = <64>; // Guess
d-cache-sets = <4>;
d-cache-size = <32768>;
d-tlb-sets = <1>; // Guess
d-tlb-size = <32>; // Guess
/* Hart-Level Interrupt Controller: Every interrupt is
* ultimately routed through a hart's HLIC before it
* interrupts that hart. */
HLIC0: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller; /* Receives interrupts */
compatible = "riscv,cpu-intc";
};
};
cpu-map {
cluster0 {
core0 {
cpu = <&CPU0>;
};
};
};
};
memory@MEM_ADDR {
device_type = "memory";
reg = /bits/ 64 <MEM_ADDR MEM_SIZE>;
};
reserved-memory {
#address-cells = <2>; /* Starting address and size */
#size-cells = <2>; /* 64 bits memory addresses */
ranges;
eth_pool: dma_pool@ETHPOOL_ADDR {
reg = /bits/ 64 <ETHPOOL_ADDR ETHPOOL_SIZE>;
compatible = "shared-dma-pool";
};
onic_pool: dma_pool@ONICPOOL_ADDR {
reg = /bits/ 64 <ONICPOOL_ADDR ONICPOOL_SIZE>;
compatible = "shared-dma-pool";
};
};
pmem@PMEM_ADDR {
/* volatile; This property indicates that this region is
* actually backed by non-persistent memory. This lets the OS
* know that it may skip the cache flushes required to ensure
* data is made persistent after a write. */
volatile;
compatible = "pmem-region";
reg = /bits/ 64 <PMEM_ADDR PMEM_SIZE>;
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "BSC,Lagarto-ox-soc", "simple-bus";
ranges;
/* For bitstream e97dd7b2-397f-11ef-abe0-bbd201a5a630 with two
* consoles */
#ifdef ENABLE_UART0
/* The serial for the kernel console */
uart_console: serial@UART0_ADDR {
compatible = "ns16550";
reg = /bits/ 64 <UART0_ADDR UART0_SIZE>;
reg-shift = <2>;
/* No interrupts for this UART, use console=hvc0 */
/* This clock is the SERIAL_CLK */
clock-frequency = <CPU_FREQ>;
current-speed = <UART0_SPEED>;
status = "okay";
};
#endif /* ENABLE_UART0 */
#ifdef ENABLE_UART1
/* The serial for interrupt tests */
uart_testing: serial@UART1_ADDR {
compatible = "ns16550";
reg = /bits/ 64 <UART1_ADDR UART1_SIZE>;
reg-shift = <2>;
/* Output interrupt 1 (the first one) */
interrupts = <1>;
interrupt-parent = <&PLIC>;
clock-frequency = <CPU_FREQ>;
current-speed = <UART1_SPEED>;
status = "okay";
};
#endif /* ENABLE_UART1 */
#ifdef ENABLE_ETHERNET
ethernet0 {
xlnx,rxmem = <1522>;
carv,mtu = <1500>;
carv,no-mac;
device_type = "network";
// 02:$node:00:01:00:$fpga -> 02:05:00:01:00:02
// 10.5.1.$N/16 -> 10.5.1.184/16
// N = 150 + ($node - 1) * 8 + $fpga
local-mac-address = [00 00 00 00 00 00];
axistream-connected = <&axi_dma>;
compatible = "xlnx,xxv-ethernet-1.0-carv";
memory-region = <&eth_pool>;
};
#endif /* ENABLE_ETHERNET */
#ifdef ENABLE_AXIDMA
dma_clk: dma_clk {
compatible = "fixed-clock";
#clock-cells = <0x0>;
clock-frequency = <AXIDMA_FREQ>;
};
axi_dma: dma@AXIDMA_ADDR {
reg = /bits/ 64 <AXIDMA_ADDR AXIDMA_SIZE>;
reg-shift = <2>;
#address-cells = <2>;
#size-cells = <2>;
xlnx,include-dre;
#dma-cells = <0x1>;
compatible = "xlnx,axi-dma-1.00.a";
clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk",
"m_axi_s2mm_aclk", "m_axi_sg_aclk";
clocks = <&dma_clk>, <&dma_clk>, <&dma_clk>, <&dma_clk>;
interrupt-names = "mm2s_introut", "s2mm_introut";
interrupt-parent = <&PLIC>;
interrupts = <2 3>;
xlnx,addrwidth = <0x28>;
xlnx,include-sg;
xlnx,sg-length-width = <0x17>;
dma-channel@AXIDMA_CH0 {
reg = /bits/ 64 <AXIDMA_CH0 0x30>;
compatible = "xlnx,axi-dma-mm2s-channel";
dma-channels = <0>;
interrupts = <2>;
xlnx,datawidth = <0x40>;
xlnx,device-id = <0x0>;
xlnx,include-dre;
};
dma-channel@AXIDMA_CH1 {
reg = /bits/ 64 <AXIDMA_CH1 0x30>;
compatible = "xlnx,axi-dma-s2mm-channel";
dma-channels = <1>;
interrupts = <3>;
xlnx,datawidth = <0x40>;
xlnx,device-id = <0x0>;
xlnx,include-dre;
};
};
#endif /* ENABLE_AXIDMA */
#ifdef ENABLE_PLIC
/* Platform-Level Interrupt Controller: Delivers interrupts to
* HARTs. */
PLIC: plic@PLIC_ADDR {
reg = /bits/ 64 <PLIC_ADDR PLIC_SIZE>;
compatible = "riscv,plic0";
interrupt-controller; /* Receives interrupts */
#address-cells = <0>;
#interrupt-cells = <1>;
/* Sends interrupts to HART interrupt controllers.
* Configures two output targets or contexts:
* - context 0: machine mode external interrupt (11)
* - context 1: supervisor mode external interrupt (9)
*/
interrupts-extended = <&HLIC0 11>, <&HLIC0 9>;
riscv,ndev = <PLIC_NDEV>;
//riscv,max-priority = <0x7>;
};
#endif /* ENABLE_PLIC */
#ifdef ENABLE_CLINT
/* Core Local Interruptor: It directly connects to the timer and
* inter-processor interrupt lines of various HARTs (or CPUs) so
* RISC-V per-HART (or per-CPU) local interrupt controller is
* the parent interrupt controller for CLINT device. The clock
* frequency of CLINT is specified via "timebase-frequency" DT
* property of "/cpus" DT node. The "timebase-frequency" DT
* property is described in
* Documentation/devicetree/bindings/riscv/cpus.yaml
*/
clint: clint@CLINT_ADDR {
reg = /bits/ 64 <CLINT_ADDR CLINT_SIZE>;
reg-names = "control";
interrupts-extended = <&HLIC0 3>, <&HLIC0 7>;
compatible = "riscv,clint0";
};
#endif /* ENABLE_CLINT */
#if 0
/* There is another auxiliar clint (timer) at 40010000 for
* tests, but we don't tell the kernel so we can use it for
* testing interrupts manually. */
aux_timer: clint@AUXTIMER_ADDR {
reg = /bits/ 64 <AUXTIMER_ADDR AUXTIMER_SIZE>;
reg-names = "control";
interrupts = <4>; /* PLIC input source 4 */
interrupt-parent = <&PLIC>;
compatible = "riscv,clint0";
};
#endif
#ifdef ENABLE_SPI
serial@UART2_ADDR {
compatible = "ns16750";
reg = /bits/ 64 <UART2_ADDR UART2_SIZE>;
interrupt-parent = <&PLIC>;
interrupts = <5>;
clock-frequency = <CPU_FREQ>;
current-speed = <UART2_SPEED>;
status = "okay";
};
spi@SPI_ADDR {
compatible = "ti,keystone-spi";
reg = /bits/ 64 <SPI_ADDR SPI_SIZE>;
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&PLIC>;
interrupt-names = "intvec0", "intvec1";
interrupts = <6 0>, <7 0>;
ti,davinci-spi-intr-line = <0>;
spi-max-frequency = <24000000>;
loopback-mode = <1>;
status = "okay";
};
#endif /* ENABLE_SPI */
};
};

76
dts/lagarto_ox.h Normal file
View File

@ -0,0 +1,76 @@
/* Toggles */
#define ENABLE_UART0
#define ENABLE_UART1
#define ENABLE_ETHERNET
#define ENABLE_AXIDMA
#define ENABLE_PLIC
#define ENABLE_CLINT
//#define ENABLE_SPI
#define CPU_FREQ 50000000 /* 50 MHz */
/* FIXME: The real RTC frequency is around half that, as the divider was wrongly
* configured. So for now lets use the real frequency:
* 50e6 / (1525*2) = 16393.44262295082 -> 16393 Hz */
#define RTC_FREQ 16393
/* Memory layout:
*
* [0x0_4000_0000, 0x0_6000_0000) -> IO (512 MiB)
* [0x0_6000_0000, 0x0_7000_0000) -> DMA pool (256 MiB)
* [0x0_7000_0000, 0x0_8000_0000) -> DMA pool (256 MiB)
* [0x0_8000_0000, 0x1_8000_0000) -> RAM memory (4 GiB)
* [0x1_8000_0000, 0x1_c000_0000) -> Unused (1 GiB)
* [0x1_c000_0000, 0x2_8000_0000) -> PMEM (3 GiB)
*/
#define UART0_SPEED 115200
#define UART0_ADDR 0x40001000
#define UART0_SIZE 0x00001000
#define UART1_SPEED UART0_SPEED
#define UART1_ADDR 0x40003000
#define UART1_SIZE 0x00001000
/* UART2 via SPI */
#define UART2_SPEED UART0_SPEED
#define UART2_ADDR 0x40005000
#define UART2_SIZE 0x00001000
#define SPI_ADDR 0x40007000
#define SPI_SIZE 0x00001000
#define AUXTIMER_ADDR 0x40010000
#define AUXTIMER_SIZE 0x00010000
#define CLINT_ADDR 0x40100000
#define CLINT_SIZE 0x00010000
#define AXIDMA_ADDR 0x40400000
#define AXIDMA_SIZE 0x00400000
#define AXIDMA_CH0 0x40400000
#define AXIDMA_CH1 0x40400030
#define AXIDMA_FREQ 156250000
#define PLIC_ADDR 0x40800000
#define PLIC_SIZE 0x00400000
#ifdef ENABLE_SPI
# define PLIC_NDEV 7 /* extra UART2 + 2 x SPI */
#else
# define PLIC_NDEV 4
#endif
#define ETHPOOL_ADDR 0x60000000
#define ETHPOOL_SIZE 0x10000000
#define ONICPOOL_ADDR 0x70000000
#define ONICPOOL_SIZE 0x10000000
/* Notice addresses > 32 bits from here */
#define MEM_ADDR 0x080000000
#define MEM_SIZE 0x100000000
#define PMEM_ADDR 0x1c0000000
#define PMEM_SIZE 0x0c0000000

View File

@ -1,24 +1,56 @@
{
"nodes": {
"bscpkgs": {
"inputs": {
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1713974364,
"narHash": "sha256-ilZTVWSaNP1ibhQIIRXE+q9Lj2XOH+F9W3Co4QyY1eU=",
"ref": "refs/heads/master",
"rev": "de89197a4a7b162db7df9d41c9d07759d87c5709",
"revCount": 937,
"type": "git",
"url": "https://git.sr.ht/~rodarima/bscpkgs"
},
"original": {
"type": "git",
"url": "https://git.sr.ht/~rodarima/bscpkgs"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1706092046,
"narHash": "sha256-Cbethl95Cu+WVIWfaAnRRBZiz5PmXxQvg4vXNqIZQUg=",
"owner": "rodarima",
"lastModified": 1700390070,
"narHash": "sha256-de9KYi8rSJpqvBfNwscWdalIJXPo8NjdIZcEJum1mH0=",
"path": "/nix/store/z7y28qzhk7driiwcw78k0mb24laknm0f-source",
"rev": "e4ad989506ec7d71f7302cc3067abd82730a4beb",
"type": "path"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1720031269,
"narHash": "sha256-rwz8NJZV+387rnWpTYcXaRNvzUSnnF9aHONoJIYmiUQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "57e7c8fa4fdc414a936ce83afd0c70fb0a3a31d5",
"rev": "9f4128e00b0ae8ec65918efeba59db998750ead6",
"type": "github"
},
"original": {
"owner": "rodarima",
"ref": "fix-pkgs-static-gcc-march",
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
"bscpkgs": "bscpkgs",
"nixpkgs": "nixpkgs_2"
}
}
},

View File

@ -1,17 +1,20 @@
{
inputs.nixpkgs.url = "github:rodarima/nixpkgs/fix-pkgs-static-gcc-march";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
inputs.bscpkgs.url = "git+https://git.sr.ht/~rodarima/bscpkgs";
outputs = { self, nixpkgs, ... }:
outputs = {self, nixpkgs, ...}@inputs:
let
system = "x86_64-linux";
overlay = import ./overlay.nix;
pkgs = import nixpkgs { inherit system; };
nixosSystem = import (nixpkgs + "/nixos/lib/eval-config.nix");
mkRoots = pkgs: list: pkgs.writeText "gcroots.json"
(builtins.toJSON (map (x: { drv = x; attrs = x.drvAttrs; }) list));
in {
overlay = import ./overlay.nix;
#overlay = import ./overlay.nix;
nixosConfigurations = {
# The qemu configuration defines a system that runs in the RISC-V
# architecture, but is build from an x86 host machine.
qemu = nixpkgs.lib.nixosSystem {
qemu = nixosSystem {
specialArgs = { inherit self; };
system = "${system}";
modules = [
./configuration.nix
@ -20,7 +23,8 @@
};
# Same, but disable compressed instructions
qemu-nc = nixpkgs.lib.nixosSystem {
qemu-nc = nixosSystem {
specialArgs = { inherit self; };
system = "${system}";
modules = [
./configuration.nix
@ -30,7 +34,8 @@
};
# FPGA Lagarto Hun CPU
lagarto-hun = nixpkgs.lib.nixosSystem {
lagarto-hun = nixosSystem {
specialArgs = { inherit self; };
system = "${system}";
modules = [
./configuration.nix
@ -38,35 +43,105 @@
./no-compressed.nix
];
};
# FPGA Lagarto Ox CPU
lagarto-ox = nixosSystem {
specialArgs = { inherit self; };
system = "${system}";
modules = [
./configuration.nix
./lagarto-ox.nix
./no-compressed.nix
];
};
};
# A development shell with QEMU ready to boot the RISC-V system in an x86
# machine.
devShells.x86_64-linux.default =
devShells.x86_64-linux.qemu-lagarto-hun =
let
nixosconf = self.nixosConfigurations.qemu-nc;
syspkgs = nixosconf.pkgs;
toplevel = nixosconf.config.system.build.toplevel;
in pkgs.mkShell {
in syspkgs.mkShell {
pname = "qemu-shell";
buildInputs = with pkgs; [ qemu e2fsprogs ];
nativeBuildInputs = with syspkgs; [ qemu e2fsprogs ];
# Here we tell the run script where to find the system
NIXOS_SYSTEM_TOPLEVEL = toplevel;
OPENSBI = syspkgs.opensbi-uboot;
};
devShells.x86_64-linux.lagarto-hun =
let
nixosconf = self.nixosConfigurations.lagarto-hun;
syspkgs = nixosconf.pkgs;
build = nixosconf.config.system.build;
in pkgs.mkShell {
in syspkgs.mkShell {
pname = "lagarto-hun-shell";
COMMIT = if self ? rev then self.rev else "dirty";
TOPLEVEL = build.toplevel;
OPENSBI = syspkgs.opensbi;
KERNEL = build.kernel;
INITRD = build.initialRamdisk;
ROOTFS = build.sdImage;
UBOOT_ENV = syspkgs.uboot-env;
shellHook = ''
echo "Here are the current system pieces:"
echo " COMMIT = $COMMIT"
echo " TOPLEVEL = $TOPLEVEL"
echo " KERNEL = $KERNEL"
echo " OPENSBI = $OPENSBI"
echo " INITRD = $INITRD"
echo " ROOTFS = $ROOTFS"
echo " UBOOT_ENV = $UBOOT_ENV"
'';
};
devShells.x86_64-linux.lagarto-ox =
let
nixosconf = self.nixosConfigurations.lagarto-ox;
syspkgs = nixosconf.pkgs;
build = nixosconf.config.system.build;
in syspkgs.mkShell rec {
pname = "lagarto-ox-shell";
COMMIT = if self ? rev then self.rev else "dirty";
TOPLEVEL = build.toplevel;
OPENSBI = syspkgs.opensbi;
KERNEL = build.kernel;
INITRD = build.initialRamdisk;
ROOTFS = build.sdImage;
UBOOT_ENV = syspkgs.uboot-env;
BITSTREAM = syspkgs.bitstream;
BOOTROM = syspkgs.bootrom;
GCROOT = mkRoots syspkgs [
syspkgs.stdenv KERNEL OPENSBI syspkgs.riscv-tools
];
shellHook = ''
echo "Here are the current system pieces:"
echo " COMMIT = $COMMIT"
echo " TOPLEVEL = $TOPLEVEL"
echo " KERNEL = $KERNEL"
echo " OPENSBI = $OPENSBI"
echo " INITRD = $INITRD"
echo " ROOTFS = $ROOTFS"
echo " UBOOT_ENV = $UBOOT_ENV"
echo " BITSTREAM = $BITSTREAM"
echo " BOOTROM = $BOOTROM"
echo " GCROOT = $GCROOT"
'';
};
devShells.x86_64-linux.lagarto-ox-rd =
let
nixosconf = self.nixosConfigurations.lagarto-ox;
syspkgs = nixosconf.pkgs;
in self.outputs.devShells.x86_64-linux.lagarto-ox.overrideAttrs (old:{
TOPLEVEL = "";
ROOTFS = "";
GCROOT = mkRoots syspkgs [ syspkgs.stdenv old.OPENSBI ];
});
devShells.x86_64-linux.default =
self.outputs.devShells.x86_64-linux.lagarto-ox-rd;
};
}

View File

@ -1,12 +1,12 @@
#!/usr/bin/bash
set -x
#set -x
set -e
source ./env.sh
#bitstream="-w system-acme_ea-4h2v.bit"
bitstream="-w bitstream.bit"
./fpgactl $bitstream -b opensbi.bin -k kernel.bin -i initrd.bin -r rootfs.img
./fpgactl $bitstream -R bootrom.bin -b opensbi.bin -k kernel.bin -i initrd.bin -r rootfs.img
picocom -b 115200 /dev/ttyUSB2
picocom -b 115200 $FPGACTL_UART

View File

@ -1,21 +1,56 @@
#!/bin/bash
# Source this file to setup the environment
INSTALL_PATH=/home/tools
LOAD_BITSTREAM=$INSTALL_PATH/scripts
HOSTNAME=$(hostname)
function setup_cucu()
{
INSTALL_PATH=/home/tools
LOAD_BITSTREAM=$INSTALL_PATH/scripts
export DMA_IP_DRIVERS="$INSTALL_PATH/drivers/$hostname/dma_ip_drivers-onic-gamma/xilinx_pcie_drivers"
if [ ! -d $DMA_IP_DRIVERS ]; then
echo "error: DMA_IP_DRIVERS $DMA_IP_DRIVERS directory does not exist" >&2
return
fi
export PATH="$DMA_IP_DRIVERS/QDMA/linux-kernel/bin/:$PATH"
if [ -x /opt/Xilinx/Vivado/2020.1/settings64.sh ]; then
source /opt/Xilinx/Vivado/2020.1/settings64.sh
elif [ -x /opt/Xilinx/Vivado/2021.2/settings64.sh ]; then
source /opt/Xilinx/Vivado/2021.2/settings64.sh
fi
}
export DMA_IP_DRIVERS="$INSTALL_PATH/drivers/$HOSTNAME/dma_ip_drivers-onic-gamma/xilinx_pcie_drivers"
function setup_meep()
{
. /nfs/apps/XILINX/xilinx_22_env.sh
export PATH="$PATH:/apps/QDMA/meep-ionic/2022.1.4.4/linux-kernel/bin/"
if [ ! -d $DMA_IP_DRIVERS ]; then
echo "error: DMA_IP_DRIVERS $DMA_IP_DRIVERS directory does not exist" >&2
return
fi
# Select the first FPGA in the node
local line=$(grep fpgan /etc/motd | sed -n 2p | tr -d ' ')
export FPGACTL_PCIDEV=$(echo "$line" | awk -F'|' '{print $5}')
export FPGACTL_SERIAL=$(echo "$line" | awk -F'|' '{print $4}')
export FPGACTL_UART=$(echo "$line" | awk -F'|' '{print "/dev/"$7}')
export PATH="$DMA_IP_DRIVERS/QDMA/linux-kernel/bin/:$PATH"
# Setup mappings
if [ -x /opt/Xilinx/Vivado/2020.1/settings64.sh ]; then
source /opt/Xilinx/Vivado/2020.1/settings64.sh
elif [ -x /opt/Xilinx/Vivado/2021.2/settings64.sh ]; then
source /opt/Xilinx/Vivado/2021.2/settings64.sh
fi
# Delta between where we load in the dma device and RAM
local delta_addr=-0x60000000
# See https://gitlab.bsc.es/hwdesign/fpga/integration-lab/fpga-tools/-/blob/6a63bcea6d1d59df3c7d62311aa4935efd54d3a3/boot_riscv/boot_sa.sh#L36-40
export FPGACTL_BOOTLOADER_ADDR=$((0x80000000+$delta_addr))
export FPGACTL_KERNEL_ADDR=$((0x84000000+$delta_addr))
export FPGACTL_INITRD_ADDR=$((0x8c300000+$delta_addr))
export FPGACTL_ROOTFS_ADDR=$((0x1c0000000+$delta_addr))
export FPGACTL_BOOTROM_ADDR=$((0x00000100))
}
hostname=$(hostname)
case "$hostname" in
cucu) setup_cucu ;;
fpgan*) setup_meep ;;
*) echo "ERROR: unknown host $hostname";;
esac

View File

@ -27,9 +27,7 @@ function check_environment() # {{{
} # }}}
function create_qdma_queue() # {{{
{
pcidir="/sys/bus/pci/devices/0000:08:00.0"
if [ ! -d "$pcidir/qdma" ]; then
if [ ! -d "$pcidir" ]; then
echo "missing pci directory: $pcidir" >&2
exit 1
fi
@ -44,48 +42,71 @@ function create_qdma_queue() # {{{
exit 1
fi
if [ ! -c "/dev/qdma08000-MM-1" ]; then
echo 2 | sudo dd of="$pcidir/qdma/qmax"
dma-ctl qdma08000 q add mode mm idx 1 dir bi
dma-ctl qdma08000 q start idx 1 dir bi
sudo chmod go+rw "/dev/qdma08000-MM-1"
sudo chmod go+rw "$pcidir/resource0"
sudo chmod go+rw "$pcidir/resource0_wc"
sudo chmod go+rw "$pcidir/resource2"
sudo chmod go+rw "$pcidir/resource2_wc"
if [ ! -r "$pcidir/qdma/qmax" ]; then
echo "cannot read qmax file: $pcidir/qdma/qmax" >&2
exit 1
fi
if [ ! -c "/dev/qdma08000-MM-0" ]; then
dma-ctl qdma08000 q add mode mm idx 0 dir bi
dma-ctl qdma08000 q start idx 0 dir bi
sudo chmod go+rw "/dev/qdma08000-MM-0"
# There should be two queues
local qmax=$(cat "$pcidir/qdma/qmax")
if [ "$qmax" != 2 ]; then
if [ -w "$pcidir/qdma/qmax" ]; then
echo 2 | dd of="$pcidir/qdma/qmax"
else
echo 2 | sudo dd of="$pcidir/qdma/qmax"
fi
fi
# Create the two queues if they don't exist
if [ ! -c "/dev/${qdmadev}-MM-1" ]; then
dma-ctl "${qdmadev}" q add mode mm idx 1 dir bi
dma-ctl "${qdmadev}" q start idx 1 dir bi
fi
if [ ! -c "/dev/${qdmadev}-MM-0" ]; then
dma-ctl "${qdmadev}" q add mode mm idx 0 dir bi
dma-ctl "${qdmadev}" q start idx 0 dir bi
fi
# Wait for udev to process the new devices
udevadm settle
# Ensure we have write access. On some clusters this is automatically done
# by udev rules, on others we are expect to use sudo.
for f in /dev/${qdmadev}-MM-{0,1} ${pcidir}/resource{0,0_wc,2,2_wc}; do
test -w "$f" || sudo chmod go+rw "$f"
done
sleep 2
} # }}}
function do_system_reset() # {{{
function do_cpu_reset() # {{{
{
# UartBootEn (bit2) + system reset (bit0)
dma-ctl qdma08000 reg write bar 2 0x0 0x0 > /dev/null
sleep 0.2
# Release system reset, we must wait until the memory is filled with 0s
dma-ctl qdma08000 reg write bar 2 0x0 0x1 > /dev/null
#sleep 5
if [ "$model" == "hun" ]; then
# UartBootEn (bit2) + system reset (bit0)
dma-ctl "${qdmadev}" reg write bar 2 0x0 0x0
sleep 0.2
dma-ctl "${qdmadev}" reg write bar 2 0x0 0x1
elif [ "$model" == "ox" ]; then
dma-ctl "${qdmadev}" reg write bar 2 0x0 0x0
sleep 0.2
fi
} # }}}
function do_system_release() # {{{
function do_cpu_release() # {{{
{
# Release Ariane's reset
dma-ctl qdma08000 reg write bar 2 0x0 0x3 > /dev/null
if [ "$model" == "hun" ]; then
# Release Ariane's reset
dma-ctl "${qdmadev}" reg write bar 2 0x0 0x3
elif [ "$model" == "ox" ]; then
dma-ctl "${qdmadev}" reg write bar 2 0x0 0x1
fi
} # }}}
function copy_by_dma() # {{{
{
ifile="$1"
address="$2"
ofile="/dev/qdma08000-MM-1"
bs=$((8*1024*1024)) # 8 MiB
ofile="/dev/${qdmadev}-MM-1"
#bs=$((8*1024*1024)) # 8 MiB
bs=$((1*1024*1024)) # 1 MiB
total_size=$(stat --format "%s" "$ifile")
@ -101,6 +122,7 @@ function copy_by_dma() # {{{
dd if="$ifile" skip=$skip count=1 bs=$bs of="$ofile" seek=$dst oflag=seek_bytes status=none
let skip=$skip+1
done
#dma-to-device -d "$ofile" -s "$total_size" -a "$address" -f "$ifile"
} # }}}
function load_file_in_memory() # {{{
@ -110,23 +132,24 @@ function load_file_in_memory() # {{{
address=$(($address_hex))
total_size=$(stat --format "%s" "$file")
md5sum=$(md5sum "$file" | cut -d' ' -f1)
# Previous tests...
#strace -f dma-to-device -d /dev/qdma08000-MM-1 -a "$address" -s $((8*1024*1024)) -f "$file"
#strace -f dd if="$file" bs=16M seek="${address}" oflag=seek_bytes of=/dev/qdma08000-MM-1 status=progress conv=sync
#strace -f fpgakit/fpgadd -i "$file" -a "$address" -d /dev/qdma08000-MM-1 -c 1024 -s 1024
#strace -f dma-to-device -d /dev/${qdmadev}-MM-1 -a "$address" -s $((8*1024*1024)) -f "$file"
#strace -f dd if="$file" bs=16M seek="${address}" oflag=seek_bytes of=/dev/${qdmadev}-MM-1 status=progress conv=sync
#strace -f fpgakit/fpgadd -i "$file" -a "$address" -d /dev/${qdmadev}-MM-1 -c 1024 -s 1024
#ID=08 ./load_image.sh "$file" "$address"
# Now dd seems to work fine, but I will leave this as fallback:
copy_by_dma "$file" "$address"
#dd if="$file" bs=8M seek="${address}" oflag=seek_bytes of=/dev/qdma08000-MM-1 status=none
#dd if="$file" bs=8M seek="${address}" oflag=seek_bytes of=/dev/${qdmadev}-MM-1 status=none
printf "loaded '%s' at 0x%x with size %d\n" "$file" "$address" "$total_size" >&2
printf "loaded '%s' at 0x%x with size %d and md5 %s\n" "$file" "$address" "$total_size" "$md5sum" >&2
} # }}}
function do_boot_only() # {{{
{
do_system_reset
do_cpu_reset
./load_image.sh ${OSBI} $((0x80000000)) &&
@ -135,7 +158,7 @@ function do_boot_only() # {{{
sleep 2 &&
# #Release Ariane's reset
dma-ctl qdma08000 reg write bar 2 0x0 0x3 &&
dma-ctl "${qdmadev}" reg write bar 2 0x0 0x3 &&
sleep 10 &&
@ -143,7 +166,7 @@ function do_boot_only() # {{{
echo mount -o nolock -o rw -o retrans=10 192.168.0.16:/media/sda2/scratch/xavim/point /root &&
if [ ! -c /dev/qdma08000-MM-0 ] ; then
if [ ! -c "/dev/${qdmadev}-MM-0" ] ; then
/home/tools/drivers/`/bin/hostname`/dma_ip_drivers-onic-gamma/create-queue-qdma.sh -2
fi &&
@ -155,7 +178,7 @@ function do_boot_only() # {{{
} # }}}
function do_reload_fs() # {{{
{
do_system_reset
do_cpu_reset
#~xavim/LAGARTO_LINUX-4.1/./load_image.sh \
# /home/xavim/ARIANE_LINUX-3.0/recovery/fedora-fs-dx-java-cucu-0.108.raw.recovered \
@ -172,7 +195,7 @@ function do_reload_fs() # {{{
sleep 2
do_system_release
do_cpu_release
create_qdma_queue
# uncomment to enable eth-over-pcie
@ -180,23 +203,25 @@ function do_reload_fs() # {{{
} # }}}
function upload_bitstream_file() # {{{
{
bitfile="$1"
if [ -z "$jtagserial" ]; then
>&2 echo "JTAG serial required"
usage
fi
fpgajtag=$(lsusb -vd 0403: 2>&1 | grep iSerial | awk ' { print $3; }')
if [ -z "$fpgajtag" ]; then
echo "error: cannot find JTAG serial" >&2
exit 1
if [ -z "$bitstream" ]; then
>&2 echo "bitstream file required"
usage
fi
script=$(mktemp vivado-XXXXXXXXXX.tcl)
cat > "$script" <<EOF
open_hw_manager
connect_hw_server -url localhost:3121
current_hw_target "localhost:3121/xilinx_tcf/Xilinx/${fpgajtag}A"
current_hw_target "localhost:3121/xilinx_tcf/Xilinx/${jtagserial}A"
open_hw_target
set dev [lindex [get_hw_devices] 0]
current_hw_device \$dev
set_property PROGRAM.FILE ${bitfile} \$dev
set_property PROGRAM.FILE ${bitstream} \$dev
program_hw_devices \$dev
exit
EOF
@ -213,7 +238,7 @@ function unload_modules() # {{{
# Unload modules
for mod in $drvlist; do
if is_module_loaded "$mod"; then
sudo rmmod $mod
sudo rmmod $mod
fi
done
@ -223,14 +248,22 @@ function remove_pci_devices() # {{{
for slot in $(lspci -mm -d 10ee: | awk '{printf "0000:%s\n",$1}'); do
devdir="/sys/bus/pci/devices/$slot"
if [ -d $devdir ]; then
echo 1 | sudo dd "of=$devdir/remove"
if [ -w "$devdir/remove" ]; then
echo 1 | dd "of=$devdir/remove"
else
echo 1 | sudo dd "of=$devdir/remove"
fi
fi
done
} # }}}
function rescan_pci_devices() # {{{
{
echo 1 | sudo dd of=/sys/bus/pci/rescan
if [ -w /sys/bus/pci/rescan ]; then
echo 1 | dd of=/sys/bus/pci/rescan
else
echo 1 | sudo dd of=/sys/bus/pci/rescan
fi
} # }}}
function load_qdma_modules() # {{{
{
@ -245,21 +278,91 @@ function load_qdma_modules() # {{{
sudo insmod "$drv" "hw_buffers=$hw_buffers"
sleep 4
} # }}}
function select_pcidev() # {{{
{
if [ -z "$pcidev" ]; then
>&2 echo -e "error: missing PCI device (hint: lspci -d 10ee:902f)"
usage
fi
# Ensure it is ok
local matches=$(lspci -s "$pcidev")
if [ -z "$matches" ]; then
>&2 echo "no match for PCI device '$pcidev'"
exit 1
fi
local n="$(echo "$matches" | wc -l)"
if [ "$n" -gt 1 ]; then
>&2 echo "multiple matches for PCI device '$pcidev'"
exit 1
fi
# Fill the PCI device with the domain
local fulldev=$(lspci -s "$pcidev" -D | cut -d' ' -f1)
pcidir="/sys/bus/pci/devices/$fulldev"
if [ ! -d "$pcidir" ]; then
>&2 echo "cannot find PCI dir: $pcidir"
exit 1
fi
# Set the PCI device to the full device
pcidev="$fulldev"
# Find slot
slot=$(lspci -s "$pcidev" -vm | grep PhySlot | cut -f2)
if [ -z "$slot" ]; then
>&2 echo "cannot find physical slot for PCI '$pcidev'"
exit 1
fi
local devid=$(echo "$pcidev" | cut -d: -f2- | tr -d ':.')
qdmadev="qdma${devid}"
} # }}}
function preload_hook() #{{{
{
case "$hostname" in
cucu)
unload_modules "xocl xclmgmt qdma_pf xdma" # qdma_vf not removable
remove_pci_devices
;;
fpgan*)
;;
*)
echo "hostname $hostname not known"
exit 1
;;
esac
} #}}}
function postload_hook() #{{{
{
rescan_pci_devices
case "$hostname" in
cucu)
unload_modules "qdma_pf xdma" # qdma_vf not removable
remove_pci_devices
load_qdma_modules
rescan_pci_devices
;;
fpgan*)
;;
*)
echo "hostname $hostname not known"
exit 1
;;
esac
create_qdma_queue
} #}}}
function load_bitstream() # {{{
{
bitstream="$1"
unload_modules "xocl xclmgmt qdma_pf xdma" # qdma_vf not removable
remove_pci_devices
upload_bitstream_file "$bitstream"
rescan_pci_devices
unload_modules "qdma_pf xdma" # qdma_vf not removable
remove_pci_devices
load_qdma_modules
rescan_pci_devices
create_qdma_queue
preload_hook
upload_bitstream_file
postload_hook
} # }}}
bitstream=
@ -267,34 +370,51 @@ bootloader=
kernel=
initrd=
rootfs=
bootrom=
resetcpu=
verbose=
pcidev=
model=ox
# Internal
slot=
pcidir=
qdmadev=
bootloader_addr=0x80000000
kernel_addr=0x84000000
initrd_addr=0x8c300000
rootfs_addr=0x180000000
bootloader_addr="${FPGACTL_BOOTLOADER_ADDR:-0x80000000}"
kernel_addr="${FPGACTL_KERNEL_ADDR:-0x84000000}"
initrd_addr="${FPGACTL_INITRD_ADDR:-0x8c300000}"
rootfs_addr="${FPGACTL_ROOTFS_ADDR:-0x140000000}"
bootrom_addr="${FPGACTL_BOOTROM_ADDR:-0x60000100}"
hostname="${hostname:-$(hostname)}"
echo "hostname=$hostname"
function usage()
{
echo "" >&2
echo "Usage: $0 [-v] [-w bitstream] [-b bootloader] [-k kernel] [-i initrd]" >&2
echo "Usage: $0 [-p pcidev] [-v] [-w bitstream] [-j serial] [-b bootloader] [-k kernel] [-i initrd] [-R bootroom] " >&2
echo "" >&2
echo "First writes the bitstream if given. Then loads the rest of files" >&2
echo "into memory and restarts the CPU." >&2
echo "" >&2
echo "Options" >&2
echo " -p pcidev Select PCI device (same format as lspci -s)." >&2
echo " Read from \$FPGACTL_PCIDEV if not given." >&2
echo " -w bitstream Write the bitstream file to the FPGA" >&2
echo " -j serial JTAG serial (can be found by lsusb -v)" >&2
echo " Read from \$FPGACTL_SERIAL if not given." >&2
echo " -b bootloader Load the bootloader file in $bootloader_addr" >&2
echo " -k kernel Load the kernel file in $kernel_addr" >&2
echo " -i initrd Load the initrd file in $initrd_addr" >&2
echo " -r rootfs Load the rootfs file in $rootfs_addr" >&2
echo " -R bootrom Load the bootrom file in $bootrom_addr" >&2
echo " -m model CPU model: Either 'hun' or 'ox' (default ox)" >&2
echo " -v Be verbose" >&2
echo "" >&2
exit 1
}
while getopts "hvw:b:k:i:r:" opt; do
while getopts "hvw:b:k:i:r:p:j:m:R:" opt; do
case "${opt}" in
v) verbose=1 ;;
w) bitstream="${OPTARG}" ;;
@ -302,21 +422,32 @@ while getopts "hvw:b:k:i:r:" opt; do
k) kernel="${OPTARG}"; resetcpu=1 ;;
i) initrd="${OPTARG}"; resetcpu=1 ;;
r) rootfs="${OPTARG}"; resetcpu=1 ;;
R) bootrom="${OPTARG}"; resetcpu=1 ;;
p) pcidev="${OPTARG}" ;;
j) jtagserial="${OPTARG}" ;;
m) model="${OPTARG}" ;;
h) usage ;;
*) usage ;;
esac
done
jtagserial="${jtagserial:-$FPGACTL_SERIAL}"
pcidev="${pcidev:-$FPGACTL_PCIDEV}"
test "$verbose" && set -x
check_environment
select_pcidev
test "$bitstream" && load_bitstream "$bitstream"
test "$resetcpu" && do_system_reset
test "$resetcpu" && do_cpu_reset
test "$bootloader" && load_file_in_memory "$bootloader" $bootloader_addr
test "$kernel" && load_file_in_memory "$kernel" $kernel_addr
test "$initrd" && load_file_in_memory "$initrd" $initrd_addr
test "$rootfs" && load_file_in_memory "$rootfs" $rootfs_addr
test "$resetcpu" && do_system_release
test "$bootrom" && load_file_in_memory "$bootrom" $bootrom_addr
test "$resetcpu" && do_cpu_release
exit 0
# vim:ts=2:sw=2:ai:foldmethod=marker:foldlevel=0:

54
fpga/run-login.sh Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/bash
# There are several situations in which we may find the jobs:
# - There are no jobs queued or running
# - There is at least one job running
# - There is one job queued
# - There was a job running but ended and is now ending
set -x
set -e
path="$1"
allocated=
# First determine if we already have jobs already
n=$(squeue --me -lh | wc -l)
if [ "$n" -gt 1 ]; then
echo "Too many jobs queued already" >&2
exit 1
fi
if [ "$n" == 0 ]; then
# No running jobs, so allocate a new job
salloc -N 1 --constraint=dmaqdma --no-shell -t 1-00
allocated=1
# Wait until the job is running
while [ "$n" != 1 ]; do
sleep 2
n=$(squeue --me -lh | grep RUNNING | wc -l)
done
else
# There is one job, ensure it is running
n=$(squeue --me -lh | grep RUNNING | wc -l)
if [ "$n" != 1 ]; then
echo "The job is not running, stopping" >&2
exit 1
fi
fi
# If this point is reached there is one job running
host=$(squeue --me -h -o %N)
echo "Switching to $host"
# Continue the execution there
ssh "$host" "$path/run-node.sh" "$path"
# Cancel our job if it was successful
if [ "$allocated" ]; then
scancel --me
fi

38
fpga/run-node.sh Executable file
View File

@ -0,0 +1,38 @@
#!/usr/bin/bash
#set -x
set -e
echo "Hello from $(hostname)"
path="$1"
cd "$path"
# First kill any picocom instance
killall picocom || true
# Setup the environment
. env.sh
set -x
# Then perform the boot
./fpgactl -w bitstream.bit -b opensbi.bin -k kernel.bin -i initrd.bin -r rootfs.img
# Normal timeouts
timeout=$((30 * 60)) # Always stop after 30 min
timeout_silent=$((3 * 60)) # Stop if 3 min without output
# Timeouts for SPEC benchmarks
#timeout=$((12 * 60 * 60)) # Always stop after 12 h
#timeout_silent=$((4 * 60 * 60)) # Stop if 4 h without output (some benchmarks take 1.6h)
# Set dead switch
sleep $timeout && killall picocom &
# Note: --imap igncr is broken so we replace it with LF.
# See https://github.com/npat-efault/picocom/pull/114
# It looks like picocom is abandoned, we may want to switch to minicom or
# stty+cat
picocom --imap crlf -q -x $(($timeout_silent*1000)) -b 115200 $FPGACTL_UART

22
fpga/run-remotely.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
# Executes a pipeline in a remote machine taking the values from the environment
# Usage fpga/run-remotely.sh <host>:<path>
set -e
dst=fpgalogin1:nixos
if [ "$1" != "" ]; then
dst="$1"
fi
path=${dst#*:}
# Copy all required elements to the destination machine
fpga/upload.sh "$dst"
# Launch the pipeline from there
set +x
#ssh fpgalogin1 "$path/run-login.sh" "$path" | awk -f fpga/verify.awk
ssh fpgalogin1 "$path/run-login.sh" "$path"

View File

@ -3,15 +3,28 @@
set -e
set -x
dst=femu:nixos/
#dst=femu:nixos
dst=fpgalogin1:nixos
rsync -a fpga/fpgactl "$dst"
rsync -a fpga/boot.sh "$dst"
rsync -a fpga/env.sh "$dst"
rsync "$OPENSBI/share/opensbi/lp64/fpga/openpiton/firmware/fw_payload.bin" "$dst/opensbi.bin"
if [ "$1" != "" ]; then
dst="$1"
fi
rsync -a fpga/run-login.sh "$dst/"
rsync -a fpga/run-node.sh "$dst/"
rsync -a fpga/fpgactl "$dst/"
rsync -a fpga/boot.sh "$dst/"
rsync -a fpga/env.sh "$dst/"
rsync $(find "$OPENSBI" -name fw_payload.bin) "$dst/opensbi.bin"
rsync "$KERNEL/Image" "$dst/kernel.bin"
rsync "$INITRD/initrd" "$dst/initrd.bin"
rsync "$ROOTFS/sd-image/rootfs.img" "$dst/rootfs.img"
if [ -n "$ROOTFS" ]; then
rsync "$ROOTFS/sd-image/rootfs.img" "$dst/rootfs.img"
else
echo "Skipping rootfs"
fi
rsync "$BITSTREAM" "$dst/bitstream.bit"
rsync "$BOOTROM" "$dst/bootrom.bin"
rsync "$UBOOT_ENV" "$dst/uboot.env"
echo "Now go to $dst and run ./boot.sh"

20
fpga/verify.awk Normal file
View File

@ -0,0 +1,20 @@
BEGIN {
bootrom_ok = 0
opensbi_ok = 0
test_ok = 0
}
/RBOOTROM/ { bootrom_ok = 1 }
/^OpenSBI v/ { opensbi_ok = 1 }
/^TEST-RESULT-OK/ { test_ok = 1 }
{ printf "line> "; print }
END {
printf "Test summary:\n"
printf " Bootrom: %s\n", bootrom_ok ? "OK" : "FAIL";
printf " OpenSBI: %s\n", opensbi_ok ? "OK" : "FAIL";
printf " Result: %s\n", test_ok ? "OK" : "FAIL";
if (test_ok)
exit 0;
else
exit 1;
}

View File

@ -57,6 +57,12 @@
serviceConfig.Restart = "always";
};
# Disable hvc0 as it is racing for the same console
systemd.services."serial-getty@hvc0" = {
enable = lib.mkForce false;
wantedBy = lib.mkForce [ ];
};
sdImage = {
# The image will be loaded as-is in memory, so no compression
compressImage = false;
@ -96,13 +102,13 @@
initrd = "${config.system.build.initialRamdisk}/initrd";
in prev.runCommand "uboot.txt" {} ''
cat > $out <<EOF
# Create pmem
fdt mknode / pmem@0x180000000
fdt set /pmem@0x180000000 compatible "pmem-region"
fdt set /pmem@0x180000000 reg <0x1 0x80000000 0x0 0x80000000>
# Create pmem of 3 GiB [0x140000000, 0x200000000)
fdt mknode / pmem@0x140000000
fdt set /pmem@0x140000000 compatible "pmem-region"
fdt set /pmem@0x140000000 reg <0x1 0x40000000 0x0 0xc0000000>
# Reduce memory
fdt set /memory@80000000 reg <0x00000000 0x80000000 0x00000001 0x00000000>
# Reduce memory to 3 GiB [0x80000000, 0x140000000)
fdt set /memory@80000000 reg <0x0 0x80000000 0x0 0xc0000000>
# Set kernel options
setenv bootargs "root=/dev/ram0 loglevel=7 debug rw earlycon=sbi boot.trace console=hvc0 init=${init}"
@ -120,6 +126,7 @@
"PLATFORM=fpga/openpiton"
"FW_PAYLOAD_PATH=${final.uboot}/u-boot-nodtb.bin"
];
patches = [ ./patches/opensbi-lagarto-hun.patch ];
});
}) ];
}

617
lagarto-ox.nix Normal file
View File

@ -0,0 +1,617 @@
{ config, lib, utils, pkgs, modulesPath, self, ... }:
{
imports = [
"${modulesPath}/installer/sd-card/sd-image.nix"
];
#nixpkgs.crossSystem = {
# system = "riscv64-linux";
# gcc.arch = "rv64imafd";
# gcc.tune = "generic";
#};
# We don't need any firmware
hardware.firmware = lib.mkForce [];
# Doesn't work, it gets activated via the kernel socket.
# # No need for udev
# services.udev.enable = false;
# systemd.suppressedSystemUnits = [
# "systemd-udev-trigger.service"
# ];
# Output the unit name so we can remove it
systemd.extraConfig = ''
StatusUnitFormat=name
'';
# Prevent executing the nscd program as it seems to hang the CPU
system.activationScripts.users = lib.mkForce (
let
cfg = config.users;
spec = pkgs.writeText "users-groups.json" (builtins.toJSON {
inherit (cfg) mutableUsers;
users = lib.mapAttrsToList (_: u:
{
inherit (u)
name uid group description home homeMode createHome isSystemUser
password hashedPasswordFile hashedPassword
autoSubUidGidRange subUidRanges subGidRanges
initialPassword initialHashedPassword expires;
shell = utils.toShellPath u.shell;
}) cfg.users;
groups = lib.attrValues cfg.groups;
});
in
if !config.systemd.sysusers.enable then {
supportsDryActivation = true;
text = ''
install -m 0700 -d /root
install -m 0755 -d /home
${pkgs.perl.withPackages (p: [ p.FileSlurp p.JSON ])}/bin/perl \
-w ${./patches/update-users-groups.pl} ${spec}
'';
} else "" # keep around for backwards compatibility
);
# Also disable the nscd daemon
services.nscd.enable = false;
system.nssModules = lib.mkForce []; # Required
system.build.bootStage2 = let
useHostResolvConf = config.networking.resolvconf.enable && config.networking.useHostResolvConf;
bootStage2 = pkgs.substituteAll {
src = ./patches/stage-2-init.sh;
shellDebug = "${pkgs.bashInteractive}/bin/bash";
bashInteractive = "${pkgs.bashInteractive}";
bench2 = "${pkgs.bench2}";
shell = "${pkgs.bash}/bin/bash";
inherit (config.boot) readOnlyNixStore systemdExecutable extraSystemdUnitPaths;
inherit (config.system.nixos) distroName;
isExecutable = true;
inherit useHostResolvConf;
inherit (config.system.build) earlyMountScript;
path = lib.makeBinPath ([
pkgs.coreutils
pkgs.util-linux
pkgs.strace
] ++ lib.optional useHostResolvConf pkgs.openresolv);
postBootCommands = pkgs.writeText "local-cmds"
''
${config.boot.postBootCommands}
${config.powerManagement.powerUpCommands}
'';
};
in lib.mkForce bootStage2;
boot.kernelPackages = pkgs.linuxPackages_latest;
boot = {
extraModulePackages = [
# Add the custom Ethernet module
#pkgs.xilinx-axienet-carv
];
kernelModules = config.boot.initrd.kernelModules;
kernelPatches = [
{
name = assert false; "sbi-early-console";
patch = null;
extraConfig =
# Early console via SBI
''
RISCV_SBI y
RISCV_SBI_V01 y
SERIAL_EARLYCON y
SERIAL_EARLYCON_RISCV_SBI y
HVC_DRIVER y
HVC_RISCV_SBI y
''
# Enable console driver
+''
SERIAL_8250 y
SERIAL_8250_CONSOLE y
SERIAL_OF_PLATFORM y
CONSOLE_POLL y
''
# Allows regions of persistent memory to be described in the device-tree.
+ ''
OF_PMEM y
''
# Allow you to use a contiguous range of reserved memory as one or more
# persistent block devices (/dev/pmem0)
+ ''
LIBNVDIMM y
BLK_DEV_PMEM y
''
# No vector extensions
+ ''
RISCV_ISA_V n
RISCV_ISA_V_DEFAULT_ENABLE n
''
# Debugging
+ ''
DEBUG_KERNEL y
DEBUG_MISC y
DEBUG_WX y
MAGIC_SYSRQ y
SYSRQ_SERIAL y
DEBUG_VM y
SOFTLOCKUP_DETECTOR y
SOFTLOCKUP_DETECTOR_INTR_STORM y
HARDLOCKUP_DETECTOR y
DETECT_HUNG_TASK y
WQ_WATCHDOG y
WQ_CPU_INTENSIVE_REPORT y
TRACING y
BOOTTIME_TRACING y
STRICT_DEVMEM n
MMIOTRACE y
''
# Disable SMP so we don't have IPI
+ ''
SMP n
''
# SPI driver
+ ''
COMPILE_TEST y
SPI y
SPI_DAVINCI m
''
;
}
];
initrd = {
# Avoid zstd as we don't have the tools in "cucu" machine
compressor = "gzip";
kernelModules = [
# DMA for Ethernet
#"xilinx_dma"
# Load the Ethernet module by default
#"xxvnet_carv"
# For SPI
"spi_davinci"
"spidev"
];
# Custom init script
extraFiles = {
"/shell".source = pkgs.writeScript "shell" ''
#!${config.system.build.extraUtils}/bin/ash
set -x
export PATH=${config.system.build.extraUtils}/bin
ash
'';
"/testplic".source = pkgs.writeScript "testplic" ''
#!${config.system.build.extraUtils}/bin/ash
export PATH=${config.system.build.extraUtils}/bin
set -x
(
echo "--- Testing threshold register init value"
# Ensure that reading a few times the threshold value
# always gives the same initial value 0
t1=$(devmem 0x40a00000) # Read context 1 threshold value
t2=$(devmem 0x40a00000) # Read context 1 threshold value
t3=$(devmem 0x40a00000) # Read context 1 threshold value
found="$t1 $t2 $t3"
expected="0x00000000 0x00000000 0x00000000"
if [ "$found" = "$expected" ]; then
echo "--- Threshold init value: OK"
else
echo "found =$found"
echo "expected=$expected"
echo "--- Threshold init value: FAIL"
fi
)
(
echo "--- Testing threshold register stability"
# Write the priority register of an interrupt and ensure
# the threshold register didn't change
devmem 0x40a00000 32 0 # Write context 1 threshold value 0
devmem 0x40800010 32 5 # Write source 4 priority value 5
t1=$(devmem 0x40a00000) # Read context 1 threshold value
t2=$(devmem 0x40a00000) # Read context 1 threshold value
found="$t1 $t2"
expected="0x00000000 0x00000000"
if [ "$found" = "$expected" ]; then
echo "--- Threshold stability: OK"
else
echo "found =$found"
echo "expected=$expected"
echo "--- Threshold stability: FAIL"
fi
)
(
echo "--- Testing claim register"
# Use aux timer on source 4 for this one
pending=$(devmem 0x40801000) # Dump pending bits of sources 0-31
# Ensure the aux timer is pending
if [ "$pending" = "0x00000010" ]; then
# Make sure the priority is higher than the threshold
devmem 0x40800010 32 0x10 # Write source 4 priority value 16
devmem 0x40802080 32 0x10 # Enable source 4 in context 1
# Writing the threshold has to be last, otherwise it will change
devmem 0x40a00000 32 0 # Write context 1 threshold value 0
c1=$(devmem 0x40a01004) # Claim context 1
c2=$(devmem 0x40a01004) # Claim context 1
c3=$(devmem 0x40a01004) # Claim context 1
found="$c1 $c2 $c3"
expected="0x00000004 0x00000004 0x00000004"
if [ "$found" = "$expected" ]; then
echo "--- Testing claim register: OK"
else
echo "found =$found"
echo "expected=$expected"
echo "--- Testing claim register: FAIL"
fi
else
echo "unknown pending bits: $pending"
echo "--- Testing claim register: SKIP"
fi
)
set +x
#echo "all done, dropping to a shell..."
#ash
'';
"/preinit".source = pkgs.writeScript "preinit" ''
#!${config.system.build.extraUtils}/bin/ash
export PATH=${config.system.build.extraUtils}/bin
# csrtool all-in-order
# ip addr
# cat /proc/interrupts
# modprobe xxvnet_carv
# plictool -c2
# plictool -c2
# plictool -c2
# ip addr
exec /init
'';
};
# Add riscv-tools to initrd
extraUtilsCommands = ''
cp -a ${pkgs.riscv-tools}/bin/* $out/bin
'';
# Write a counter to the DMA region, so we can check the kernel is not
# dead. Monitor from the host with:
# while [ 1 ]; do xxd -s $((0x1bfff0000 - 0x60000000)) \
# -l 4 /dev/qdma34000-MM-1; sleep 0.2; done
preDeviceCommands = ''
# Seed RNG
seedrng -d /tmp || true
mv /tmp/seed.no-credit /tmp/seed.credit || true
seedrng -d /tmp || true
echo "Available entropy: $(cat /proc/sys/kernel/random/entropy_avail)"
# Last chance to enter a shell
if read -t 3 -p 'Press enter for shell... '; then
allowShell=1
fail
fi
# echo "Running tests..."
# sh /testplic
# echo "Creating a heartbeat counter at 0x1bfff0000"
# sh -c 'hb=0; while [ 1 ]; do let hb=$hb+1; devmem 0x1bfff0000 32 $hb; done' &
''
+
# Disable proactive compaction. May be better to disable CONFIG_COMPACTION.
''
echo 0 > /proc/sys/vm/compaction_proactiveness
''
# +
# # Show stacktrace on calls to the hvc_remove function.
# ''
# echo "Mount debugfs"
# mkdir -p /sys/kernel/debug/
# mount -t debugfs none /sys/kernel/debug/
# td=/sys/kernel/debug/tracing
# echo hvc_remove > $td/set_ftrace_filter
# echo function > $td/current_tracer
# echo 1 > $td/options/func_stack_trace
# ''
# FIXME: Disable sched_switch for now, as it still hangs the boot...
# +
# # Exclude the second pid, which is the kthread that will dump the trace to
# # the console, otherwise we live lock the kernel. Then enable the
# # sched_switch events.
# ''
# echo "Mount debugfs"
# mkdir -p /sys/kernel/debug/
# mount -t debugfs none /sys/kernel/debug/
# echo "Exclude pid 2 from sched"
# echo '(prev_pid != 2 && next_pid != 2)' > /sys/kernel/debug/tracing/events/sched/filter
# echo "Enable sched_switch events"
# echo 1 > /sys/kernel/debug/tracing/events/sched/sched_switch/enable
# ''
;
};
loader = {
grub.enable = false;
generic-extlinux-compatible.enable = true;
};
};
# No network
services.openssh.enable = false;
networking.useDHCP = false;
# Run getty on /dev/console and restartt until it works
systemd.services."serial-getty@console" = {
enable = true;
after = [ "network.target" ];
wantedBy = [ "getty.target" ]; # to start at boot
serviceConfig.Restart = "always";
};
# Disable hvc0 as it is racing for the same console
systemd.services."serial-getty@hvc0" = {
enable = lib.mkForce false;
wantedBy = lib.mkForce [ ];
};
services.getty.autologinUser = lib.mkForce "root";
sdImage = {
# The image will be loaded as-is in memory, so no compression
compressImage = false;
imageName = "rootfs.img";
# Not needed for now
expandOnBoot = false;
populateFirmwareCommands = "";
populateRootCommands = ''
mkdir -p ./files/boot
${config.boot.loader.generic-extlinux-compatible.populateCmd} \
-c ${config.system.build.toplevel} \
-d ./files/boot
'';
};
nixpkgs.overlays = [ (final: prev: {
#busybox = prev.busybox.overrideAttrs (old: {
# # Print some debug lines on switch_root to see where it hangs.
# patches = (old.patches or []) ++ [ ./patches/busybox-debug.patch ];
#});
linuxPackages_latest = prev.linuxPackages_latest;
#linuxPackages_latest = prev.linuxPackages_latest.extend (lib.const (ksuper: {
# kernel = ksuper.kernel.override {
# stdenv = prev.gcc8Stdenv;
# };
#}));
bench2 = final.writeShellScript "bench2" ''
# Performs minimal FS setup and runs the SPEC benchmark
mkdir /tmp /bin /root
mount -t tmpfs tmpfs /tmp
export TMPDIR=/tmp
# We need /bin/sh
ln -s $(which sh) /bin/sh
# Check CPU usage
vmstat 5 5
bash -x speclaunch
cat /tmp/spec/time.csv
# Give me a shell at the end
bash -l
'';
ox-dtb = prev.stdenv.mkDerivation rec {
name = "ox.dtb";
src = ./dts;
dontConfigure = true;
nativeBuildInputs = [ prev.buildPackages.dtc ];
buildPhase = ''
make lagarto_ox.dtb
'';
installPhase = ''
mkdir $out
cp lagarto_ox.* $out
'';
dontFixup = true;
hardeningDisable = [ "all" ];
};
#bitstream = "${final.bitstreams}/lagarto-3-ox/gold.bit";
bitstream = "${final.bitstreams}/lagarto-3-ox/ox_u55c_87a14c32_fix_threshold.bit";
bootrom = "${final.rbootrom}/rbootrom.bin";
uboot = prev.ubootQemuRiscv64Smode.override {
filesToInstall = [ "u-boot-nodtb.bin" ];
#version = "2023.07.02-print-cpu-probe";
#src = builtins.fetchGit {
# url = "file:///home/Computational/rarias/riscv/u-boot";
# rev = "f80a22a480f0e4157647bacf90e663be457c72c4";
#};
patches = [
#./patches/u-boot-debug.patch
./patches/uboot-debug-ext-interrupts.patch
./patches/uboot-exception-extras.patch
];
# Copy our environment to board/emulation/qemu-riscv/environ.env
preConfigure = ''
cp ${final.uboot-env} board/emulation/qemu-riscv/environ.env
'';
#postConfigure = ''
# echo --------------------------- generated config:
# cat .config
# echo ---------------------------
#'';
#postBuild = ''
# echo --------------------------- generated env starts
# cat include/generated/env.in
# echo --------------------------- generated env ends
#'';
#
# CONFIG_SERIAL_PRESENT=n
# CONFIG_SYS_NS16550=n
extraConfig = ''
CONFIG_RISCV_ISA_C=n
CONFIG_REQUIRE_SERIAL_CONSOLE=n
CONFIG_SERIAL=y
CONFIG_SERIAL_PUTS=y
CONFIG_SHOW_BOOT_PROGRESS=y
CONFIG_SHOW_REGS=y
CONFIG_LIBCOMMON_SUPPORT=y
CONFIG_SERIAL_SEARCH_ALL=n
CONFIG_SERIAL_PROBE_ALL=n
CONFIG_OF_CONTROL=y
CONFIG_OF_EMBED=y
CONFIG_OF_HAS_PRIOR_STAGE=y
CONFIG_BLKMAP=y
CONFIG_CMD_BLKMAP=y
CONFIG_SBI_V01=y
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_ANNOUNCE=y
CONFIG_DEBUG_SBI_CONSOLE=y
CONFIG_SMP=n
CONFIG_TRACE_EARLY=y
CONFIG_CMD_MEMTEST=y
CONFIG_CMD_EXCEPTION=y
CONFIG_CMD_TIMER=y
CONFIG_ENV_SOURCE_FILE="environ"
''
# # Enable debug logs
# +
# ''
# CONFIG_LOG=y
# CONFIG_LOGLEVEL=9
# CONFIG_LOG_MAX_LEVEL=9
# CONFIG_LOG_DEFAULT_LEVEL=9
# ''
;
extraMakeFlags = [
#"V=1"
#"KCPPFLAGS=-DLOG_DEBUG"
#"EXT_DTB=${final.ox-dtb}/lagarto_ox.dtb"
];
};
uboot-env = let
init = "${config.system.build.toplevel}/init";
initrd = "${config.system.build.initialRamdisk}/initrd";
# Create pmem of 3 GiB [0x140000000, 0x200000000)
#fdt mknode / pmem@0x140000000
#fdt set /pmem@0x140000000 compatible "pmem-region"
#fdt set /pmem@0x140000000 reg <0x1 0x40000000 0x0 0xc0000000>
# Reduce memory to 3 GiB [0x80000000, 0x140000000)
#fdt set /memory@80000000 reg <0x0 0x80000000 0x0 0xc0000000>
# Set kernel bootcmd options.
# rdinit=/preinit boot custom preinit script
# console=ttyS0,115200n8 use serial driver (slow)
# Systemd options
# systemd.log_level=debug
# systemd.log_target=console
# NixOS interesting options:
# debug1 enable debug shell in stage 1
# debug2 enable debug shell in stage 2 (custom)
# bench2 run benchmark on stage 2 (custom)
# boot.trace enable set -x in stage 1
# boot.tracedebug enable set -x in stage 2
# Ftrace interesting options:
# trace_event=initcall:* trace the init function of drivers
# trace_options=sym-addr display function address
# tp_printk write ftrace events to console
# trace_buf_size=1M set ftrace buffer to 1M
#
in prev.runCommand "uboot.txt" {} ''
cat > $out <<EOF
xtrace=yes
bootargs=root=/dev/ram0 loglevel=7 rw earlycon=sbi console=hvc0 debug2 init=${init}
ramdisk_size=$(stat --format %s $(readlink -f ${initrd}))
bootcmd=fdt print; booti \''${kernel_addr_r} \''${ramdisk_addr_r}:\''${ramdisk_size} \''${fdtcontroladdr}
EOF
'';
opensbi = prev.opensbi.overrideAttrs (old: rec {
#version = "1.4";
version = "1.5";
src = prev.fetchFromGitHub {
owner = "riscv-software-src";
repo = "opensbi";
rev = "v${version}";
#hash = "sha256-T8ZeAzjM9aeTXitjE7s+m+jjGGtDo2jK1qO5EuKiVLU="; #1.4
hash = "sha256-vK14P97FcaVz4GDr/0055Z6s/k7BPKPQGZ/MQxbOWu0="; #1.5
};
#NIX_DEBUG=5;
makeFlags = [
"PLATFORM=generic"
#"CONFIG_SBI_ECALL_RFENCE=n"
#"PLATFORM_RISCV_ISA=rv64imafd" # No compressed instructions
#"PLATFORM_RISCV_ISA=rv64g" # No compressed instructions
#"PLATFORM_RISCV_ABI=lp64d"
"FW_PAYLOAD_PATH=${final.uboot}/u-boot-nodtb.bin"
"FW_FDT_PATH=${final.ox-dtb}/lagarto_ox.dtb"
# Ensure it doesn't overlap from the 0x80200000 where the kernel will be
# placed.
"FW_PAYLOAD_FDT_ADDR=0xc0000000"
];
patches = [
#./patches/opensbi-timer-debug.patch # Print calls to machine trap
#./patches/opensbi-enable-meip.patch
#./patches/opensbi-enable-seip.patch
#./patches/opensbi-test-plic.patch # Working delegation test, disabled for now
./patches/opensbi-dump-mregs.patch
#./patches/opensbi-dont-delegate.patch
#./patches/ox-alveo-platform-plic.patch
];
});
# Custom kernel driver for the Ethernet
xilinx-axienet-carv = let
kernel = config.boot.kernelPackages.kernel;
in prev.stdenv.mkDerivation rec {
pname = "xilinx-axienet-carv";
version = src.shortRev;
src = builtins.fetchGit {
url = "git@gitlab-internal.bsc.es:meep/meep-os/lagarto-openpiton-sdk.git";
rev = "d2ae2e788bf1cc60676599184a9ec1128cc81d81";
ref = "master";
};
patches = [
./patches/ethernet-driver-poll.patch
./patches/ethernet-driver-build.patch
./patches/ethernet-driver-kbuild.patch
];
preConfigure = ''
export sourceRoot=$PWD/drivers
cd drivers
#rm Makefile
'';
nativeBuildInputs = kernel.moduleBuildDependencies;
makeFlags = kernel.makeFlags ++ [
"-C"
"${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
"M=$(PWD)"
];
buildFlags = [ "modules" ];
installFlags = [ "INSTALL_MOD_PATH=${placeholder "out"}" ];
installTargets = [ "modules_install" ];
};
}) ];
}

View File

@ -3,5 +3,97 @@ final: prev:
# Changes to packages from nixpkgs
{
clangEpi = final.callPackage ./pkgs/llvm-epi/default.nix { openmp = null; };
clangEpiUnwrapped = final.callPackage ./pkgs/llvm-epi/clang.nix { };
stdenvClangEpi = final.stdenv.override { cc = final.buildPackages.clangEpi; allowedRequisites = null; };
rvb = final.callPackage ./pkgs/rvb/default.nix { };
rvb-clang = final.callPackage ./pkgs/rvb/default.nix { stdenv = final.stdenvClangEpi; };
stream = final.callPackage ./pkgs/stream/default.nix { };
spec-cpu-tools = final.callPackage ./pkgs/spec-cpu/tools.nix { };
spec-cpu = final.callPackage ./pkgs/spec-cpu/default.nix { };
spec-cpu-mini = final.callPackage ./pkgs/spec-cpu/mini.nix { };
specinvoke = final.callPackage ./pkgs/spec-cpu/specinvoke.nix { };
speclaunch = final.callPackage ./pkgs/spec-cpu/speclaunch.nix { };
spec-cpu-clang = final.callPackage ./pkgs/spec-cpu/default.nix { stdenv = final.stdenvClangEpi; };
blis = ((prev.blis.override {
blas64 = true;
withArchitecture = "generic";
}).overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or []) ++ [
prev.buildPackages.gfortran
];
})).overrideDerivation (old : {
configureFlags = [
"--enable-cblas"
"--blas-int-size=64"
"--enable-threading=openmp"
#"--build=x86_64-unknown-linux-gnu"
#"--host=riscv64-unknown-linux-gnu"
"generic"
];
});
riscv-tools = prev.pkgsStatic.stdenv.mkDerivation {
name = "riscv-tools";
src = ./tools;
makeFlags = [ "PREFIX=${placeholder "out"}" ];
};
bitstreams = builtins.fetchGit {
url = "git@bscpm03.bsc.es:rarias/bitstreams.git";
rev = "2f899627a226890c6f9820aa44e34c2ecea03faf";
};
# Baremetal tests for standalone FPGA
sa-fpga-tests = prev.pkgsStatic.stdenv.mkDerivation {
name = "sa-fpga-tests";
src = builtins.fetchGit {
url = "git@gitlab-internal.bsc.es:hwdesign/rtl/core-tile/sa-fpga.git";
rev = "720be4f1f5dd0ef963135992578be2ab55fb5537";
ref = "main";
};
dontConfigure = true;
patches = [
#./patches/sa-fpga-crt.patch
#./patches/sa-fpga-text-address.patch
./patches/sa-fpga-uart.patch
./patches/sa-fpga-plic-registers.patch
./patches/sa-fpga-add-plic-claim-test.patch
];
buildPhase = ''
cd fpga_core_bridge/simulator/tests/c_tests/
make RISCV_PREFIX=riscv64-unknown-linux-musl-
# Generate binary images to be loaded in memory
for f in *.riscv; do
# Don't copy 0x40000000 section
$OBJCOPY -R .tohost -O binary $f $f.bin
done
'';
installPhase = ''
ls -lah
make install install_dir=$out
cp -a *.bin $out
'';
dontFixup = true;
hardeningDisable = [ "all" ];
};
rbootrom = prev.pkgsStatic.stdenv.mkDerivation {
name = "rbootrom";
src = ./bootrom;
dontConfigure = true;
buildPhase = ''
make
'';
installPhase = ''
mkdir $out
cp rbootrom.bin rbootrom.elf $out/
'';
dontFixup = true;
hardeningDisable = [ "all" ];
};
}

View File

@ -0,0 +1,438 @@
diff --git a/include/sbi_utils/serial/alveo_uart.h b/include/sbi_utils/serial/alveo_uart.h
new file mode 100644
index 0000000..0b6408c
--- /dev/null
+++ b/include/sbi_utils/serial/alveo_uart.h
@@ -0,0 +1,13 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SERIAL_ALVEO_UART_H__
+#define __SERIAL_ALVEO_UART_H__
+
+#include <sbi/sbi_types.h>
+
+int alveo_uart_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
+ u32 reg_width, u32 reg_offset);
+
+#endif
diff --git a/lib/utils/serial/Kconfig b/lib/utils/serial/Kconfig
index e3589ca..b754c7c 100644
--- a/lib/utils/serial/Kconfig
+++ b/lib/utils/serial/Kconfig
@@ -84,6 +84,10 @@ config SERIAL_UART8250
bool "8250 UART support"
default n
+config SERIAL_ALVEO_UART
+ bool "ALveo UART support"
+ default n
+
config SERIAL_XILINX_UARTLITE
bool "Xilinx UART Lite support"
default n
diff --git a/lib/utils/serial/alveo_uart.c b/lib/utils/serial/alveo_uart.c
new file mode 100644
index 0000000..a351741
--- /dev/null
+++ b/lib/utils/serial/alveo_uart.c
@@ -0,0 +1,123 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi_utils/serial/alveo_uart.h>
+
+/* clang-format off */
+
+#define UART_RBR_OFFSET 0 /* In: Recieve Buffer Register */
+#define UART_THR_OFFSET 0 /* Out: Transmitter Holding Register */
+#define UART_DLL_OFFSET 0 /* Out: Divisor Latch Low */
+#define UART_IER_OFFSET 1 /* I/O: Interrupt Enable Register */
+#define UART_DLM_OFFSET 1 /* Out: Divisor Latch High */
+#define UART_FCR_OFFSET 2 /* Out: FIFO Control Register */
+#define UART_IIR_OFFSET 2 /* I/O: Interrupt Identification Register */
+#define UART_LCR_OFFSET 3 /* Out: Line Control Register */
+#define UART_MCR_OFFSET 4 /* Out: Modem Control Register */
+#define UART_LSR_OFFSET 5 /* In: Line Status Register */
+#define UART_MSR_OFFSET 6 /* In: Modem Status Register */
+#define UART_SCR_OFFSET 7 /* I/O: Scratch Register */
+#define UART_MDR1_OFFSET 8 /* I/O: Mode Register */
+
+#define UART_LSR_FIFOE 0x80 /* Fifo error */
+#define UART_LSR_TEMT 0x40 /* Transmitter empty */
+#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+#define UART_LSR_BI 0x10 /* Break interrupt indicator */
+#define UART_LSR_FE 0x08 /* Frame error indicator */
+#define UART_LSR_PE 0x04 /* Parity error indicator */
+#define UART_LSR_OE 0x02 /* Overrun error indicator */
+#define UART_LSR_DR 0x01 /* Receiver data ready */
+#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */
+
+/* clang-format on */
+
+static volatile char *alveo_uart_base;
+static u32 alveo_uart_in_freq;
+static u32 alveo_uart_baudrate;
+static u32 alveo_uart_reg_width;
+static u32 alveo_uart_reg_shift;
+
+static u32 get_reg(u32 num)
+{
+ u32 offset = num << alveo_uart_reg_shift;
+
+ if (alveo_uart_reg_width == 1)
+ return readb(alveo_uart_base + offset);
+ else if (alveo_uart_reg_width == 2)
+ return readw(alveo_uart_base + offset);
+ else
+ return readl(alveo_uart_base + offset);
+}
+
+static void set_reg(u32 num, u32 val)
+{
+ u32 offset = num << alveo_uart_reg_shift;
+
+ if (alveo_uart_reg_width == 1)
+ writeb(val, alveo_uart_base + offset);
+ else if (alveo_uart_reg_width == 2)
+ writew(val, alveo_uart_base + offset);
+ else
+ writel(val, alveo_uart_base + offset);
+}
+
+static void alveo_uart_putc(char ch)
+{
+ while (!(get_reg(UART_LSR_OFFSET) & UART_LSR_TEMT))
+ ;
+
+ set_reg(UART_THR_OFFSET, ch);
+}
+
+static int alveo_uart_getc(void)
+{
+ if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
+ return get_reg(UART_RBR_OFFSET);
+ return -1;
+}
+
+static struct sbi_console_device alveo_uart_console = {
+ .name = "alveo_uart",
+ .console_putc = alveo_uart_putc,
+ .console_getc = alveo_uart_getc
+};
+
+int alveo_uart_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
+ u32 reg_width, u32 reg_offset)
+{
+ u16 bdiv = 0;
+
+ alveo_uart_base = (volatile char *)base + reg_offset;
+ alveo_uart_reg_shift = reg_shift;
+ alveo_uart_reg_width = reg_width;
+ alveo_uart_in_freq = in_freq;
+ alveo_uart_baudrate = baudrate;
+
+ if (alveo_uart_baudrate) {
+ bdiv = alveo_uart_in_freq / (16 * alveo_uart_baudrate);
+ }
+
+ /* Disable all interrupts */
+ set_reg(UART_IER_OFFSET, 0x00);
+ /* Enable DLAB */
+ set_reg(UART_LCR_OFFSET, 0x80);
+
+ if (bdiv) {
+ /* Set divisor low byte */
+ set_reg(UART_DLL_OFFSET, bdiv & 0xff);
+ /* Set divisor high byte */
+ set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
+ }
+
+ /* 8 bits, no parity, one stop bit */
+ set_reg(UART_LCR_OFFSET, 0x03); // previous was 0x0B
+ /* Disable all interrupts*/
+ set_reg(UART_IER_OFFSET, 0x00);
+
+ sbi_console_set_device(&alveo_uart_console);
+
+ return 0;
+}
diff --git a/lib/utils/serial/objects.mk b/lib/utils/serial/objects.mk
index 1e6bd2e..0268bdf 100644
--- a/lib/utils/serial/objects.mk
+++ b/lib/utils/serial/objects.mk
@@ -44,5 +44,6 @@ libsbiutils-objs-$(CONFIG_SERIAL_SHAKTI) += serial/shakti-uart.o
libsbiutils-objs-$(CONFIG_SERIAL_SIFIVE) += serial/sifive-uart.o
libsbiutils-objs-$(CONFIG_SERIAL_LITEX) += serial/litex-uart.o
libsbiutils-objs-$(CONFIG_SERIAL_UART8250) += serial/uart8250.o
+libsbiutils-objs-$(CONFIG_SERIAL_ALVEO_UART) += serial/alveo_uart.o
libsbiutils-objs-$(CONFIG_SERIAL_XILINX_UARTLITE) += serial/xlnx-uartlite.o
libsbiutils-objs-$(CONFIG_SERIAL_SEMIHOSTING) += serial/semihosting.o
diff --git a/platform/fpga/sargantana_alveo/Kconfig b/platform/fpga/sargantana_alveo/Kconfig
new file mode 100644
index 0000000..bf3e7e6
--- /dev/null
+++ b/platform/fpga/sargantana_alveo/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+config PLATFORM_SARGANTANA_ALVEO_FPGA
+ bool
+ select FDT
+ select IPI_MSWI
+ select IRQCHIP_PLIC
+ select SERIAL_ALVEO_UART
+ select TIMER_MTIMER
+ default y
diff --git a/platform/fpga/sargantana_alveo/configs/defconfig b/platform/fpga/sargantana_alveo/configs/defconfig
new file mode 100644
index 0000000..e69de29
diff --git a/platform/fpga/sargantana_alveo/objects.mk b/platform/fpga/sargantana_alveo/objects.mk
new file mode 100644
index 0000000..d444abe
--- /dev/null
+++ b/platform/fpga/sargantana_alveo/objects.mk
@@ -0,0 +1,87 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+
+# Compiler pre-processor flags
+platform-cppflags-y =
+
+# C Compiler and assembler flags.
+platform-cflags-y =
+platform-asflags-y =
+
+# Linker flags: additional libraries and object files that the platform
+# code needs can be added here
+platform-ldflags-y =
+
+#
+# Command for platform specific "make run"
+# Useful for development and debugging on plaftform simulator (such as QEMU)
+#
+# platform-runcmd = your_platform_run.sh
+
+#
+# Platform RISC-V XLEN, ABI, ISA and Code Model configuration.
+# These are optional parameters but platforms can optionaly provide it.
+# Some of these are guessed based on GCC compiler capabilities
+#
+PLATFORM_RISCV_XLEN = 64
+PLATFORM_RISCV_ABI = lp64d
+PLATFORM_RISCV_ISA = rv64imafd
+PLATFORM_RISCV_CODE_MODEL = medany
+
+# Space separated list of object file names to be compiled for the platform
+platform-objs-y += platform.o
+
+#
+# If the platform support requires a builtin device tree file, the name of
+# the device tree compiled file should be specified here. The device tree
+# source file be in the form <dt file name>.dts
+#
+# platform-objs-y += <dt file name>.o
+
+# Firmware load address configuration. This is mandatory.
+FW_TEXT_START=0x80000000
+
+# Optional parameter for path to external FDT
+# FW_FDT_PATH="path to platform flattened device tree file"
+
+#
+# Dynamic firmware configuration.
+# Optional parameters are commented out. Uncomment and define these parameters
+# as needed.
+#
+FW_DYNAMIC=n
+
+#
+# Jump firmware configuration.
+# Optional parameters are commented out. Uncomment and define these parameters
+# as needed.
+#
+FW_JUMP=n
+# This needs to be 4MB aligned for 32-bit support
+# This needs to be 2MB aligned for 64-bit support
+# ifeq ($(PLATFORM_RISCV_XLEN), 32)
+# FW_JUMP_ADDR=0x80400000
+# else
+# FW_JUMP_ADDR=0x80200000
+# endif
+# FW_JUMP_FDT_ADDR=0x82200000
+
+#
+# Firmware with payload configuration.
+# Optional parameters are commented out. Uncomment and define these parameters
+# as needed.
+#
+FW_PAYLOAD=y
+# This needs to be 4MB aligned for 32-bit support
+# This needs to be 2MB aligned for 64-bit support
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+FW_PAYLOAD_OFFSET=0x400000
+else
+FW_PAYLOAD_OFFSET=0x200000
+endif
+FW_PAYLOAD_ALIGN=0x1000
+# FW_PAYLOAD_PATH="path to next boot stage binary image file"
+# FW_PAYLOAD_FDT_ADDR=0x82200000
diff --git a/platform/fpga/sargantana_alveo/platform.c b/platform/fpga/sargantana_alveo/platform.c
new file mode 100644
index 0000000..a359b34
--- /dev/null
+++ b/platform/fpga/sargantana_alveo/platform.c
@@ -0,0 +1,146 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_platform.h>
+
+/*
+ * Include these files as needed.
+ * See objects.mk SARGANTANA_ALVEO_xxx configuration parameters.
+ */
+
+#include <sbi_utils/serial/alveo_uart.h>
+#include <sbi/sbi_timer.h>
+
+#define SARGANTANA_ALVEO_HART_COUNT 1
+
+#define SARGANTANA_ALVEO_UART_BASE_ADDR 0x40000000
+#define SARGANTANA_ALVEO_UART_OFFSET 0x1000
+//#define SARGANTANA_ALVEO_UART_ADDR SARGANTANA_ALVEO_UART_BASE_ADDR + SARGANTANA_ALVEO_UART_XLNX_OFFSET
+#define SARGANTANA_ALVEO_UART_INPUT_FREQ 50000000
+#define SARGANTANA_ALVEO_UART_BAUDRATE 115200
+
+#define SARGANTANA_ALVEO_TIMER_BASE 0x40170000
+#define ADDR_TIME_L 0x0u // 32 lower bits of the time register
+#define ADDR_TIME_H 0x1u // 32 higher bits of the time register
+#define ADDR_TIMECMP_L 0x2u // 32 lower bits of the time comparator
+#define ADDR_TIMECMP_H 0x3u // 32 higher bits of the time comparator
+
+volatile uint32_t *timer_base_ptr = (uint32_t *)(SARGANTANA_ALVEO_TIMER_BASE);
+
+/*
+ * Platform early initialization.
+ */
+static int sargantana_alveo_early_init(bool cold_boot)
+{
+ return 0;
+}
+
+/*
+ * Platform final initialization.
+ */
+static int sargantana_alveo_final_init(bool cold_boot)
+{
+ return 0;
+}
+
+/*
+ * Initialize the platform console.
+ */
+static int sargantana_alveo_console_init(void)
+{
+ return alveo_uart_init(SARGANTANA_ALVEO_UART_BASE_ADDR,
+ SARGANTANA_ALVEO_UART_INPUT_FREQ,
+ SARGANTANA_ALVEO_UART_BAUDRATE,
+ 2, 4,
+ SARGANTANA_ALVEO_UART_OFFSET);
+}
+
+/*
+ * Initialize the platform interrupt controller for current HART.
+ */
+static int sargantana_alveo_irqchip_init(bool cold_boot)
+{
+ u32 hartid = current_hartid();
+ return hartid;
+}
+
+/*
+ * Initialize IPI for current HART.
+ */
+static int sargantana_alveo_ipi_init(bool cold_boot)
+{
+ return 0;
+}
+
+/*
+ * Get platform timer value.
+ */
+static u64 sargantana_alveo_timer_value(void)
+{
+ return ((u64)*(timer_base_ptr + ADDR_TIME_H) << 32) + *(timer_base_ptr + ADDR_TIME_L);
+}
+
+/*
+ * Start platform timer event for current HART.
+ */
+static void sargantana_alveo_timer_event_start(u64 next_event)
+{
+ *(timer_base_ptr + ADDR_TIMECMP_H) = next_event >> 32;
+ *(timer_base_ptr + ADDR_TIMECMP_L) = next_event;
+}
+
+/*
+ * Stop platform timer event for current HART.
+ */
+static void sargantana_alveo_timer_event_stop(void)
+{
+
+ *(timer_base_ptr + ADDR_TIMECMP_H) = 0;
+ *(timer_base_ptr + ADDR_TIMECMP_L) = 0;
+}
+
+static struct sbi_timer_device mtimer = {
+ .name = "generic_timer", // TODO Where the timer comes from? I would prefer a better name :p
+ .timer_freq = SARGANTANA_ALVEO_UART_INPUT_FREQ,
+ .timer_value = sargantana_alveo_timer_value,
+ .timer_event_start = sargantana_alveo_timer_event_start,
+ .timer_event_stop = sargantana_alveo_timer_event_stop
+};
+
+/*
+ * Initialize platform timer for current HART.
+ */
+static int sargantana_alveo_timer_init(bool cold_boot)
+{
+ *(timer_base_ptr + ADDR_TIMECMP_H) = 0;
+ *(timer_base_ptr + ADDR_TIMECMP_L) = 0;
+ sbi_timer_set_device(&mtimer);
+ return 0;
+}
+
+/*
+ * Platform descriptor.
+ */
+const struct sbi_platform_operations sargantana_alveo_ops = {
+ .early_init = sargantana_alveo_early_init,
+ .final_init = sargantana_alveo_final_init,
+ .console_init = sargantana_alveo_console_init,
+ .irqchip_init = sargantana_alveo_irqchip_init,
+ .ipi_init = sargantana_alveo_ipi_init,
+ .timer_init = sargantana_alveo_timer_init
+};
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "Sargantana (for Xilinx Alveo FPGA)",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = SARGANTANA_ALVEO_HART_COUNT,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&sargantana_alveo_ops
+};

View File

@ -0,0 +1,68 @@
Only in busybox-1.36.1-mod: tags
diff -up -r busybox-1.36.1/util-linux/switch_root.c busybox-1.36.1-mod/util-linux/switch_root.c
--- busybox-1.36.1/util-linux/switch_root.c 2021-09-30 00:04:47.000000000 +0200
+++ busybox-1.36.1-mod/util-linux/switch_root.c 2024-07-01 16:08:28.336541504 +0200
@@ -181,6 +181,8 @@ int switch_root_main(int argc UNUSED_PAR
unsigned dry_run = 0;
dev_t rootdev;
+ printf("HELLO THIS IS SWITCH ROOT STARTING\n");
+
// Parse args. '+': stop at first non-option
if (ENABLE_SWITCH_ROOT && (!ENABLE_RUN_INIT || applet_name[0] == 's')) {
//usage:#define switch_root_trivial_usage
@@ -241,12 +243,15 @@ int switch_root_main(int argc UNUSED_PAR
if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) {
bb_error_msg_and_die("'%s' is not a regular file", "/init");
}
+ printf("SWITCH ROOT LINE %d OK\n", __LINE__);
statfs("/", &stfs); // this never fails
+ printf("SWITCH ROOT LINE %d OK\n", __LINE__);
if ((unsigned)stfs.f_type != RAMFS_MAGIC
&& (unsigned)stfs.f_type != TMPFS_MAGIC
) {
bb_simple_error_msg_and_die("root filesystem is not ramfs/tmpfs");
}
+ printf("SWITCH ROOT LINE %d OK\n", __LINE__);
if (!dry_run) {
// Zap everything out of rootdev
@@ -258,19 +263,26 @@ int switch_root_main(int argc UNUSED_PAR
bb_simple_perror_msg_and_die("error moving root");
}
}
+ printf("SWITCH ROOT LINE %d OK\n", __LINE__);
+ printf("XCHROOT\n");
xchroot(".");
+ printf("SWITCH ROOT LINE %d OK\n", __LINE__);
// The chdir is needed to recalculate "." and ".." links
/*xchdir("/"); - done in xchroot */
// If a new console specified, redirect stdin/stdout/stderr to it
if (console) {
+ printf("REDIRECTING CONSOLE\n");
+ printf("SWITCH ROOT LINE %d OK\n", __LINE__);
int fd = open_or_warn(console, O_RDWR);
if (fd >= 0) {
xmove_fd(fd, 0);
xdup2(0, 1);
xdup2(0, 2);
}
+ printf("SWITCH ROOT LINE %d OK\n", __LINE__);
}
+ printf("SWITCH ROOT LINE %d OK\n", __LINE__);
if (dry_run) {
// Does NEW_INIT look like it can be executed?
@@ -280,8 +292,11 @@ int switch_root_main(int argc UNUSED_PAR
if (access(argv[0], X_OK) == 0)
return 0;
} else {
+ printf("SWITCH ROOT LINE %d OK\n", __LINE__);
+ printf("LAUNCHING EXECV\n");
// Exec NEW_INIT
execv(argv[0], argv);
+ printf("RETURNED FROM EXECV???\n");
}
bb_perror_msg_and_die("can't execute '%s'", argv[0]);
}

View File

@ -0,0 +1,21 @@
diff --git a/drivers/xxvnet_carv.c b/drivers/xxvnet_carv.c
index d3f60f9..9fd4c21 100644
--- a/drivers/xxvnet_carv.c
+++ b/drivers/xxvnet_carv.c
@@ -36,6 +36,7 @@
#include <linux/iopoll.h>
#include <linux/random.h>
#include <linux/clk.h>
+#include <linux/platform_device.h>
#include "xxvnet_carv.h"
@@ -1511,7 +1512,7 @@ axienet_dma_probe(struct platform_device *pdev, struct net_device *ndev)
spin_lock_init(&q->tx_lock);
spin_lock_init(&q->rx_lock);
- netif_napi_add(ndev, &lp->napi, axienet_rx_poll, AXIENET_NAPI_WEIGHT);
+ netif_napi_add(ndev, &lp->napi, axienet_rx_poll);
return 0;
}

View File

@ -0,0 +1,7 @@
diff --git a/drivers/Kbuild b/drivers/Kbuild
index 28d6c0f..7f02860 100644
--- a/drivers/Kbuild
+++ b/drivers/Kbuild
@@ -1,2 +1 @@
obj-m := xxvnet_carv.o
-obj-m := xilinx_dma.o

View File

@ -0,0 +1,23 @@
diff --git a/drivers/xxvnet_carv.c b/drivers/xxvnet_carv.c
index eb664bb..d3f60f9 100644
--- a/drivers/xxvnet_carv.c
+++ b/drivers/xxvnet_carv.c
@@ -1435,12 +1435,12 @@ static void axienet_poll_controller(struct net_device *ndev)
{
struct axienet_local *lp = netdev_priv(ndev);
- disable_irq(lp->tx_irq);
- disable_irq(lp->rx_irq);
- axienet_rx_irq(lp->tx_irq, ndev);
- axienet_tx_irq(lp->rx_irq, ndev);
- enable_irq(lp->tx_irq);
- enable_irq(lp->rx_irq);
+ disable_irq(lp->dq->tx_irq);
+ disable_irq(lp->dq->rx_irq);
+ axienet_rx_irq(lp->dq->tx_irq, ndev);
+ axienet_tx_irq(lp->dq->rx_irq, ndev);
+ enable_irq(lp->dq->tx_irq);
+ enable_irq(lp->dq->rx_irq);
}
#endif

View File

@ -0,0 +1,37 @@
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index c366701..c5b5249 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -199,7 +199,7 @@ static int delegate_traps(struct sbi_scratch *scratch)
return 0;
/* Send M-mode interrupts and most exceptions to S-mode */
- interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
+ interrupts = MIP_SSIP | MIP_STIP;
interrupts |= sbi_pmu_irq_bit();
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index 0ae604a..dd4592a 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -37,8 +37,7 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
if (rc)
return rc;
- if (ext_irqfn != default_irqfn)
- csr_set(CSR_MIE, MIP_MEIP);
+ csr_set(CSR_MIE, MIP_MEIP);
return 0;
}
@@ -47,8 +46,7 @@ void sbi_irqchip_exit(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
- if (ext_irqfn != default_irqfn)
- csr_clear(CSR_MIE, MIP_MEIP);
+ csr_clear(CSR_MIE, MIP_MEIP);
sbi_platform_irqchip_exit(plat);
}

View File

@ -0,0 +1,19 @@
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index c366701..1ef6145 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -241,6 +241,14 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
prefix, suffix, csr_read(CSR_MIDELEG));
sbi_printf("%sMEDELEG%s: 0x%" PRILX "\n",
prefix, suffix, csr_read(CSR_MEDELEG));
+ sbi_printf("%sMTVEC%s : 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MTVEC));
+ sbi_printf("%sMIE%s : 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MIE));
+ sbi_printf("%sMIP%s : 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MIP));
+ sbi_printf("%sMSTATUS%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MSTATUS));
}
unsigned int sbi_hart_mhpm_mask(struct sbi_scratch *scratch)

View File

@ -0,0 +1,24 @@
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index 0ae604a..dd4592a 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -37,8 +37,7 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
if (rc)
return rc;
- if (ext_irqfn != default_irqfn)
- csr_set(CSR_MIE, MIP_MEIP);
+ csr_set(CSR_MIE, MIP_MEIP);
return 0;
}
@@ -47,8 +46,7 @@ void sbi_irqchip_exit(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
- if (ext_irqfn != default_irqfn)
- csr_clear(CSR_MIE, MIP_MEIP);
+ csr_clear(CSR_MIE, MIP_MEIP);
sbi_platform_irqchip_exit(plat);
}

View File

@ -0,0 +1,26 @@
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index 0ae604a..94832c8 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -37,8 +37,8 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
if (rc)
return rc;
- if (ext_irqfn != default_irqfn)
- csr_set(CSR_MIE, MIP_MEIP);
+ csr_set(CSR_MIE, MIP_MEIP | MIP_SEIP);
+ csr_set(CSR_MSTATUS, MSTATUS_MIE | MSTATUS_SIE);
return 0;
}
@@ -47,8 +47,8 @@ void sbi_irqchip_exit(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
- if (ext_irqfn != default_irqfn)
- csr_clear(CSR_MIE, MIP_MEIP);
+ csr_clear(CSR_MIE, MIP_MEIP | MIP_SEIP);
+ csr_clear(CSR_MSTATUS, MSTATUS_MIE | MSTATUS_SIE);
sbi_platform_irqchip_exit(plat);
}

View File

@ -0,0 +1,13 @@
--- a/platform/fpga/openpiton/platform.c 2024-03-12 16:27:13.886525365 +0100
+++ b/platform/fpga/openpiton/platform.c 2024-05-27 11:42:47.748244398 +0200
@@ -24,8 +24,8 @@
#define OPENPITON_DEFAULT_UART_REG_WIDTH 1
#define OPENPITON_DEFAULT_UART_REG_OFFSET 0
#define OPENPITON_DEFAULT_PLIC_ADDR 0xfff1100000
-#define OPENPITON_DEFAULT_PLIC_NUM_SOURCES 2
-#define OPENPITON_DEFAULT_HART_COUNT 3
+#define OPENPITON_DEFAULT_PLIC_NUM_SOURCES 3
+#define OPENPITON_DEFAULT_HART_COUNT 20
#define OPENPITON_DEFAULT_CLINT_ADDR 0xfff1020000
#define OPENPITON_DEFAULT_ACLINT_MTIMER_FREQ 1000000
#define OPENPITON_DEFAULT_ACLINT_MSWI_ADDR \

View File

@ -0,0 +1,200 @@
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index 0ae604a..e34e90c 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -9,6 +9,9 @@
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
+#include <sbi/sbi_console.h>
+
+static void do_plic_test(void);
static int default_irqfn(void)
{
@@ -37,8 +40,10 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
if (rc)
return rc;
- if (ext_irqfn != default_irqfn)
- csr_set(CSR_MIE, MIP_MEIP);
+ //csr_set(CSR_MIE, MIP_SEIP);
+ //csr_set(CSR_MSTATUS, MSTATUS_SIE);
+
+ do_plic_test();
return 0;
}
@@ -47,8 +52,170 @@ void sbi_irqchip_exit(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
- if (ext_irqfn != default_irqfn)
- csr_clear(CSR_MIE, MIP_MEIP);
+ //csr_clear(CSR_MIE, MIP_SEIP);
+ //csr_clear(CSR_MSTATUS, MSTATUS_SIE);
sbi_platform_irqchip_exit(plat);
}
+
+
+/* ----------------- PLIC tests ---------------- */
+
+
+#define MIE_MEIE (1UL << 11) // Machine External Interrupt Enable
+#define SIE_SEIE (1UL << 9)
+#define MIDELEG_SEIE (1UL << 9) // Delegate Machine External Interrupt to Supervisor
+#define PLIC_TIMER_PORT 4
+// Base address of PLIC
+#define PLIC_BASE 0x40800000UL
+#define PLIC_PRIORITY_OFFSET 0x0UL
+#define PLIC_PENDING_OFFSET 0x1000UL
+#define PLIC_ENABLE_OFFSET 0x2080UL
+#define PLIC_THRESHOLD_OFFSET 0x201000UL
+#define PLIC_CLAIM_OFFSET 0x201004UL
+
+// Aux timer
+#define AUX_TIMER_BASE 0x40010000UL
+#define MTIMECMP_OFFSET 0x4000UL
+#define MTIME_OFFSET 0xBFF8UL
+
+#define MSTATUS_MPP_MASK (3 << 11)
+#define MSTATUS_MPP_SUPERVISOR (1 << 11)
+
+static volatile unsigned long *mtime = (unsigned long *)(AUX_TIMER_BASE + MTIME_OFFSET);
+static volatile unsigned long *mtimecmp = (unsigned long *)(AUX_TIMER_BASE + MTIMECMP_OFFSET);
+
+
+static void dumpregs(int machine)
+{
+ char *prefix = "\t";
+ char *suffix = "\t";
+ sbi_printf("Registers:\n");
+ if (machine) {
+ sbi_printf("%sMIE%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MIE));
+ sbi_printf("%sMIP%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MIP));
+ sbi_printf("%sMSTATUS%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MSTATUS));
+ sbi_printf("%sMIDELEG%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MIDELEG));
+ }
+ sbi_printf("%sSIE%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_SIE));
+ sbi_printf("%sSIP%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_SIP));
+ sbi_printf("%sSSTATUS%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_SSTATUS));
+ sbi_printf("%sSTVEC%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_STVEC));
+}
+
+static void __attribute__((optimize("O0"))) switch_to_supervisor_mode(int (*target_address)(void))
+{
+ unsigned long mstatus;
+
+ // Read the current mstatus
+ asm volatile("csrr %0, mstatus" : "=r"(mstatus));
+
+ // Set the MPP field to supervisor mode
+ mstatus = (mstatus & ~MSTATUS_MPP_MASK) | MSTATUS_MPP_SUPERVISOR;
+
+ // Write back the modified mstatus
+ asm volatile("csrw mstatus, %0" : : "r"(mstatus));
+
+ // Set the mepc to the target address
+ asm volatile("csrw mepc, %0" : : "r"(target_address));
+
+ // Use mret to return to the specified address in supervisor mode
+ asm volatile("mret");
+}
+
+static int supervisor_mode_code(void)
+{
+ sbi_printf("Hello from supervisor\n");
+ dumpregs(0);
+
+ /* Enable timer interrupt */
+ *mtimecmp = *mtime + 10000;
+
+ sbi_printf("Timer alarm programmed\n");
+ sbi_printf("Waiting for interrupt...\n");
+ int i = 0;
+ char *s = "-\\|/";
+ while (1) {
+ for (volatile unsigned long j = 0; j < 100000; j++);
+ sbi_printf("\r%c", s[i++]);
+ if (i >= 4)
+ i = 0;
+ }
+ return 0;
+}
+
+static void __attribute__((aligned(4))) __attribute__((interrupt ("supervisor"))) supervisor_trap_entry(void)
+{
+ sbi_printf("\nSupervisor Trap Entry Reached!\n");
+ sbi_printf("\nTEST-RESULT-OK\n");
+ while (1) {
+ }
+}
+
+static void do_plic_test(void)
+{
+ sbi_printf("--- TESTING PLIC ---\n");
+
+ /* Disable auxiliar timer interrupt */
+ *mtimecmp = 0xffffffffUL;
+ sbi_printf("Timer interrupt disabled\n");
+
+
+ /* Enable supervisor interrupt delegation */
+
+ csr_set(CSR_SIE, SIE_SEIE); // Enable supervisor external interrupts
+ csr_set(CSR_SSTATUS, SSTATUS_SIE); // Enable global interrupts in supervisor mode
+ csr_set(CSR_MIDELEG, MIDELEG_SEIE); // Delegate machine interrupts to supervisor mode
+ csr_write(CSR_STVEC, &supervisor_trap_entry);
+
+ sbi_printf("Enabled supervisor delegation:\n");
+
+ dumpregs(1);
+
+ /* Configure PLIC aux timer input */
+ volatile unsigned *plic_priority = (unsigned *)(PLIC_BASE + PLIC_PRIORITY_OFFSET + PLIC_TIMER_PORT * 4);
+ volatile unsigned *plic_enable = (unsigned *)(PLIC_BASE + PLIC_ENABLE_OFFSET);
+ volatile unsigned *plic_threshold = (unsigned *)(PLIC_BASE + PLIC_THRESHOLD_OFFSET);
+ volatile unsigned *plic_claim = (unsigned *)(PLIC_BASE + PLIC_CLAIM_OFFSET);
+ volatile unsigned *plic_pending = (unsigned *)(PLIC_BASE + PLIC_PENDING_OFFSET);
+
+ sbi_printf("Enabling timer in PLIC\n");
+ *plic_priority = PLIC_TIMER_PORT;
+ *plic_threshold = PLIC_TIMER_PORT - 1;
+ *plic_enable |= (1 << PLIC_TIMER_PORT);
+
+ /* Clear interrupt */
+ sbi_printf("Pending: %d\n", *plic_pending);
+ unsigned claim = *plic_claim;
+ sbi_printf("Claim: %d\n", claim);
+ *plic_claim = claim;
+ sbi_printf("Pending: %d\n", *plic_pending);
+
+ sbi_printf("Clearing MIP\n");
+ csr_write(CSR_MIP, 0);
+
+ /* Enable external timer interrupts */
+ //sbi_printf("Enabling MEIE in MIE register\n");
+ //csr_set(CSR_MIE, MIE_MEIE); /* Needed? */
+ //sbi_printf("Enabling MIE in MSTATUS register\n");
+ //csr_set(CSR_MSTATUS, MSTATUS_MIE); /* Needed? */
+
+ sbi_printf("Switching to supervisor\n");
+
+ dumpregs(1);
+
+ switch_to_supervisor_mode(&supervisor_mode_code);
+
+ /* Never reached */
+ while (1);
+}
+
+

View File

@ -0,0 +1,229 @@
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index 7b618de..65e42b0 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -183,13 +183,17 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
u64 *time_delta;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ sbi_printf("sbi_timer_init: begins\n");
+
if (cold_boot) {
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta));
if (!time_delta_off)
return SBI_ENOMEM;
- if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR))
+ if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR)) {
+ sbi_printf("sbi_timer_init: got Zicntr extension\n");
get_time_val = get_ticks;
+ }
} else {
if (!time_delta_off)
return SBI_ENOMEM;
@@ -198,7 +202,10 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta = 0;
- return sbi_platform_timer_init(plat, cold_boot);
+ int rc = sbi_platform_timer_init(plat, cold_boot);
+ if (rc)
+ sbi_printf("sbi_platform_timer: sbi_platform_timer_init failed (%d)\n", rc);
+ return rc;
}
void sbi_timer_exit(struct sbi_scratch *scratch)
diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c
index b4f3a17..cde2073 100644
--- a/lib/sbi/sbi_trap.c
+++ b/lib/sbi/sbi_trap.c
@@ -283,6 +283,7 @@ static int sbi_trap_aia_irq(void)
*/
struct sbi_trap_context *sbi_trap_handler(struct sbi_trap_context *tcntx)
{
+ sbi_printf("<");
int rc = SBI_ENOTSUPP;
const char *msg = "trap handler failed";
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
@@ -295,6 +296,7 @@ struct sbi_trap_context *sbi_trap_handler(struct sbi_trap_context *tcntx)
sbi_trap_set_context(scratch, tcntx);
if (mcause & MCAUSE_IRQ_MASK) {
+ sbi_printf("i(%lu)", mcause & ~MCAUSE_IRQ_MASK);
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
SBI_HART_EXT_SMAIA))
rc = sbi_trap_aia_irq();
@@ -306,35 +308,42 @@ struct sbi_trap_context *sbi_trap_handler(struct sbi_trap_context *tcntx)
switch (mcause) {
case CAUSE_ILLEGAL_INSTRUCTION:
+ sbi_printf("I");
rc = sbi_illegal_insn_handler(tcntx);
msg = "illegal instruction handler failed";
break;
case CAUSE_MISALIGNED_LOAD:
+ sbi_printf("L");
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_LOAD);
rc = sbi_misaligned_load_handler(tcntx);
msg = "misaligned load handler failed";
break;
case CAUSE_MISALIGNED_STORE:
+ sbi_printf("S");
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_STORE);
rc = sbi_misaligned_store_handler(tcntx);
msg = "misaligned store handler failed";
break;
case CAUSE_SUPERVISOR_ECALL:
case CAUSE_MACHINE_ECALL:
+ sbi_printf("E");
rc = sbi_ecall_handler(tcntx);
msg = "ecall handler failed";
break;
case CAUSE_LOAD_ACCESS:
+ sbi_printf("l");
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_ACCESS_LOAD);
rc = sbi_load_access_handler(tcntx);
msg = "load fault handler failed";
break;
case CAUSE_STORE_ACCESS:
+ sbi_printf("s");
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_ACCESS_STORE);
rc = sbi_store_access_handler(tcntx);
msg = "store fault handler failed";
break;
default:
+ sbi_printf("R");
/* If the trap came from S or U mode, redirect it there */
msg = "trap redirect failed";
rc = sbi_trap_redirect(regs, trap);
@@ -344,6 +353,8 @@ struct sbi_trap_context *sbi_trap_handler(struct sbi_trap_context *tcntx)
trap_done:
if (rc)
sbi_trap_error(msg, rc, tcntx);
+ else
+ sbi_printf(">");
if (((regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT) != PRV_M)
sbi_sse_process_pending_events(regs);
diff --git a/lib/utils/timer/fdt_timer.c b/lib/utils/timer/fdt_timer.c
index f468730..db20526 100644
--- a/lib/utils/timer/fdt_timer.c
+++ b/lib/utils/timer/fdt_timer.c
@@ -7,6 +7,7 @@
* Anup Patel <anup.patel@wdc.com>
*/
+#include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
@@ -39,19 +40,26 @@ static int fdt_timer_cold_init(void)
void *fdt = fdt_get_address();
for (pos = 0; pos < fdt_timer_drivers_size; pos++) {
+ sbi_printf("fdt_timer_cold_init: pos = %d\n", pos);
drv = fdt_timer_drivers[pos];
noff = -1;
while ((noff = fdt_find_match(fdt, noff,
drv->match_table, &match)) >= 0) {
+
+ sbi_printf("fdt_timer_cold_init: got match, name = %s\n", match->compatible);
if (!fdt_node_is_enabled(fdt, noff))
continue;
+ sbi_printf("fdt_timer_cold_init: enabled\n");
+
/* drv->cold_init must not be NULL */
if (drv->cold_init == NULL)
return SBI_EFAIL;
rc = drv->cold_init(fdt, noff, match);
+ sbi_printf("fdt_timer_cold_init: drc->cold_init = %d\n", rc);
+
if (rc == SBI_ENODEV)
continue;
if (rc)
@@ -69,6 +77,7 @@ static int fdt_timer_cold_init(void)
* We can't fail here since systems with Sstc might not provide
* mtimer/clint DT node in the device tree.
*/
+ sbi_printf("fdt_timer_cold_init: returns 0\n");
return 0;
}
@@ -78,9 +87,15 @@ int fdt_timer_init(bool cold_boot)
if (cold_boot) {
rc = fdt_timer_cold_init();
- if (rc)
+ if (rc) {
+ sbi_printf("fdt_timer_init: fdt_timer_cold_init failed (%d)\n", rc);
return rc;
+ }
}
- return fdt_timer_warm_init();
+ rc = fdt_timer_warm_init();
+ if (rc)
+ sbi_printf("fdt_timer_init: fdt_timer_warm_init failed (%d)\n", rc);
+
+ return rc;
}
diff --git a/lib/utils/timer/fdt_timer_mtimer.c b/lib/utils/timer/fdt_timer_mtimer.c
index 9e27e3a..cef2ee6 100644
--- a/lib/utils/timer/fdt_timer_mtimer.c
+++ b/lib/utils/timer/fdt_timer_mtimer.c
@@ -8,6 +8,7 @@
*/
#include <libfdt.h>
+#include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_list.h>
@@ -33,6 +34,7 @@ static struct aclint_mtimer_data *mt_reference = NULL;
static int timer_mtimer_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
+
int rc;
unsigned long addr[2], size[2];
struct timer_mtimer_node *mtn, *n;
@@ -40,6 +42,8 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
const struct timer_mtimer_quirks *quirks = match->data;
bool is_clint = quirks && quirks->is_clint;
+ sbi_printf("timer_mtimer_cold_init: begins, is_clint = %d\n", (int) is_clint);
+
mtn = sbi_zalloc(sizeof(*mtn));
if (!mtn)
return SBI_ENOMEM;
@@ -49,6 +53,7 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
&addr[0], &size[0], &addr[1], &size[1],
&mt->first_hartid, &mt->hart_count);
if (rc) {
+ sbi_printf("timer_mtimer_cold_init: fdt_parse_aclint_node failed (%d)\n", rc);
sbi_free(mtn);
return rc;
}
@@ -57,6 +62,7 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
rc = fdt_parse_timebase_frequency(fdt, &mt->mtime_freq);
if (rc) {
+ sbi_printf("timer_mtimer_cold_init: fdt_parse_timebase_frequency failed (%d)\n", rc);
sbi_free(mtn);
return rc;
}
@@ -83,6 +89,11 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
mt->mtimecmp_size = size[1];
}
+ sbi_printf("timer_mtimer_cold_init: mtime_addr = 0x%08lx\n", mt->mtime_addr);
+ sbi_printf("timer_mtimer_cold_init: mtime_size = 0x%08lx\n", mt->mtime_size);
+ sbi_printf("timer_mtimer_cold_init: mtimecmp_addr = 0x%08lx\n", mt->mtimecmp_addr);
+ sbi_printf("timer_mtimer_cold_init: mtimecmp_size = 0x%08lx\n", mt->mtimecmp_size);
+
/* Apply additional quirks */
if (quirks) {
mt->has_64bit_mmio = quirks->has_64bit_mmio;

View File

@ -0,0 +1,167 @@
diff --git a/platform/fpga/ox_alveo/Kconfig b/platform/fpga/ox_alveo/Kconfig
new file mode 100644
index 0000000..bf3e7e6
--- /dev/null
+++ b/platform/fpga/ox_alveo/Kconfig
@@ -0,0 +1,5 @@
+config PLATFORM_OX_ALVEO_FPGA
+ bool
+ select SERIAL_UART8250
+ select IRQCHIP_PLIC
+ default y
diff --git a/platform/fpga/ox_alveo/configs/defconfig b/platform/fpga/ox_alveo/configs/defconfig
new file mode 100644
index 0000000..e69de29
diff --git a/platform/fpga/ox_alveo/objects.mk b/platform/fpga/ox_alveo/objects.mk
new file mode 100644
index 0000000..d444abe
--- /dev/null
+++ b/platform/fpga/ox_alveo/objects.mk
@@ -0,0 +1,19 @@
+platform-cppflags-y =
+platform-cflags-y =
+platform-asflags-y =
+platform-ldflags-y =
+PLATFORM_RISCV_XLEN = 64
+PLATFORM_RISCV_ABI = lp64d
+PLATFORM_RISCV_ISA = rv64g
+PLATFORM_RISCV_CODE_MODEL = medany
+
+platform-objs-y += platform.o
+
+FW_TEXT_START=0x80000000
+
+FW_DYNAMIC=n
+FW_JUMP=n
+FW_PAYLOAD=y
+
+FW_PAYLOAD_OFFSET=0x200000
+FW_PAYLOAD_ALIGN=0x1000
diff --git a/platform/fpga/ox_alveo/platform.c b/platform/fpga/ox_alveo/platform.c
new file mode 100644
index 0000000..a359b34
--- /dev/null
+++ b/platform/fpga/ox_alveo/platform.c
@@ -0,0 +1,122 @@
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_platform.h>
+#include <sbi_utils/serial/uart8250.h>
+#include <sbi/sbi_timer.h>
+#include <sbi_utils/irqchip/plic.h>
+
+#define OX_ALVEO_HART_COUNT 1
+
+#define OX_ALVEO_UART_BASE_ADDR 0x40000000
+#define OX_ALVEO_UART_OFFSET 0x1000
+#define OX_ALVEO_UART_INPUT_FREQ 50000000
+#define OX_ALVEO_UART_BAUDRATE 115200
+#define OX_ALVEO_PLIC_ADDR 0x40800000
+#define OX_ALVEO_PLIC_NUM_SOURCES 3
+
+#define OX_ALVEO_TIMER_BASE 0x40170000
+#define ADDR_TIME_L 0x0u // 32 lower bits of the time register
+#define ADDR_TIME_H 0x1u // 32 higher bits of the time register
+#define ADDR_TIMECMP_L 0x2u // 32 lower bits of the time comparator
+#define ADDR_TIMECMP_H 0x3u // 32 higher bits of the time comparator
+
+volatile uint32_t *timer_base_ptr = (uint32_t *)(OX_ALVEO_TIMER_BASE);
+
+static struct plic_data plic = {
+ .addr = OX_ALVEO_PLIC_ADDR,
+ .num_src = OX_ALVEO_PLIC_NUM_SOURCES,
+};
+
+static int ox_alveo_early_init(bool cold_boot) // Platform early initialization.
+{
+ return 0;
+}
+
+static int ox_alveo_final_init(bool cold_boot) // Platform final initialization.
+{
+ return 0;
+}
+
+static int ox_alveo_console_init(void) // Initialize the platform console.
+{
+ return uart8250_init(OX_ALVEO_UART_BASE_ADDR,
+ OX_ALVEO_UART_INPUT_FREQ,
+ OX_ALVEO_UART_BAUDRATE,
+ 2, 4,
+ OX_ALVEO_UART_OFFSET);
+}
+
+static int ox_alveo_irqchip_init(bool cold_boot) // Initialize the platform interrupt controller for current HART.
+{
+ u32 hartid = current_hartid();
+ int ret;
+
+ /* Example if the generic PLIC driver is used */
+ if (cold_boot) {
+ ret = plic_cold_irqchip_init(&plic);
+ if (ret)
+ return ret;
+ }
+
+ return plic_warm_irqchip_init(&plic, 2 * hartid, -1);
+}
+
+static int ox_alveo_ipi_init(bool cold_boot) // Initialize IPI for current HART.
+{
+ return 0;
+}
+
+static u64 ox_alveo_timer_value(void) // Get platform timer value.
+{
+ return ((u64)*(timer_base_ptr + ADDR_TIME_H) << 32) + *(timer_base_ptr + ADDR_TIME_L);
+}
+
+static void ox_alveo_timer_event_start(u64 next_event) // Start platform timer event for current HART.
+{
+ *(timer_base_ptr + ADDR_TIMECMP_H) = next_event >> 32;
+ *(timer_base_ptr + ADDR_TIMECMP_L) = next_event;
+}
+
+static void ox_alveo_timer_event_stop(void) // Stop platform timer event for current HART.
+{
+
+ *(timer_base_ptr + ADDR_TIMECMP_H) = 0;
+ *(timer_base_ptr + ADDR_TIMECMP_L) = 0;
+}
+
+static struct sbi_timer_device mtimer = {
+ .name = "axi_timer",
+ .timer_freq = OX_ALVEO_UART_INPUT_FREQ,
+ .timer_value = ox_alveo_timer_value,
+ .timer_event_start = ox_alveo_timer_event_start,
+ .timer_event_stop = ox_alveo_timer_event_stop
+};
+
+static int ox_alveo_timer_init(bool cold_boot) // Initialize platform timer for current HART.
+{
+ *(timer_base_ptr + ADDR_TIMECMP_H) = 0;
+ *(timer_base_ptr + ADDR_TIMECMP_L) = 0;
+ sbi_timer_set_device(&mtimer);
+ return 0;
+}
+
+const struct sbi_platform_operations ox_alveo_ops = { // Platform descriptor.
+ .early_init = ox_alveo_early_init,
+ .final_init = ox_alveo_final_init,
+ .console_init = ox_alveo_console_init,
+ .irqchip_init = ox_alveo_irqchip_init,
+ .ipi_init = ox_alveo_ipi_init,
+ .timer_init = ox_alveo_timer_init
+};
+
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "ox (Rodrigo NixOS version)",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = OX_ALVEO_HART_COUNT,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(OX_ALVEO_HART_COUNT),
+ .platform_ops_addr = (unsigned long)&ox_alveo_ops
+};

View File

@ -0,0 +1,148 @@
diff --git a/platform/fpga/ox_alveo/Kconfig b/platform/fpga/ox_alveo/Kconfig
new file mode 100644
index 0000000..bf3e7e6
--- /dev/null
+++ b/platform/fpga/ox_alveo/Kconfig
@@ -0,0 +1,4 @@
+config PLATFORM_OX_ALVEO_FPGA
+ bool
+ select SERIAL_UART8250
+ default y
diff --git a/platform/fpga/ox_alveo/configs/defconfig b/platform/fpga/ox_alveo/configs/defconfig
new file mode 100644
index 0000000..e69de29
diff --git a/platform/fpga/ox_alveo/objects.mk b/platform/fpga/ox_alveo/objects.mk
new file mode 100644
index 0000000..d444abe
--- /dev/null
+++ b/platform/fpga/ox_alveo/objects.mk
@@ -0,0 +1,19 @@
+platform-cppflags-y =
+platform-cflags-y =
+platform-asflags-y =
+platform-ldflags-y =
+PLATFORM_RISCV_XLEN = 64
+PLATFORM_RISCV_ABI = lp64d
+PLATFORM_RISCV_ISA = rv64imafd
+PLATFORM_RISCV_CODE_MODEL = medany
+
+platform-objs-y += platform.o
+
+FW_TEXT_START=0x80000000
+
+FW_DYNAMIC=n
+FW_JUMP=n
+FW_PAYLOAD=y
+
+FW_PAYLOAD_OFFSET=0x200000
+FW_PAYLOAD_ALIGN=0x1000
diff --git a/platform/fpga/ox_alveo/platform.c b/platform/fpga/ox_alveo/platform.c
new file mode 100644
index 0000000..a359b34
--- /dev/null
+++ b/platform/fpga/ox_alveo/platform.c
@@ -0,0 +1,104 @@
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_platform.h>
+#include <sbi_utils/serial/uart8250.h>
+#include <sbi/sbi_timer.h>
+
+#define OX_ALVEO_HART_COUNT 1
+
+#define OX_ALVEO_UART_BASE_ADDR 0x40000000
+#define OX_ALVEO_UART_OFFSET 0x1000
+#define OX_ALVEO_UART_INPUT_FREQ 50000000
+#define OX_ALVEO_UART_BAUDRATE 115200
+
+#define OX_ALVEO_TIMER_BASE 0x40170000
+#define ADDR_TIME_L 0x0u // 32 lower bits of the time register
+#define ADDR_TIME_H 0x1u // 32 higher bits of the time register
+#define ADDR_TIMECMP_L 0x2u // 32 lower bits of the time comparator
+#define ADDR_TIMECMP_H 0x3u // 32 higher bits of the time comparator
+
+volatile uint32_t *timer_base_ptr = (uint32_t *)(OX_ALVEO_TIMER_BASE);
+
+static int ox_alveo_early_init(bool cold_boot) // Platform early initialization.
+{
+ return 0;
+}
+
+static int ox_alveo_final_init(bool cold_boot) // Platform final initialization.
+{
+ return 0;
+}
+
+static int ox_alveo_console_init(void) // Initialize the platform console.
+{
+ return uart8250_init(OX_ALVEO_UART_BASE_ADDR,
+ OX_ALVEO_UART_INPUT_FREQ,
+ OX_ALVEO_UART_BAUDRATE,
+ 2, 4,
+ OX_ALVEO_UART_OFFSET);
+}
+
+static int ox_alveo_irqchip_init(bool cold_boot) // Initialize the platform interrupt controller for current HART.
+{
+ u32 hartid = current_hartid();
+ return hartid;
+}
+
+static int ox_alveo_ipi_init(bool cold_boot) // Initialize IPI for current HART.
+{
+ return 0;
+}
+
+static u64 ox_alveo_timer_value(void) // Get platform timer value.
+{
+ return ((u64)*(timer_base_ptr + ADDR_TIME_H) << 32) + *(timer_base_ptr + ADDR_TIME_L);
+}
+
+static void ox_alveo_timer_event_start(u64 next_event) // Start platform timer event for current HART.
+{
+ *(timer_base_ptr + ADDR_TIMECMP_H) = next_event >> 32;
+ *(timer_base_ptr + ADDR_TIMECMP_L) = next_event;
+}
+
+static void ox_alveo_timer_event_stop(void) // Stop platform timer event for current HART.
+{
+
+ *(timer_base_ptr + ADDR_TIMECMP_H) = 0;
+ *(timer_base_ptr + ADDR_TIMECMP_L) = 0;
+}
+
+static struct sbi_timer_device mtimer = {
+ .name = "axi_timer",
+ .timer_freq = OX_ALVEO_UART_INPUT_FREQ,
+ .timer_value = ox_alveo_timer_value,
+ .timer_event_start = ox_alveo_timer_event_start,
+ .timer_event_stop = ox_alveo_timer_event_stop
+};
+
+static int ox_alveo_timer_init(bool cold_boot) // Initialize platform timer for current HART.
+{
+ *(timer_base_ptr + ADDR_TIMECMP_H) = 0;
+ *(timer_base_ptr + ADDR_TIMECMP_L) = 0;
+ sbi_timer_set_device(&mtimer);
+ return 0;
+}
+
+const struct sbi_platform_operations ox_alveo_ops = { // Platform descriptor.
+ .early_init = ox_alveo_early_init,
+ .final_init = ox_alveo_final_init,
+ .console_init = ox_alveo_console_init,
+ .irqchip_init = ox_alveo_irqchip_init,
+ .ipi_init = ox_alveo_ipi_init,
+ .timer_init = ox_alveo_timer_init
+};
+
+const struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "ox (for Xilinx Alveo FPGA)",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = OX_ALVEO_HART_COUNT,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&ox_alveo_ops
+};

View File

@ -0,0 +1,92 @@
commit 1a2c5f12e7676930123cfe7853f1805cf3680c25
Author: Rodrigo Arias Mallo <rodrigo.arias@bsc.es>
Date: Tue Oct 1 12:59:38 2024 +0200
Add claim test
diff --git a/fpga_core_bridge/simulator/tests/c_tests/Makefile b/fpga_core_bridge/simulator/tests/c_tests/Makefile
index f744131..91d61b6 100644
--- a/fpga_core_bridge/simulator/tests/c_tests/Makefile
+++ b/fpga_core_bridge/simulator/tests/c_tests/Makefile
@@ -23,6 +23,7 @@ bmarks = \
plic \
plic_supervisor \
plic_threshold \
+ plic_claim \
clint_supervisor \
uart
diff --git a/fpga_core_bridge/simulator/tests/c_tests/plic_claim/plic_claim.c b/fpga_core_bridge/simulator/tests/c_tests/plic_claim/plic_claim.c
new file mode 100644
index 0000000..352adb9
--- /dev/null
+++ b/fpga_core_bridge/simulator/tests/c_tests/plic_claim/plic_claim.c
@@ -0,0 +1,68 @@
+#include "util.h"
+
+#define PLIC_BASE 0x40800000
+
+int main(void)
+{
+ uart_init();
+
+ /* This test requires the auxiliar timer to cause a pending
+ * interrupt in the source 4. All the other pending bits must be
+ * zero. */
+
+ uint32_t src = 4;
+ uint32_t mask = 1 << src;
+
+ /* 0x001000: Interrupt Source #0 to #31 Pending Bits */
+ volatile uint32_t *pending = PLIC_BASE + 0x001000;
+
+ /* Manually enable the pending register on both timer and serial */
+ *pending = (1<<4) | (1<<1);
+
+ uint32_t p;
+ /* Wait for a interrupt on the serial line */
+ while ((p = *pending) != (1<<4) | (1<<1)) {
+ printf("waiting, pending=");
+ printhex(p);
+ printf("\n");
+ }
+
+ /* 0x002080: Interrupt Source #0 to #31 Enable Bits on context 1 */
+ volatile uint32_t *enable = PLIC_BASE + 0x002080;
+ *enable = (1<<4) | (1<<1); /* Enable source 4 (aux timer) and 1
+ (serial) */
+
+ /* 0x000004: Interrupt source 1 priority */
+ /* 0x000008: Interrupt source 2 priority */
+ /* 0x00000c: Interrupt source 3 priority */
+ /* 0x000010: Interrupt source 4 priority */
+ for (uint32_t i = 1; i <= 4; i++) {
+ volatile uint32_t *priority = PLIC_BASE + i * 4;
+ *priority = 1; /* Make priority larger than threshold */
+ }
+
+ /* 0x201000: Priority threshold for context 1 */
+ volatile uint32_t *threshold = PLIC_BASE + 0x201000;
+ *threshold = 0; /* Make threshold small */
+
+ /* Now the context 1 must be receiving interrupts from the aux
+ * timer. Let's try to claim the interrupt. */
+
+ /* Read claim */
+
+ /* 0x201004: Interrupt Claim Process for context 1 */
+ volatile uint32_t *claim = PLIC_BASE + 0x201004;
+ while (1) {
+ uint32_t c = *claim;
+ if (c == src)
+ break;
+ printf("ERROR: unexpected claim found, expecting 4: ");
+ printhex(c);
+ printf("\n");
+ }
+
+ while (1)
+ printf("SUCCESS: Claim test succeeded\n");
+
+ return 0;
+}

15
patches/sa-fpga-crt.patch Normal file
View File

@ -0,0 +1,15 @@
diff --git a/fpga_core_bridge/simulator/tests/c_tests/common/crt.S b/fpga_core_bridge/simulator/tests/c_tests/common/crt.S
index 3f5bb2c..bd738b1 100644
--- a/fpga_core_bridge/simulator/tests/c_tests/common/crt.S
+++ b/fpga_core_bridge/simulator/tests/c_tests/common/crt.S
@@ -59,10 +59,6 @@ _start:
#else
bltz t0, 1f
#endif
-2:
- li a0, 1
- sw a0, tohost, t0
- j 2b
1:
#ifdef __riscv_flen

View File

@ -0,0 +1,92 @@
diff --git a/fpga_core_bridge/simulator/tests/c_tests/plic_supervisor/plic_supervisor_test.c b/fpga_core_bridge/simulator/tests/c_tests/plic_supervisor/plic_supervisor_test.c
index 0cfa681..78d97cb 100644
--- a/fpga_core_bridge/simulator/tests/c_tests/plic_supervisor/plic_supervisor_test.c
+++ b/fpga_core_bridge/simulator/tests/c_tests/plic_supervisor/plic_supervisor_test.c
@@ -68,6 +68,48 @@ uintptr_t handle_trap(uint64_t cause, uint64_t epc, uintptr_t regs[32])
return epc;
}
+static void dumpregs(int machine)
+{
+ printf("Registers:");
+ if (machine) {
+ uint64_t mie;
+ asm volatile("csrr %0, mie" : "=r"(mie));
+ printf("\n MIE: ");
+ printhex(mie);
+
+ uint64_t mip;
+ asm volatile("csrr %0, mip" : "=r"(mip));
+ printf("\n MIP: ");
+ printhex(mip);
+
+ uint64_t mstatus;
+ asm volatile("csrr %0, mstatus" : "=r"(mstatus));
+ printf("\nMSTATUS: ");
+ printhex(mstatus);
+
+ uint64_t mideleg;
+ asm volatile("csrr %0, mideleg" : "=r"(mideleg));
+ printf("\nMIDELEG: ");
+ printhex(mideleg);
+ }
+
+ uint64_t sie;
+ asm volatile("csrr %0, sie" : "=r"(sie));
+ printf("\n SIE: ");
+ printhex(sie);
+
+ uint64_t sip;
+ asm volatile("csrr %0, sip" : "=r"(sip));
+ printf("\n SIP: ");
+ printhex(sip);
+
+ uint64_t sstatus;
+ asm volatile("csrr %0, sstatus" : "=r"(sstatus));
+ printf("\nSSTATUS: ");
+ printhex(sstatus);
+ printf("\n");
+}
+
// Define the bit positions for the external interrupt enable in mie and mideleg registers
#define SIE_SEIE (1 << 9) // Supervisor External Interrupt Enable
#define MIDELEG_MEIE (1 << 11) // Delegate Machine External Interrupt to Supervisor
@@ -156,16 +198,19 @@ void __attribute__((optimize("O0"))) switch_to_supervisor_mode(uint64_t* target_
asm volatile("mret");
}
-uint64_t supervisor_mode_code() {
- int count = 0;
- while (1) {
- if (count == 10000) {
- uart_write_string("\nWaiting for interrupt in supervisor mode...");
- count = 0;
- }
- count++;
- }
- return 0;
+uint64_t supervisor_mode_code()
+{
+ uart_write_string("\nHello from supervisor mode...");
+ dumpregs(0);
+ int count = 0;
+ while (1) {
+ if (count == 10000) {
+ uart_write_string("\nWaiting for interrupt in supervisor mode...");
+ count = 0;
+ }
+ count++;
+ }
+ return 0;
}
void main(void) {
@@ -181,6 +226,8 @@ void main(void) {
// Enable external timer interrupts
// enable_external_timer_interrupt();
+ dumpregs(1);
+
// Switch to supervisor mode and execute supervisor_mode_code
switch_to_supervisor_mode(&supervisor_mode_code);

View File

@ -0,0 +1,13 @@
diff --git a/fpga_core_bridge/simulator/tests/c_tests/common/test.ld b/fpga_core_bridge/simulator/tests/c_tests/common/test.ld
index 8321d86..f83a9ee 100644
--- a/fpga_core_bridge/simulator/tests/c_tests/common/test.ld
+++ b/fpga_core_bridge/simulator/tests/c_tests/common/test.ld
@@ -26,7 +26,7 @@ SECTIONS
.tohost : { *(.tohost) }
/* text: test code section */
- . = 0x80000000;
+ . = 0x20020000;
.text.init : { *(.text.init) }
. = ALIGN(0x1000);

View File

@ -0,0 +1,31 @@
diff --git a/fpga_core_bridge/simulator/tests/c_tests/common/syscalls.c b/fpga_core_bridge/simulator/tests/c_tests/common/syscalls.c
index 278ea97..287e5fc 100644
--- a/fpga_core_bridge/simulator/tests/c_tests/common/syscalls.c
+++ b/fpga_core_bridge/simulator/tests/c_tests/common/syscalls.c
@@ -592,8 +592,18 @@ int uart_is_transmit_empty() {
// Function to write a character to the UART
void uart_write_char(char c) {
- while (!uart_is_transmit_empty());
+ //while (!uart_is_transmit_empty());
+
+ /* Delay it a bit, as checking the transmit holding register doesn't seem to
+ * work in the FPGA */
+ for (volatile long i = 0; i < 10000; i++)
+ ;
+
*(volatile uint8_t *)(UART_BASE + UART_THR) = c;
+
+ /* Make new line go back to the start of the line */
+ if (c == '\n')
+ uart_write_char('\r');
}
// Function to write a string to the UART
@@ -602,4 +612,4 @@ void uart_write_string(const char* str) {
uart_write_char(*str++);
asm("fence");
}
-}
\ No newline at end of file
+}

157
patches/stage-2-init.sh Executable file
View File

@ -0,0 +1,157 @@
#! @shell@
#set -x
systemConfig=@systemConfig@
export HOME=/root PATH="@path@"
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" != true ]; then
# Print a greeting.
echo
echo -e "\e[1;32m<<< @distroName@ Stage 2 >>>\e[0m"
echo
# Process the kernel command line.
for o in $(</proc/cmdline); do
case $o in
boot.debugtrace)
# Show each command.
set -x
;;
debug2)
export PATH="@bashInteractive@/bin:@systemConfig@/sw/bin:$PATH"
setsid bash -c "exec bash -l </dev/hvc0 >/dev/hvc0 2>/dev/hvc0"
;;
bench2)
export PATH="@bashInteractive@/bin:@systemConfig@/sw/bin:$PATH"
setsid bash -c "exec @bench2@ </dev/hvc0 >/dev/hvc0 2>/dev/hvc0"
;;
esac
done
# Normally, stage 1 mounts the root filesystem read/writable.
# However, in some environments, stage 2 is executed directly, and the
# root is read-only. So make it writable here.
if [ -z "$container" ]; then
mount -n -o remount,rw none /
fi
fi
# Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a
# stage 1, we need to do that here.
if [ ! -e /proc/1 ]; then
specialMount() {
local device="$1"
local mountPoint="$2"
local options="$3"
local fsType="$4"
# We must not overwrite this mount because it's bind-mounted
# from stage 1's /run
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" = true ] && [ "${mountPoint}" = /run ]; then
return
fi
install -m 0755 -d "$mountPoint"
mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
}
source @earlyMountScript@
fi
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" = true ] || [ ! -c /dev/kmsg ] ; then
echo "booting system configuration ${systemConfig}"
else
echo "booting system configuration $systemConfig" > /dev/kmsg
fi
# Make /nix/store a read-only bind mount to enforce immutability of
# the Nix store. Note that we can't use "chown root:nixbld" here
# because users/groups might not exist yet.
# Silence chown/chmod to fail gracefully on a readonly filesystem
# like squashfs.
chown -f 0:30000 /nix/store
chmod -f 1775 /nix/store
if [ -n "@readOnlyNixStore@" ]; then
if ! [[ "$(findmnt --noheadings --output OPTIONS /nix/store)" =~ ro(,|$) ]]; then
if [ -z "$container" ]; then
mount --bind /nix/store /nix/store
else
mount --rbind /nix/store /nix/store
fi
mount -o remount,ro,bind /nix/store
fi
fi
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" != true ]; then
# Use /etc/resolv.conf supplied by systemd-nspawn, if applicable.
if [ -n "@useHostResolvConf@" ] && [ -e /etc/resolv.conf ]; then
resolvconf -m 1000 -a host </etc/resolv.conf
fi
# # Log the script output to /dev/kmsg or /run/log/stage-2-init.log.
# # Only at this point are all the necessary prerequisites ready for these commands.
# exec {logOutFd}>&1 {logErrFd}>&2
# if test -w /dev/kmsg; then
# exec > >(tee -i /proc/self/fd/"$logOutFd" | while read -r line; do
# if test -n "$line"; then
# echo "<7>stage-2-init: $line" > /dev/kmsg
# fi
# done) 2>&1
# else
# mkdir -p /run/log
# exec > >(tee -i /run/log/stage-2-init.log) 2>&1
# fi
fi
# Required by the activation script
install -m 0755 -d /etc
if [ ! -h "/etc/nixos" ]; then
install -m 0755 -d /etc/nixos
fi
install -m 01777 -d /tmp
# Run the script that performs all configuration activation that does
# not have to be done at boot time.
echo "running activation script..."
#strace -f $systemConfig/activate
$systemConfig/activate
echo "activation script OK"
# Record the boot configuration.
ln -sfn "$systemConfig" /run/booted-system
# Run any user-specified commands.
@shell@ @postBootCommands@
# Ensure systemd doesn't try to populate /etc, by forcing its first-boot
# heuristic off. It doesn't matter what's in /etc/machine-id for this purpose,
# and systemd will immediately fill in the file when it starts, so just
# creating it is enough. This `: >>` pattern avoids forking and avoids changing
# the mtime if the file already exists.
: >> /etc/machine-id
# No need to restore the stdout/stderr streams we never redirected and
# especially no need to start systemd
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" != true ]; then
# Reset the logging file descriptors.
#exec 1>&$logOutFd 2>&$logErrFd
#exec {logOutFd}>&- {logErrFd}>&-
# Start systemd in a clean environment.
echo "starting systemd..."
exec @systemdExecutable@ "$@"
fi

View File

@ -0,0 +1,83 @@
diff --git a/common/board_f.c b/common/board_f.c
index 1688e27071..216839febb 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -978,6 +978,8 @@ static const init_fnc_t init_sequence_f[] = {
void board_init_f(ulong boot_flags)
{
+ puts("board_init_f() called\n");
+
gd->flags = boot_flags;
gd->have_console = 0;
@@ -990,6 +992,7 @@ void board_init_f(ulong boot_flags)
/* NOTREACHED - jump_to_copy() does not return */
hang();
#endif
+ puts("board_init_f() ends ok\n");
}
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
diff --git a/common/board_r.c b/common/board_r.c
index d798c00a80..cb8119a603 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -786,6 +786,8 @@ static init_fnc_t init_sequence_r[] = {
void board_init_r(gd_t *new_gd, ulong dest_addr)
{
+ puts("board_init_r called\n");
+
/*
* The pre-relocation drivers may be using memory that has now gone
* away. Mark serial as unavailable - this will fall back to the debug
diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c
index d6484d7f4b..64a507248d 100644
--- a/drivers/cpu/riscv_cpu.c
+++ b/drivers/cpu/riscv_cpu.c
@@ -92,10 +92,13 @@ static int riscv_cpu_get_count(const struct udevice *dev)
static int riscv_cpu_bind(struct udevice *dev)
{
+ puts("riscv_cpu_bind called()\n");
+
struct cpu_plat *plat = dev_get_parent_plat(dev);
struct driver *drv;
int ret;
+ puts("looking for timebase-frequency\n");
/* save the hart id */
plat->cpu_id = dev_read_addr(dev);
/* first examine the property in current cpu node */
@@ -105,6 +108,8 @@ static int riscv_cpu_bind(struct udevice *dev)
dev_read_u32(dev->parent, "timebase-frequency",
&plat->timebase_freq);
+ printf("timebase-frequency=%lu\n", (unsigned long) plat->timebase_freq);
+
/*
* Bind riscv-timer driver on boot hart.
*
@@ -125,6 +130,8 @@ static int riscv_cpu_bind(struct udevice *dev)
device_bind_with_driver_data(dev, drv, "riscv_timer",
plat->timebase_freq, ofnode_null(),
NULL);
+ } else {
+ printf("ignoring cpu_id=%d\n", plat->cpu_id);
}
return 0;
diff --git a/lib/hang.c b/lib/hang.c
index 2735774f9a..84eff21ffc 100644
--- a/lib/hang.c
+++ b/lib/hang.c
@@ -22,6 +22,8 @@
*/
void hang(void)
{
+ puts("oh no, we are in hang()\n");
+
#if !defined(CONFIG_SPL_BUILD) || \
(CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT) && \
CONFIG_IS_ENABLED(SERIAL))

View File

@ -0,0 +1,31 @@
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 6cecadfac5..f649844b23 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -81,7 +81,7 @@ _start:
#if CONFIG_IS_ENABLED(RISCV_MMODE)
li t0, MIE_MSIE
#else
- li t0, SIE_SSIE
+ li t0, (SIE_SSIE + SIE_SEIE + SIE_STIE)
#endif
csrs MODE_PREFIX(ie), t0
#endif
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
index a26ccc721f..b8d2a71223 100644
--- a/arch/riscv/lib/interrupts.c
+++ b/arch/riscv/lib/interrupts.c
@@ -193,10 +193,13 @@ ulong handle_trap(ulong cause, ulong epc, ulong tval, struct pt_regs *regs)
switch (irq) {
case IRQ_M_EXT:
case IRQ_S_EXT:
+ printf("u-boot: got ext interrupt %lu\n", irq);
+ show_regs(regs);
external_interrupt(0); /* handle external interrupt */
break;
case IRQ_M_TIMER:
case IRQ_S_TIMER:
+ printf("u-boot: got timer interrupt %lu\n", irq);
timer_interrupt(0); /* handle timer interrupt */
break;
default:

View File

@ -0,0 +1,65 @@
diff --git a/cmd/riscv/exception.c b/cmd/riscv/exception.c
index f38f454a0b..9de4effe47 100644
--- a/cmd/riscv/exception.c
+++ b/cmd/riscv/exception.c
@@ -56,6 +56,40 @@ static int do_undefined(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_FAILURE;
}
+static int do_sregs(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ ulong stvec, sie, sip, sstatus;
+
+ asm volatile ("fence");
+ asm volatile ("csrr %0, stvec" : "=r"(stvec) : );
+ asm volatile ("csrr %0, sie" : "=r"(sie) : );
+ asm volatile ("csrr %0, sip" : "=r"(sip) : );
+ asm volatile ("csrr %0, sstatus" : "=r"(sstatus) : );
+
+ printf("stvec : 0x%016lx\n", stvec);
+ printf("sie : 0x%016lx\n", sie);
+ printf("sip : 0x%016lx\n", sip);
+ printf("sstatus : 0x%016lx\n", sstatus);
+
+ return CMD_RET_SUCCESS;
+}
+
+static int do_enable(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ ulong which = SIE_SSIE | SIE_SEIE | SIE_STIE;
+
+ asm volatile (
+ "csrsi sstatus, 2\n" /* Enable SIE */
+ "csrs sie, %0\n" /* Enable selected interrupts */
+ : /* no output */
+ : "r" (which)
+ );
+
+ return CMD_RET_SUCCESS;
+}
+
static struct cmd_tbl cmd_sub[] = {
U_BOOT_CMD_MKENT(compressed, CONFIG_SYS_MAXARGS, 1, do_compressed,
"", ""),
@@ -67,6 +101,10 @@ static struct cmd_tbl cmd_sub[] = {
"", ""),
U_BOOT_CMD_MKENT(undefined, CONFIG_SYS_MAXARGS, 1, do_undefined,
"", ""),
+ U_BOOT_CMD_MKENT(sregs, CONFIG_SYS_MAXARGS, 1, do_sregs,
+ "", ""),
+ U_BOOT_CMD_MKENT(enable, CONFIG_SYS_MAXARGS, 1, do_enable,
+ "", ""),
};
static char exception_help_text[] =
@@ -77,6 +115,8 @@ static char exception_help_text[] =
" ialign16 - 16 bit aligned instruction\n"
" undefined - illegal instruction\n"
" unaligned - load address misaligned\n"
+ " sregs - print supervisor registers\n"
+ " enable - enable supervisor interrupts\n"
;
#include <exception.h>

View File

@ -0,0 +1,379 @@
use strict;
use warnings;
use File::Path qw(make_path);
use File::Slurp;
use Getopt::Long;
use JSON;
use Time::Piece;
# Keep track of deleted uids and gids.
my $uidMapFile = "/var/lib/nixos/uid-map";
my $uidMap = -e $uidMapFile ? decode_json(read_file($uidMapFile)) : {};
my $gidMapFile = "/var/lib/nixos/gid-map";
my $gidMap = -e $gidMapFile ? decode_json(read_file($gidMapFile)) : {};
my $is_dry = ($ENV{'NIXOS_ACTION'} // "") eq "dry-activate";
GetOptions("dry-activate" => \$is_dry);
make_path("/var/lib/nixos", { mode => 0755 }) unless $is_dry;
sub updateFile {
my ($path, $contents, $perms) = @_;
return if $is_dry;
write_file($path, { atomic => 1, binmode => ':utf8', perms => $perms // 0644 }, $contents) or die;
}
# Converts an ISO date to number of days since 1970-01-01
sub dateToDays {
my ($date) = @_;
my $time = Time::Piece->strptime($date, "%Y-%m-%d");
return $time->epoch / 60 / 60 / 24;
}
sub nscdInvalidate {
system("echo", "nscd", "--invalidate", $_[0]) unless $is_dry;
}
sub hashPassword {
my ($password) = @_;
my $salt = "";
my @chars = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
$salt .= $chars[rand 64] for (1..8);
return crypt($password, '$6$' . $salt . '$');
}
sub dry_print {
if ($is_dry) {
print STDERR ("$_[1] $_[2]\n")
} else {
print STDERR ("$_[0] $_[2]\n")
}
}
# Functions for allocating free GIDs/UIDs. FIXME: respect ID ranges in
# /etc/login.defs.
sub allocId {
my ($used, $prevUsed, $idMin, $idMax, $up, $getid) = @_;
my $id = $up ? $idMin : $idMax;
while ($id >= $idMin && $id <= $idMax) {
if (!$used->{$id} && !$prevUsed->{$id} && !defined &$getid($id)) {
$used->{$id} = 1;
return $id;
}
$used->{$id} = 1;
if ($up) { $id++; } else { $id--; }
}
die "$0: out of free UIDs or GIDs\n";
}
my (%gidsUsed, %uidsUsed, %gidsPrevUsed, %uidsPrevUsed);
sub allocGid {
my ($name) = @_;
my $prevGid = $gidMap->{$name};
if (defined $prevGid && !defined $gidsUsed{$prevGid}) {
dry_print("reviving", "would revive", "group '$name' with GID $prevGid");
$gidsUsed{$prevGid} = 1;
return $prevGid;
}
return allocId(\%gidsUsed, \%gidsPrevUsed, 400, 999, 0, sub { my ($gid) = @_; getgrgid($gid) });
}
sub allocUid {
my ($name, $isSystemUser) = @_;
my ($min, $max, $up) = $isSystemUser ? (400, 999, 0) : (1000, 29999, 1);
my $prevUid = $uidMap->{$name};
if (defined $prevUid && $prevUid >= $min && $prevUid <= $max && !defined $uidsUsed{$prevUid}) {
dry_print("reviving", "would revive", "user '$name' with UID $prevUid");
$uidsUsed{$prevUid} = 1;
return $prevUid;
}
return allocId(\%uidsUsed, \%uidsPrevUsed, $min, $max, $up, sub { my ($uid) = @_; getpwuid($uid) });
}
# Read the declared users/groups
my $spec = decode_json(read_file($ARGV[0]));
# Don't allocate UIDs/GIDs that are manually assigned.
foreach my $g (@{$spec->{groups}}) {
$gidsUsed{$g->{gid}} = 1 if defined $g->{gid};
}
foreach my $u (@{$spec->{users}}) {
$uidsUsed{$u->{uid}} = 1 if defined $u->{uid};
}
# Likewise for previously used but deleted UIDs/GIDs.
$uidsPrevUsed{$_} = 1 foreach values %{$uidMap};
$gidsPrevUsed{$_} = 1 foreach values %{$gidMap};
# Read the current /etc/group.
sub parseGroup {
chomp;
my @f = split(':', $_, -4);
my $gid = $f[2] eq "" ? undef : int($f[2]);
$gidsUsed{$gid} = 1 if defined $gid;
return ($f[0], { name => $f[0], password => $f[1], gid => $gid, members => $f[3] });
}
my %groupsCur = -f "/etc/group" ? map { parseGroup } read_file("/etc/group", { binmode => ":utf8" }) : ();
# Read the current /etc/passwd.
sub parseUser {
chomp;
my @f = split(':', $_, -7);
my $uid = $f[2] eq "" ? undef : int($f[2]);
$uidsUsed{$uid} = 1 if defined $uid;
return ($f[0], { name => $f[0], fakePassword => $f[1], uid => $uid,
gid => $f[3], description => $f[4], home => $f[5], shell => $f[6] });
}
my %usersCur = -f "/etc/passwd" ? map { parseUser } read_file("/etc/passwd", { binmode => ":utf8" }) : ();
# Read the groups that were created declaratively (i.e. not by groups)
# in the past. These must be removed if they are no longer in the
# current spec.
my $declGroupsFile = "/var/lib/nixos/declarative-groups";
my %declGroups;
$declGroups{$_} = 1 foreach split / /, -e $declGroupsFile ? read_file($declGroupsFile, { binmode => ":utf8" }) : "";
# Idem for the users.
my $declUsersFile = "/var/lib/nixos/declarative-users";
my %declUsers;
$declUsers{$_} = 1 foreach split / /, -e $declUsersFile ? read_file($declUsersFile, { binmode => ":utf8" }) : "";
# Generate a new /etc/group containing the declared groups.
my %groupsOut;
foreach my $g (@{$spec->{groups}}) {
my $name = $g->{name};
my $existing = $groupsCur{$name};
my %members = map { ($_, 1) } @{$g->{members}};
if (defined $existing) {
$g->{gid} = $existing->{gid} if !defined $g->{gid};
if ($g->{gid} != $existing->{gid}) {
dry_print("warning: not applying", "warning: would not apply", "GID change of group $name ($existing->{gid} -> $g->{gid}) in /etc/group");
$g->{gid} = $existing->{gid};
}
$g->{password} = $existing->{password}; # do we want this?
if ($spec->{mutableUsers}) {
# Merge in non-declarative group members.
foreach my $uname (split /,/, $existing->{members} // "") {
$members{$uname} = 1 if !defined $declUsers{$uname};
}
}
} else {
$g->{gid} = allocGid($name) if !defined $g->{gid};
$g->{password} = "x";
}
$g->{members} = join ",", sort(keys(%members));
$groupsOut{$name} = $g;
$gidMap->{$name} = $g->{gid};
}
# Update the persistent list of declarative groups.
updateFile($declGroupsFile, join(" ", sort(keys %groupsOut)));
# Merge in the existing /etc/group.
foreach my $name (keys %groupsCur) {
my $g = $groupsCur{$name};
next if defined $groupsOut{$name};
if (!$spec->{mutableUsers} || defined $declGroups{$name}) {
dry_print("removing group", "would remove group", "$name");
} else {
$groupsOut{$name} = $g;
}
}
# Rewrite /etc/group. FIXME: acquire lock.
my @lines = map { join(":", $_->{name}, $_->{password}, $_->{gid}, $_->{members}) . "\n" }
(sort { $a->{gid} <=> $b->{gid} } values(%groupsOut));
updateFile($gidMapFile, to_json($gidMap, {canonical => 1}));
updateFile("/etc/group", \@lines);
nscdInvalidate("group");
# Generate a new /etc/passwd containing the declared users.
my %usersOut;
foreach my $u (@{$spec->{users}}) {
my $name = $u->{name};
# Resolve the gid of the user.
if ($u->{group} =~ /^[0-9]$/) {
$u->{gid} = $u->{group};
} elsif (defined $groupsOut{$u->{group}}) {
$u->{gid} = $groupsOut{$u->{group}}->{gid} // die;
} else {
warn "warning: user $name has unknown group $u->{group}\n";
$u->{gid} = 65534;
}
my $existing = $usersCur{$name};
if (defined $existing) {
$u->{uid} = $existing->{uid} if !defined $u->{uid};
if ($u->{uid} != $existing->{uid}) {
dry_print("warning: not applying", "warning: would not apply", "UID change of user $name ($existing->{uid} -> $u->{uid}) in /etc/passwd");
$u->{uid} = $existing->{uid};
}
} else {
$u->{uid} = allocUid($name, $u->{isSystemUser}) if !defined $u->{uid};
if (!defined $u->{hashedPassword}) {
if (defined $u->{initialPassword}) {
$u->{hashedPassword} = hashPassword($u->{initialPassword});
} elsif (defined $u->{initialHashedPassword}) {
$u->{hashedPassword} = $u->{initialHashedPassword};
}
}
}
# Ensure home directory incl. ownership and permissions.
if ($u->{createHome} and !$is_dry) {
make_path($u->{home}, { mode => oct($u->{homeMode}) }) if ! -e $u->{home};
chown $u->{uid}, $u->{gid}, $u->{home};
chmod oct($u->{homeMode}), $u->{home};
}
if (defined $u->{hashedPasswordFile}) {
if (-e $u->{hashedPasswordFile}) {
$u->{hashedPassword} = read_file($u->{hashedPasswordFile});
chomp $u->{hashedPassword};
} else {
warn "warning: password file $u->{hashedPasswordFile} does not exist\n";
}
} elsif (defined $u->{password}) {
$u->{hashedPassword} = hashPassword($u->{password});
}
if (!defined $u->{shell}) {
if (defined $existing) {
$u->{shell} = $existing->{shell};
} else {
warn "warning: no declarative or previous shell for $name, setting shell to nologin\n";
$u->{shell} = "/run/current-system/sw/bin/nologin";
}
}
$u->{fakePassword} = $existing->{fakePassword} // "x";
$usersOut{$name} = $u;
$uidMap->{$name} = $u->{uid};
}
# Update the persistent list of declarative users.
updateFile($declUsersFile, join(" ", sort(keys %usersOut)));
# Merge in the existing /etc/passwd.
foreach my $name (keys %usersCur) {
my $u = $usersCur{$name};
next if defined $usersOut{$name};
if (!$spec->{mutableUsers} || defined $declUsers{$name}) {
dry_print("removing user", "would remove user", "$name");
} else {
$usersOut{$name} = $u;
}
}
# Rewrite /etc/passwd. FIXME: acquire lock.
@lines = map { join(":", $_->{name}, $_->{fakePassword}, $_->{uid}, $_->{gid}, $_->{description}, $_->{home}, $_->{shell}) . "\n" }
(sort { $a->{uid} <=> $b->{uid} } (values %usersOut));
updateFile($uidMapFile, to_json($uidMap, {canonical => 1}));
updateFile("/etc/passwd", \@lines);
nscdInvalidate("passwd");
# Rewrite /etc/shadow to add new accounts or remove dead ones.
my @shadowNew;
my %shadowSeen;
foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow", { binmode => ":utf8" }) : ()) {
chomp $line;
# struct name copied from `man 3 shadow`
my ($sp_namp, $sp_pwdp, $sp_lstch, $sp_min, $sp_max, $sp_warn, $sp_inact, $sp_expire, $sp_flag) = split(':', $line, -9);
my $u = $usersOut{$sp_namp};;
next if !defined $u;
$sp_pwdp = "!" if !$spec->{mutableUsers};
$sp_pwdp = $u->{hashedPassword} if defined $u->{hashedPassword} && !$spec->{mutableUsers}; # FIXME
$sp_expire = dateToDays($u->{expires}) if defined $u->{expires};
chomp $sp_pwdp;
push @shadowNew, join(":", $sp_namp, $sp_pwdp, $sp_lstch, $sp_min, $sp_max, $sp_warn, $sp_inact, $sp_expire, $sp_flag) . "\n";
$shadowSeen{$sp_namp} = 1;
}
foreach my $u (values %usersOut) {
next if defined $shadowSeen{$u->{name}};
my $hashedPassword = "!";
$hashedPassword = $u->{hashedPassword} if defined $u->{hashedPassword};
my $expires = "";
$expires = dateToDays($u->{expires}) if defined $u->{expires};
# FIXME: set correct value for sp_lstchg.
push @shadowNew, join(":", $u->{name}, $hashedPassword, "1::::", $expires, "") . "\n";
}
updateFile("/etc/shadow", \@shadowNew, 0640);
{
my $uid = getpwnam "root";
my $gid = getgrnam "shadow";
my $path = "/etc/shadow";
(chown($uid, $gid, $path) || die "Failed to change ownership of $path: $!") unless $is_dry;
}
# Rewrite /etc/subuid & /etc/subgid to include default container mappings
my $subUidMapFile = "/var/lib/nixos/auto-subuid-map";
my $subUidMap = -e $subUidMapFile ? decode_json(read_file($subUidMapFile)) : {};
my (%subUidsUsed, %subUidsPrevUsed);
$subUidsPrevUsed{$_} = 1 foreach values %{$subUidMap};
sub allocSubUid {
my ($name, @rest) = @_;
# TODO: No upper bounds?
my ($min, $max, $up) = (100000, 100000 * 100, 1);
my $prevId = $subUidMap->{$name};
if (defined $prevId && !defined $subUidsUsed{$prevId}) {
$subUidsUsed{$prevId} = 1;
return $prevId;
}
my $id = allocId(\%subUidsUsed, \%subUidsPrevUsed, $min, $max, $up, sub { my ($uid) = @_; getpwuid($uid) });
my $offset = $id - 100000;
my $count = $offset * 65536;
my $subordinate = 100000 + $count;
return $subordinate;
}
my @subGids;
my @subUids;
foreach my $u (values %usersOut) {
my $name = $u->{name};
foreach my $range (@{$u->{subUidRanges}}) {
my $value = join(":", ($name, $range->{startUid}, $range->{count}));
push @subUids, $value;
}
foreach my $range (@{$u->{subGidRanges}}) {
my $value = join(":", ($name, $range->{startGid}, $range->{count}));
push @subGids, $value;
}
if($u->{autoSubUidGidRange}) {
my $subordinate = allocSubUid($name);
$subUidMap->{$name} = $subordinate;
my $value = join(":", ($name, $subordinate, 65536));
push @subUids, $value;
push @subGids, $value;
}
}
updateFile("/etc/subuid", join("\n", @subUids) . "\n");
updateFile("/etc/subgid", join("\n", @subGids) . "\n");
updateFile($subUidMapFile, encode_json($subUidMap) . "\n");

124
pkgs/llvm-epi/clang.nix Normal file
View File

@ -0,0 +1,124 @@
{
stdenv
, llvmPackages_latest
, lib
, fetchFromGitHub
, cmake
, bash
, python3
, perl
, which
, elfutils
, libffi
, zlib
, pkg-config
, enableDebug ? false
, gitUrl ? "https://repo.hca.bsc.es/gitlab/rferrer/llvm-epi.git"
, gitBranch ? "EPI-0.7"
, gitCommit ? "479518dc58dfceb23fc90667a5d6253e429f0fc2"
}:
let
llvmPackages = llvmPackages_latest;
llvmStdenv = llvmPackages.stdenv;
# needed to set the rpath of libstdc++ for clang-tblgen
gcc = stdenv.cc;
git = rec {
version = src.shortRev;
src = builtins.fetchGit {
url = gitUrl;
ref = gitBranch;
rev = gitCommit;
};
};
source = git;
in llvmStdenv.mkDerivation rec {
pname = "clang-epi";
inherit (source) src version;
enableParallelBuilding = true;
isClang = true;
patches = if (gitBranch == "EPI-0.7") then [
./include-cstdint.patch
] else [
];
# See https://reviews.llvm.org/D135402
env.LDFLAGS = "-Wl,--undefined-version";
passthru = {
CC = "clang";
CXX = "clang++";
};
nativeBuildInputs = [
zlib
gcc.cc.lib # Required for libstdc++.so.6
];
buildInputs = [
which
bash
python3
perl
cmake
llvmPackages.lld
elfutils
libffi
pkg-config
zlib
];
# Error with -D_FORTIFY_SOURCE=2, see https://bugs.gentoo.org/636604:
# /build/source/compiler-rt/lib/tsan/dd/dd_interceptors.cpp:225:20:
# error: redefinition of 'realpath'
# Requires disabling the "fortify" set of flags, however, for performance we
# disable all:
hardeningDisable = [ "all" ];
cmakeBuildType = if enableDebug then "Debug" else "Release";
dontStrip = enableDebug;
dontUseCmakeBuildDir = true;
# Fix shebangs, /usr/bin/env doesn't exist
prePatch = ''
patchShebangs clang/utils/EPI/generate-epi-builtins-def.py
'';
# Fix the host triple, as it has changed in a newer config.guess:
# https://git.savannah.gnu.org/gitweb/?p=config.git;a=commitdiff;h=ca9bfb8cc75a2be1819d89c664a867785c96c9ba
preConfigure = ''
mkdir -p build
cd build
cmakeDir="../llvm"
cmakeFlagsArray=(
"-DLLVM_HOST_TRIPLE=${llvmStdenv.targetPlatform.config}"
"-DLLVM_DEFAULT_TARGET_TRIPLE=riscv64-unknown-linux-gnu"
"-DLLVM_TARGETS_TO_BUILD=RISCV"
"-DLLVM_BUILD_LLVM_DYLIB=ON"
"-DLLVM_LINK_LLVM_DYLIB=ON"
# Required to run clang-ast-dump and clang-tblgen during build
"-DCMAKE_BUILD_RPATH=$PWD/lib:${zlib}/lib:${gcc.cc.lib}/lib"
"-DLLVM_ENABLE_LLD=ON"
"-DCMAKE_CXX_FLAGS_DEBUG=-g -ggnu-pubnames"
"-DCMAKE_EXE_LINKER_FLAGS_DEBUG=-Wl,--gdb-index"
"-DLLVM_LIT_ARGS=-sv --xunit-xml-output=xunit.xml"
"-DLLVM_ENABLE_PROJECTS=clang;lld"
"-DLLVM_ENABLE_ASSERTIONS=ON"
"-DLLVM_INSTALL_TOOLCHAIN_ONLY=ON"
"-DCMAKE_INSTALL_BINDIR=bin"
"-DLLVM_ENABLE_ZLIB=FORCE_ON"
"-DLLVM_ENABLE_LIBXML2=OFF"
# Set the rpath to include external libraries (zlib) both on build and
# install
"-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON"
"-DCMAKE_INSTALL_RPATH=${zlib}/lib:${gcc.cc.lib}/lib"
)
'';
}

46
pkgs/llvm-epi/default.nix Normal file
View File

@ -0,0 +1,46 @@
{
stdenv
, lib
, gcc
, clangEpiUnwrapped
, openmp ? null
, wrapCCWith
, llvmPackages_latest
, ompss2rt ? null
}:
let
# We need to replace the lld linker from bintools with our linker just built,
# otherwise we run into incompatibility issues when mixing compiler and linker
# versions.
bintools-unwrapped = llvmPackages_latest.tools.bintools-unwrapped.override {
lld = clangEpiUnwrapped;
};
bintools = llvmPackages_latest.tools.bintools.override {
bintools = bintools-unwrapped;
};
targetConfig = stdenv.targetPlatform.config;
inherit gcc;
cc = clangEpiUnwrapped;
in wrapCCWith {
inherit cc bintools;
# extraPackages adds packages to depsTargetTargetPropagated
extraPackages = lib.optional (openmp != null) openmp;
extraBuildCommands = ''
echo "-target ${targetConfig}" >> $out/nix-support/cc-cflags
echo "-B${gcc.cc}/lib/gcc/${targetConfig}/${gcc.version}" >> $out/nix-support/cc-cflags
echo "-L${gcc.cc}/lib/gcc/${targetConfig}/${gcc.version}" >> $out/nix-support/cc-ldflags
echo "-L${gcc.cc.lib}/lib" >> $out/nix-support/cc-ldflags
for dir in ${gcc.cc}/include/c++/*; do
echo "-isystem $dir" >> $out/nix-support/libcxx-cxxflags
done
for dir in ${gcc.cc}/include/c++/*/${targetConfig}; do
echo "-isystem $dir" >> $out/nix-support/libcxx-cxxflags
done
echo "--gcc-toolchain=${gcc}" >> $out/nix-support/cc-cflags
wrap clang++ $wrapper $ccPath/clang++
'';
}

View File

@ -0,0 +1,10 @@
--- a/llvm/include/llvm/Support/Signals.h 2024-09-25 08:34:21.257642944 +0200
+++ b/llvm/include/llvm/Support/Signals.h 2024-09-25 08:35:12.593556793 +0200
@@ -15,6 +15,7 @@
#define LLVM_SUPPORT_SIGNALS_H
#include <string>
+#include <cstdint>
namespace llvm {
class StringRef;

79
pkgs/rvb/Makefile Normal file
View File

@ -0,0 +1,79 @@
include Makefile.in
HPC_BENCHMARKS_DIRS=\
axpy \
jacobi-2d \
somier \
# Require submodules:
# fft \
# fftp \
# Require vehave:
# lulesh \
# Missing compare_array_double:
# gemm \
# Broken, not found:
# spmv
DESKTOP_BENCHMARKS_DIRS=\
blackscholes \
canneal \
particlefilter \
streamcluster \
swaptions
#pathfinder
MICRO_BENCHMARKS_DIRS=
#BuffCopyUnit \
#BuffCopyStrided \
#BuffCopyIndexed \
#FpuMicroKernel \
#InstrNopBalance \
#MemArithBalance \
#LatencyVrgather
.PHONY: default all clean $(HPC_BENCHMARKS_DIRS) $(MICRO_BENCHMARKS_DIRS)
all: base
default:
@cd common; make; cd ..
@$(foreach dir,$(HPC_BENCHMARKS_DIRS),${MAKE} -C hpc_benchmarks/$(dir);)
@$(foreach dir,$(DESKTOP_BENCHMARKS_DIRS),${MAKE} -C desktop_benchmarks/$(dir);)
@$(foreach dir,$(MICRO_BENCHMARKS_DIRS),${MAKE} -C micro_benchmarks/$(dir);)
all-types:
@cd common; make all; cd ..
@$(foreach dir,$(HPC_BENCHMARKS_DIRS),${MAKE} -C hpc_benchmarks/$(dir) all ;)
@$(foreach dir,$(DESKTOP_BENCHMARKS_DIRS),${MAKE} -C desktop_benchmarks/$(dir) all ;)
@$(foreach dir,$(MICRO_BENCHMARKS_DIRS),${MAKE} -C micro_benchmarks/$(dir) all ;)
base:
@cd common; make all; cd ..
@$(foreach dir,$(HPC_BENCHMARKS_DIRS),${MAKE} -C hpc_benchmarks/$(dir) base ;)
@$(foreach dir,$(DESKTOP_BENCHMARKS_DIRS),${MAKE} -C desktop_benchmarks/$(dir) base ;)
@$(foreach dir,$(MICRO_BENCHMARKS_DIRS),${MAKE} -C micro_benchmarks/$(dir) base ;)
install:
@$(foreach dir,$(HPC_BENCHMARKS_DIRS),${MAKE} -C hpc_benchmarks/$(dir) install ;)
@$(foreach dir,$(DESKTOP_BENCHMARKS_DIRS),${MAKE} -C desktop_benchmarks/$(dir) install ;)
@$(foreach dir,$(MICRO_BENCHMARKS_DIRS),${MAKE} -C micro_benchmarks/$(dir) install ;)
fftp:
${MAKE} -C third_party fftw
${MAKE} -C hpc_benchmarks/fftp all
${MAKE} -C hpc_benchmarks/fftp/test all
spmv-ellpack:
rm -rf hpc_benchmarks/spmv-ellpack/spmv/build
mkdir -p hpc_benchmarks/spmv-ellpack/spmv/build
cd hpc_benchmarks/spmv-ellpack/spmv/build;\
../configure riscv;\
INDEX64=1 EPI_EXT=07 PATH=${EPI_LLVM_HOME}/bin:${PATH} make
clean:
@cd common; make clean; cd ..
@$(foreach dir,$(HPC_BENCHMARKS_DIRS),${MAKE} -C hpc_benchmarks/$(dir) clean ;)
@$(foreach dir,$(DESKTOP_BENCHMARKS_DIRS),${MAKE} -C desktop_benchmarks/$(dir) clean ;)
@$(foreach dir,$(MICRO_BENCHMARKS_DIRS),${MAKE} -C micro_benchmarks/$(dir) clean ;)
@rm -rf hpc_benchmarks/spmv-ellpack/spmv/build

83
pkgs/rvb/Makefile.in Normal file
View File

@ -0,0 +1,83 @@
#Compile all benchmarks with individual settings defined in their Makefiles
_default-target: default
# RVB_ROOT defined as argument
# TODO: RVB_COMMON_DIR should substitute COMMON_DIR
COMMON_DIR=$(RVB_ROOT)/common
RVB_COMMON_DIR=$(RVB_ROOT)/common
#CC=clang
#CXX=clang++
# Needs EPI clang
#MEPI=-mepi
MEPI=
#VREPORT_FLAGS=-Rpass=loop-vectorize -Rpass-missed=loop-vectorize -Rpass-analysis=loop-vectorize
#Available CFLAGS conditional compilation:
# -DUSE_MALLOC_HP, redefines the use of malloc and free
#Makefile: General compiler flags: CFLAGS, CFLAGS_<VERSION_1>, CFLAGS_<VERSION_2>, ...
#CFLAGS=-B ${LLVM_BIN} -Wall -Wextra -march=rv64g -O2 -I${RVB_COMMON_DIR}
CFLAGS=-B ${LLVM_BIN} -Wall -Wextra -O2 -I${RVB_COMMON_DIR}
LDFLAGS=
#Only scalar instructions
CFLAGS_SCALAR=${CFLAGS} -DRVB_USE_SCALAR
LDFLAGS_SCALAR=
#NOVEC=-fno-vectorize
NOVEC=
#Vector instructions using intrinsics
CFLAGS_VECTORIAL=${CFLAGS} ${NOVEC} $(MEPI)
LDFLAGS_VECTORIAL=
# TODO: RVV should substitute VECTORIAL (?)
#Vector instructions using intrinsics
CFLAGS_RVV=${CFLAGS} -DRVB_USE_RVV ${NOVEC} $(MEPI)
LDFLAGS_RVV=${LDFLAGS}
#Vector instructions only when code is annotate
CFLAGS_EXPLICIT_AUTOVECTORIZATION=${CFLAGS} -fopenmp-simd ${NOVEC} $(MEPI) ${VREPORT_FLAGS}
LDFLAGS_EXPLICIT_AUTOVECTORIZATION=
# TODO: OMP substitutes EXPLICIT_AUTOVECTORIZATION
#Vector instructions only when code is annotate
CFLAGS_OMP=${CFLAGS} -DRVB_USE_OMP -fopenmp-simd $(MEPI) ${VREPORT_FLAGS}
LDFLAGS_OMP=${LDFLAGS}
#Vector instructions when compiler decides
CFLAGS_AUTOVECTORIZATION=${CFLAGS} -fopenmp-simd $(MEPI) ${VREPORT_FLAGS}
LDFLAGS_AUTOVECTORIZATION=
# TODO: AUTOVECT shoud substitue AUTOVECTORIZATION (?)
#Vector instructions when compiler decides
CFLAGS_AUTOVECT=${CFLAGS} -DRVB_USE_AUTOVECT -fopenmp-simd $(MEPI) ${VREPORT_FLAGS}
LDFLAGS_AUTOVECT=${LDFLAGS}
# CBLAS library compile and link flags
CFLAGS_CBLAS=${CFLAGS} -DRVB_USE_CBLAS -I${CBLAS_INC} -I${LLVM_INC}
LDFLAGS_CBLAS=${LDFLAGS} -L${CBLAS_LIB} -lblis -Wl,-rpath,${CBLAS_LIB} -fopenmp
# BARE-METAL compile and link flags
# You may consider to disable OpenPiton Stream: -DDISABLE_OPSTREAM
CFLAGS_BMETAL=${CFLAGS} -DRVB_USE_BMETAL -B ${RVB_BMETAL_DIR} \
--target=riscv64-unknown-elf \
-I../ \
-I/apps/riscv/llvm/EPI-0.7/cross/development/riscv64-unknown-linux-gnu/sysroot/usr/include \
-I/usr/include/riscv64-linux-gnu \
-I/usr/include \
-I${RVB_BMETAL_DIR}/env \
-I${RVB_BMETAL_DIR} \
-DPREALLOCATE=1 -mcmodel=medany \
-static -std=gnu99 \
-ffast-math \
-fno-common \
-fno-builtin-printf \
${RVB_BMETAL_DIR}/syscalls.c \
${RVB_BMETAL_DIR}/crt.S \
-static -nostdlib -T \
${RVB_BMETAL_DIR}/test.ld

35
pkgs/rvb/default.nix Normal file
View File

@ -0,0 +1,35 @@
{
stdenv
, blis
, gitBranch ? "nix-fixes"
, gitURL ? "git@gitlab-internal.bsc.es:rarias/risc-v-benchmarks.git"
, gitCommit ? "da202d6f818421b72e06c39b5417ad2f8f6ca23c"
}:
stdenv.mkDerivation rec {
pname = "rvb";
version = "${src.shortRev}";
src = builtins.fetchGit {
url = gitURL;
ref = gitBranch;
rev = gitCommit;
submodules = true;
};
buildInputs = [ blis ];
configurePhase = ''
export RVB_ROOT=$(readlink -f .)
export CBLAS_HOME=${blis}
export CBLAS_INC=${blis}/include/blis
export CBLAS_LIB=${blis}/lib
rm Makefile.in
ln -s ${./Makefile.in} Makefile.in
rm Makefile
ln -s ${./Makefile} Makefile
'';
enableParallelBuilding = false;
hardeningDisable = [ "all" ];
installFlags = [ "DESTDIR=$(out)" ];
dontStrip = true;
}

66
pkgs/spec-cpu/Makefile Normal file
View File

@ -0,0 +1,66 @@
include Makefile.in
HPC_BENCHMARKS_DIRS=\
axpy \
jacobi-2d \
somier \
# Require submodules:
# fft \
# fftp \
# Require vehave:
# lulesh \
# Missing compare_array_double:
# gemm \
# Broken, not found:
# spmv
DESKTOP_BENCHMARKS_DIRS=\
blackscholes \
canneal \
particlefilter \
pathfinder \
streamcluster \
swaptions
MICRO_BENCHMARKS_DIRS=\
BuffCopyUnit \
BuffCopyStrided \
BuffCopyIndexed \
FpuMicroKernel \
InstrNopBalance \
MemArithBalance \
LatencyVrgather
.PHONY: default all clean $(HPC_BENCHMARKS_DIRS) $(MICRO_BENCHMARKS_DIRS)
default:
@cd common; make; cd ..
@$(foreach dir,$(HPC_BENCHMARKS_DIRS),${MAKE} -C hpc_benchmarks/$(dir);)
@$(foreach dir,$(DESKTOP_BENCHMARKS_DIRS),${MAKE} -C desktop_benchmarks/$(dir);)
@$(foreach dir,$(MICRO_BENCHMARKS_DIRS),${MAKE} -C micro_benchmarks/$(dir);)
all:
@cd common; make all; cd ..
@$(foreach dir,$(HPC_BENCHMARKS_DIRS),${MAKE} -C hpc_benchmarks/$(dir) all ;)
@$(foreach dir,$(DESKTOP_BENCHMARKS_DIRS),${MAKE} -C desktop_benchmarks/$(dir) all ;)
@$(foreach dir,$(MICRO_BENCHMARKS_DIRS),${MAKE} -C micro_benchmarks/$(dir) all ;)
fftp:
${MAKE} -C third_party fftw
${MAKE} -C hpc_benchmarks/fftp all
${MAKE} -C hpc_benchmarks/fftp/test all
spmv-ellpack:
rm -rf hpc_benchmarks/spmv-ellpack/spmv/build
mkdir -p hpc_benchmarks/spmv-ellpack/spmv/build
cd hpc_benchmarks/spmv-ellpack/spmv/build;\
../configure riscv;\
INDEX64=1 EPI_EXT=07 PATH=${EPI_LLVM_HOME}/bin:${PATH} make
clean:
@cd common; make clean; cd ..
@$(foreach dir,$(HPC_BENCHMARKS_DIRS),${MAKE} -C hpc_benchmarks/$(dir) clean ;)
@$(foreach dir,$(DESKTOP_BENCHMARKS_DIRS),${MAKE} -C desktop_benchmarks/$(dir) clean ;)
@$(foreach dir,$(MICRO_BENCHMARKS_DIRS),${MAKE} -C micro_benchmarks/$(dir) clean ;)
@rm -rf hpc_benchmarks/spmv-ellpack/spmv/build

80
pkgs/spec-cpu/Makefile.in Normal file
View File

@ -0,0 +1,80 @@
#Compile all benchmarks with individual settings defined in their Makefiles
_default-target: default
# RVB_ROOT defined as argument
# TODO: RVB_COMMON_DIR should substitute COMMON_DIR
COMMON_DIR=$(RVB_ROOT)/common
RVB_COMMON_DIR=$(RVB_ROOT)/common
CC=clang
CXX=clang++
# Needs EPI clang
#MEPI=-mepi
MEPI=
VREPORT_FLAGS=-Rpass=loop-vectorize -Rpass-missed=loop-vectorize -Rpass-analysis=loop-vectorize
#Available CFLAGS conditional compilation:
# -DUSE_MALLOC_HP, redefines the use of malloc and free
#Makefile: General compiler flags: CFLAGS, CFLAGS_<VERSION_1>, CFLAGS_<VERSION_2>, ...
#CFLAGS=-B ${LLVM_BIN} -Wall -Wextra -march=rv64g -O2 -I${RVB_COMMON_DIR}
CFLAGS=-B ${LLVM_BIN} -Wall -Wextra -O2 -I${RVB_COMMON_DIR}
LDFLAGS=
#Only scalar instructions
CFLAGS_SCALAR=${CFLAGS} -DRVB_USE_SCALAR
LDFLAGS_SCALAR=
#Vector instructions using intrinsics
CFLAGS_VECTORIAL=${CFLAGS} -fno-vectorize $(MEPI)
LDFLAGS_VECTORIAL=
# TODO: RVV should substitute VECTORIAL (?)
#Vector instructions using intrinsics
CFLAGS_RVV=${CFLAGS} -DRVB_USE_RVV -fno-vectorize $(MEPI)
LDFLAGS_RVV=${LDFLAGS}
#Vector instructions only when code is annotate
CFLAGS_EXPLICIT_AUTOVECTORIZATION=${CFLAGS} -fopenmp-simd -fno-vectorize $(MEPI) ${VREPORT_FLAGS}
LDFLAGS_EXPLICIT_AUTOVECTORIZATION=
# TODO: OMP substitutes EXPLICIT_AUTOVECTORIZATION
#Vector instructions only when code is annotate
CFLAGS_OMP=${CFLAGS} -DRVB_USE_OMP -fopenmp-simd -fno-vectorize $(MEPI) ${VREPORT_FLAGS}
LDFLAGS_OMP=${LDFLAGS}
#Vector instructions when compiler decides
CFLAGS_AUTOVECTORIZATION=${CFLAGS} -fopenmp-simd $(MEPI) ${VREPORT_FLAGS}
LDFLAGS_AUTOVECTORIZATION=
# TODO: AUTOVECT shoud substitue AUTOVECTORIZATION (?)
#Vector instructions when compiler decides
CFLAGS_AUTOVECT=${CFLAGS} -DRVB_USE_AUTOVECT -fopenmp-simd $(MEPI) ${VREPORT_FLAGS}
LDFLAGS_AUTOVECT=${LDFLAGS}
# CBLAS library compile and link flags
CFLAGS_CBLAS=${CFLAGS} -DRVB_USE_CBLAS -I${CBLAS_INC} -I${LLVM_INC}
LDFLAGS_CBLAS=${LDFLAGS} -L${CBLAS_LIB} -lblis -Wl,-rpath,${CBLAS_LIB} -fopenmp
# BARE-METAL compile and link flags
# You may consider to disable OpenPiton Stream: -DDISABLE_OPSTREAM
CFLAGS_BMETAL=${CFLAGS} -DRVB_USE_BMETAL -B ${RVB_BMETAL_DIR} \
--target=riscv64-unknown-elf \
-I../ \
-I/apps/riscv/llvm/EPI-0.7/cross/development/riscv64-unknown-linux-gnu/sysroot/usr/include \
-I/usr/include/riscv64-linux-gnu \
-I/usr/include \
-I${RVB_BMETAL_DIR}/env \
-I${RVB_BMETAL_DIR} \
-DPREALLOCATE=1 -mcmodel=medany \
-static -std=gnu99 \
-ffast-math \
-fno-common \
-fno-builtin-printf \
${RVB_BMETAL_DIR}/syscalls.c \
${RVB_BMETAL_DIR}/crt.S \
-static -nostdlib -T \
${RVB_BMETAL_DIR}/test.ld

61
pkgs/spec-cpu/default.nix Normal file
View File

@ -0,0 +1,61 @@
{
stdenv
, spec-cpu-tools
, libarchive
, xz
, gnutar
, gfortran
, coreutils
, requireFile
, autoPatchelfHook
, libxcrypt-legacy
, lib
, benchSize ? "test"
}:
stdenv.mkDerivation rec {
pname = "spec-cpu";
version = "1.1.7";
src = null;
unpackPhase = "true";
# We need a working specxz binary
config = ./gcc-linux-x86.cfg;
buildPhase = ''
cp ${config} config.cfg
chmod +w config.cfg
export SPEC_NOCHECK=1
mkdir out
runcpu \
--verbose=80 \
--tune=base \
--size=${benchSize} \
--output_root=$PWD/out \
--config=$PWD/config.cfg \
--define build_ncpus=$NIX_BUILD_CORES \
--action=runsetup \
all
'';
# 519.lbm_r
# 502.gcc_r
# all
# We only need the run directories
installPhase = ''
# Remove build/ and exe/ directories, we only need run/
rm -rf out/benchspec/CPU/*/build/
rm -rf out/benchspec/CPU/*/exe/
mkdir -p $out
cp -a out/benchspec $out
'';
#buildInputs = [ ];
nativeBuildInputs = [ spec-cpu-tools gfortran ];
enableParallelBuilding = false;
hardeningDisable = [ "all" ];
dontStrip = true;
meta.broken = (stdenv.buildPlatform.config != "x86_64-unknown-linux-gnu") ||
(stdenv.hostPlatform.config != "riscv64-unknown-linux-gnu") ||
(stdenv.targetPlatform.config != "riscv64-unknown-linux-gnu");
}

View File

@ -0,0 +1,391 @@
#------------------------------------------------------------------------------
# SPEC CPU(R) 2017 config for gcc/g++/gfortran on Linux x86
#------------------------------------------------------------------------------
#
# Usage: (1) Copy this to a new name
# cd $SPEC/config
# cp Example-x.cfg myname.cfg
# (2) Change items that are marked 'EDIT' (search for it)
#
# SPEC tested this config file with:
# Compiler version(s): Various. See note "Older GCC" below.
# Operating system(s): Oracle Linux Server 6, 7, 8 /
# Red Hat Enterprise Linux Server 6, 7, 8
# SUSE Linux Enterprise Server 15
# Ubuntu 19.04
# Hardware: Xeon, EPYC
#
# If your system differs, this config file might not work.
# You might find a better config file at https://www.spec.org/cpu2017/results
#
# Note: Older GCC
#
# Please use the newest GCC that you can. The default version packaged with
# your operating system may be very old; look for alternate packages with a
# newer version.
#
# If you have no choice and must use an old version, here is what to expect:
#
# - "peak" tuning: Several benchmarks will fail at peak tuning if you use
# compilers older than GCC 7.
# In that case, please use base only.
# See: https://www.spec.org/cpu2017/Docs/overview.html#Q16
# https://www.spec.org/cpu2017/Docs/config.html#tune
# Peak tuning is expected to work for all or nearly all
# benchmarks as of GCC 7 or later.
# Exception:
# - See topic "628.pop2_s basepeak", below.
#
# - "base" tuning: This config file is expected to work for base tuning with
# GCC 4.8.5 or later
# Exception:
# - Compilers vintage about 4.9 may need to turn off the
# tree vectorizer, by adding to the base OPTIMIZE flags:
# -fno-tree-loop-vectorize
#
# Unexpected errors? Try reducing the optimization level, or try removing:
# -march=native
#
# Compiler issues: Contact your compiler vendor, not SPEC.
# For SPEC help: https://www.spec.org/cpu2017/Docs/techsupport.html
#------------------------------------------------------------------------------
#--------- Label --------------------------------------------------------------
# Arbitrary string to tag binaries (no spaces allowed)
# Two Suggestions: # (1) EDIT this label as you try new ideas.
%ifndef %{label}
% define label "nix" # (2) Use a label meaningful to *you*.
%endif
#--------- Preprocessor -------------------------------------------------------
%ifndef %{bits} # EDIT to control 32 or 64 bit compilation. Or,
% define bits 64 # you can set it on the command line using:
%endif # 'runcpu --define bits=nn'
%ifndef %{build_ncpus} # EDIT to adjust number of simultaneous compiles.
% define build_ncpus 8 # Or, you can set it on the command line:
%endif # 'runcpu --define build_ncpus=nn'
# Don't change this part.
%if %{bits} == 64
% define model -m64
%elif %{bits} == 32
% define model -m32
%else
% error Please define number of bits - see instructions in config file
%endif
%if %{label} =~ m/ /
% error Your label "%{label}" contains spaces. Please try underscores instead.
%endif
%if %{label} !~ m/^[a-zA-Z0-9._-]+$/
% error Illegal character in label "%{label}". Please use only alphanumerics, underscore, hyphen, and period.
%endif
#--------- Global Settings ----------------------------------------------------
# For info, see:
# https://www.spec.org/cpu2017/Docs/config.html#fieldname
# Example: https://www.spec.org/cpu2017/Docs/config.html#tune
command_add_redirect = 1
flagsurl = $[top]/config/flags/gcc.xml
ignore_errors = 1
iterations = 1
label = %{label}-m%{bits}
line_width = 1020
log_line_width = 1020
makeflags = --jobs=%{build_ncpus}
mean_anyway = 1
output_format = txt,html,cfg,pdf,csv
preenv = 1
reportable = 0
tune = base,peak # EDIT if needed: set to "base" for old GCC.
# See note "Older GCC" above.
#--------- How Many CPUs? -----------------------------------------------------
# Both SPECrate and SPECspeed can test multiple chips / cores / hw threads
# - For SPECrate, you set the number of copies.
# - For SPECspeed, you set the number of threads.
# See: https://www.spec.org/cpu2017/Docs/system-requirements.html#MultipleCPUs
#
# q. How many should I set?
# a. Unknown, you will have to try it and see!
#
# To get you started, some suggestions:
#
# copies - This config file defaults to testing only 1 copy. You might
# try changing it to match the number of cores on your system,
# or perhaps the number of virtual CPUs as reported by:
# grep -c processor /proc/cpuinfo
# Be sure you have enough memory. See:
# https://www.spec.org/cpu2017/Docs/system-requirements.html#memory
#
# threads - This config file sets a starting point. You could try raising
# it. A higher thread count is much more likely to be useful for
# fpspeed than for intspeed.
#
intrate,fprate:
copies = 1 # EDIT to change number of copies (see above)
intspeed,fpspeed:
threads = 4 # EDIT to change number of OpenMP threads (see above)
#------- Compilers ------------------------------------------------------------
default:
# EDIT: The parent directory for your compiler.
# Do not include the trailing /bin/
# Do not include a trailing slash
# Examples:
# 1 On a Red Hat system, you said:
# 'yum install devtoolset-9'
# Use: % define gcc_dir "/opt/rh/devtoolset-9/root/usr"
#
# 2 You built GCC in: /disk1/mybuild/gcc-10.1.0/bin/gcc
# Use: % define gcc_dir "/disk1/mybuild/gcc-10.1.0"
#
# 3 You want: /usr/bin/gcc
# Use: % define gcc_dir "/usr"
# WARNING: See section "Older GCC" above.
#
#%ifndef %{gcc_dir}
#% define gcc_dir "@GCC_DIR@" # EDIT (see above)
#%endif
# EDIT: If your compiler version is 10 or greater, you must enable the next
# line to avoid compile errors for several FP benchmarks
#
%define GCCge10 # EDIT: remove the '#' from column 1 if using GCC 10 or later
# EDIT if needed: the preENV line adds library directories to the runtime
# path. You can adjust it, or add lines for other environment variables.
# See: https://www.spec.org/cpu2017/Docs/config.html#preenv
# and: https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
#preENV_LD_LIBRARY_PATH = %{gcc_dir}/lib64/:%{gcc_dir}/lib/:/lib64
#preENV_LD_LIBRARY_PATH = %{gcc_dir}/lib64/:%{gcc_dir}/lib/:/lib64:%{ENV_LD_LIBRARY_PATH}
#SPECLANG = %{gcc_dir}/bin/
CC = %{ENV_CC} -std=c99
CXX = %{ENV_CXX} -std=c++03
FC = %{ENV_FC}
# How to say "Show me your version, please"
CC_VERSION_OPTION = --version
CXX_VERSION_OPTION = --version
FC_VERSION_OPTION = --version
default:
%if %{bits} == 64
sw_base_ptrsize = 64-bit
sw_peak_ptrsize = 64-bit
%else
sw_base_ptrsize = 32-bit
sw_peak_ptrsize = 32-bit
%endif
#--------- Portability --------------------------------------------------------
default: # data model applies to all benchmarks
%if %{bits} == 32
# Strongly recommended because at run-time, operations using modern file
# systems may fail spectacularly and frequently (or, worse, quietly and
# randomly) if a program does not accommodate 64-bit metadata.
EXTRA_PORTABILITY = -D_FILE_OFFSET_BITS=64
%else
EXTRA_PORTABILITY = -DSPEC_LP64
%endif
# Benchmark-specific portability (ordered by last 2 digits of bmark number)
500.perlbench_r,600.perlbench_s: #lang='C'
%if %{bits} == 32
% define suffix IA32
%else
% define suffix X64
%endif
PORTABILITY = -DSPEC_LINUX_%{suffix}
521.wrf_r,621.wrf_s: #lang='F,C'
CPORTABILITY = -DSPEC_CASE_FLAG
FPORTABILITY = -fconvert=big-endian
523.xalancbmk_r,623.xalancbmk_s: #lang='CXX'
PORTABILITY = -DSPEC_LINUX
526.blender_r: #lang='CXX,C'
PORTABILITY = -funsigned-char -DSPEC_LINUX
527.cam4_r,627.cam4_s: #lang='F,C'
PORTABILITY = -DSPEC_CASE_FLAG
628.pop2_s: #lang='F,C'
CPORTABILITY = -DSPEC_CASE_FLAG
FPORTABILITY = -fconvert=big-endian
#----------------------------------------------------------------------
# GCC workarounds that do not count as PORTABILITY
#----------------------------------------------------------------------
# The workarounds in this section would not qualify under the SPEC CPU
# PORTABILITY rule.
# - In peak, they can be set as needed for individual benchmarks.
# - In base, individual settings are not allowed; set for whole suite.
# See:
# https://www.spec.org/cpu2017/Docs/runrules.html#portability
# https://www.spec.org/cpu2017/Docs/runrules.html#BaseFlags
#
# Integer workarounds - peak
#
500.perlbench_r,600.perlbench_s=peak: # https://www.spec.org/cpu2017/Docs/benchmarks/500.perlbench_r.html
EXTRA_CFLAGS = -fno-strict-aliasing -fno-unsafe-math-optimizations -fno-finite-math-only
502.gcc_r,602.gcc_s=peak: # https://www.spec.org/cpu2017/Docs/benchmarks/502.gcc_r.html
EXTRA_CFLAGS = -fno-strict-aliasing -fgnu89-inline
505.mcf_r,605.mcf_s=peak: # https://www.spec.org/cpu2017/Docs/benchmarks/505.mcf_r.html
EXTRA_CFLAGS = -fno-strict-aliasing
525.x264_r,625.x264_s=peak: # https://www.spec.org/cpu2017/Docs/benchmarks/525.x264_r.html
EXTRA_CFLAGS = -fcommon
#
# Integer workarounds - base - combine the above - https://www.spec.org/cpu2017/Docs/runrules.html#BaseFlags
#
intrate,intspeed=base:
EXTRA_CFLAGS = -fno-strict-aliasing -fno-unsafe-math-optimizations -fno-finite-math-only -fgnu89-inline -fcommon
#
# Floating Point workarounds - peak
#
511.povray_r=peak: # https://www.spec.org/cpu2017/Docs/benchmarks/511.povray_r.html
EXTRA_CFLAGS = -fno-strict-aliasing
521.wrf_r,621.wrf_s=peak: # https://www.spec.org/cpu2017/Docs/benchmarks/521.wrf_r.html
% ifdef %{GCCge10} # workaround for GCC v10 (and presumably later)
EXTRA_FFLAGS = -fallow-argument-mismatch
% endif
527.cam4_r,627.cam4_s=peak: # https://www.spec.org/cpu2017/Docs/benchmarks/527.cam4_r.html
EXTRA_CFLAGS = -fno-strict-aliasing
% ifdef %{GCCge10} # workaround for GCC v10 (and presumably later)
EXTRA_FFLAGS = -fallow-argument-mismatch
% endif
# See also topic "628.pop2_s basepeak" below
628.pop2_s=peak: # https://www.spec.org/cpu2017/Docs/benchmarks/628.pop2_s.html
% ifdef %{GCCge10} # workaround for GCC v10 (and presumably later)
EXTRA_FFLAGS = -fallow-argument-mismatch
% endif
#
# FP workarounds - base - combine the above - https://www.spec.org/cpu2017/Docs/runrules.html#BaseFlags
#
fprate,fpspeed=base:
EXTRA_CFLAGS = -fno-strict-aliasing
% ifdef %{GCCge10} # workaround for GCC v10 (and presumably later)
EXTRA_FFLAGS = -fallow-argument-mismatch
% endif
#-------- Tuning Flags common to Base and Peak --------------------------------
#
# Speed (OpenMP and Autopar allowed)
#
%if %{bits} == 32
intspeed,fpspeed:
#
# Many of the speed benchmarks (6nn.benchmark_s) do not fit in 32 bits
# If you wish to run SPECint2017_speed or SPECfp2017_speed, please use
#
# runcpu --define bits=64
#
fail_build = 1
%else
intspeed,fpspeed:
EXTRA_OPTIMIZE = -fopenmp -DSPEC_OPENMP
fpspeed:
#
# 627.cam4 needs a big stack; the preENV will apply it to all
# benchmarks in the set, as required by the rules.
#
preENV_OMP_STACKSIZE = 120M
%endif
#-------- Base Tuning Flags ----------------------------------------------
# EDIT if needed -- If you run into errors, you may need to adjust the
# optimization - for example you may need to remove
# the -march=native. See topic "Older GCC" above.
#
default=base: # flags for all base
OPTIMIZE = -g -O3 -march=native
#-------- Peak Tuning Flags ----------------------------------------------
default=peak:
OPTIMIZE = -g -Ofast -march=native -flto
PASS1_FLAGS = -fprofile-generate
PASS2_FLAGS = -fprofile-use
# 628.pop2_s basepeak: Depending on the interplay of several optimizations,
# 628.pop2_s might not validate with peak tuning. Use the base
# version instead. See:
# https:// www.spec.org/cpu2017/Docs/benchmarks/628.pop2_s.html
628.pop2_s=peak:
basepeak = yes
#------------------------------------------------------------------------------
# Tester and System Descriptions - EDIT all sections below this point
#------------------------------------------------------------------------------
# For info about any field, see
# https://www.spec.org/cpu2017/Docs/config.html#fieldname
# Example: https://www.spec.org/cpu2017/Docs/config.html#hw_memory
#-------------------------------------------------------------------------------
#--------- EDIT to match your version -----------------------------------------
default:
sw_compiler001 = C/C++/Fortran: Version 10.1.0 of GCC, the
sw_compiler002 = GNU Compiler Collection
#--------- EDIT info about you ------------------------------------------------
# To understand the difference between hw_vendor/sponsor/tester, see:
# https://www.spec.org/cpu2017/Docs/config.html#test_sponsor
intrate,intspeed,fprate,fpspeed: # Important: keep this line
hw_vendor = My Corporation
tester = My Corporation
test_sponsor = My Corporation
license_num = nnn (Your SPEC license number)
# prepared_by = # Ima Pseudonym # Whatever you like: is never output
#--------- EDIT system availability dates -------------------------------------
intrate,intspeed,fprate,fpspeed: # Important: keep this line
# Example # Brief info about field
hw_avail = # Nov-2099 # Date of LAST hardware component to ship
sw_avail = # Nov-2099 # Date of LAST software component to ship
fw_bios = # Version Mumble released May-2099 # Firmware information
#--------- EDIT system information --------------------------------------------
intrate,intspeed,fprate,fpspeed: # Important: keep this line
# Example # Brief info about field
# hw_cpu_name = # Intel Xeon E9-9999 v9 # chip name
hw_cpu_nominal_mhz = # 9999 # Nominal chip frequency, in MHz
hw_cpu_max_mhz = # 9999 # Max chip frequency, in MHz
# hw_disk = # 9 x 9 TB SATA III 9999 RPM # Size, type, other perf-relevant info
hw_model = # TurboBlaster 3000 # system model name
# hw_nchips = # 99 # number chips enabled
hw_ncores = # 9999 # number cores enabled
hw_ncpuorder = # 1-9 chips # Ordering options
hw_nthreadspercore = # 9 # number threads enabled per core
hw_other = # TurboNUMA Router 10 Gb # Other perf-relevant hw, or "None"
# hw_memory001 = # 999 GB (99 x 9 GB 2Rx4 PC4-2133P-R, # The 'PCn-etc' is from the JEDEC
# hw_memory002 = # running at 1600 MHz) # label on the DIMM.
hw_pcache = # 99 KB I + 99 KB D on chip per core # Primary cache size, type, location
hw_scache = # 99 KB I+D on chip per 9 cores # Second cache or "None"
hw_tcache = # 9 MB I+D on chip per chip # Third cache or "None"
hw_ocache = # 9 GB I+D off chip per system board # Other cache or "None"
# sw_file = # ext99 # File system
# sw_os001 = # Linux Sailboat # Operating system
# sw_os002 = # Distribution 7.2 SP1 # and version
sw_other = # TurboHeap Library V8.1 # Other perf-relevant sw, or "None"
# sw_state = # Run level 99 # Software state.
power_management = # briefly summarize power settings
# Note: Some commented-out fields above are automatically set to preliminary
# values by sysinfo
# https://www.spec.org/cpu2017/Docs/config.html#sysinfo
# Uncomment lines for which you already know a better answer than sysinfo

70
pkgs/spec-cpu/launcher.sh Normal file
View File

@ -0,0 +1,70 @@
#!/bin/bash
set -e
if [ -z "$SPEC" ]; then
SPEC=$(spec-cpu-mini)
fi
if [ -z "$SPEC" ]; then
echo "cannot find spec, set SPEC variable"
exit 1
fi
where=$TMPDIR
if [ -z "$where" ]; then
if [ -d /tmp ]; then
where=/tmp
else
where=$PWD
fi
fi
cwd=$(readlink -f $where)
# Place the outcome here
wd="$cwd/spec"
mkdir -p "$wd"
benchniter=1
benchsize=test
benchtune=base
echo "--- Placing output in $wd ---"
printf 'benchmark\tsize\ttune\titer\ttime_s\n' > "$wd/time.csv"
for srcbench in $SPEC/benchspec/CPU/*; do
name=$(basename $srcbench)
bench="$wd/$name"
bench_out="$wd/$name.csv"
rm -rf "$bench"
cp -r "$srcbench" "$bench"
chmod +w -R "$bench"
rundir="$bench/run/run_${benchtune}_${benchsize}_nix-m64.0000"
sed -i '/^-C/d' "$rundir/speccmds.cmd"
echo "--- Running $name for $benchniter iterations ---"
(
#set -x
cd $rundir
specinvoke -i $benchniter -E speccmds.cmd > /dev/null
#set +x
)
# Print time
awk '/^run [0-9]* elapsed time/{printf \
"%s\t%s\t%s\t%s\t%s\n", \
"'$name'","'$benchsize'","'$benchtune'",$2,$7}' \
"$rundir/speccmds.out" > "$bench_out"
cat "$bench_out"
# Accumulate in main CSV
cat "$bench_out" >> "$wd/time.csv"
# Erase intermediate files as they occupy RAM.
rm -rf "$bench"
done
echo "--- RESULTS in $wd/time.csv ---"
cat "$wd/time.csv"
echo "---------------------------------------"

60
pkgs/spec-cpu/mini.nix Normal file
View File

@ -0,0 +1,60 @@
{
stdenv
, spec-cpu
, spec-cpu-tools
, specinvoke
, speclaunch
}:
stdenv.mkDerivation rec {
pname = "spec-cpu-mini";
version = spec-cpu.version;
src = null;
unpackPhase = "true";
# Select only a subset of the benchmarks:
# https://www.spec.org/cpu2017/Docs/#benchdocs
benchList = [
# -- SPECspeed 2017 Integer --
"600.perlbench_s"
"602.gcc_s"
"605.mcf_s"
"620.omnetpp_s"
#"623.xalancbmk_s" # Big
#"625.x264_s" # Big
#"631.deepsjeng_s" # Requires 7 GiB of RAM
"641.leela_s"
"648.exchange2_s"
# "657.xz_s" # Runs out of memory with 700 MiB of RAM
];
dontConfigure = true;
buildPhase = ''
pwd
mkdir -p benchspec/CPU
for bench in $benchList; do
cp -r ${spec-cpu}/benchspec/CPU/$bench benchspec/CPU/
done
# Make writable
chmod -R +w benchspec
# Remove environment
find benchspec -name '*.cmd' | xargs sed -i '/^-E/d'
# Remove compare script as it refers to spec-cpu-tools
find benchspec -name 'compare.cmd' -delete
'';
installPhase = ''
pwd
mkdir -p $out
cp -r benchspec/ $out
mkdir -p $out/bin
echo -e "#!$SHELL\necho $out" > $out/bin/spec-cpu-mini
chmod +x $out/bin/spec-cpu-mini
cp ${specinvoke}/bin/specinvoke $out/bin
cp ${speclaunch}/bin/speclaunch $out/bin
'';
enableParallelBuilding = false;
hardeningDisable = [ "all" ];
dontStrip = true;
}

View File

@ -0,0 +1,15 @@
--- a/unix.c 2024-10-08 12:30:18.785111397 +0200
+++ b/unix.c 2024-10-08 12:32:09.580923368 +0200
@@ -165,7 +165,11 @@ pid_t invoke(copy_info_t *ui, command_in
/* We could redirect them here. This might be useful for VMS? */
*(si->command_ptr) = cmd;
si->invoke_args[0] = si->shell;
- execve(si->shell, si->invoke_args, env);
+ if (execve(si->shell, si->invoke_args, env) != 0) {
+ fprintf (stderr, "Can't execute command: %s(%d)\n",
+ STRERROR(errno), errno);
+ specinvoke_exit (1, si);
+ }
} else { /* Parent */
ui->pid = pid;
fprintf (si->outfp,

View File

@ -0,0 +1,33 @@
{
stdenv
, libarchive
, spec-cpu-tools
, runCommandNoCC
}:
let
version = spec-cpu-tools.version;
tar = runCommandNoCC "specinvoke-${version}.tar" {
src = spec-cpu-tools.src;
nativeBuildInputs = [ libarchive ];
} ''
mkdir iso
bsdtar -C iso -xf $src
cp iso/install_archives/tools-src.tar $out
'';
in stdenv.mkDerivation {
pname = "specinvoke";
version = version;
src = tar;
sourceRoot = "tools/src/specinvoke/";
patches = [
./specinvoke-execve.patch
];
# Almost no bugs
preInstall = ''
mkdir -p $out/bin
'';
enableParallelBuilding = false;
hardeningDisable = [ "all" ];
dontStrip = true;
}

View File

@ -0,0 +1,21 @@
{
stdenv
, bash
}:
stdenv.mkDerivation {
name = "speclaunch";
src = ./launcher.sh;
dontUnpack = true;
dontConfigure = true;
dontBuild = true;
installPhase = ''
mkdir -p $out/bin
cp $src $out/bin/speclaunch
chmod +x $out/bin/speclaunch
'';
buildInputs = [ bash ];
enableParallelBuilding = false;
hardeningDisable = [ "all" ];
dontStrip = true;
}

106
pkgs/spec-cpu/tools.nix Normal file
View File

@ -0,0 +1,106 @@
{
stdenv
, libarchive
, xz
, gnutar
, gfortran
, coreutils
, requireFile
, autoPatchelfHook
, libxcrypt-legacy
, glibc
, lib
}:
stdenv.mkDerivation rec {
pname = "spec-cpu-tools";
version = "1.1.7";
src = requireFile {
name = "cpu2017-1.1.7.iso";
sha256 = "02630819h64dyy57wkj33fhwwqgbw6mqc5awh1zm48pkvvl0l600";
message = ''
Missing SPEC CPU 2017 1.1.7.
Add it to the store with:
$ nix-prefetch-url file:/path/to/cpu2017-1.1.7.iso
/nix/store/mk4hr8xwd62akp7iw5khq638ssba8qz0-cpu2017-1.1.7.iso
Notice that the name must match exactly "cpu2017-1.1.7.iso".
'';
};
unpackPhase = ''
set -x
mkdir iso
bsdtar -C iso -xf $src
chmod +w -R iso
#for f in iso/install_archives/benchball/*; do
# bsdtar -xf $f
#done
#mkdir src
#bsdtar -C src -xf iso/install_archives/benchball/cpu2017-1.1.7.base.tar.xz
#bsdtar -C src -xf iso/install_archives/benchball/519.lbm_r-1.000503.tar.xz
sourceRoot="$PWD/iso"
set +x
'';
# We need a working specxz binary
configurePhase = ''
patchShebangs install.sh
set -x
# Replace "spec*" tools by symlinks to working binaries
pushd tools/bin/linux-x86_64
ln -fs ${xz}/bin/xz specxz
ln -fs ${gnutar}/bin/tar spectar
patchelf \
--set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
specsha512sum
ls -l spec*
./specxz -h
./spectar --help
ldd ./specsha512sum
./specsha512sum --help
popd
# sha512sum requires -e, not provided by coreutils
export SPEC="$sourceRoot"
# Don't run the tests
sed -i 's/^.*shrc will.*$/exit 0/g' install.sh
set +x
'';
installPhase = ''
bash -x install.sh -f -d $out -u linux-x86_64
'';
preFixup = ''
# Fix temporary directory creation
sed -i '/^sub get_tmp_directory/a\ return tempdir(CLEANUP => 1);' \
$out/bin/common/util_common.pl
sed -i '/my $dir = jp($top, $config->resultdir, $subdir);/c\ my $dir = ::get_tmp_directory($config, 1);' \
$out/bin/harness/log.pl
'';
# Missing libdb-4.7.so
autoPatchelfIgnoreMissingDeps = true;
nativeBuildInputs = [ libxcrypt-legacy libarchive autoPatchelfHook ];
#buildInputs = [ libxcrypt-legacy ];
enableParallelBuilding = false;
hardeningDisable = [ "all" ];
dontStrip = true;
meta.broken = (stdenv.buildPlatform.config != "x86_64-unknown-linux-gnu") ||
(stdenv.hostPlatform.config != "x86_64-unknown-linux-gnu") ||
(stdenv.targetPlatform.config != "riscv64-unknown-linux-gnu");
}

33
pkgs/stream/default.nix Normal file
View File

@ -0,0 +1,33 @@
{
stdenv
, fetchFromGitHub
}:
stdenv.mkDerivation rec {
pname = "stream";
version = "4dbce1d0";
src = fetchFromGitHub {
owner = "jeffhammond";
repo = "STREAM";
rev = "4dbce1d0fdb7410e8f21b48f3381bc0a1341967f";
sha256 = "sha256-sBwdPeaMyI/wH1Nq0yQtb/kvi5913e0azXaulOJIG3A=";
};
# CFLAGS='-O2 -fopenmp -DSTREAM_ARRAY_SIZE=40000000'
buildPhase = ''
set -x
make stream_c.exe CC=$CC FC=$FC CFLAGS=-O2
set +x
'';
#nativeBuildInputs = [ gfortran ];
dontStrip = true;
dontConfigure = true;
enableParallelBuilding = false;
hardeningDisable = [ "all" ];
installPhase = ''
mkdir -p $out/bin
cp -a stream_c.exe $out/bin/stream
'';
}

4
tools/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
plictool
csrtool
memtool
*.bin

20
tools/Makefile Normal file
View File

@ -0,0 +1,20 @@
CFLAGS=-Wall -static
PREFIX?=/usr/local
bin=plictool csrtool memtool unalign
all: $(bin)
clean:
rm -f $(bin)
install:
mkdir -p $(PREFIX)/bin
cp -a $(bin) $(PREFIX)/bin
plictool: plictool.c
csrtool: csrtool.c
memtool: memtool.c
unalign: unalign.c

34
tools/csrtool.c Normal file
View File

@ -0,0 +1,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
/* Print */
if (argc > 1) {
// Wait for all memory operations to finish
__asm__ volatile ("fence");
if (strcmp(argv[1], "mem-in-order") == 0) {
__asm__ volatile ("fence");
__asm__ volatile ("csrwi 0x801, 2");
} else if (strcmp(argv[1], "all-in-order") == 0) {
__asm__ volatile ("fence");
__asm__ volatile ("csrwi 0x801, 7");
} else if (strcmp(argv[1], "all-out-of-order") == 0) {
__asm__ volatile ("fence");
__asm__ volatile ("csrwi 0x801, 0");
} else {
fprintf(stderr, "unknown '%s', use: mem-in-order, all-in-order or all-out-of-order\n", argv[1]);
exit(1);
}
}
// Wait for all memory operations to finish
__asm__ volatile ("fence");
unsigned result;
asm("csrr %0, 0x801" : "=r"(result) : );
printf("CSR 0x801 = %xu\n", result);
return 0;
}

214
tools/memtool.c Normal file
View File

@ -0,0 +1,214 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: MIT
* Author: Rodrigo Arias Mallo <rodrigo.arias@bsc.es> */
/* This is just a small tool to exercise the memory which attempts to
* stress the virtual memory, in a crude attempt to reproduce the hangs
* that we were observing while booting NixOS. */
/* Changelog:
* v0.0.1 (2024-07-10): Start version with "chain" and "fill" tests.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define MAX_SIZE (1024L * 1024L)
struct block {
struct block *next;
size_t size;
uint32_t data[];
};
struct chain {
struct block *front;
struct block *tail;
long maxsize;
long nbytes;
long nblocks;
};
static int
allocate(struct chain *chain)
{
/* Constraint the number of elements based on the maxsize */
long maxn = chain->maxsize / sizeof(uint32_t);
long n = (long) rand() % maxn;
size_t size = sizeof(struct block) + n * sizeof(uint32_t);
printf("allocating...\n");
struct block *b = malloc(size);
/* No mem */
if (b == NULL)
return -1;
b->size = size;
b->next = NULL;
/* Populate the block with some data */
printf("filling...\n");
for (long i = 0; i < n; i++)
b->data[i] = rand();
/* Add it to the chain */
if (chain->tail)
chain->tail->next = b;
chain->tail = b;
/* And to the front if it is the first */
if (!chain->front)
chain->front = b;
chain->nblocks++;
chain->nbytes += size;
return 0;
}
static int
deallocate(struct chain *chain)
{
/* May run out of blocks */
if (!chain->front)
return -1;
struct block *b = chain->front;
chain->front = b->next;
/* Last block */
if (chain->tail == b)
chain->tail = NULL;
chain->nblocks--;
chain->nbytes -= b->size;
printf("deallocating...\n");
free(b);
return 0;
}
static void
do_chain(int argc, char *argv[])
{
struct chain chain = {0};
/* Default 1 MiB */
chain.maxsize = 1024L * 1024L;
if (argc > 0)
chain.maxsize = atol(argv[0]);
printf("mode chain: maxsize=%ldK\n", chain.maxsize / 1024);
srand(123);
for (long iter = 0; ; iter++) {
int p = rand() % 100;
int is_alloc = (p > 10);
int ret = 0;
char c;
if (is_alloc) {
if (allocate(&chain) == 0)
c = 'A';
else
c = '-';
} else {
if (deallocate(&chain) == 0)
c = 'D';
else
c = '-';
}
printf("iter=%ld nblocks=%ld allocated=%ldK (%c)\n",
iter, chain.nblocks, chain.nbytes / 1024,
c);
}
}
static void
do_fill(int argc, char *argv[])
{
/* Default: 256 MiB */
long nbytes = 256L * 1024L * 1024L;
if (argc > 0)
nbytes = atol(argv[0]);
long n = nbytes / sizeof(int);
printf("mode fill: nbytes=%ldM, n=%ld\n",
nbytes / (1024L * 1024L), n);
int *buf = malloc(nbytes);
if (!buf) {
perror("malloc failed");
exit(1);
}
for (long i = 0; i < n; i++) {
buf[i] = i;
if ((i % (1024L * 1024L)) == 0)
printf("written=%ldK, addr=%p OK\n",
i * sizeof(int) / 1024L,
&buf[i]);
}
free(buf);
printf("fill test OK\n");
}
static void
usage(void)
{
printf(
"Usage: memtool <command> [<options>...]\n"
"\n"
"Available commands:\n"
" chain [<maxsize>]\n"
" Creates a chain of blocks of random size, each up to maxsize\n"
" or 1MiB if not given. Blocks are freed with 10% probability\n"
" starting from the oldest.\n"
"\n"
" fill [<size>]\n"
" Allocates a vector of the given size (or 256 MiB if not given)\n"
" and initializes it with a increasing value per element.\n"
"\n");
exit(1);
}
int main(int argc, char *argv[])
{
printf("memtool v0.0.1 - Rodrigo Arias Mallo <rodrigo.arias@bsc.es>\n");
if (argc < 2)
usage();
/* Skip program name */
argc--; argv++;
const char *mode = argv[0];
/* Skip mode */
argc--; argv++;
if (strcmp(mode, "chain") == 0)
do_chain(argc, argv);
else if (strcmp(mode, "fill") == 0)
do_fill(argc, argv);
else
usage();
return 0;
}

388
tools/plictool.c Normal file
View File

@ -0,0 +1,388 @@
/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: MIT
* Author: Rodrigo Arias Mallo <rodrigo.arias@bsc.es> */
/* Small utility to manage the PLIC. */
/* Changelog:
* v0.0.1 (2024-09-03): Initial version.
* v0.0.2 (2024-09-04): Print contexts in another line and masked information.
* v0.0.3 (2024-09-04): Make output format more clear and add manual.
* v0.0.4 (2024-09-30): Implement support for claiming an interrupt.
* v0.0.5 (2024-10-02): Support other read/write operations.
*/
#define VERSION "v0.0.5"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
int operation;
const char *plic_address_str = "0x40800000";
long ncontexts = 2L;
long maxsources = 1024L;
long nsources = 1024L;
long context = -1;
long source = -1;
long value = -1;
bool value_set = NULL;
struct ctx {
uint32_t threshold;
};
struct source_ctx {
bool enabled;
bool masked;
uint32_t threshold;
const char *state;
};
struct source {
bool pending;
bool show;
uint32_t priority;
struct source_ctx *ctx;
long ncontexts;
};
static uint32_t
read_reg(void *base, size_t offset)
{
volatile uint32_t *p = base + offset;
return *p;
}
static void
write_reg(void *base, size_t offset, uint32_t value)
{
volatile uint32_t *p = base + offset;
*p = value;
}
uint32_t
claim_get(void *base, uint32_t ctx)
{
return read_reg(base, 0x200004L + ctx * 0x1000);
}
static void
claim_set(void *base, uint32_t ctx, uint32_t value)
{
write_reg(base, 0x200004L + ctx * 0x1000, value);
}
uint32_t
thre_get(void *base, uint32_t ctx)
{
return read_reg(base, 0x200000L + (ctx * 0x1000L));
}
static void
thre_set(void *base, uint32_t ctx, uint32_t value)
{
write_reg(base, 0x200000L + (ctx * 0x1000L), value);
}
uint32_t
prio_get(void *base, uint32_t s)
{
return read_reg(base, s * 4L);
}
static void
prio_set(void *base, uint32_t s, uint32_t value)
{
write_reg(base, s * 4L, value);
}
uint32_t
pending_get(void *base, uint32_t s)
{
uint32_t offset = 0x1000L + (s / 32L) * 4L;
uint32_t pending = read_reg(base, offset);
long shift = s % 32L;
return (pending >> shift) & 1;
}
static void
pending_set(void *base, uint32_t s, uint32_t value)
{
uint32_t offset = 0x1000L + (s / 32L) * 4L;
uint32_t pending = read_reg(base, offset);
long shift = s % 32L;
if (value)
pending |= (1L << shift);
else
pending &= ~(1L << shift);
write_reg(base, offset, pending);
}
uint32_t
enable_get(void *base, uint32_t c, uint32_t s)
{
size_t off_en = 0x2000L + 0x80L * c + (s / 32L) * 4L;
uint32_t enabled_reg = read_reg(base, off_en);
long shift = s % 32L;
return (enabled_reg >> shift) & 1;
}
static void
enable_set(void *base, uint32_t c, uint32_t s, uint32_t value)
{
size_t off_en = 0x2000L + 0x80L * c + (s / 32L) * 4L;
uint32_t enabled_reg = read_reg(base, off_en);
long shift = s % 32L;
if (value)
enabled_reg |= (1L << shift);
else
enabled_reg &= ~(1L << shift);
write_reg(base, off_en, enabled_reg);
}
static void
source_init(struct source *src, long ncontexts)
{
memset(src, 0, sizeof(struct source));
src->ctx = calloc(ncontexts, sizeof(struct source_ctx));
src->ncontexts = ncontexts;
if (src->ctx == NULL) {
perror("calloc failed");
exit(1);
}
}
static void
source_reset(struct source *src)
{
src->pending = false;
src->show = false;
src->priority = 0;
memset(src->ctx, 0, src->ncontexts * sizeof(struct source_ctx));
}
static void
source_free(struct source *src)
{
free(src->ctx);
}
static void
source_read(struct source *src, void *base, long s)
{
uint32_t pending_reg = read_reg(base, 0x1000L + (s / 32L) * 4L);
long shift = s % 32L;
src->pending = (pending_reg >> shift) & 1;
src->priority = read_reg(base, 0x0000L + (s * 4L));
bool ctx_show = 0;
for (long c = 0; c < src->ncontexts; c++) {
struct source_ctx *ctx = &src->ctx[c];
size_t off_en = 0x2000L + 0x80L * c + (s / 32L) * 4L;
uint32_t enabled_reg = read_reg(base, off_en);
ctx->enabled = (enabled_reg >> shift) & 1;
ctx->threshold = read_reg(base, 0x200000L + (c * 0x1000L));
ctx->masked = src->priority <= ctx->threshold;
ctx_show = ctx_show || ctx->enabled;
if (!ctx->enabled)
ctx->state = "-";
else if (ctx->masked)
ctx->state = "masked";
else
ctx->state = "firing";
}
/* Show the source if it has some bit to non-zero */
src->show = src->pending || src->priority || ctx_show;
}
static void
list_sources(void *base)
{
printf("Source\tPend\tPrio");
for (long i = 0; i < ncontexts; i++) {
uint32_t threshold = read_reg(base, 0x200000L + (i * 0x1000L));
printf("\tC%ld(%u)", i, threshold);
}
printf("\n");
struct source s;
source_init(&s, ncontexts);
for (long i = 0; i < nsources; i++) {
source_reset(&s);
source_read(&s, base, i);
if (!s.show)
continue;
printf("%ld\t%s\t%u", i, s.pending ? "yes" : "-", s.priority);
for (long j = 0; j < ncontexts; j++)
printf("\t%s", s.ctx[j].state);
printf("\n");
}
source_free(&s);
}
static void usage(void)
{
printf("plictool "VERSION" -- Rodrigo Arias Mallo <rodrigo.arias@bsc.es>\n");
fprintf(stderr,
"Usage:\n"
" plictool [-a addr] [-L] [-n nsrc] [-x nctx] # List (default)\n"
" plictool [-a addr] -C ctx [-w value] # Claim\n"
" plictool [-a addr] -T ctx [-w value] # Threshold\n"
" plictool [-a addr] -I src [-w value] # Priority\n"
" plictool [-a addr] -P src [-w value] # Pending\n"
" plictool [-a addr] -E src -c ctx [-w value] # Enabled\n"
" plictool -v # Version\n"
);
exit(1);
}
int main(int argc, char *argv[])
{
const char *memfile = "/dev/mem";
int opt;
while ((opt = getopt(argc, argv, "f:a:LC:T:P:I:E:n:x:c:w:vh")) != -1) {
switch (opt) {
/* Common flags */
case 'f':
memfile = optarg;
break;
case 'a':
plic_address_str = optarg;
break;
case 'n':
nsources = atol(optarg);
break;
case 'x':
ncontexts = atol(optarg);
break;
case 'C': /* claim */
case 'T': /* threshold */
operation = opt;
context = atol(optarg);
break;
case 'P': /* pending */
case 'I': /* priority */
case 'E': /* enable */
operation = opt;
source = atol(optarg);
break;
case 'L': /* list */
operation = opt;
break;
case 'c':
context = atol(optarg);
break;
case 'w':
value = atol(optarg);
value_set = true;
break;
case 'v':
printf("plictool "VERSION"\n");
exit(0);
case 'h':
default: /* '?' */
usage();
break;
}
}
if (operation == 'P' || operation == 'I' || operation == 'E') {
if (source < 0) {
fprintf(stderr, "missing source\n");
exit(1);
}
}
if (operation == 'C' || operation == 'T' || operation == 'E') {
if (context < 0) {
fprintf(stderr, "missing context\n");
exit(1);
}
}
unsigned long long plic_address = strtoull(plic_address_str, NULL, 16);
//printf("plictool "VERSION" addr=0x%08llx nsrc=%ld nctx=%ld\n",
// plic_address, nsources, ncontexts);
int fd = open(memfile, O_RDWR | O_SYNC);
if (fd == -1) {
fprintf(stderr, "cannot open %s: %s", memfile, strerror(errno));
exit(1);
}
size_t map_size = 0x4000000UL;
void *map_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, plic_address);
if (map_base == MAP_FAILED) {
perror("mmap failed");
if (errno == EPERM) {
fprintf(stderr, "Have you disabled 'CONFIG_STRICT_DEVMEM' and "
"'CONFIG_IO_STRICT_DEVMEM' in the kernel config?\n"
"Hint: zgrep STRICT_DEVMEM /proc/config.gz\n");
}
exit(1);
}
if (operation == 'C') { /* claim */
if (value_set)
claim_set(map_base, context, value);
else
printf("%u\n", claim_get(map_base, context));
} else if (operation == 'T') { /* threshold */
if (value_set)
thre_set(map_base, context, value);
else
printf("%u\n", thre_get(map_base, context));
} else if (operation == 'I') { /* priority */
if (value_set)
prio_set(map_base, source, value);
else
printf("%u\n", prio_get(map_base, source));
} else if (operation == 'P') { /* pending */
if (value_set)
pending_set(map_base, source, value);
else
printf("%u\n", pending_get(map_base, source));
} else if (operation == 'E') { /* enable */
if (value_set)
enable_set(map_base, context, source, value);
else
printf("%u\n", enable_get(map_base, context, source));
} else /* list */ {
list_sources(map_base);
}
munmap(map_base, map_size);
close(fd);
return 0;
}

239
tools/unalign.c Normal file
View File

@ -0,0 +1,239 @@
/*
* unalign_check - check the CPU behaviour on different alignments
* Copyright (C) 2021 Matteo Croce <mcroce@linux.microsoft.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <time.h>
#include <sys/mman.h>
#define ACT_READ 0
#define ACT_WRITE 1
#define ACT_XOR 2
#define ACT_COPY 3
#define READ(SIZE) \
case SIZE / 8: { \
volatile uint##SIZE##_t *buf2 = (uint##SIZE##_t *)buf; \
int i; \
for (i = 0; i < count; i++) \
(void)buf2[i]; \
break; \
}
#define WRITE(SIZE) \
case SIZE / 8: { \
volatile uint##SIZE##_t *buf2 = (uint##SIZE##_t *)buf; \
int i; \
for (i = 0; i < count; i++) \
buf2[i] = (uint##SIZE##_t)0xaabbccdd11223344; \
break; \
}
#define XOR(SIZE) \
case SIZE / 8: { \
volatile uint##SIZE##_t *buf2 = (uint##SIZE##_t *)buf; \
int i; \
for (i = 0; i < count; i++) \
buf2[i] = ~buf2[i]; \
break; \
}
#define COPY(SIZE) \
case SIZE / 8: { \
volatile uint##SIZE##_t *buf2 = (uint##SIZE##_t *)buf; \
int i; \
for (i = 0; i < count / 2; i++) \
buf2[i] = buf2[i + count / 2]; \
for (i = count / 2; i < count; i++) \
buf2[i] = buf2[i - count / 2]; \
break; \
}
static void do_read(void *buf, size_t count, int size)
{
switch (size) {
READ(8);
READ(16);
READ(32);
READ(64);
}
}
static void do_write(void *buf, size_t count, int size)
{
switch (size) {
WRITE(8);
WRITE(16);
WRITE(32);
WRITE(64);
}
}
static void do_xor(void *buf, size_t count, int size)
{
switch (size) {
XOR(8);
XOR(16);
XOR(32);
XOR(64);
}
}
static void do_copy(void *buf, size_t count, int size)
{
switch (size) {
COPY(8);
COPY(16);
COPY(32);
COPY(64);
}
}
static uint64_t time_sub(struct timespec *since, struct timespec *to)
{
if (to->tv_sec == since->tv_sec)
return to->tv_nsec - since->tv_nsec;
return (to->tv_sec - since->tv_sec) * 1000000000 + to->tv_nsec - since->tv_nsec;
}
static void __attribute__ ((noreturn)) usage(char *argv0, int ret)
{
fprintf(ret ? stderr : stdout,
"usage: %s [-rwxc1234h] [-l length] [-u unalignment]\n"
"\n"
"Options:\n"
" -r read memory (default)\n"
" -w write memory\n"
" -x xor memory\n"
" -c copy memory\n"
" -l SIZE use SIZE Mb for the test (default 100)\n"
" -u BYTE unalign buffer by BYTE bytes (default 0)\n"
" -1 read 1 byte at time\n"
" -2 read 2 bytes at time\n"
" -4 read 4 bytes at time (default)\n"
" -8 read 8 bytes at time\n"
" -h this help\n",
argv0);
exit(ret);
}
static const char *actions[] = {
"read",
"write",
"xor",
"copy",
};
int main(int argc, char *argv[])
{
struct timespec before, after;
uint64_t elapsed;
int action = ACT_READ;
size_t len = 100 * 1024 * 1024;
int shift = 0;
int size = sizeof(long);
char *buf;
int c;
while((c = getopt(argc, argv, "hrwxc1248l:u:")) != -1) {
switch (c) {
case 'r':
action = ACT_READ;
break;
case 'w':
action = ACT_WRITE;
break;
case 'x':
action = ACT_XOR;
break;
case 'c':
action = ACT_COPY;
break;
case 'l':
len = atol(optarg) * 1024 * 1024;
if (len <= 0) {
fprintf(stderr, "Invalid size %s\n", optarg);
return 1;
}
break;
case 'u':
shift = atoi(optarg);
break;
case '1':
case '2':
case '4':
case '8':
size = c - '0';
break;
case 'h':
default:
usage(argv[0], c != 'h');
}
}
shift %= size;
if (optind != argc)
usage(argv[0], 1);
buf = malloc(len);
if (!buf) {
perror("malloc");
return 1;
}
if (mlock(buf, len)) {
perror("mlock");
return 1;
}
clock_gettime(CLOCK_MONOTONIC, &before);
switch (action) {
case ACT_READ:
do_read(buf + shift, (len - shift) / size, size);
break;
case ACT_WRITE:
do_write(buf + shift, (len - shift) / size, size);
break;
case ACT_XOR:
do_xor(buf + shift, (len - shift) / size, size);
break;
case ACT_COPY:
do_copy(buf + shift, (len - shift) / size, size);
break;
}
clock_gettime(CLOCK_MONOTONIC, &after);
elapsed = time_sub(&before, &after);
printf( "size: %lu Mb\n"
"%s size: %d bit\n"
"unalignment: %d byte\n"
"elapsed time: %.2f sec\n"
"throughput: %.2f Mb/s\n",
len / 1024 / 1024,
actions[action], size * 8,
shift,
elapsed / 1E9,
(len / 1024 / 1024) / (elapsed / 1E9));
return 0;
}

14
vm.nix
View File

@ -47,8 +47,8 @@
INET y
NETWORK_FILESYSTEMS y
OVERLAY_FS y
"9P_FS" y
"9P_FS_POSIX_ACL" y
#"9P_FS" y
#"9P_FS_POSIX_ACL" y
PCI y
VIRTIO_PCI y
PCI_HOST_GENERIC y
@ -63,7 +63,15 @@
nixpkgs.overlays = [
(final: prev: {
qemu = prev.qemu.override { rutabagaSupport = false; };
qemu = prev.qemu.override {
pulseSupport = false;
pipewireSupport = false;
sdlSupport = false;
jackSupport = false;
gtkSupport = false;
vncSupport = false;
smartcardSupport = false;
};
uboot-custom = prev.ubootQemuRiscv64Smode.override {
# Override preboot to set 'bootcmd' directly to the kernel address in RAM