booster: WIP: use new bitstream as part of the updater

Rework Booster so that it uses the bitstream that it is installing
in order to validate that the new image will actually work.

This removes any sort of binary ABI compatibility issues, and
prevents us from installing an image onto a device that it doesn't
support.

Additionally, this installer should be resistant to bricking, though
that has yet to be tested.

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2019-07-24 20:52:44 +08:00
parent c40446fb93
commit da52534fe3
19 changed files with 3272 additions and 0 deletions

120
booster/Makefile Normal file
View File

@ -0,0 +1,120 @@
GIT_VERSION := $(shell git describe --tags)
# Earlier versions of the Raspberry Pi image only had riscv32-gcc
ifneq (,$(wildcard /usr/bin/riscv32-unknown-elf-gcc))
TRGT ?= riscv32-unknown-elf-
else
TRGT ?= riscv64-unknown-elf-
endif
CC := $(TRGT)gcc
CXX := $(TRGT)g++
OBJCOPY := $(TRGT)objcopy
RM := rm -rf
COPY := cp -a
PATH_SEP := /
ifeq ($(OS),Windows_NT)
COPY := copy
RM := del
PATH_SEP := \\
endif
BASE_DIR := .
LD_DIR := $(BASE_DIR)/ld
LDSCRIPT := $(BASE_DIR)/ld/linker.ld
ADD_CFLAGS := -I$(BASE_DIR)/include -D__vexriscv__ -march=rv32i -mabi=ilp32
ADD_LFLAGS :=
PACKAGE := booster
LDSCRIPTS := $(LDSCRIPT) $(LD_DIR)/output_format.ld $(LD_DIR)/regions.ld
SRC_DIR := $(BASE_DIR)/src
THIRD_PARTY := $(BASE_DIR)/third_party
DBG_CFLAGS := -ggdb -g -DDEBUG -Wall
DBG_LFLAGS := -ggdb -g -Wall
CFLAGS := $(ADD_CFLAGS) \
-Wall -Wextra \
-ffunction-sections -fdata-sections -fno-common \
-fomit-frame-pointer -O0 \
-march=rv32i \
-flto \
-DGIT_VERSION=u\"$(GIT_VERSION)\" -std=gnu11
CXXFLAGS := $(CFLAGS) -std=c++11 -fno-rtti -fno-exceptions
LFLAGS := $(CFLAGS) $(ADD_LFLAGS) -L$(LD_DIR) \
-nostartfiles \
-Wl,--gc-sections \
-Wl,--no-warn-mismatch \
-Wl,--script=$(LDSCRIPT) \
-Wl,--build-id=none
OBJ_DIR := .obj
CSOURCES := $(wildcard $(SRC_DIR)/*.c)
CPPSOURCES := $(wildcard $(SRC_DIR)/*.cpp)
ASOURCES := $(wildcard $(SRC_DIR)/*.S)
COBJS := $(addprefix $(OBJ_DIR)/, $(notdir $(CSOURCES:.c=.o)))
CXXOBJS := $(addprefix $(OBJ_DIR)/, $(notdir $(CPPSOURCES:.cpp=.o)))
AOBJS := $(addprefix $(OBJ_DIR)/, $(notdir $(ASOURCES:.S=.o)))
OBJECTS := $(COBJS) $(CXXOBJS) $(AOBJS)
VPATH := $(SRC_DIR)
QUIET := @
ALL := all
TARGET := $(PACKAGE).elf
CLEAN := clean
$(ALL): $(TARGET) $(PACKAGE).bin $(PACKAGE).ihex
$(OBJECTS): | $(OBJ_DIR)
$(TARGET): $(OBJECTS) $(LDSCRIPTS)
$(QUIET) echo " LD $@"
$(QUIET) $(CC) $(OBJECTS) $(LFLAGS) -o $@
$(PACKAGE).bin: $(TARGET)
$(QUIET) echo " OBJCOPY $@"
$(QUIET) $(OBJCOPY) -O binary $(TARGET) $@
$(PACKAGE).dfu: $(TARGET)
$(QUIET) echo " DFU $@"
$(QUIET) $(COPY) $(PACKAGE).bin $@
$(QUIET) dfu-suffix -v 1209 -p 70b1 -a $@
$(PACKAGE).ihex: $(TARGET)
$(QUIET) echo " IHEX $(PACKAGE).ihex"
$(QUIET) $(OBJCOPY) -O ihex $(TARGET) $@
$(DEBUG): CFLAGS += $(DBG_CFLAGS)
$(DEBUG): LFLAGS += $(DBG_LFLAGS)
CFLAGS += $(DBG_CFLAGS)
LFLAGS += $(DBG_LFLAGS)
$(DEBUG): $(TARGET)
$(OBJ_DIR):
$(QUIET) mkdir $(OBJ_DIR)
$(COBJS) : $(OBJ_DIR)/%.o : %.c $(BASE_DIR)/Makefile
$(QUIET) echo " CC $< $(notdir $@)"
$(QUIET) $(CC) -c $< $(CFLAGS) -o $@ -MMD
$(OBJ_DIR)/%.o: %.cpp
$(QUIET) echo " CXX $< $(notdir $@)"
$(QUIET) $(CXX) -c $< $(CXXFLAGS) -o $@ -MMD
$(OBJ_DIR)/%.o: %.S
$(QUIET) echo " AS $< $(notdir $@)"
$(QUIET) $(CC) -x assembler-with-cpp -c $< $(CFLAGS) -o $@ -MMD
.PHONY: clean
clean:
$(QUIET) echo " RM $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))"
-$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))
$(QUIET) echo " RM $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))"
-$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.o))
$(QUIET) echo " RM $(TARGET) $(PACKAGE).bin $(PACKAGE).symbol $(PACKAGE).ihex $(PACKAGE).dfu"
-$(QUIET) $(RM) $(TARGET) $(PACKAGE).bin $(PACKAGE).symbol $(PACKAGE).ihex $(PACKAGE).dfu
include $(wildcard $(OBJ_DIR)/*.d)

92
booster/README.md Normal file
View File

@ -0,0 +1,92 @@
Booster: the Foboot Updater
===========================
Foboot cannot update itself. It resides at offset 0, and writes to offset
`0x40000`. Any errors in writing would result in an unbootable device.
`Booster` is used to guide the installation of Foboot. Much like a booster
rocket helps guide a payload into orbit, Booster guides the installation of
Foboot, and is then discarded.
Usage
-----
First, compile fobooster. Then, append the application header, and finally append the application itself. This can be accomplished with `make-booster`.
```sh
cd toboot/
make
cd ../booster/
make
gcc make-booster.c -o make-booster
./make-booster [flash-id] ../toboot/toboot.bin toboot-booster.bin
```
The following flash-id values are known:
EVT: 0xef177018
PVT: 0xc2152815
Hacker: 0x1f148601
The resulting `foboot-booster.bin` can be flashed with Foboot itself as
an ordinary program.
Design
------
The goal of Booster is to load a new bitstream onto Fomu. Because this
bitstream contains code + a CPU, Booster will actually run from within
the context of this new CPU.
**THE NEW IMAGE IS ASSUMED TO BE 0x19700 (104192) BYTES LONG**. The new
image is padded by appending 0-bytes to it in order to get it to the
correct length.
The SPI flash image looks something like this:
| Hex Address | Decimal Address | Purpose |
|------------:|-----------------:|-----------------------------------------------------------------------------|
| 0x000000 | 0 | Instructs the FPGA where to find SB_WARMBOOT images S0-S3 and for cold boot |
| 0x0000a0 | 160 | Normal offset for Foboot |
| 0x040000 | 262144 | New version of Foboot, including new CPU Core |
| 0x05a000 | 368640 | Start of Booster program |
| 0x05a004 | 368644 | Booster signature |
| 0x05a008 | 368648 | Booster length (not including bitstream / new image) |
| 0x05a00c | 368652 | Booster checksum |
| 0x05a010 | 368656 | Actual length of new image |
| 0x05a014 | 368660 | Length of xxHash region |
| 0x05a018 | 368664 | xxHash seed |
| 0x05a01c | 368668 | SPI ID of the target device |
| 0x1FFFFF | 20097151 | End of flash |
The "Booster Signature" is `0x4260fa37` -- if it contains this value, then
this might be a Booster program.
The "Booster Checksum" is the result of summing together `[Booster length]`
8-bit bytes, starting at offset `0x05a010`. If this value is equal to
`Booster checksum`, then Foboot will simply transfer control over to address
`0x05a000`.
### Booster execution flow
The first thing Booster does is validate the new image. It does this by
performing an `xxHash` of the new image, from address 0x040000. If the image
does not match the hash, it will erase itself and show an error.
Next, Booster will validate that the start of the target image has a valid
SB_WARMBOOT block. This specialized check ensures we don't accidentally write
an invalid image.
If the address matches, it checks the SPI ID. If the ID does not match, then
it will erase itself and show an error.
If the ID does match, the update will begin.
The first step of the update is to erase block 0 and reprogram it with a
temporary block that will point execution to address 0x400a0. This offset
means that we can switch from the updater to Foboot by rewriting the execution
address from 0x4000a0 to 0x0000a0.
**From this point forward, Booster is effectively the only program on flash.**
The

21
booster/include/booster.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef FOBOOSTER_H_
#define FOBOOSTER_H_
#include <stdint.h>
#include <stdbool.h>
#define XXH_NO_LONG_LONG
#define XXH_FORCE_ALIGN_CHECK 0
#define XXH_FORCE_NATIVE_FORMAT 0
#define XXH_PRIVATE_API
#include "xxhash.h"
#define BOOSTER_SEED 0xc38b9e66L
#define BOOSTER_SIGNATURE 0x4260fa37
struct booster_data
{
uint32_t xxhash;
};
#endif /* FOBOOSTER_H_ */

711
booster/include/csr.h Normal file
View File

@ -0,0 +1,711 @@
#ifndef __GENERATED_CSR_H
#define __GENERATED_CSR_H
#include <stdint.h>
static inline void csr_writeb(uint8_t value, uint32_t addr)
{
*((volatile uint8_t *)addr) = value;
}
static inline uint8_t csr_readb(uint32_t addr)
{
return *(volatile uint8_t *)addr;
}
static inline void csr_writew(uint16_t value, uint32_t addr)
{
*((volatile uint16_t *)addr) = value;
}
static inline uint16_t csr_readw(uint32_t addr)
{
return *(volatile uint16_t *)addr;
}
static inline void csr_writel(uint32_t value, uint32_t addr)
{
*((volatile uint32_t *)addr) = value;
}
static inline uint32_t csr_readl(uint32_t addr)
{
return *(volatile uint32_t *)addr;
}
/* ctrl */
#define CSR_CTRL_BASE 0xe0000000
#define CSR_CTRL_RESET_ADDR 0xe0000000
#define CSR_CTRL_RESET_SIZE 1
static inline unsigned char ctrl_reset_read(void) {
unsigned char r = csr_readl(0xe0000000);
return r;
}
static inline void ctrl_reset_write(unsigned char value) {
csr_writel(value, 0xe0000000);
}
#define CSR_CTRL_SCRATCH_ADDR 0xe0000004
#define CSR_CTRL_SCRATCH_SIZE 4
static inline unsigned int ctrl_scratch_read(void) {
unsigned int r = csr_readl(0xe0000004);
r <<= 8;
r |= csr_readl(0xe0000008);
r <<= 8;
r |= csr_readl(0xe000000c);
r <<= 8;
r |= csr_readl(0xe0000010);
return r;
}
static inline void ctrl_scratch_write(unsigned int value) {
csr_writel(value >> 24, 0xe0000004);
csr_writel(value >> 16, 0xe0000008);
csr_writel(value >> 8, 0xe000000c);
csr_writel(value, 0xe0000010);
}
#define CSR_CTRL_BUS_ERRORS_ADDR 0xe0000014
#define CSR_CTRL_BUS_ERRORS_SIZE 4
static inline unsigned int ctrl_bus_errors_read(void) {
unsigned int r = csr_readl(0xe0000014);
r <<= 8;
r |= csr_readl(0xe0000018);
r <<= 8;
r |= csr_readl(0xe000001c);
r <<= 8;
r |= csr_readl(0xe0000020);
return r;
}
/* picorvspi */
#define CSR_PICORVSPI_BASE 0xe0005000
#define CSR_PICORVSPI_CFG1_ADDR 0xe0005000
#define CSR_PICORVSPI_CFG1_SIZE 1
static inline unsigned char picorvspi_cfg1_read(void) {
unsigned char r = csr_readl(0xe0005000);
return r;
}
static inline void picorvspi_cfg1_write(unsigned char value) {
csr_writel(value, 0xe0005000);
}
#define CSR_PICORVSPI_CFG2_ADDR 0xe0005004
#define CSR_PICORVSPI_CFG2_SIZE 1
static inline unsigned char picorvspi_cfg2_read(void) {
unsigned char r = csr_readl(0xe0005004);
return r;
}
static inline void picorvspi_cfg2_write(unsigned char value) {
csr_writel(value, 0xe0005004);
}
#define CSR_PICORVSPI_CFG3_ADDR 0xe0005008
#define CSR_PICORVSPI_CFG3_SIZE 1
static inline unsigned char picorvspi_cfg3_read(void) {
unsigned char r = csr_readl(0xe0005008);
return r;
}
static inline void picorvspi_cfg3_write(unsigned char value) {
csr_writel(value, 0xe0005008);
}
#define CSR_PICORVSPI_CFG4_ADDR 0xe000500c
#define CSR_PICORVSPI_CFG4_SIZE 1
static inline unsigned char picorvspi_cfg4_read(void) {
unsigned char r = csr_readl(0xe000500c);
return r;
}
static inline void picorvspi_cfg4_write(unsigned char value) {
csr_writel(value, 0xe000500c);
}
#define CSR_PICORVSPI_STAT1_ADDR 0xe0005010
#define CSR_PICORVSPI_STAT1_SIZE 1
static inline unsigned char picorvspi_stat1_read(void) {
unsigned char r = csr_readl(0xe0005010);
return r;
}
#define CSR_PICORVSPI_STAT2_ADDR 0xe0005014
#define CSR_PICORVSPI_STAT2_SIZE 1
static inline unsigned char picorvspi_stat2_read(void) {
unsigned char r = csr_readl(0xe0005014);
return r;
}
#define CSR_PICORVSPI_STAT3_ADDR 0xe0005018
#define CSR_PICORVSPI_STAT3_SIZE 1
static inline unsigned char picorvspi_stat3_read(void) {
unsigned char r = csr_readl(0xe0005018);
return r;
}
#define CSR_PICORVSPI_STAT4_ADDR 0xe000501c
#define CSR_PICORVSPI_STAT4_SIZE 1
static inline unsigned char picorvspi_stat4_read(void) {
unsigned char r = csr_readl(0xe000501c);
return r;
}
/* reboot */
#define CSR_REBOOT_BASE 0xe0006000
#define CSR_REBOOT_CTRL_ADDR 0xe0006000
#define CSR_REBOOT_CTRL_SIZE 1
static inline unsigned char reboot_ctrl_read(void) {
unsigned char r = csr_readl(0xe0006000);
return r;
}
static inline void reboot_ctrl_write(unsigned char value) {
csr_writel(value, 0xe0006000);
}
#define CSR_REBOOT_ADDR_ADDR 0xe0006004
#define CSR_REBOOT_ADDR_SIZE 4
static inline unsigned int reboot_addr_read(void) {
unsigned int r = csr_readl(0xe0006004);
r <<= 8;
r |= csr_readl(0xe0006008);
r <<= 8;
r |= csr_readl(0xe000600c);
r <<= 8;
r |= csr_readl(0xe0006010);
return r;
}
static inline void reboot_addr_write(unsigned int value) {
csr_writel(value >> 24, 0xe0006004);
csr_writel(value >> 16, 0xe0006008);
csr_writel(value >> 8, 0xe000600c);
csr_writel(value, 0xe0006010);
}
/* rgb */
#define CSR_RGB_BASE 0xe0006800
#define CSR_RGB_DAT_ADDR 0xe0006800
#define CSR_RGB_DAT_SIZE 1
static inline unsigned char rgb_dat_read(void) {
unsigned char r = csr_readl(0xe0006800);
return r;
}
static inline void rgb_dat_write(unsigned char value) {
csr_writel(value, 0xe0006800);
}
#define CSR_RGB_ADDR_ADDR 0xe0006804
#define CSR_RGB_ADDR_SIZE 1
static inline unsigned char rgb_addr_read(void) {
unsigned char r = csr_readl(0xe0006804);
return r;
}
static inline void rgb_addr_write(unsigned char value) {
csr_writel(value, 0xe0006804);
}
#define CSR_RGB_CTRL_ADDR 0xe0006808
#define CSR_RGB_CTRL_SIZE 1
static inline unsigned char rgb_ctrl_read(void) {
unsigned char r = csr_readl(0xe0006808);
return r;
}
static inline void rgb_ctrl_write(unsigned char value) {
csr_writel(value, 0xe0006808);
}
/* timer0 */
#define CSR_TIMER0_BASE 0xe0002800
#define CSR_TIMER0_LOAD_ADDR 0xe0002800
#define CSR_TIMER0_LOAD_SIZE 4
static inline unsigned int timer0_load_read(void) {
unsigned int r = csr_readl(0xe0002800);
r <<= 8;
r |= csr_readl(0xe0002804);
r <<= 8;
r |= csr_readl(0xe0002808);
r <<= 8;
r |= csr_readl(0xe000280c);
return r;
}
static inline void timer0_load_write(unsigned int value) {
csr_writel(value >> 24, 0xe0002800);
csr_writel(value >> 16, 0xe0002804);
csr_writel(value >> 8, 0xe0002808);
csr_writel(value, 0xe000280c);
}
#define CSR_TIMER0_RELOAD_ADDR 0xe0002810
#define CSR_TIMER0_RELOAD_SIZE 4
static inline unsigned int timer0_reload_read(void) {
unsigned int r = csr_readl(0xe0002810);
r <<= 8;
r |= csr_readl(0xe0002814);
r <<= 8;
r |= csr_readl(0xe0002818);
r <<= 8;
r |= csr_readl(0xe000281c);
return r;
}
static inline void timer0_reload_write(unsigned int value) {
csr_writel(value >> 24, 0xe0002810);
csr_writel(value >> 16, 0xe0002814);
csr_writel(value >> 8, 0xe0002818);
csr_writel(value, 0xe000281c);
}
#define CSR_TIMER0_EN_ADDR 0xe0002820
#define CSR_TIMER0_EN_SIZE 1
static inline unsigned char timer0_en_read(void) {
unsigned char r = csr_readl(0xe0002820);
return r;
}
static inline void timer0_en_write(unsigned char value) {
csr_writel(value, 0xe0002820);
}
#define CSR_TIMER0_UPDATE_VALUE_ADDR 0xe0002824
#define CSR_TIMER0_UPDATE_VALUE_SIZE 1
static inline unsigned char timer0_update_value_read(void) {
unsigned char r = csr_readl(0xe0002824);
return r;
}
static inline void timer0_update_value_write(unsigned char value) {
csr_writel(value, 0xe0002824);
}
#define CSR_TIMER0_VALUE_ADDR 0xe0002828
#define CSR_TIMER0_VALUE_SIZE 4
static inline unsigned int timer0_value_read(void) {
unsigned int r = csr_readl(0xe0002828);
r <<= 8;
r |= csr_readl(0xe000282c);
r <<= 8;
r |= csr_readl(0xe0002830);
r <<= 8;
r |= csr_readl(0xe0002834);
return r;
}
#define CSR_TIMER0_EV_STATUS_ADDR 0xe0002838
#define CSR_TIMER0_EV_STATUS_SIZE 1
static inline unsigned char timer0_ev_status_read(void) {
unsigned char r = csr_readl(0xe0002838);
return r;
}
static inline void timer0_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0002838);
}
#define CSR_TIMER0_EV_PENDING_ADDR 0xe000283c
#define CSR_TIMER0_EV_PENDING_SIZE 1
static inline unsigned char timer0_ev_pending_read(void) {
unsigned char r = csr_readl(0xe000283c);
return r;
}
static inline void timer0_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe000283c);
}
#define CSR_TIMER0_EV_ENABLE_ADDR 0xe0002840
#define CSR_TIMER0_EV_ENABLE_SIZE 1
static inline unsigned char timer0_ev_enable_read(void) {
unsigned char r = csr_readl(0xe0002840);
return r;
}
static inline void timer0_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe0002840);
}
/* touch */
#define CSR_TOUCH_BASE 0xe0005800
#define CSR_TOUCH_O_ADDR 0xe0005800
#define CSR_TOUCH_O_SIZE 1
static inline unsigned char touch_o_read(void) {
unsigned char r = csr_readl(0xe0005800);
return r;
}
static inline void touch_o_write(unsigned char value) {
csr_writel(value, 0xe0005800);
}
#define CSR_TOUCH_OE_ADDR 0xe0005804
#define CSR_TOUCH_OE_SIZE 1
static inline unsigned char touch_oe_read(void) {
unsigned char r = csr_readl(0xe0005804);
return r;
}
static inline void touch_oe_write(unsigned char value) {
csr_writel(value, 0xe0005804);
}
#define CSR_TOUCH_I_ADDR 0xe0005808
#define CSR_TOUCH_I_SIZE 1
static inline unsigned char touch_i_read(void) {
unsigned char r = csr_readl(0xe0005808);
return r;
}
/* usb */
#define CSR_USB_BASE 0xe0004800
#define CSR_USB_PULLUP_OUT_ADDR 0xe0004800
#define CSR_USB_PULLUP_OUT_SIZE 1
static inline unsigned char usb_pullup_out_read(void) {
unsigned char r = csr_readl(0xe0004800);
return r;
}
static inline void usb_pullup_out_write(unsigned char value) {
csr_writel(value, 0xe0004800);
}
#define CSR_USB_EP_0_OUT_EV_STATUS_ADDR 0xe0004804
#define CSR_USB_EP_0_OUT_EV_STATUS_SIZE 1
static inline unsigned char usb_ep_0_out_ev_status_read(void) {
unsigned char r = csr_readl(0xe0004804);
return r;
}
static inline void usb_ep_0_out_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0004804);
}
#define CSR_USB_EP_0_OUT_EV_PENDING_ADDR 0xe0004808
#define CSR_USB_EP_0_OUT_EV_PENDING_SIZE 1
static inline unsigned char usb_ep_0_out_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0004808);
return r;
}
static inline void usb_ep_0_out_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0004808);
}
#define CSR_USB_EP_0_OUT_EV_ENABLE_ADDR 0xe000480c
#define CSR_USB_EP_0_OUT_EV_ENABLE_SIZE 1
static inline unsigned char usb_ep_0_out_ev_enable_read(void) {
unsigned char r = csr_readl(0xe000480c);
return r;
}
static inline void usb_ep_0_out_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe000480c);
}
#define CSR_USB_EP_0_OUT_LAST_TOK_ADDR 0xe0004810
#define CSR_USB_EP_0_OUT_LAST_TOK_SIZE 1
static inline unsigned char usb_ep_0_out_last_tok_read(void) {
unsigned char r = csr_readl(0xe0004810);
return r;
}
#define CSR_USB_EP_0_OUT_RESPOND_ADDR 0xe0004814
#define CSR_USB_EP_0_OUT_RESPOND_SIZE 1
static inline unsigned char usb_ep_0_out_respond_read(void) {
unsigned char r = csr_readl(0xe0004814);
return r;
}
static inline void usb_ep_0_out_respond_write(unsigned char value) {
csr_writel(value, 0xe0004814);
}
#define CSR_USB_EP_0_OUT_DTB_ADDR 0xe0004818
#define CSR_USB_EP_0_OUT_DTB_SIZE 1
static inline unsigned char usb_ep_0_out_dtb_read(void) {
unsigned char r = csr_readl(0xe0004818);
return r;
}
static inline void usb_ep_0_out_dtb_write(unsigned char value) {
csr_writel(value, 0xe0004818);
}
#define CSR_USB_EP_0_OUT_OBUF_HEAD_ADDR 0xe000481c
#define CSR_USB_EP_0_OUT_OBUF_HEAD_SIZE 1
static inline unsigned char usb_ep_0_out_obuf_head_read(void) {
unsigned char r = csr_readl(0xe000481c);
return r;
}
static inline void usb_ep_0_out_obuf_head_write(unsigned char value) {
csr_writel(value, 0xe000481c);
}
#define CSR_USB_EP_0_OUT_OBUF_EMPTY_ADDR 0xe0004820
#define CSR_USB_EP_0_OUT_OBUF_EMPTY_SIZE 1
static inline unsigned char usb_ep_0_out_obuf_empty_read(void) {
unsigned char r = csr_readl(0xe0004820);
return r;
}
#define CSR_USB_EP_0_IN_EV_STATUS_ADDR 0xe0004824
#define CSR_USB_EP_0_IN_EV_STATUS_SIZE 1
static inline unsigned char usb_ep_0_in_ev_status_read(void) {
unsigned char r = csr_readl(0xe0004824);
return r;
}
static inline void usb_ep_0_in_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0004824);
}
#define CSR_USB_EP_0_IN_EV_PENDING_ADDR 0xe0004828
#define CSR_USB_EP_0_IN_EV_PENDING_SIZE 1
static inline unsigned char usb_ep_0_in_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0004828);
return r;
}
static inline void usb_ep_0_in_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0004828);
}
#define CSR_USB_EP_0_IN_EV_ENABLE_ADDR 0xe000482c
#define CSR_USB_EP_0_IN_EV_ENABLE_SIZE 1
static inline unsigned char usb_ep_0_in_ev_enable_read(void) {
unsigned char r = csr_readl(0xe000482c);
return r;
}
static inline void usb_ep_0_in_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe000482c);
}
#define CSR_USB_EP_0_IN_LAST_TOK_ADDR 0xe0004830
#define CSR_USB_EP_0_IN_LAST_TOK_SIZE 1
static inline unsigned char usb_ep_0_in_last_tok_read(void) {
unsigned char r = csr_readl(0xe0004830);
return r;
}
#define CSR_USB_EP_0_IN_RESPOND_ADDR 0xe0004834
#define CSR_USB_EP_0_IN_RESPOND_SIZE 1
static inline unsigned char usb_ep_0_in_respond_read(void) {
unsigned char r = csr_readl(0xe0004834);
return r;
}
static inline void usb_ep_0_in_respond_write(unsigned char value) {
csr_writel(value, 0xe0004834);
}
#define CSR_USB_EP_0_IN_DTB_ADDR 0xe0004838
#define CSR_USB_EP_0_IN_DTB_SIZE 1
static inline unsigned char usb_ep_0_in_dtb_read(void) {
unsigned char r = csr_readl(0xe0004838);
return r;
}
static inline void usb_ep_0_in_dtb_write(unsigned char value) {
csr_writel(value, 0xe0004838);
}
#define CSR_USB_EP_0_IN_IBUF_HEAD_ADDR 0xe000483c
#define CSR_USB_EP_0_IN_IBUF_HEAD_SIZE 1
static inline unsigned char usb_ep_0_in_ibuf_head_read(void) {
unsigned char r = csr_readl(0xe000483c);
return r;
}
static inline void usb_ep_0_in_ibuf_head_write(unsigned char value) {
csr_writel(value, 0xe000483c);
}
#define CSR_USB_EP_0_IN_IBUF_EMPTY_ADDR 0xe0004840
#define CSR_USB_EP_0_IN_IBUF_EMPTY_SIZE 1
static inline unsigned char usb_ep_0_in_ibuf_empty_read(void) {
unsigned char r = csr_readl(0xe0004840);
return r;
}
#define CSR_USB_EP_1_IN_EV_STATUS_ADDR 0xe0004844
#define CSR_USB_EP_1_IN_EV_STATUS_SIZE 1
static inline unsigned char usb_ep_1_in_ev_status_read(void) {
unsigned char r = csr_readl(0xe0004844);
return r;
}
static inline void usb_ep_1_in_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0004844);
}
#define CSR_USB_EP_1_IN_EV_PENDING_ADDR 0xe0004848
#define CSR_USB_EP_1_IN_EV_PENDING_SIZE 1
static inline unsigned char usb_ep_1_in_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0004848);
return r;
}
static inline void usb_ep_1_in_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0004848);
}
#define CSR_USB_EP_1_IN_EV_ENABLE_ADDR 0xe000484c
#define CSR_USB_EP_1_IN_EV_ENABLE_SIZE 1
static inline unsigned char usb_ep_1_in_ev_enable_read(void) {
unsigned char r = csr_readl(0xe000484c);
return r;
}
static inline void usb_ep_1_in_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe000484c);
}
#define CSR_USB_EP_1_IN_LAST_TOK_ADDR 0xe0004850
#define CSR_USB_EP_1_IN_LAST_TOK_SIZE 1
static inline unsigned char usb_ep_1_in_last_tok_read(void) {
unsigned char r = csr_readl(0xe0004850);
return r;
}
#define CSR_USB_EP_1_IN_RESPOND_ADDR 0xe0004854
#define CSR_USB_EP_1_IN_RESPOND_SIZE 1
static inline unsigned char usb_ep_1_in_respond_read(void) {
unsigned char r = csr_readl(0xe0004854);
return r;
}
static inline void usb_ep_1_in_respond_write(unsigned char value) {
csr_writel(value, 0xe0004854);
}
#define CSR_USB_EP_1_IN_DTB_ADDR 0xe0004858
#define CSR_USB_EP_1_IN_DTB_SIZE 1
static inline unsigned char usb_ep_1_in_dtb_read(void) {
unsigned char r = csr_readl(0xe0004858);
return r;
}
static inline void usb_ep_1_in_dtb_write(unsigned char value) {
csr_writel(value, 0xe0004858);
}
#define CSR_USB_EP_1_IN_IBUF_HEAD_ADDR 0xe000485c
#define CSR_USB_EP_1_IN_IBUF_HEAD_SIZE 1
static inline unsigned char usb_ep_1_in_ibuf_head_read(void) {
unsigned char r = csr_readl(0xe000485c);
return r;
}
static inline void usb_ep_1_in_ibuf_head_write(unsigned char value) {
csr_writel(value, 0xe000485c);
}
#define CSR_USB_EP_1_IN_IBUF_EMPTY_ADDR 0xe0004860
#define CSR_USB_EP_1_IN_IBUF_EMPTY_SIZE 1
static inline unsigned char usb_ep_1_in_ibuf_empty_read(void) {
unsigned char r = csr_readl(0xe0004860);
return r;
}
#define CSR_USB_EP_2_OUT_EV_STATUS_ADDR 0xe0004864
#define CSR_USB_EP_2_OUT_EV_STATUS_SIZE 1
static inline unsigned char usb_ep_2_out_ev_status_read(void) {
unsigned char r = csr_readl(0xe0004864);
return r;
}
static inline void usb_ep_2_out_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0004864);
}
#define CSR_USB_EP_2_OUT_EV_PENDING_ADDR 0xe0004868
#define CSR_USB_EP_2_OUT_EV_PENDING_SIZE 1
static inline unsigned char usb_ep_2_out_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0004868);
return r;
}
static inline void usb_ep_2_out_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0004868);
}
#define CSR_USB_EP_2_OUT_EV_ENABLE_ADDR 0xe000486c
#define CSR_USB_EP_2_OUT_EV_ENABLE_SIZE 1
static inline unsigned char usb_ep_2_out_ev_enable_read(void) {
unsigned char r = csr_readl(0xe000486c);
return r;
}
static inline void usb_ep_2_out_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe000486c);
}
#define CSR_USB_EP_2_OUT_LAST_TOK_ADDR 0xe0004870
#define CSR_USB_EP_2_OUT_LAST_TOK_SIZE 1
static inline unsigned char usb_ep_2_out_last_tok_read(void) {
unsigned char r = csr_readl(0xe0004870);
return r;
}
#define CSR_USB_EP_2_OUT_RESPOND_ADDR 0xe0004874
#define CSR_USB_EP_2_OUT_RESPOND_SIZE 1
static inline unsigned char usb_ep_2_out_respond_read(void) {
unsigned char r = csr_readl(0xe0004874);
return r;
}
static inline void usb_ep_2_out_respond_write(unsigned char value) {
csr_writel(value, 0xe0004874);
}
#define CSR_USB_EP_2_OUT_DTB_ADDR 0xe0004878
#define CSR_USB_EP_2_OUT_DTB_SIZE 1
static inline unsigned char usb_ep_2_out_dtb_read(void) {
unsigned char r = csr_readl(0xe0004878);
return r;
}
static inline void usb_ep_2_out_dtb_write(unsigned char value) {
csr_writel(value, 0xe0004878);
}
#define CSR_USB_EP_2_OUT_OBUF_HEAD_ADDR 0xe000487c
#define CSR_USB_EP_2_OUT_OBUF_HEAD_SIZE 1
static inline unsigned char usb_ep_2_out_obuf_head_read(void) {
unsigned char r = csr_readl(0xe000487c);
return r;
}
static inline void usb_ep_2_out_obuf_head_write(unsigned char value) {
csr_writel(value, 0xe000487c);
}
#define CSR_USB_EP_2_OUT_OBUF_EMPTY_ADDR 0xe0004880
#define CSR_USB_EP_2_OUT_OBUF_EMPTY_SIZE 1
static inline unsigned char usb_ep_2_out_obuf_empty_read(void) {
unsigned char r = csr_readl(0xe0004880);
return r;
}
#define CSR_USB_EP_2_IN_EV_STATUS_ADDR 0xe0004884
#define CSR_USB_EP_2_IN_EV_STATUS_SIZE 1
static inline unsigned char usb_ep_2_in_ev_status_read(void) {
unsigned char r = csr_readl(0xe0004884);
return r;
}
static inline void usb_ep_2_in_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0004884);
}
#define CSR_USB_EP_2_IN_EV_PENDING_ADDR 0xe0004888
#define CSR_USB_EP_2_IN_EV_PENDING_SIZE 1
static inline unsigned char usb_ep_2_in_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0004888);
return r;
}
static inline void usb_ep_2_in_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0004888);
}
#define CSR_USB_EP_2_IN_EV_ENABLE_ADDR 0xe000488c
#define CSR_USB_EP_2_IN_EV_ENABLE_SIZE 1
static inline unsigned char usb_ep_2_in_ev_enable_read(void) {
unsigned char r = csr_readl(0xe000488c);
return r;
}
static inline void usb_ep_2_in_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe000488c);
}
#define CSR_USB_EP_2_IN_LAST_TOK_ADDR 0xe0004890
#define CSR_USB_EP_2_IN_LAST_TOK_SIZE 1
static inline unsigned char usb_ep_2_in_last_tok_read(void) {
unsigned char r = csr_readl(0xe0004890);
return r;
}
#define CSR_USB_EP_2_IN_RESPOND_ADDR 0xe0004894
#define CSR_USB_EP_2_IN_RESPOND_SIZE 1
static inline unsigned char usb_ep_2_in_respond_read(void) {
unsigned char r = csr_readl(0xe0004894);
return r;
}
static inline void usb_ep_2_in_respond_write(unsigned char value) {
csr_writel(value, 0xe0004894);
}
#define CSR_USB_EP_2_IN_DTB_ADDR 0xe0004898
#define CSR_USB_EP_2_IN_DTB_SIZE 1
static inline unsigned char usb_ep_2_in_dtb_read(void) {
unsigned char r = csr_readl(0xe0004898);
return r;
}
static inline void usb_ep_2_in_dtb_write(unsigned char value) {
csr_writel(value, 0xe0004898);
}
#define CSR_USB_EP_2_IN_IBUF_HEAD_ADDR 0xe000489c
#define CSR_USB_EP_2_IN_IBUF_HEAD_SIZE 1
static inline unsigned char usb_ep_2_in_ibuf_head_read(void) {
unsigned char r = csr_readl(0xe000489c);
return r;
}
static inline void usb_ep_2_in_ibuf_head_write(unsigned char value) {
csr_writel(value, 0xe000489c);
}
#define CSR_USB_EP_2_IN_IBUF_EMPTY_ADDR 0xe00048a0
#define CSR_USB_EP_2_IN_IBUF_EMPTY_SIZE 1
static inline unsigned char usb_ep_2_in_ibuf_empty_read(void) {
unsigned char r = csr_readl(0xe00048a0);
return r;
}
/* constants */
#define NMI_INTERRUPT 0
static inline int nmi_interrupt_read(void) {
return 0;
}
#define TIMER0_INTERRUPT 1
static inline int timer0_interrupt_read(void) {
return 1;
}
#define UART_INTERRUPT 2
static inline int uart_interrupt_read(void) {
return 2;
}
#define USB_INTERRUPT 3
static inline int usb_interrupt_read(void) {
return 3;
}
#define CSR_DATA_WIDTH 8
static inline int csr_data_width_read(void) {
return 8;
}
#define SYSTEM_CLOCK_FREQUENCY 12000000
static inline int system_clock_frequency_read(void) {
return 12000000;
}
#define CONFIG_CLOCK_FREQUENCY 12000000
static inline int config_clock_frequency_read(void) {
return 12000000;
}
#define CONFIG_CPU_RESET_ADDR 0
static inline int config_cpu_reset_addr_read(void) {
return 0;
}
#define CONFIG_CPU_TYPE "VEXRISCV"
static inline const char * config_cpu_type_read(void) {
return "VEXRISCV";
}
#define CONFIG_CPU_VARIANT "VEXRISCV"
static inline const char * config_cpu_variant_read(void) {
return "VEXRISCV";
}
#define CONFIG_CSR_DATA_WIDTH 8
static inline int config_csr_data_width_read(void) {
return 8;
}
#endif

11
booster/include/rgb.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _RGB_H_
#define _RGB_H_
void rgb_init(void);
void rgb_mode_idle(void);
void rgb_mode_done(void);
void rgb_mode_writing(void);
void rgb_mode_error(void);
void rgb_wheel(unsigned char);
#endif /* _RGB_H_ */

22
booster/include/spi.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _FOBOOST_SPI_H
#define _FOBOOST_SPI_H
#include <stdint.h>
#define SPI_ERASE_SECTOR_SIZE 4096
#define SPI_PROGRAM_PAGE_SIZE 256
void spiBegin(void);
void spiEnd(void);
void spiPause(void);
void spiCommand(uint8_t cmd);
uint8_t spiCommandRx(void);
uint8_t spiReadStatus(void);
void spiBeginErase4(uint32_t erase_addr);
void spiBeginErase32(uint32_t erase_addr);
void spiBeginErase64(uint32_t erase_addr);
int spiIsBusy(void);
void spiBeginWrite(uint32_t addr, const void *v_data, unsigned int count);
uint32_t spiId(void);
#endif /* _FOBOOST_SPI_H */

912
booster/include/xxhash.c Normal file
View File

@ -0,0 +1,912 @@
/*
* xxHash - Fast Hash algorithm
* Copyright (C) 2012-2016, Yann Collet
*
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at :
* - xxHash homepage: http://www.xxhash.com
* - xxHash source repository : https://github.com/Cyan4973/xxHash
*/
/* *************************************
* Tuning parameters
***************************************/
/*!XXH_FORCE_MEMORY_ACCESS :
* By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
* Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
* The below switch allow to select different access method for improved performance.
* Method 0 (default) : use `memcpy()`. Safe and portable.
* Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
* This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
* Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
* It can generate buggy code on targets which do not support unaligned memory accesses.
* But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
* See http://stackoverflow.com/a/32095106/646947 for details.
* Prefer these methods in priority order (0 > 1 > 2)
*/
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
# define XXH_FORCE_MEMORY_ACCESS 2
# elif defined(__INTEL_COMPILER) || \
(defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|| defined(__ARM_ARCH_7S__) ))
# define XXH_FORCE_MEMORY_ACCESS 1
# endif
#endif
/*!XXH_ACCEPT_NULL_INPUT_POINTER :
* If input pointer is NULL, xxHash default behavior is to dereference it, triggering a segfault.
* When this macro is enabled, xxHash actively checks input for null pointer.
* It it is, result for null input pointers is the same as a null-length input.
*/
#ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */
# define XXH_ACCEPT_NULL_INPUT_POINTER 0
#endif
/*!XXH_FORCE_NATIVE_FORMAT :
* By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
* Results are therefore identical for little-endian and big-endian CPU.
* This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
* Should endian-independence be of no importance for your application, you may set the #define below to 1,
* to improve speed for Big-endian CPU.
* This option has no impact on Little_Endian CPU.
*/
#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */
# define XXH_FORCE_NATIVE_FORMAT 0
#endif
/*!XXH_FORCE_ALIGN_CHECK :
* This is a minor performance trick, only useful with lots of very small keys.
* It means : check for aligned/unaligned input.
* The check costs one initial branch per hash;
* set it to 0 when the input is guaranteed to be aligned,
* or when alignment doesn't matter for performance.
*/
#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
# define XXH_FORCE_ALIGN_CHECK 0
# else
# define XXH_FORCE_ALIGN_CHECK 1
# endif
#endif
/* *************************************
* Includes & Memory related functions
***************************************/
/*! Modify the local functions below should you wish to use some other memory routines
* for malloc(), free() */
#include <stdlib.h>
static void* XXH_malloc(size_t s) { return malloc(s); }
static void XXH_free (void* p) { free(p); }
/*! and for memcpy() */
#include <string.h>
static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
#define XXH_STATIC_LINKING_ONLY
#include "xxhash.h"
/* *************************************
* Compiler Specific Options
***************************************/
#ifdef _MSC_VER /* Visual Studio */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
# define FORCE_INLINE static __forceinline
#else
# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
# ifdef __GNUC__
# define FORCE_INLINE static inline __attribute__((always_inline))
# else
# define FORCE_INLINE static inline
# endif
# else
# define FORCE_INLINE static
# endif /* __STDC_VERSION__ */
#endif
/* *************************************
* Basic Types
***************************************/
#ifndef MEM_MODULE
# if !defined (__VMS) \
&& (defined (__cplusplus) \
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# include <stdint.h>
typedef uint8_t BYTE;
typedef uint16_t U16;
typedef uint32_t U32;
# else
typedef unsigned char BYTE;
typedef unsigned short U16;
typedef unsigned int U32;
# endif
#endif
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
/* currently only defined for gcc and icc */
typedef union { U32 u32; } __attribute__((packed)) unalign;
static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
#else
/* portable and safe solution. Generally efficient.
* see : http://stackoverflow.com/a/32095106/646947
*/
static U32 XXH_read32(const void* memPtr)
{
U32 val;
memcpy(&val, memPtr, sizeof(val));
return val;
}
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
/* ****************************************
* Compiler-specific Functions and Macros
******************************************/
#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
#if defined(_MSC_VER)
# define XXH_rotl32(x,r) _rotl(x,r)
# define XXH_rotl64(x,r) _rotl64(x,r)
#else
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
#endif
#if defined(_MSC_VER) /* Visual Studio */
# define XXH_swap32 _byteswap_ulong
#elif XXH_GCC_VERSION >= 403
# define XXH_swap32 __builtin_bswap32
#else
static U32 XXH_swap32 (U32 x)
{
return ((x << 24) & 0xff000000 ) |
((x << 8) & 0x00ff0000 ) |
((x >> 8) & 0x0000ff00 ) |
((x >> 24) & 0x000000ff );
}
#endif
/* *************************************
* Architecture Macros
***************************************/
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
#ifndef XXH_CPU_LITTLE_ENDIAN
static const int g_one = 1;
# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one))
#endif
/* ***************************
* Memory reads
*****************************/
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
{
if (align==XXH_unaligned)
return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
else
return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
}
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
{
return XXH_readLE32_align(ptr, endian, XXH_unaligned);
}
static U32 XXH_readBE32(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
}
/* *************************************
* Macros
***************************************/
#define XXH_STATIC_ASSERT(c) { enum { XXH_sa = 1/(int)(!!(c)) }; } /* use after variable declarations */
XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
/* *******************************************************************
* 32-bit hash functions
*********************************************************************/
static const U32 PRIME32_1 = 2654435761U;
static const U32 PRIME32_2 = 2246822519U;
static const U32 PRIME32_3 = 3266489917U;
static const U32 PRIME32_4 = 668265263U;
static const U32 PRIME32_5 = 374761393U;
static U32 XXH32_round(U32 seed, U32 input)
{
seed += input * PRIME32_2;
seed = XXH_rotl32(seed, 13);
seed *= PRIME32_1;
return seed;
}
FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
{
const BYTE* p = (const BYTE*)input;
const BYTE* bEnd = p + len;
U32 h32;
#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
if (p==NULL) {
len=0;
bEnd=p=(const BYTE*)(size_t)16;
}
#endif
if (len>=16) {
const BYTE* const limit = bEnd - 16;
U32 v1 = seed + PRIME32_1 + PRIME32_2;
U32 v2 = seed + PRIME32_2;
U32 v3 = seed + 0;
U32 v4 = seed - PRIME32_1;
do {
v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
} while (p<=limit);
h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
} else {
h32 = seed + PRIME32_5;
}
h32 += (U32) len;
while (p+4<=bEnd) {
h32 += XXH_get32bits(p) * PRIME32_3;
h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
p+=4;
}
while (p<bEnd) {
h32 += (*p) * PRIME32_5;
h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
p++;
}
h32 ^= h32 >> 15;
h32 *= PRIME32_2;
h32 ^= h32 >> 13;
h32 *= PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
{
#if 0
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH32_state_t state;
XXH32_reset(&state, seed);
XXH32_update(&state, input, len);
return XXH32_digest(&state);
#else
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if (XXH_FORCE_ALIGN_CHECK) {
if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
else
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
} }
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
else
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
#endif
}
/*====== Hash streaming ======*/
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
{
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
}
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
{
XXH_free(statePtr);
return XXH_OK;
}
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
{
memcpy(dstState, srcState, sizeof(*dstState));
}
XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
{
XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
memset(&state, 0, sizeof(state));
state.v1 = seed + PRIME32_1 + PRIME32_2;
state.v2 = seed + PRIME32_2;
state.v3 = seed + 0;
state.v4 = seed - PRIME32_1;
/* do not write into reserved, planned to be removed in a future version */
memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
return XXH_OK;
}
FORCE_INLINE
XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
{
const BYTE* p = (const BYTE*)input;
const BYTE* const bEnd = p + len;
if (input==NULL)
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
return XXH_OK;
#else
return XXH_ERROR;
#endif
state->total_len_32 += (unsigned)len;
state->large_len |= (len>=16) | (state->total_len_32>=16);
if (state->memsize + len < 16) { /* fill in tmp buffer */
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
state->memsize += (unsigned)len;
return XXH_OK;
}
if (state->memsize) { /* some data left from previous update */
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
{ const unsigned* p32 = state->mem32;
state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian));
}
p += 16-state->memsize;
state->memsize = 0;
}
if (p <= bEnd-16) {
const BYTE* const limit = bEnd - 16;
U32 v1 = state->v1;
U32 v2 = state->v2;
U32 v3 = state->v3;
U32 v4 = state->v4;
do {
v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
} while (p<=limit);
state->v1 = v1;
state->v2 = v2;
state->v3 = v3;
state->v4 = v4;
}
if (p < bEnd) {
XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
state->memsize = (unsigned)(bEnd-p);
}
return XXH_OK;
}
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
else
return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
}
FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
{
const BYTE * p = (const BYTE*)state->mem32;
const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
U32 h32;
if (state->large_len) {
h32 = XXH_rotl32(state->v1, 1)
+ XXH_rotl32(state->v2, 7)
+ XXH_rotl32(state->v3, 12)
+ XXH_rotl32(state->v4, 18);
} else {
h32 = state->v3 /* == seed */ + PRIME32_5;
}
h32 += state->total_len_32;
while (p+4<=bEnd) {
h32 += XXH_readLE32(p, endian) * PRIME32_3;
h32 = XXH_rotl32(h32, 17) * PRIME32_4;
p+=4;
}
while (p<bEnd) {
h32 += (*p) * PRIME32_5;
h32 = XXH_rotl32(h32, 11) * PRIME32_1;
p++;
}
h32 ^= h32 >> 15;
h32 *= PRIME32_2;
h32 ^= h32 >> 13;
h32 *= PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_digest_endian(state_in, XXH_littleEndian);
else
return XXH32_digest_endian(state_in, XXH_bigEndian);
}
/*====== Canonical representation ======*/
/*! Default XXH result types are basic unsigned 32 and 64 bits.
* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
* These functions allow transformation of hash result into and from its canonical format.
* This way, hash values can be written into a file or buffer, remaining comparable across different systems.
*/
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
{
XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
memcpy(dst, &hash, sizeof(*dst));
}
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
{
return XXH_readBE32(src);
}
#ifndef XXH_NO_LONG_LONG
/* *******************************************************************
* 64-bit hash functions
*********************************************************************/
/*====== Memory access ======*/
#ifndef MEM_MODULE
# define MEM_MODULE
# if !defined (__VMS) \
&& (defined (__cplusplus) \
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# include <stdint.h>
typedef uint64_t U64;
# else
/* if compiler doesn't support unsigned long long, replace by another 64-bit type */
typedef unsigned long long U64;
# endif
#endif
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
/* currently only defined for gcc and icc */
typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64;
static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; }
#else
/* portable and safe solution. Generally efficient.
* see : http://stackoverflow.com/a/32095106/646947
*/
static U64 XXH_read64(const void* memPtr)
{
U64 val;
memcpy(&val, memPtr, sizeof(val));
return val;
}
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
#if defined(_MSC_VER) /* Visual Studio */
# define XXH_swap64 _byteswap_uint64
#elif XXH_GCC_VERSION >= 403
# define XXH_swap64 __builtin_bswap64
#else
static U64 XXH_swap64 (U64 x)
{
return ((x << 56) & 0xff00000000000000ULL) |
((x << 40) & 0x00ff000000000000ULL) |
((x << 24) & 0x0000ff0000000000ULL) |
((x << 8) & 0x000000ff00000000ULL) |
((x >> 8) & 0x00000000ff000000ULL) |
((x >> 24) & 0x0000000000ff0000ULL) |
((x >> 40) & 0x000000000000ff00ULL) |
((x >> 56) & 0x00000000000000ffULL);
}
#endif
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
{
if (align==XXH_unaligned)
return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
else
return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
}
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
{
return XXH_readLE64_align(ptr, endian, XXH_unaligned);
}
static U64 XXH_readBE64(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
}
/*====== xxh64 ======*/
static const U64 PRIME64_1 = 11400714785074694791ULL;
static const U64 PRIME64_2 = 14029467366897019727ULL;
static const U64 PRIME64_3 = 1609587929392839161ULL;
static const U64 PRIME64_4 = 9650029242287828579ULL;
static const U64 PRIME64_5 = 2870177450012600261ULL;
static U64 XXH64_round(U64 acc, U64 input)
{
acc += input * PRIME64_2;
acc = XXH_rotl64(acc, 31);
acc *= PRIME64_1;
return acc;
}
static U64 XXH64_mergeRound(U64 acc, U64 val)
{
val = XXH64_round(0, val);
acc ^= val;
acc = acc * PRIME64_1 + PRIME64_4;
return acc;
}
FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
{
const BYTE* p = (const BYTE*)input;
const BYTE* bEnd = p + len;
U64 h64;
#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
if (p==NULL) {
len=0;
bEnd=p=(const BYTE*)(size_t)32;
}
#endif
if (len>=32) {
const BYTE* const limit = bEnd - 32;
U64 v1 = seed + PRIME64_1 + PRIME64_2;
U64 v2 = seed + PRIME64_2;
U64 v3 = seed + 0;
U64 v4 = seed - PRIME64_1;
do {
v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
} while (p<=limit);
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
h64 = XXH64_mergeRound(h64, v1);
h64 = XXH64_mergeRound(h64, v2);
h64 = XXH64_mergeRound(h64, v3);
h64 = XXH64_mergeRound(h64, v4);
} else {
h64 = seed + PRIME64_5;
}
h64 += (U64) len;
while (p+8<=bEnd) {
U64 const k1 = XXH64_round(0, XXH_get64bits(p));
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
p+=8;
}
if (p+4<=bEnd) {
h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
p+=4;
}
while (p<bEnd) {
h64 ^= (*p) * PRIME64_5;
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
p++;
}
h64 ^= h64 >> 33;
h64 *= PRIME64_2;
h64 ^= h64 >> 29;
h64 *= PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
{
#if 0
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH64_state_t state;
XXH64_reset(&state, seed);
XXH64_update(&state, input, len);
return XXH64_digest(&state);
#else
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if (XXH_FORCE_ALIGN_CHECK) {
if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
else
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
} }
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
else
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
#endif
}
/*====== Hash Streaming ======*/
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
{
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
}
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
{
XXH_free(statePtr);
return XXH_OK;
}
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
{
memcpy(dstState, srcState, sizeof(*dstState));
}
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
{
XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
memset(&state, 0, sizeof(state));
state.v1 = seed + PRIME64_1 + PRIME64_2;
state.v2 = seed + PRIME64_2;
state.v3 = seed + 0;
state.v4 = seed - PRIME64_1;
/* do not write into reserved, planned to be removed in a future version */
memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
return XXH_OK;
}
FORCE_INLINE
XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
{
const BYTE* p = (const BYTE*)input;
const BYTE* const bEnd = p + len;
if (input==NULL)
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
return XXH_OK;
#else
return XXH_ERROR;
#endif
state->total_len += len;
if (state->memsize + len < 32) { /* fill in tmp buffer */
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
state->memsize += (U32)len;
return XXH_OK;
}
if (state->memsize) { /* tmp buffer is full */
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
p += 32-state->memsize;
state->memsize = 0;
}
if (p+32 <= bEnd) {
const BYTE* const limit = bEnd - 32;
U64 v1 = state->v1;
U64 v2 = state->v2;
U64 v3 = state->v3;
U64 v4 = state->v4;
do {
v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
} while (p<=limit);
state->v1 = v1;
state->v2 = v2;
state->v3 = v3;
state->v4 = v4;
}
if (p < bEnd) {
XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
state->memsize = (unsigned)(bEnd-p);
}
return XXH_OK;
}
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
else
return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
}
FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
{
const BYTE * p = (const BYTE*)state->mem64;
const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
U64 h64;
if (state->total_len >= 32) {
U64 const v1 = state->v1;
U64 const v2 = state->v2;
U64 const v3 = state->v3;
U64 const v4 = state->v4;
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
h64 = XXH64_mergeRound(h64, v1);
h64 = XXH64_mergeRound(h64, v2);
h64 = XXH64_mergeRound(h64, v3);
h64 = XXH64_mergeRound(h64, v4);
} else {
h64 = state->v3 + PRIME64_5;
}
h64 += (U64) state->total_len;
while (p+8<=bEnd) {
U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
p+=8;
}
if (p+4<=bEnd) {
h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
p+=4;
}
while (p<bEnd) {
h64 ^= (*p) * PRIME64_5;
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
p++;
}
h64 ^= h64 >> 33;
h64 *= PRIME64_2;
h64 ^= h64 >> 29;
h64 *= PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_digest_endian(state_in, XXH_littleEndian);
else
return XXH64_digest_endian(state_in, XXH_bigEndian);
}
/*====== Canonical representation ======*/
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
{
XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
memcpy(dst, &hash, sizeof(*dst));
}
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
{
return XXH_readBE64(src);
}
#endif /* XXH_NO_LONG_LONG */

294
booster/include/xxhash.h Normal file
View File

@ -0,0 +1,294 @@
/*
xxHash - Extremely Fast Hash algorithm
Header File
Copyright (C) 2012-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- xxHash source repository : https://github.com/Cyan4973/xxHash
*/
/* Notice extracted from xxHash homepage :
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
It also successfully passes all tests from the SMHasher suite.
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
Name Speed Q.Score Author
xxHash 5.4 GB/s 10
CrapWow 3.2 GB/s 2 Andrew
MumurHash 3a 2.7 GB/s 10 Austin Appleby
SpookyHash 2.0 GB/s 10 Bob Jenkins
SBox 1.4 GB/s 9 Bret Mulvey
Lookup3 1.2 GB/s 9 Bob Jenkins
SuperFastHash 1.2 GB/s 1 Paul Hsieh
CityHash64 1.05 GB/s 10 Pike & Alakuijala
FNV 0.55 GB/s 5 Fowler, Noll, Vo
CRC32 0.43 GB/s 9
MD5-32 0.33 GB/s 10 Ronald L. Rivest
SHA1-32 0.28 GB/s 10
Q.Score is a measure of quality of the hash function.
It depends on successfully passing SMHasher test set.
10 is a perfect score.
A 64-bit version, named XXH64, is available since r35.
It offers much better speed, but for 64-bit applications only.
Name Speed on 64 bits Speed on 32 bits
XXH64 13.8 GB/s 1.9 GB/s
XXH32 6.8 GB/s 6.0 GB/s
*/
#ifndef XXHASH_H_5627135585666179
#define XXHASH_H_5627135585666179 1
#if defined (__cplusplus)
extern "C" {
#endif
/* ****************************
* Definitions
******************************/
#include <stddef.h> /* size_t */
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
/* ****************************
* API modifier
******************************/
/** XXH_PRIVATE_API
* This is useful to include xxhash functions in `static` mode
* in order to inline them, and remove their symbol from the public list.
* Methodology :
* #define XXH_PRIVATE_API
* #include "xxhash.h"
* `xxhash.c` is automatically included.
* It's not useful to compile and link it as a separate module.
*/
#ifdef XXH_PRIVATE_API
# ifndef XXH_STATIC_LINKING_ONLY
# define XXH_STATIC_LINKING_ONLY
# endif
# if defined(__GNUC__)
# define XXH_PUBLIC_API static __inline __attribute__((unused))
# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
# define XXH_PUBLIC_API static inline
# elif defined(_MSC_VER)
# define XXH_PUBLIC_API static __inline
# else
/* this version may generate warnings for unused static functions */
# define XXH_PUBLIC_API static
# endif
#else
# define XXH_PUBLIC_API /* do nothing */
#endif /* XXH_PRIVATE_API */
/*!XXH_NAMESPACE, aka Namespace Emulation :
If you want to include _and expose_ xxHash functions from within your own library,
but also want to avoid symbol collisions with other libraries which may also include xxHash,
you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values).
Note that no change is required within the calling program as long as it includes `xxhash.h` :
regular symbol name will be automatically translated by this header.
*/
#ifdef XXH_NAMESPACE
# define XXH_CAT(A,B) A##B
# define XXH_NAME2(A,B) XXH_CAT(A,B)
# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
#endif
/* *************************************
* Version
***************************************/
#define XXH_VERSION_MAJOR 0
#define XXH_VERSION_MINOR 6
#define XXH_VERSION_RELEASE 4
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
/*-**********************************************************************
* 32-bit hash
************************************************************************/
typedef unsigned int XXH32_hash_t;
/*! XXH32() :
Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input".
The memory between input & input+length must be valid (allocated and read-accessible).
"seed" can be used to alter the result predictably.
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
/*====== Streaming ======*/
typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
/*
These functions generate the xxHash of an input provided in multiple segments.
Note that, for small input, they are slower than single-call functions, due to state management.
For small input, prefer `XXH32()` and `XXH64()` .
XXH state must first be allocated, using XXH*_createState() .
Start a new hash by initializing state with a seed, using XXH*_reset().
Then, feed the hash state by calling XXH*_update() as many times as necessary.
Obviously, input must be allocated and read accessible.
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
Finally, a hash value can be produced anytime, by using XXH*_digest().
This function returns the nn-bits hash as an int or long long.
It's still possible to continue inserting input into the hash state after a digest,
and generate some new hashes later on, by calling again XXH*_digest().
When done, free XXH state space if it was allocated dynamically.
*/
/*====== Canonical representation ======*/
typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
* These functions allow transformation of hash result into and from its canonical format.
* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
*/
#ifndef XXH_NO_LONG_LONG
/*-**********************************************************************
* 64-bit hash
************************************************************************/
typedef unsigned long long XXH64_hash_t;
/*! XXH64() :
Calculate the 64-bit hash of sequence of length "len" stored at memory address "input".
"seed" can be used to alter the result predictably.
This function runs faster on 64-bit systems, but slower on 32-bit systems (see benchmark).
*/
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
/*====== Streaming ======*/
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
/*====== Canonical representation ======*/
typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
#endif /* XXH_NO_LONG_LONG */
#ifdef XXH_STATIC_LINKING_ONLY
/* ================================================================================================
This section contains declarations which are not guaranteed to remain stable.
They may change in future versions, becoming incompatible with a different version of the library.
These declarations should only be used with static linking.
Never use them in association with dynamic linking !
=================================================================================================== */
/* These definitions are only meant to make possible
static allocation of XXH state, on stack or in a struct for example.
Never use members directly. */
struct XXH32_state_s {
unsigned total_len_32;
unsigned large_len;
unsigned v1;
unsigned v2;
unsigned v3;
unsigned v4;
unsigned mem32[4]; /* buffer defined as U32 for alignment */
unsigned memsize;
unsigned reserved; /* never read nor write, will be removed in a future version */
}; /* typedef'd to XXH32_state_t */
#ifndef XXH_NO_LONG_LONG /* remove 64-bit support */
struct XXH64_state_s {
unsigned long long total_len;
unsigned long long v1;
unsigned long long v2;
unsigned long long v3;
unsigned long long v4;
unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
unsigned memsize;
unsigned reserved[2]; /* never read nor write, will be removed in a future version */
}; /* typedef'd to XXH64_state_t */
#endif
#ifdef XXH_PRIVATE_API
# include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */
#endif
#endif /* XXH_STATIC_LINKING_ONLY */
#if defined (__cplusplus)
}
#endif
#endif /* XXHASH_H_5627135585666179 */

60
booster/ld/linker.ld Normal file
View File

@ -0,0 +1,60 @@
INCLUDE output_format.ld
ENTRY(_start)
__DYNAMIC = 0;
INCLUDE regions.ld
SECTIONS
{
.startup :
{
. = ALIGN(4);
*(.text.start)
. = ALIGN(4);
_estartup = .;
} > rom
.bss :
{
. = ALIGN(4);
_fbss = .;
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
_end = .;
} > sram
.data : AT (ADDR(.startup) + SIZEOF (.startup))
{
_fdata = .;
_ftext = .;
*(.text .stub .text.* .gnu.linkonce.t.*)
_etext = .;
. = ALIGN(4);
_frodata = .;
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
*(.srodata)
_erodata = .;
. = ALIGN(4);
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
_gp = ALIGN(16);
*(.sdata .sdata.* .gnu.linkonce.s.* .sdata2 .sdata2.*)
*(.ramtext .ramtext.*)
_edata = ALIGN(16); /* Make sure _edata is >= _gp. */
} > sram
booster_data = ADDR(.data) + SIZEOF(.data);
booster_src = ADDR(.startup) + SIZEOF(.startup) + SIZEOF(.data);
}
PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4);

View File

@ -0,0 +1 @@
OUTPUT_FORMAT("elf32-littleriscv")

4
booster/ld/regions.ld Normal file
View File

@ -0,0 +1,4 @@
MEMORY {
sram : ORIGIN = 0x10000000, LENGTH = 0x00020000
rom : ORIGIN = 0x2005a000, LENGTH = 0x00026000
}

132
booster/make-booster.c Normal file
View File

@ -0,0 +1,132 @@
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef __APPLE__
#include <libkern/OSByteOrder.h>
#define htole32(x) OSSwapHostToLittleInt32(x)
#else
#include <endian.h>
#endif
#define BOOSTER_BIN "booster.bin"
#include "booster.h"
static uint8_t bitstream_buffer[0x1a000];
int main(int argc, char **argv)
{
struct booster_data booster_data;
struct stat stat_buf;
if (argc != 4)
{
fprintf(stderr, "Usage: %s [device-id] [infile] [outfile]\n", argv[0]);
fprintf(stderr, "The device-id is one of the following:\n");
fprintf(stderr, " 0xef177018 Evaluation EVT\n");
fprintf(stderr, " 0xc2152815 Production PVT\n");
fprintf(stderr, " 0x1f148601 Hacker board\n");
return 1;
}
uint32_t device_id = strtoul(argv[1], NULL, 0);
char *infile_name = argv[2];
char *outfile_name = argv[3];
int booster_fd = open(BOOSTER_BIN, O_RDONLY);
if (booster_fd == -1)
{
perror("Unable to open " BOOSTER_BIN " (try running 'make -Iinclude')");
return 8;
}
if (-1 == fstat(booster_fd, &stat_buf))
{
perror("Unable to determine size of booster");
return 4;
}
uint32_t booster_size = stat_buf.st_size;
if (booster_size & 3) {
fprintf(stderr, "Error: booster_size is not a multiple of 32-bits\n");
return 1;
}
int bitstream_fd = open(infile_name, O_RDONLY);
if (bitstream_fd == -1)
{
perror("Unable to open input bitstream file");
return 2;
}
if (-1 == fstat(bitstream_fd, &stat_buf))
{
perror("Unable to determine size of input file");
return 4;
}
uint32_t bitstream_size = stat_buf.st_size;
int outfile_fd = open(outfile_name, O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (outfile_fd == -1)
{
perror("Unable to open output file");
return 3;
}
// Copy booster into RAM so we can patch it and calculate its size
uint8_t booster_buffer[booster_size];
if (read(booster_fd, booster_buffer, sizeof(booster_buffer)) != sizeof(booster_buffer))
{
perror("Unable to read booster into RAM");
return 11;
}
// Copy the bitstream into RAM
memset(bitstream_buffer, 0, sizeof(bitstream_buffer));
if (read(bitstream_fd, bitstream_buffer, bitstream_size) != bitstream_size)
{
perror("Unable to read bitstream into RAM");
return 11;
}
// Patch the bitstream such that it boots to ofset 0x040000
bitstream_buffer[9] = 0x04;
// Patch up Booster
uint32_t booster_sum = 0;
uint32_t booster_offset = 0;
for (booster_offset = 0x20; booster_offset < booster_size; booster_offset++)
{
booster_sum += booster_buffer[booster_offset];
}
uint32_t *booster_ptr = (uint32_t *)booster_buffer;
// booster_ptr[0] = j crt_init
booster_ptr[1] = htole32(BOOSTER_SIGNATURE); // booster_signature
booster_ptr[2] = htole32(booster_size); // booster length
booster_ptr[3] = htole32(booster_sum); // booster checksum
booster_ptr[4] = htole32(bitstream_size); // image length
booster_ptr[5] = htole32(sizeof(bitstream_buffer) + sizeof(booster_buffer)); // hash length
booster_ptr[6] = htole32(BOOSTER_SEED); // image seed
booster_ptr[7] = htole32(device_id); // spi id
uint8_t mega_buffer[sizeof(booster_buffer) + sizeof(bitstream_buffer)];
memcpy(mega_buffer, bitstream_buffer, sizeof(bitstream_buffer));
memcpy(mega_buffer + sizeof(bitstream_buffer), booster_buffer, sizeof(booster_buffer));
booster_data.xxhash = htole32(XXH32(mega_buffer, sizeof(mega_buffer), BOOSTER_SEED));
if (sizeof(mega_buffer) != write(outfile_fd, mega_buffer, sizeof(mega_buffer)))
{
perror("Unable to write image to output file");
return 12;
}
if (sizeof(booster_data) != write(outfile_fd, &booster_data, sizeof(booster_data)))
{
perror("Unable to write booster data to output file");
return 7;
}
close(bitstream_fd);
close(outfile_fd);
close(booster_fd);
}

105
booster/src/crt0-vexriscv.S Normal file
View File

@ -0,0 +1,105 @@
.global fobooster_main
.global isr
.section .text.start
.global _start
.global booster_signature
.global booster_length
.global booster_checksum
.global image_length
.global hash_length
.global image_seed
.global spi_id
_start:
j crt_init
booster_signature:
.word 0x4260fa37
booster_length:
.word 0
booster_checksum:
.word 0
image_length:
.word 0
hash_length:
.word 0
image_seed:
.word 0
spi_id:
.word 0
.global trap_entry
.section .text
trap_entry:
sw x1, - 1*4(sp)
sw x5, - 2*4(sp)
sw x6, - 3*4(sp)
sw x7, - 4*4(sp)
sw x10, - 5*4(sp)
sw x11, - 6*4(sp)
sw x12, - 7*4(sp)
sw x13, - 8*4(sp)
sw x14, - 9*4(sp)
sw x15, -10*4(sp)
sw x16, -11*4(sp)
sw x17, -12*4(sp)
sw x28, -13*4(sp)
sw x29, -14*4(sp)
sw x30, -15*4(sp)
sw x31, -16*4(sp)
addi sp,sp,-16*4
call isr
lw x1 , 15*4(sp)
lw x5, 14*4(sp)
lw x6, 13*4(sp)
lw x7, 12*4(sp)
lw x10, 11*4(sp)
lw x11, 10*4(sp)
lw x12, 9*4(sp)
lw x13, 8*4(sp)
lw x14, 7*4(sp)
lw x15, 6*4(sp)
lw x16, 5*4(sp)
lw x17, 4*4(sp)
lw x28, 3*4(sp)
lw x29, 2*4(sp)
lw x30, 1*4(sp)
lw x31, 0*4(sp)
addi sp,sp,16*4
mret
.section .text.start
crt_init:
la sp, _fstack + 4
la a0, trap_entry
csrw mtvec, a0
bss_init:
la a0, _fbss
la a1, _ebss
bss_loop:
beq a0,a1,bss_done
sw zero,0(a0)
add a0,a0,4
j bss_loop
bss_done:
/* Load DATA */
la t0, _estartup
la t1, _fdata
la t2, _edata
3:
lw t3, 0(t0)
sw t3, 0(t1)
/* _edata is aligned to 16 bytes. Use word-xfers. */
addi t0, t0, 4
addi t1, t1, 4
bltu t1, t2, 3b
# li a0, 0x880 //880 enable timer + external interrupt sources (until mstatus.MIE is set, they will never trigger an interrupt)
# csrw mie,a0
call fobooster_main
infinite_loop:
j infinite_loop

121
booster/src/div.S Normal file
View File

@ -0,0 +1,121 @@
.text
.align 2
#ifndef __riscv64
/* Our RV64 64-bit routines are equivalent to our RV32 32-bit routines. */
# define __udivdi3 __udivsi3
# define __umoddi3 __umodsi3
# define __divdi3 __divsi3
# define __moddi3 __modsi3
#else
.globl __udivsi3
__udivsi3:
/* Compute __udivdi3(a0 << 32, a1 << 32); cast result to uint32_t. */
sll a0, a0, 32
sll a1, a1, 32
move t0, ra
jal __udivdi3
sext.w a0, a0
jr t0
.globl __umodsi3
__umodsi3:
/* Compute __udivdi3((uint32_t)a0, (uint32_t)a1); cast a1 to uint32_t. */
sll a0, a0, 32
sll a1, a1, 32
srl a0, a0, 32
srl a1, a1, 32
move t0, ra
jal __udivdi3
sext.w a0, a1
jr t0
.globl __modsi3
__modsi3 = __moddi3
.globl __divsi3
__divsi3:
/* Check for special case of INT_MIN/-1. Otherwise, fall into __divdi3. */
li t0, -1
beq a1, t0, .L20
#endif
.globl __divdi3
__divdi3:
bltz a0, .L10
bltz a1, .L11
/* Since the quotient is positive, fall into __udivdi3. */
.globl __udivdi3
__udivdi3:
mv a2, a1
mv a1, a0
li a0, -1
beqz a2, .L5
li a3, 1
bgeu a2, a1, .L2
.L1:
blez a2, .L2
slli a2, a2, 1
slli a3, a3, 1
bgtu a1, a2, .L1
.L2:
li a0, 0
.L3:
bltu a1, a2, .L4
sub a1, a1, a2
or a0, a0, a3
.L4:
srli a3, a3, 1
srli a2, a2, 1
bnez a3, .L3
.L5:
ret
.globl __umoddi3
__umoddi3:
/* Call __udivdi3(a0, a1), then return the remainder, which is in a1. */
move t0, ra
jal __udivdi3
move a0, a1
jr t0
/* Handle negative arguments to __divdi3. */
.L10:
neg a0, a0
bgez a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */
neg a1, a1
j __divdi3 /* Compute __udivdi3(-a0, -a1). */
.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */
neg a1, a1
.L12:
move t0, ra
jal __divdi3
neg a0, a0
jr t0
.globl __moddi3
__moddi3:
move t0, ra
bltz a1, .L31
bltz a0, .L32
.L30:
jal __udivdi3 /* The dividend is not negative. */
move a0, a1
jr t0
.L31:
neg a1, a1
bgez a0, .L30
.L32:
neg a0, a0
jal __udivdi3 /* The dividend is hella negative. */
neg a0, a1
jr t0
#ifdef __riscv64
/* continuation of __divsi3 */
.L20:
sll t0, t0, 31
bne a0, t0, __divdi3
ret
#endif

117
booster/src/libc.c Normal file
View File

@ -0,0 +1,117 @@
/* $OpenBSD: strlen.c,v 1.8 2014/06/10 04:17:37 deraadt Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <string.h>
size_t
strlen(const char *str)
{
const char *s;
for (s = str; *s; ++s)
;
return (s - str);
}
/**
* memcpy - Copies one area of memory to another
* @dest: Destination
* @src: Source
* @n: The size to copy.
*/
void *memcpy(void *to, const void *from, size_t n)
{
void *xto = to;
size_t temp;
if(!n)
return xto;
if((long)to & 1) {
char *cto = to;
const char *cfrom = from;
*cto++ = *cfrom++;
to = cto;
from = cfrom;
n--;
}
if((long)from & 1) {
char *cto = to;
const char *cfrom = from;
for (; n; n--)
*cto++ = *cfrom++;
return xto;
}
if(n > 2 && (long)to & 2) {
short *sto = to;
const short *sfrom = from;
*sto++ = *sfrom++;
to = sto;
from = sfrom;
n -= 2;
}
if((long)from & 2) {
short *sto = to;
const short *sfrom = from;
temp = n >> 1;
for (; temp; temp--)
*sto++ = *sfrom++;
to = sto;
from = sfrom;
if(n & 1) {
char *cto = to;
const char *cfrom = from;
*cto = *cfrom;
}
return xto;
}
temp = n >> 2;
if(temp) {
long *lto = to;
const long *lfrom = from;
for(; temp; temp--)
*lto++ = *lfrom++;
to = lto;
from = lfrom;
}
if(n & 2) {
short *sto = to;
const short *sfrom = from;
*sto++ = *sfrom++;
to = sto;
from = sfrom;
}
if(n & 1) {
char *cto = to;
const char *cfrom = from;
*cto = *cfrom;
}
return xto;
}

231
booster/src/main.c Normal file
View File

@ -0,0 +1,231 @@
#include <booster.h>
#include <csr.h>
#include <spi.h>
#include <rgb.h>
extern uint32_t booster_signature;
extern uint32_t booster_length;
extern uint32_t booster_checksum;
extern uint32_t image_length;
extern uint32_t hash_length;
extern uint32_t image_seed;
extern uint32_t spi_id;
extern struct booster_data booster_data;
uint32_t read_spi_id;
uint32_t cached_image_length;
uint32_t cached_spi_id;
// Note: This multiboot reference has the initial image
// booting to offset 0x40000, which is where the recovery
// image will be.
// We patch the target image when we generate the install
// image, so this is as designed.
static uint8_t multiboot_reference[] = {
0x7e, 0xaa, 0x99, 0x7e, 0x92, 0x00, 0x00, 0x44,
0x03, 0x04 /* SEE ABOVE */, 0x00, 0xa0, 0x82, 0x00, 0x00, 0x01,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7e, 0xaa, 0x99, 0x7e, 0x92, 0x00, 0x00, 0x44,
0x03, 0x00, 0x00, 0xa0, 0x82, 0x00, 0x00, 0x01,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static uint32_t cached_image[0x1a000/4];
void msleep(int ms)
{
timer0_en_write(0);
timer0_reload_write(0);
timer0_load_write(SYSTEM_CLOCK_FREQUENCY/1000*ms);
timer0_en_write(1);
timer0_update_value_write(1);
while(timer0_value_read())
timer0_update_value_write(1);
}
__attribute__((noreturn)) void reboot(void)
{
uint8_t image_index = 2;
reboot_ctrl_write(0xac | (image_index & 3) << 0);
while (1)
;
__builtin_unreachable();
}
// Returns whether the flash controller is busy
static bool ftfl_busy()
{
return spiIsBusy();
}
// Wait for the flash memory controller to finish any pending operation.
static void ftfl_busy_wait()
{
while (ftfl_busy())
;
}
// Erase the sector that contains the specified address.
static void ftfl_begin_erase_sector(uint32_t address)
{
ftfl_busy_wait();
spiBeginErase4(address);
}
/// Erase Booster from flash, and retarget
static void erase_booster(void)
{
ftfl_busy_wait();
// On reboot, go back to the primary bootloader
uint8_t zero = 0;
spiBeginWrite(9, &zero, 1);
ftfl_busy_wait();
// // Erase our bitstream
// !!! Don't erase our bitstream, since we don't have the
// !!! ability to dynamically update SB_WARMBOOT.
// !!! Instead, we'll actually reboot into the image located
// !!! at offset 0x40000, but without Booster present. This
// !!! will be functionally identical to booting to the image
// !!! at offset 0x00000, since it was simply copied from here.
// ftfl_begin_erase_sector(0x40000);
// ftfl_busy_wait();
// Erase Booster
ftfl_begin_erase_sector(0x5a000);
}
__attribute__((noreturn)) static void finish_flashing(void)
{
erase_booster();
ftfl_busy_wait();
reboot();
}
enum error_code {
NO_ERROR = 0,
INVALID_IMAGE_SIZE = 1,
HASH_MISMATCH = 2,
SPI_MISMATCH = 3,
MISSING_MULTIBOOT = 4,
};
volatile enum error_code error_code;
__attribute__((noreturn)) static void error(enum error_code code)
{
error_code = code;
rgb_mode_error();
while(1);
erase_booster();
ftfl_busy_wait();
while(1);
}
void isr(void)
{
/* unused */
}
volatile uint32_t should_continue = 0;
uint32_t calculated_hash;
__attribute__((noreturn)) void fobooster_main(void)
{
uint32_t bytes_left;
uint32_t target_addr;
const void *current_ptr;
uint32_t page_offset;
rgb_init();
// while(!should_continue);
// If the booster data doesn't fit in our cached image, error out.
if (image_length > sizeof(cached_image))
{
error(INVALID_IMAGE_SIZE);
}
// Ensure the hash matches what's expected.
calculated_hash = XXH32((const void *)0x20040000, hash_length, image_seed);
if (calculated_hash != booster_data.xxhash)
{
error(HASH_MISMATCH);
}
// We want to run entirely from RAM, so copy the booster payload to RAM too.
memcpy(cached_image, (const void *)0x20040000, image_length);
// Ensure the multiboot at least looks sane
for (target_addr = 0; target_addr < sizeof(multiboot_reference); target_addr++)
{
if (((uint8_t *)cached_image)[target_addr] != multiboot_reference[target_addr])
{
error(MISSING_MULTIBOOT);
}
}
// Patch the target image so that it goes to our program if the user
// reboots.
((uint8_t *)cached_image)[9] = 0x04;
// Now that everything is copied to RAM, disable memory-mapped SPI mode.
// This puts the SPI into bit-banged mode, which allows us to write to it.
cached_spi_id = spi_id; // Copy spi_id over first, since it is still on the flash.
cached_image_length = image_length;
picorvspi_cfg4_write(0);
ftfl_busy_wait();
read_spi_id = spiId();
if (cached_spi_id != read_spi_id) {
error(SPI_MISMATCH);
}
bytes_left = cached_image_length;
target_addr = 0;
current_ptr = &cached_image[0];
uint32_t check_block[SPI_ERASE_SECTOR_SIZE/sizeof(uint32_t)];
uint8_t c = 80;
while (bytes_left && (target_addr < 131072))
{
// Check to see if the sector has changed -- don't do anything if it hasn't.
picorvspi_cfg4_write(0x80);
memcpy(check_block, (void *)(target_addr + 0x20000000), SPI_ERASE_SECTOR_SIZE);
picorvspi_cfg4_write(0x00);
if (!memcmp(check_block, current_ptr, SPI_ERASE_SECTOR_SIZE)) {
current_ptr += SPI_ERASE_SECTOR_SIZE;
target_addr += SPI_ERASE_SECTOR_SIZE;
bytes_left -= SPI_ERASE_SECTOR_SIZE;
continue;
}
// Erase one 4096-byte block
ftfl_begin_erase_sector(target_addr);
// Program each 256-byte page
for (page_offset = 0;
bytes_left && (page_offset < SPI_ERASE_SECTOR_SIZE);
page_offset += SPI_PROGRAM_PAGE_SIZE)
{
rgb_wheel(c+=10);
uint32_t bytes_to_write = bytes_left;
if (bytes_to_write > SPI_PROGRAM_PAGE_SIZE)
bytes_to_write = SPI_PROGRAM_PAGE_SIZE;
ftfl_busy_wait();
spiBeginWrite(target_addr, current_ptr, bytes_to_write);
current_ptr += SPI_PROGRAM_PAGE_SIZE;
target_addr += SPI_PROGRAM_PAGE_SIZE;
bytes_left -= bytes_to_write;
}
}
rgb_mode_writing();
msleep(1000);
finish_flashing();
}

26
booster/src/mul.S Normal file
View File

@ -0,0 +1,26 @@
.text
.align 2
#ifdef __riscv64
#define _RISCV_SZPTR 64
#define _RISCV_SZINT 64
#else
/* Our RV64 64-bit routine is equivalent to our RV32 32-bit routine. */
# define __muldi3 __mulsi3
#define _RISCV_SZPTR 32
#define _RISCV_SZINT 32
#endif
.globl __muldi3
__muldi3:
mv a2, a0
li a0, 0
.L1:
slli a3, a1, _RISCV_SZPTR-1
bgez a3, .L2
add a0, a0, a2
.L2:
srli a1, a1, 1
slli a2, a2, 1
bnez a1, .L1
ret

123
booster/src/rgb.c Normal file
View File

@ -0,0 +1,123 @@
#include <csr.h>
enum led_registers
{
LEDDCR0 = 8,
LEDDBR = 9,
LEDDONR = 10,
LEDDOFR = 11,
LEDDBCRR = 5,
LEDDBCFR = 6,
LEDDPWRR = 1,
LEDDPWRG = 2,
LEDDPWRB = 3,
};
#define BREATHE_ENABLE (1 << 7)
#define BREATHE_EDGE_ON (0 << 6)
#define BREATHE_EDGE_BOTH (1 << 6)
#define BREATHE_MODE_MODULATE (1 << 5)
#define BREATHE_RATE(x) ((x & 7) << 0)
#define RGB_SWITCH_MODE(x) \
do \
{ \
if (rgb_mode == x) \
return; \
rgb_mode = x; \
/* Toggle LEDD_EXE to force the mode to switch */ \
rgb_ctrl_write((1 << 1) | (1 << 2)); \
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2)); \
} while (0)
static enum {
INVALID = 0,
IDLE,
WRITING,
ERROR,
DONE,
} rgb_mode;
static void rgb_write(uint8_t value, uint8_t addr)
{
rgb_addr_write(addr);
rgb_dat_write(value);
}
static void rgb_switch_mode(uint8_t mode,
uint8_t onr, uint8_t ofr,
uint8_t onrate, uint8_t offrate,
uint8_t r, uint8_t g, uint8_t b)
{
RGB_SWITCH_MODE(mode);
rgb_write(onr, LEDDONR);
rgb_write(ofr, LEDDOFR);
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH | BREATHE_MODE_MODULATE | BREATHE_RATE(onrate), LEDDBCRR);
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(offrate), LEDDBCFR);
rgb_write(r, LEDDPWRR); // Red
rgb_write(g, LEDDPWRG); // Green
rgb_write(b, LEDDPWRB); // Blue
}
void rgb_mode_idle(void)
{
rgb_switch_mode(IDLE, 12, 14, 2, 3, 0x00 / 4, 0x4a / 4, 0xe1 / 4);
}
void rgb_mode_writing(void)
{
rgb_switch_mode(WRITING, 1, 2, 1, 3, 0x00 / 4, 0x7a / 4, 0x51 / 4);
}
void rgb_mode_error(void)
{
rgb_switch_mode(ERROR, 3, 3, 2, 3, 0xf0, 0x0a, 0x01);
}
void rgb_mode_done(void)
{
rgb_switch_mode(DONE, 8, 8, 2, 3, 0x14 / 4, 0xff / 4, 0x44 / 4);
}
void rgb_color(uint8_t r, uint8_t g, uint8_t b)
{
rgb_write(r, LEDDPWRG); // Red
rgb_write(g, LEDDPWRB); // Green
rgb_write(b, LEDDPWRR); // Blue
}
void rgb_wheel(uint8_t pos)
{
pos = 255 - pos;
if (pos < 85)
{
rgb_color(255 - pos * 3, 0, pos * 3);
}
else if (pos < 170)
{
pos -= 85;
rgb_color(0, pos * 3, 255 - pos * 3);
}
else
{
pos -= 170;
rgb_color(pos * 3, 255 - pos * 3, 0);
}
}
void rgb_init(void)
{
// Turn on the RGB block and current enable, as well as enabling led control
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2));
// Enable the LED driver, and set 250 Hz mode.
// Also set quick stop, which we'll use to switch patterns quickly.
rgb_write((1 << 7) | (1 << 6) | (1 << 3), LEDDCR0);
// Set clock register to 12 MHz / 64 kHz - 1
rgb_write((12000000 / 2048000) - 1, LEDDBR);
rgb_mode_writing();
}

169
booster/src/spi.c Normal file
View File

@ -0,0 +1,169 @@
#include <stdint.h>
#include <csr.h>
#define SP_MOSI_PIN 0
#define SP_MISO_PIN 1
#define SP_WP_PIN 2
#define SP_HOLD_PIN 3
#define SP_CLK_PIN 4
#define SP_CS_PIN 5
#define SP_D0_PIN 0
#define SP_D1_PIN 1
#define SP_D2_PIN 2
#define SP_D3_PIN 3
#define PI_OUTPUT 1
#define PI_INPUT 0
static void gpioWrite(int pin, int val) {
static uint8_t do_mirror;
if (val)
do_mirror |= 1 << pin;
else
do_mirror &= ~(1 << pin);
picorvspi_cfg1_write(do_mirror);
}
static int gpioRead(int pin) {
return !!(picorvspi_stat1_read() & (1 << pin));
}
void spiBegin(void) {
gpioWrite(SP_WP_PIN, 1);
gpioWrite(SP_HOLD_PIN, 1);
gpioWrite(SP_CS_PIN, 0);
}
void spiEnd(void) {
gpioWrite(SP_CS_PIN, 1);
}
void spiPause(void) {
return;
}
static uint8_t spiXfer(uint8_t out) {
int bit;
uint8_t in = 0;
for (bit = 7; bit >= 0; bit--) {
if (out & (1 << bit)) {
gpioWrite(SP_MOSI_PIN, 1);
}
else {
gpioWrite(SP_MOSI_PIN, 0);
}
gpioWrite(SP_CLK_PIN, 1);
spiPause();
in |= ((!!gpioRead(SP_MISO_PIN)) << bit);
gpioWrite(SP_CLK_PIN, 0);
spiPause();
}
return in;
}
void spiCommand(uint8_t cmd) {
spiXfer(cmd);
}
uint8_t spiCommandRx(void) {
return spiXfer(0xff);
}
uint8_t spiReadStatus(void) {
uint8_t val = 0xff;
spiBegin();
spiCommand(0x05);
val = spiCommandRx();
spiEnd();
return val;
}
void spiBeginErase4(uint32_t erase_addr) {
// Enable Write-Enable Latch (WEL)
spiBegin();
spiCommand(0x06);
spiEnd();
spiBegin();
spiCommand(0x20);
spiCommand(erase_addr >> 16);
spiCommand(erase_addr >> 8);
spiCommand(erase_addr >> 0);
spiEnd();
}
void spiBeginErase32(uint32_t erase_addr) {
// Enable Write-Enable Latch (WEL)
spiBegin();
spiCommand(0x06);
spiEnd();
spiBegin();
spiCommand(0x52);
spiCommand(erase_addr >> 16);
spiCommand(erase_addr >> 8);
spiCommand(erase_addr >> 0);
spiEnd();
}
void spiBeginErase64(uint32_t erase_addr) {
// Enable Write-Enable Latch (WEL)
spiBegin();
spiCommand(0x06);
spiEnd();
spiBegin();
spiCommand(0xD8);
spiCommand(erase_addr >> 16);
spiCommand(erase_addr >> 8);
spiCommand(erase_addr >> 0);
spiEnd();
}
int spiIsBusy(void) {
return spiReadStatus() & (1 << 0);
}
void spiBeginWrite(uint32_t addr, const void *v_data, unsigned int count) {
const uint8_t write_cmd = 0x02;
const uint8_t *data = v_data;
unsigned int i;
// Enable Write-Enable Latch (WEL)
spiBegin();
spiCommand(0x06);
spiEnd();
spiBegin();
spiCommand(write_cmd);
spiCommand(addr >> 16);
spiCommand(addr >> 8);
spiCommand(addr >> 0);
for (i = 0; (i < count) && (i < 256); i++)
spiCommand(*data++);
spiEnd();
}
uint32_t spiId(void) {
uint32_t id = 0;
spiBegin();
spiCommand(0x90); // Read manufacturer ID
spiCommand(0x00); // Dummy byte 1
spiCommand(0x00); // Dummy byte 2
spiCommand(0x00); // Dummy byte 3
id = (id << 8) | spiCommandRx(); // Manufacturer ID
id = (id << 8) | spiCommandRx(); // Device ID
spiEnd();
spiBegin();
spiCommand(0x9f); // Read device id
(void)spiCommandRx(); // Manufacturer ID (again)
id = (id << 8) | spiCommandRx(); // Memory Type
id = (id << 8) | spiCommandRx(); // Memory Size
spiEnd();
return id;
}