47 changes: 47 additions & 0 deletions payloads/external/Yabits/Kconfig
@@ -0,0 +1,47 @@
if PAYLOAD_YABITS

choice
prompt "Yabits version"
default YABITS_STABLE

config YABITS_STABLE
bool "Stable"
help
Stable Yabits version.

For reproducible builds, this option must be selected.

config YABITS_MASTER
bool "Master"
help
Newest version.

This option will fetch the newest version of the Yabits code,
updating as new changes are committed. This makes the build
non-reproducible, as it can fetch different code each time.

config YABITS_REVISION
bool "git revision"
help
Select this option if you have a specific commit or branch
that you want to use as the revision from which to
build Yabits. Using a branch name makes the build
non-reproducible, as it can fetch different code as the
branch changes.

You will be able to specify the name of a branch or a commit id
later.

endchoice

config YABITS_REVISION_ID
string "Insert a commit's SHA-1 or a branch name"
depends on YABITS_REVISION
default "origin/master"
help
The commit's SHA-1 or branch name of the revision to use.

config PAYLOAD_FILE
default "payloads/external/Yabits/uefi/build/uefi.elf"

endif
11 changes: 11 additions & 0 deletions payloads/external/Yabits/Kconfig.name
@@ -0,0 +1,11 @@
config PAYLOAD_YABITS
bool "Yabits - Yet another UEFI Bootloader (Under Development)"
depends on ARCH_X86
help
Yabits - yabits.github.io
yabits is a pure UEFI coreboot payload. Compared with
TianoCore, it is fast and lightweight. yabits is based on the
part of Minoca OS. It can run GRUB2, Linux, OpenBSD, and other
UEFI applications.

It is still under the development and not ready for production.
69 changes: 69 additions & 0 deletions payloads/external/Yabits/Makefile
@@ -0,0 +1,69 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2016 Google Inc.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; version 2 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##

TAG-$(CONFIG_YABITS_MASTER)=origin/master
NAME-$(CONFIG_YABITS_MASTER)=Master
TAG-$(CONFIG_YABITS_STABLE)=d25abb067431dee9af9f8a874a209730ab7f0e91
NAME-$(CONFIG_YABITS_STABLE)=Stable
TAG-$(CONFIG_YABITS_REVISION)=$(CONFIG_YABITS_REVISION_ID)

project_name=Yabits
project_dir=$(CURDIR)/uefi
project_git_repo=https://github.com/yabits/uefi.git
LIBCONFIG_PATH="../../../libpayload"

all: build

$(project_dir):
echo " Cloning $(project_name) from Git"
git clone $(project_git_repo) $(project_dir)

fetch: $(project_dir)
ifeq ($(TAG-y),)
echo "Error: The specified tag is invalid"
ifeq ($(CONFIG_YABITS_REVISION),y)
echo "Error: There is no revision specified for $(project_name)"
false
endif
false
endif
-cd $(project_dir); git show $(TAG-y) >/dev/null 2>&1 ; \
if [ $$? -ne 0 ] || [ "$(TAG-y)" = "origin/master" ]; then \
echo " Fetching new commits from the $(project_name) git repo"; \
git fetch; fi

checkout: fetch
echo " Checking out $(project_name) revision $(NAME-y) ($(TAG-y))"
cd $(project_dir); \
git checkout master; \
git branch -D coreboot 2>/dev/null; \
git checkout -b coreboot $(TAG-y)

build: checkout
echo " MAKE $(project_name) $(NAME-y)"
$(if $(wildcard uefi/.xcompile),,$(shell bash ../../../util/xcompile/xcompile > uefi/.xcompile))
$(MAKE) -C $(project_dir) defconfig LIBCONFIG_PATH=$(LIBCONFIG_PATH) XGCC=$(XGCCPATH)
$(MAKE) -C $(project_dir) all LIBCONFIG_PATH=$(LIBCONFIG_PATH) XGCC=$(XGCCPATH)

clean:
test -d $(project_dir) && $(MAKE) -C $(project_dir) clean LIBCONFIG_PATH=$(LIBCONFIG_PATH) XGCC=$(XGCCPATH) || exit 0

distclean:
rm -rf $(project_dir)

print-repo-info:
echo "$(project_git_repo) $(project_dir)"

.PHONY: all build checkout clean distclean fetch print-repo-info
2 changes: 1 addition & 1 deletion payloads/external/sortbootorder/Makefile
@@ -1,4 +1,4 @@
version=4.6.9
version=4.6.11
branch_name=v$(version)
project_url=https://github.com/pcengines/sortbootorder/archive/$(branch_name).tar.gz
archive_name=$(branch_name).tar.gz
Expand Down
5 changes: 5 additions & 0 deletions payloads/external/tianocore/Kconfig
Expand Up @@ -88,4 +88,9 @@ config TIANOCORE_RELEASE

endchoice

config TIANOCORE_USE_8254_TIMER
bool "TianoCore 8254 Timer"
help
Use 8254 Timer for legacy support.

endif
8 changes: 6 additions & 2 deletions payloads/external/tianocore/Makefile
Expand Up @@ -33,10 +33,14 @@ else
BUILD_TYPE=RELEASE
endif

ifneq ($(CONFIG_TIANOCORE_USE_8254_TIMER), y)
TIMER=-DUSE_HPET_TIMER
endif

ifeq ($(CONFIG_TIANOCORE_TARGET_IA32), y)
BUILD_STR=-a IA32 -t COREBOOT -p CorebootPayloadPkg/CorebootPayloadPkgIa32.dsc -b $(BUILD_TYPE)
BUILD_STR=-a IA32 -t COREBOOT -p CorebootPayloadPkg/CorebootPayloadPkgIa32.dsc -b $(BUILD_TYPE) $(TIMER)
else
BUILD_STR=-a IA32 -a X64 -t COREBOOT -p CorebootPayloadPkg/CorebootPayloadPkgIa32X64.dsc -b $(BUILD_TYPE)
BUILD_STR=-a IA32 -a X64 -t COREBOOT -p CorebootPayloadPkg/CorebootPayloadPkgIa32X64.dsc -b $(BUILD_TYPE) $(TIMER)
endif

all: build
Expand Down
367 changes: 183 additions & 184 deletions payloads/external/tianocore/tools_def.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion payloads/libpayload/Doxyfile
Expand Up @@ -806,7 +806,7 @@ HTML_HEADER =

HTML_FOOTER =

# If the HTML_FOOTER_DESCRIPTION tag is set to YES, Doxygen will
# If the HTML_FOOTER_DESCRIPTION tag is set to YES, Doxygen will
# add generated date, project name and doxygen version to HTML footer.

HTML_FOOTER_DESCRIPTION= YES
Expand Down
3 changes: 3 additions & 0 deletions payloads/libpayload/arch/x86/Kconfig
Expand Up @@ -34,4 +34,7 @@ config ARCH_SPECIFIC_OPTIONS # dummy
select LITTLE_ENDIAN
select IO_ADDRESS_SPACE

config ENABLE_APIC
bool "Enables the Local APIC"

endif
3 changes: 3 additions & 0 deletions payloads/libpayload/arch/x86/Makefile.inc
Expand Up @@ -35,6 +35,7 @@ libc-y += timer.c coreboot.c util.S
libc-y += exec.S virtual.c
libc-y += selfboot.c
libc-y += exception_asm.S exception.c
libc-y += delay.c

# Will fall back to default_memXXX() in libc/memory.c if GPL not allowed.
libc-$(CONFIG_LP_GPL) += string.c
Expand All @@ -45,3 +46,5 @@ libcbfs-$(CONFIG_LP_CBFS) += rom_media.c

# Multiboot support is configurable
libc-$(CONFIG_LP_MULTIBOOT) += multiboot.c

libc-$(CONFIG_LP_ENABLE_APIC) += apic.c
268 changes: 268 additions & 0 deletions payloads/libpayload/arch/x86/apic.c
@@ -0,0 +1,268 @@
/*
* This file is part of the libpayload project.
*
* Copyright 2018 Google LLC.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <libpayload.h>
#include <arch/apic.h>
#include <arch/cpuid.h>
#include <arch/msr.h>
#include <exception.h>

#define APIC_BASE_MSR 0x0000001B
#define APIC_BASE_MASK (0xFFFFFFFULL << 12)

#define CPUID_XAPIC_ENABLED_BIT (1 << 9)
#define CPUID_XAPIC2_ENABLED_BIT (1 << 21)

#define XAPIC_ENABLED_BIT (1 << 11)
#define X2APIC_ENABLED_BIT (1 << 10)
#define APIC_MASKED_BIT (1 << 16)
#define APIC_SW_ENABLED_BIT (1 << 8)

#define APIC_ID 0x020
#define APIC_ID_SHIFT 24
#define APIC_ID_MASK (0xFFUL << APIC_ID_SHIFT)
#define APIC_VERSION 0x030
#define APIC_MAX_LVT_SHIFT 16
#define APIC_MAX_LVT_MASK (0xFFUL << APIC_MAX_LVT_SHIFT)
#define APIC_TASK_PRIORITY 0x080
#define APIC_TASK_PRIORITY_MASK 0xFFUL
#define APIC_EOI 0x0B0
#define APIC_SPURIOUS 0x0F0
#define APIC_LVT_TIMER 0x320
#define APIC_TIMER_INIT_COUNT 0x380
#define APIC_TIMER_CUR_COUNT 0x390
#define APIC_TIMER_DIV_CFG 0x3E0

#define APIC_LVT_SIZE 0x010

#define APIC_TIMER_VECTOR 0x20

static uint32_t apic_bar;
static int _apic_initialized;
// TODO: Build a lookup table to avoid calculating it.
static uint32_t ticks_per_ms;
static volatile uint8_t timer_waiting;

enum APIC_CAPABILITY {
DISABLED = 0,
XACPI = 1 << 0,
X2ACPI = 1 << 1
};

int apic_initialized(void)
{
return _apic_initialized;
}

static inline uint32_t apic_read32(uint32_t offset)
{
return read32((void *)(apic_bar + offset));
}

static inline void apic_write32(uint32_t offset, uint32_t value)
{
write32((void *)(apic_bar + offset), value);
}

uint8_t apic_id(void)
{
die_if(!apic_bar, "APIC is not initialized");

uint8_t id =
(apic_read32(APIC_ID) & APIC_ID_MASK) >> APIC_ID_SHIFT;

return id;
}

void apic_delay(unsigned int usec)
{
die_if(!ticks_per_ms, "apic_init_timer was not run.");
die_if(timer_waiting, "timer already started.");
die_if(!interrupts_enabled(), "Interrupts disabled.");

/* The order is important so we don't underflow */
uint64_t ticks = usec * ticks_per_ms / USECS_PER_MSEC;

/* Not enough resolution */
if (!ticks)
return;

/* Disable interrupts so we don't get a race condition between
* starting the timer and the hlt instruction. */
disable_interrupts();

timer_waiting = 1;

apic_write32(APIC_TIMER_INIT_COUNT, ticks);

/* Loop in case another interrupt has fired and resumed execution. */
do {
asm volatile(
"sti\n\t"
"hlt\n\t"
/* Disable interrupts to prevent a race condition
* between checking timer_waiting and executing the hlt
* instruction again. */
"cli\n\t");
} while (timer_waiting);

/* Leave hardware interrupts enabled. */
enable_interrupts();
}

static void timer_interrupt_handler(u8 vector)
{
timer_waiting = 0;
}

void apic_eoi(void)
{
die_if(!apic_bar, "APIC is not initialized");

apic_write32(APIC_EOI, 0);
}

static enum APIC_CAPABILITY apic_capabilities(void)
{
uint32_t eax, ebx, ecx, edx;

cpuid(1, eax, ebx, ecx, edx);

enum APIC_CAPABILITY capabilities = DISABLED;

if (edx & CPUID_XAPIC_ENABLED_BIT)
capabilities |= XACPI;

if (ecx & CPUID_XAPIC2_ENABLED_BIT)
capabilities |= X2ACPI;

return capabilities;
}

static uint8_t apic_max_lvt_entries(void)
{
die_if(!apic_bar, "APIC is not initialized");

uint32_t reg = apic_read32(APIC_VERSION);
reg &= APIC_MAX_LVT_MASK;
reg >>= APIC_MAX_LVT_SHIFT;

return (uint8_t)reg;
}

static void apic_reset_all_lvts(void)
{
uint8_t max = apic_max_lvt_entries();
for (int i = 0; i <= max; ++i) {
uint32_t offset = APIC_LVT_TIMER + APIC_LVT_SIZE * i;
apic_write32(offset, APIC_MASKED_BIT);
}
}

static void apic_set_task_priority(uint8_t priority)
{
die_if(!apic_bar, "APIC is not initialized");

uint32_t tpr = apic_read32(APIC_TASK_PRIORITY);
tpr &= ~APIC_TASK_PRIORITY_MASK;
tpr |= priority;

apic_write32(APIC_TASK_PRIORITY, priority);
}

static void apic_init_timer(void)
{
die_if(!apic_bar, "APIC is not initialized");

apic_write32(APIC_LVT_TIMER, APIC_MASKED_BIT);

/* Divide the clock by 1. */
apic_write32(APIC_TIMER_DIV_CFG, 0xB);

/* Calibrate the APIC timer */
if (!ticks_per_ms) {
/* Set APIC init counter to MAX and count for 1 ms */
apic_write32(APIC_TIMER_INIT_COUNT, UINT32_MAX);

/* This is safe because apic_initialized() returns false so
* arch_ndelay() falls back to a busy loop. */
mdelay(1);

ticks_per_ms =
UINT32_MAX - apic_read32(APIC_TIMER_CUR_COUNT);
}

/* Clear the count so we don't get any stale interrupts */
apic_write32(APIC_TIMER_INIT_COUNT, 0);

/* Unmask the timer and set the vector. */
apic_write32(APIC_LVT_TIMER, APIC_TIMER_VECTOR);
}

static void apic_sw_enable(void)
{
uint32_t reg = apic_read32(APIC_SPURIOUS);
if (reg & APIC_SW_ENABLED_BIT)
return;

reg |= APIC_SW_ENABLED_BIT;

apic_write32(APIC_SPURIOUS, reg);
}

void apic_init(void)
{
uint64_t apic_bar_reg;

printf("APIC Init Started\n");

die_if(apic_initialized(), "APIC already initialized");
die_if(!(apic_capabilities() & XACPI), "APIC is not supported");

apic_bar_reg = _rdmsr(APIC_BASE_MSR);

die_if(!(apic_bar_reg & XAPIC_ENABLED_BIT), "APIC is not enabled");
die_if(apic_bar_reg & X2APIC_ENABLED_BIT,
"APIC is configured in x2APIC mode which is not supported");

apic_bar = (uint32_t)(apic_bar_reg & APIC_BASE_MASK);

apic_reset_all_lvts();
apic_set_task_priority(0);

apic_sw_enable();

apic_init_timer();

set_interrupt_handler(APIC_TIMER_VECTOR, &timer_interrupt_handler);

_apic_initialized = 1;

printf("APIC Configured\n");
}
64 changes: 64 additions & 0 deletions payloads/libpayload/arch/x86/delay.c
@@ -0,0 +1,64 @@
/*
* This file is part of the libpayload project.
*
* Copyright (C) 2018 Google LLC.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <libpayload.h>
#include <arch/apic.h>

/* The pause instruction can delay 10-140 CPU cycles, so avoid calling it when
* getting close to finishing. Depending on the timer source, the timer can be
* running at CPU frequency, bus frequency, or some arbitrary value. We assume
* that the timer is running at the CPU frequency. */
#define PAUSE_THRESHOLD_TICKS 150

/* Let's assume APIC interrupts take at least 100us */
#define APIC_INTERRUPT_LATENCY_NS (100 * NSECS_PER_USEC)


void arch_ndelay(uint64_t ns)
{
uint64_t delta = ns * timer_hz() / NSECS_PER_SEC;
uint64_t pause_delta = 0;
uint64_t apic_us = 0;
uint64_t start = timer_raw_value();

if (ns > APIC_INTERRUPT_LATENCY_NS)
apic_us = (ns - APIC_INTERRUPT_LATENCY_NS) / NSECS_PER_USEC;

if (IS_ENABLED(CONFIG_LP_ENABLE_APIC) && apic_initialized() && apic_us)
apic_delay(apic_us);

if (delta > PAUSE_THRESHOLD_TICKS)
pause_delta = delta - PAUSE_THRESHOLD_TICKS;

while (timer_raw_value() - start < pause_delta)
asm volatile("pause\n\t");

while (timer_raw_value() - start < delta)
continue;
}
30 changes: 29 additions & 1 deletion payloads/libpayload/arch/x86/exception.c
Expand Up @@ -31,12 +31,23 @@
#include <exception.h>
#include <libpayload.h>
#include <stdint.h>
#include <arch/apic.h>

#define IF_FLAG (1 << 9)
/*
* Local and I/O APICs support 240 vectors (in the range of 16 to 255) as valid
* interrupts. The Intel 64 and IA-32 architectures reserve vectors 16
* through 31 for predefined interrupts, exceptions, and Intel-reserved
* encodings.
*/
#define FIRST_USER_DEFINED_VECTOR 32

u32 exception_stack[0x400] __attribute__((aligned(8)));

static exception_hook hook;

static interrupt_handler handlers[256];

static const char *names[EXC_COUNT] = {
[EXC_DE] = "Divide by Zero",
[EXC_DB] = "Debug",
Expand Down Expand Up @@ -163,7 +174,19 @@ static void dump_exception_state(void)
void exception_dispatch(void)
{
u32 vec = exception_state->vector;
die_if(vec >= EXC_COUNT || !names[vec], "Bad exception vector %u", vec);

die_if(vec >= ARRAY_SIZE(handlers), "Invalid vector %u\n", vec);

if (handlers[vec]) {
handlers[vec](vec);
if (IS_ENABLED(CONFIG_LP_ENABLE_APIC)
&& vec >= FIRST_USER_DEFINED_VECTOR)
apic_eoi();
return;
}

die_if(vec >= EXC_COUNT || !names[vec], "Bad exception vector %u\n",
vec);

if (hook && hook(vec))
return;
Expand All @@ -185,6 +208,11 @@ void exception_install_hook(exception_hook h)
hook = h;
}

void set_interrupt_handler(u8 vector, interrupt_handler handler)
{
handlers[vector] = handler;
}

static uint32_t eflags(void)
{
uint32_t eflags;
Expand Down
25 changes: 25 additions & 0 deletions payloads/libpayload/arch/x86/exception_asm.S
Expand Up @@ -68,6 +68,14 @@ exception_stub_\num:
jmp exception_common
.endm

.altmacro
.macro user_defined_stubs from, to
stub \from
.if \to-\from
user_defined_stubs %(from+1),\to
.endif
.endm

stub 0
stub 1
stub 2
Expand Down Expand Up @@ -100,6 +108,11 @@ exception_stub_\num:
stub 29
stub_err 30
stub 31
/* Split the macro so we avoid a stack overflow. */
user_defined_stubs 32, 63
user_defined_stubs 64, 127
user_defined_stubs 128, 191
user_defined_stubs 192, 255

exception_common:
/*
Expand Down Expand Up @@ -215,6 +228,14 @@ gdt_ptr:
.long \target
.endm

.altmacro
.macro user_defined_gates from, to
interrupt_gate exception_stub_\from
.if \to-\from
user_defined_gates %(from+1),\to
.endif
.endm

.align 8
.global idt
idt:
Expand Down Expand Up @@ -250,6 +271,10 @@ idt:
interrupt_gate exception_stub_29
interrupt_gate exception_stub_30
interrupt_gate exception_stub_31
user_defined_gates 32, 63
user_defined_gates 64, 127
user_defined_gates 128, 191
user_defined_gates 192, 255
idt_end:

/* IDT pointer for use with lidt */
Expand Down
12 changes: 6 additions & 6 deletions payloads/libpayload/arch/x86/gdb.c
Expand Up @@ -38,17 +38,17 @@ static const u8 type_to_signal[] = {
[EXC_SX] = GDB_SIGFPE,
};

static int gdb_exception_hook(u32 type)
static void gdb_exception_hook(u8 vector)
{
if (type >= ARRAY_SIZE(type_to_signal) || !type_to_signal[type])
return 0;
gdb_command_loop(type_to_signal[type]);
return 1;
gdb_command_loop(type_to_signal[vector]);
}

void gdb_arch_init(void)
{
exception_install_hook(&gdb_exception_hook);
for (int vector = 0; vector < ARRAY_SIZE(type_to_signal); ++vector) {
if (type_to_signal[vector])
set_interrupt_handler(vector, &gdb_exception_hook);
}
}

void gdb_arch_enter(void)
Expand Down
7 changes: 7 additions & 0 deletions payloads/libpayload/arch/x86/main.c
Expand Up @@ -29,6 +29,7 @@

#include <exception.h>
#include <libpayload.h>
#include <arch/apic.h>

unsigned long loader_eax; /**< The value of EAX passed from the loader */
unsigned long loader_ebx; /**< The value of EBX passed from the loader */
Expand Down Expand Up @@ -57,6 +58,12 @@ int start_main(void)

exception_init();

if (IS_ENABLED(CONFIG_LP_ENABLE_APIC)) {
apic_init();

enable_interrupts();
}

/*
* Any other system init that has to happen before the
* user gets control goes here.
Expand Down
2 changes: 1 addition & 1 deletion payloads/libpayload/curses/form/frm_def.c
Expand Up @@ -62,7 +62,7 @@ static FORM default_form =
};

NCURSES_EXPORT_VAR(FORM *) _nc_Default_Form = &default_form;


/*---------------------------------------------------------------------------
| Facility : libnform
| Function : static FIELD *Insert_Field_By_Position(
Expand Down
6 changes: 0 additions & 6 deletions payloads/libpayload/include/cbfs_core.h
Expand Up @@ -245,12 +245,6 @@ struct cbfs_media {
int (*close)(struct cbfs_media *media);
};

/* returns pointer to a file entry inside CBFS or NULL */
struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name);

/* returns value with a given tag inside CBFS */
char *cbfs_find_string(const char *string, const char *filename);

/*
* Returns pointer to a copy of the file content or NULL on error.
* If the file is compressed, data will be decompressed.
Expand Down
4 changes: 4 additions & 0 deletions payloads/libpayload/include/exception.h
Expand Up @@ -36,6 +36,10 @@
typedef int (*exception_hook)(u32 type);

void exception_init(void);
/* Deprecated, use set_interrupt_handler. */
void exception_install_hook(exception_hook h);

typedef void (*interrupt_handler)(u8 vector);
void set_interrupt_handler(u8 vector, interrupt_handler handler);

#endif
45 changes: 41 additions & 4 deletions payloads/libpayload/include/libpayload.h
Expand Up @@ -464,11 +464,48 @@ unsigned int get_cpu_speed(void);
uint64_t timer_hz(void);
uint64_t timer_raw_value(void);
uint64_t timer_us(uint64_t base);
void arch_ndelay(uint64_t n);
/* Generic. */
void ndelay(unsigned int n);
void udelay(unsigned int n);
void mdelay(unsigned int n);
void delay(unsigned int n);

/**
* Delay for a specified number of nanoseconds.
*
* @param ns Number of nanoseconds to delay for.
*/
static inline void ndelay(unsigned int ns)
{
arch_ndelay((uint64_t)ns);
}

/**
* Delay for a specified number of microseconds.
*
* @param us Number of microseconds to delay for.
*/
static inline void udelay(unsigned int us)
{
arch_ndelay((uint64_t)us * NSECS_PER_USEC);
}

/**
* Delay for a specified number of milliseconds.
*
* @param ms Number of milliseconds to delay for.
*/
static inline void mdelay(unsigned int ms)
{
arch_ndelay((uint64_t)ms * NSECS_PER_MSEC);
}

/**
* Delay for a specified number of seconds.
*
* @param s Number of seconds to delay for.
*/
static inline void delay(unsigned int s)
{
arch_ndelay((uint64_t)s * NSECS_PER_SEC);
}

/**
* @defgroup readline Readline functions
Expand Down
6 changes: 3 additions & 3 deletions payloads/libpayload/include/queue.h
Expand Up @@ -95,15 +95,15 @@
struct name { \
struct type *slh_first; /* first element */ \
}

#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }

#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}

/*
* Singly-linked List access methods.
*/
Expand Down
3 changes: 3 additions & 0 deletions payloads/libpayload/include/stddef.h
Expand Up @@ -29,6 +29,9 @@ typedef __SIZE_TYPE__ ssize_t;
#define MHz (1000*KHz)
#define GHz (1000*MHz)

#define NSECS_PER_SEC 1000000000
#define USECS_PER_SEC 1000000
#define MSECS_PER_SEC 1000
#define NSECS_PER_MSEC (NSECS_PER_SEC / MSECS_PER_SEC)
#define NSECS_PER_USEC (NSECS_PER_SEC / USECS_PER_SEC)
#define USECS_PER_MSEC (USECS_PER_SEC / MSECS_PER_SEC)
45 changes: 45 additions & 0 deletions payloads/libpayload/include/x86/arch/apic.h
@@ -0,0 +1,45 @@
/*
* This file is part of the libpayload project.
*
* Copyright 2018 Google LLC.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/

#ifndef __ARCH_X86_INCLUDES_ARCH_APIC_H__
#define __ARCH_X86_INCLUDES_ARCH_APIC_H__

/** Returns 1 if apic_init has been called */
int apic_initialized(void);

void apic_init(void);

uint8_t apic_id(void);

/** Signal the end of the interrupt handler. */
void apic_eoi(void);

void apic_delay(unsigned int usec);

#endif /* __ARCH_X86_INCLUDES_ARCH_APIC_H__ */
44 changes: 3 additions & 41 deletions payloads/libpayload/libc/time.c
Expand Up @@ -158,52 +158,14 @@ int gettimeofday(struct timeval *tv, void *tz)
return 0;
}

static inline void _delay(uint64_t delta)
__attribute__((weak))
void arch_ndelay(uint64_t ns)
{
uint64_t delta = ns * timer_hz() / NSECS_PER_SEC;
uint64_t start = timer_raw_value();
while (timer_raw_value() - start < delta) ;
}

/**
* Delay for a specified number of nanoseconds.
*
* @param n Number of nanoseconds to delay for.
*/
void ndelay(unsigned int n)
{
_delay((uint64_t)n * timer_hz() / 1000000000);
}

/**
* Delay for a specified number of microseconds.
*
* @param n Number of microseconds to delay for.
*/
void udelay(unsigned int n)
{
_delay((uint64_t)n * timer_hz() / 1000000);
}

/**
* Delay for a specified number of milliseconds.
*
* @param m Number of milliseconds to delay for.
*/
void mdelay(unsigned int m)
{
_delay((uint64_t)m * timer_hz() / 1000);
}

/**
* Delay for a specified number of seconds.
*
* @param s Number of seconds to delay for.
*/
void delay(unsigned int s)
{
_delay((uint64_t)s * timer_hz());
}

u64 timer_us(u64 base)
{
static u64 hz;
Expand Down
113 changes: 0 additions & 113 deletions payloads/libpayload/libcbfs/cbfs_core.c
Expand Up @@ -265,98 +265,6 @@ void *cbfs_get_contents(struct cbfs_handle *handle, size_t *size, size_t limit)
return ret;
}

struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
{
const char *file_name;
uint32_t offset, align, romsize, name_len;
const struct cbfs_header *header;
struct cbfs_file file, *file_ptr;
struct cbfs_media default_media;

if (media == CBFS_DEFAULT_MEDIA) {
media = &default_media;
if (init_default_cbfs_media(media) != 0) {
ERROR("Failed to initialize default media.\n");
return NULL;
}
}

if (CBFS_HEADER_INVALID_ADDRESS == (header = cbfs_get_header(media)))
return NULL;

// Logical offset (for source media) of first file.
offset = ntohl(header->offset);
align = ntohl(header->align);
romsize = ntohl(header->romsize);

// TODO Add a "size" in CBFS header for a platform independent way to
// determine the end of CBFS data.
#if defined(CONFIG_LP_ARCH_X86) && CONFIG_LP_ARCH_X86
// resolve actual length of ROM used for CBFS components
// the bootblock size was not taken into account
romsize -= ntohl(header->bootblocksize);

// fine tune the length to handle alignment positioning.
// using (bootblock size) % align, to derive the
// number of bytes the bootblock is off from the alignment size.
if ((ntohl(header->bootblocksize) % align))
romsize -= (align - (ntohl(header->bootblocksize) % align));
else
romsize -= 1;
#endif

DEBUG("CBFS location: 0x%x~0x%x, align: %d\n", offset, romsize, align);
DEBUG("Looking for '%s' starting from 0x%x.\n", name, offset);

media->open(media);
while (offset < romsize &&
media->read(media, &file, offset, sizeof(file)) == sizeof(file)) {
if (memcmp(CBFS_FILE_MAGIC, file.magic,
sizeof(file.magic)) != 0) {
uint32_t new_align = align;
if (offset % align)
new_align += align - (offset % align);
ERROR("ERROR: No file header found at 0x%xx - "
"try next aligned address: 0x%x.\n", offset,
offset + new_align);
offset += new_align;
continue;
}
name_len = ntohl(file.offset) - sizeof(file);
DEBUG(" - load entry 0x%x file name (%d bytes)...\n", offset,
name_len);

// load file name (arbitrary length).
file_name = (const char*)media->map(
media, offset + sizeof(file), name_len);
if (file_name == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
ERROR("ERROR: Failed to get filename: 0x%x.\n", offset);
} else if (strcmp(file_name, name) == 0) {
int file_offset = ntohl(file.offset),
file_len = ntohl(file.len);
DEBUG("Found file (offset=0x%x, len=%d).\n",
offset + file_offset, file_len);
media->unmap(media, file_name);
file_ptr = media->map(media, offset,
file_offset + file_len);
media->close(media);
return file_ptr;
} else {
DEBUG(" (unmatched file @0x%x: %s)\n", offset,
file_name);
media->unmap(media, file_name);
}

// Move to next file.
offset += ntohl(file.len) + ntohl(file.offset);
if (offset % align)
offset += align - (offset % align);
}
media->close(media);
LOG("WARNING: '%s' not found.\n", name);
return NULL;
}

void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
int type, size_t *sz)
{
Expand Down Expand Up @@ -434,24 +342,3 @@ int cbfs_decompress(int algo, void *src, void *dst, int len)
return 0;
}
}

/*
* This will search for 'string' in the null terminated CBFS file 'filename'.
* If the string is found its address is returned.
*/
char *cbfs_find_string(const char *string, const char *filename)
{
char *data = cbfs_get_file_content( CBFS_DEFAULT_MEDIA, filename, CBFS_TYPE_RAW, NULL );
if (!data)
return NULL;
u8 length = strlen(string);

for ( ; ; ) {
if (*data == 0) // Check for end of file
break;
if (!strncmp(string, data, length)) // Check for string match
return data;
data++;
}
return NULL;
}
37 changes: 37 additions & 0 deletions payloads/linuxcheck/Makefile
@@ -0,0 +1,37 @@
LIBPAYLOAD_DIR=$(CURDIR)/libpayload
XCOMPILE=$(LIBPAYLOAD_DIR)/libpayload.xcompile
# build libpayload and put .config file in $(CURDIR) instead of ../libpayload
# to avoid pollute the libpayload source directory and possible conflicts
LPOPTS=obj="$(CURDIR)/build" DESTDIR="$(CURDIR)" DOTCONFIG="$(CURDIR)/.config"
CFLAGS += -Wall -Werror -Os -ffreestanding -nostdinc -nostdlib
ifeq ($(CONFIG_ARCH_X86),y)
TARGETARCH = i386
endif

all: linuxcheck.elf

$(LIBPAYLOAD_DIR):
$(MAKE) -C ../libpayload $(LPOPTS) defconfig
$(MAKE) -C ../libpayload $(LPOPTS)
$(MAKE) -C ../libpayload $(LPOPTS) install

ifneq ($(strip $(wildcard libpayload)),)
include $(XCOMPILE)
LPGCC = CC="$(GCC_CC_x86_32)" "$(LIBPAYLOAD_DIR)/bin/lpgcc"
%.elf: %.c Makefile
$(LPGCC) $(CFLAGS) -o $*.elf $*.c $(TARGETARCH).c
else
# If libpayload is not found, first build libpayload,
# then do the make, this time it'll find libpayload
# and generate the linuxcheck.elf target
%.elf: $(LIBPAYLOAD_DIR)
$(MAKE) all
endif

clean:
rm -f linuxcheck.elf

distclean: clean
rm -rf build libpayload .config .config.old

.PHONY: all clean distclean
48 changes: 48 additions & 0 deletions payloads/linuxcheck/i386.c
@@ -0,0 +1,48 @@
/*
* This file is part of the coreinfo project.
*
* Copyright (C) 2018 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include <libpayload-config.h>
#include <libpayload.h>
#include "linuxcheck.h"

void buts(char *s)
{
int i;
for (i = 0; i < strlen(s); i++)
outb(s[i], 0x3f8);
}

void hex4(u8 c)
{
static char *hex = "0123456789abcdef";
outb(hex[c & 0xf], 0x3f8);
}

void hex8(u8 c)
{
hex4(c >> 4);
hex4(c);
}

void hex16(u16 c)
{
hex8((u8)(c >> 8));
hex8((u8)c);
}
void hex32(u32 c)
{
hex16((u16)(c >> 16));
hex16((u16)c);
}
52 changes: 52 additions & 0 deletions payloads/linuxcheck/linuxcheck.c
@@ -0,0 +1,52 @@
/*
* This file is part of the coreinfo project.
*
* Copyright (C) 2018 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include <libpayload-config.h>
#include <libpayload.h>
#include "linuxcheck.h"

extern struct console_output_driver *console_out;
extern struct sysinfo_t lib_sysinfo;

int main(void)
{
int ret, i;

buts("Greetings from linuxcheck, via hard-coded calls to serial functions.\n");
if (console_out == NULL)
buts("Bad news: console_out is NULL\n");
if (lib_sysinfo.serial == NULL)
buts("Bad news: lib_sysinfo.serial is NULL. Very little will work well.\n");
ret = lib_get_sysinfo();
if (ret) {
buts("lib_get_sysinfo() is non-zero");
hex32(ret);
buts("\n");
}

buts("The next line should be puts works\n");
puts("puts works\n");
buts("If you did not see puts works, then you have a console issues\n");
buts("The next line should be 'printf works'\n");
printf("printf works\n");
buts(" ... if you did not see printf works, then you have a printf issue\n");
printf("Number of memory ranges: %d\n", lib_sysinfo.n_memranges);
for (i = 0; i < lib_sysinfo.n_memranges; i++) {
printf("%d: base 0x%08llx size 0x%08llx type 0x%x\n", i, lib_sysinfo.memrange[i].base, lib_sysinfo.memrange[i].size, lib_sysinfo.memrange[i].type);
}
buts("Now we will halt. Bye");
halt();
return 0;
}
22 changes: 22 additions & 0 deletions payloads/linuxcheck/linuxcheck.h
@@ -0,0 +1,22 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2018 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

/* buts is a programmed IO byte puts, which you need to write for all platforms. */
void buts(char *s);

void hex4(u8 c);
void hex8(u8 c);
void hex16(u16 c);
void hex32(u32 c);
6 changes: 6 additions & 0 deletions src/Kconfig
Expand Up @@ -586,6 +586,12 @@ config ACPI_NHLT
help
Build support for NHLT (non HD Audio) ACPI table generation.

config ACPI_BERT
bool
depends on HAVE_ACPI_TABLES
help
Build an ACPI Boot Error Record Table.

#These Options are here to avoid "undefined" warnings.
#The actual selection and help texts are in the following menu.

Expand Down
4 changes: 3 additions & 1 deletion src/arch/arm/include/arch/hlt.h
Expand Up @@ -14,7 +14,9 @@
#ifndef ARCH_HLT_H
#define ARCH_HLT_H

static inline __attribute__((always_inline)) void hlt(void)
#include <compiler.h>

static __always_inline void hlt(void)
{
for (;;) ;
}
Expand Down
4 changes: 2 additions & 2 deletions src/arch/arm/include/smp/spinlock.h
Expand Up @@ -33,7 +33,7 @@ typedef struct {
#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) != 0)
#define spin_unlock_wait(x) do { barrier(); } while (spin_is_locked(x))

static inline __attribute__((always_inline)) void spin_lock(spinlock_t *lock)
static __always_inline void spin_lock(spinlock_t *lock)
{
unsigned long tmp;
__asm__ __volatile__ (
Expand All @@ -49,7 +49,7 @@ static inline __attribute__((always_inline)) void spin_lock(spinlock_t *lock)
barrier();
}

static inline __attribute__((always_inline)) void spin_unlock(spinlock_t *lock)
static __always_inline void spin_unlock(spinlock_t *lock)
{
__asm__ __volatile__(
" str %1, [%0]\n"
Expand Down
4 changes: 3 additions & 1 deletion src/arch/arm64/include/arch/hlt.h
Expand Up @@ -14,7 +14,9 @@
#ifndef ARCH_HLT_H
#define ARCH_HLT_H

static inline __attribute__((always_inline)) void hlt(void)
#include <compiler.h>

static __always_inline void hlt(void)
{
for (;;) ;
}
Expand Down
4 changes: 3 additions & 1 deletion src/arch/mips/include/arch/hlt.h
Expand Up @@ -16,7 +16,9 @@
#ifndef __MIPS_ARCH_HLT_H
#define __MIPS_ARCH_HLT_H

static inline __attribute__((always_inline)) void hlt(void)
#include <compiler.h>

static inline __always_inline void hlt(void)
{
for (;;)
;
Expand Down
4 changes: 3 additions & 1 deletion src/arch/power8/include/arch/hlt.h
Expand Up @@ -11,7 +11,9 @@
* GNU General Public License for more details.
*/

static inline __attribute__((always_inline)) void hlt(void)
#include <compiler.h>

static __always_inline void hlt(void)
{
while (1)
;
Expand Down
4 changes: 4 additions & 0 deletions src/arch/riscv/Kconfig
Expand Up @@ -28,3 +28,7 @@ config ARCH_ROMSTAGE_RISCV
config ARCH_RAMSTAGE_RISCV
bool
default n

config RISCV_USE_ARCH_TIMER
bool
default n
14 changes: 14 additions & 0 deletions src/arch/riscv/Makefile.inc
Expand Up @@ -43,6 +43,8 @@ ifeq ($(CONFIG_ARCH_BOOTBLOCK_RISCV),y)
bootblock-y = bootblock.S
bootblock-y += trap_util.S
bootblock-y += trap_handler.c
bootblock-y += fp_asm.S
bootblock-y += misaligned.c
bootblock-y += mcall.c
bootblock-y += virtual_memory.c
bootblock-y += boot.c
Expand All @@ -54,6 +56,8 @@ bootblock-y += \
$(top)/src/lib/memmove.c \
$(top)/src/lib/memset.c

bootblock-$(CONFIG_RISCV_USE_ARCH_TIMER) += arch_timer.c

$(objcbfs)/bootblock.debug: $$(bootblock-objs)
@printf " LINK $(subst $(obj)/,,$(@))\n"
$(LD_bootblock) $(LDFLAGS_bootblock) -o $@ -L$(obj) \
Expand All @@ -80,6 +84,8 @@ romstage-y += \
$(top)/src/lib/memmove.c \
$(top)/src/lib/memset.c

romstage-$(CONFIG_RISCV_USE_ARCH_TIMER) += arch_timer.c

# Build the romstage

$(objcbfs)/romstage.debug: $$(romstage-objs)
Expand All @@ -97,6 +103,12 @@ endif #CONFIG_ARCH_ROMSTAGE_RISCV
ifeq ($(CONFIG_ARCH_RAMSTAGE_RISCV),y)

ramstage-y =
ramstage-y += ramstage.S
ramstage-y += mcall.c
ramstage-y += trap_util.S
ramstage-y += trap_handler.c
ramstage-y += fp_asm.S
ramstage-y += misaligned.c
ramstage-y += virtual_memory.c
ramstage-y += stages.c
ramstage-y += misc.c
Expand All @@ -110,6 +122,8 @@ ramstage-y += \
$(top)/src/lib/memmove.c \
$(top)/src/lib/memset.c

ramstage-$(CONFIG_RISCV_USE_ARCH_TIMER) += arch_timer.c

$(eval $(call create_class_compiler,rmodules,riscv))

ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/mainboard.c
Expand Down
28 changes: 28 additions & 0 deletions src/arch/riscv/arch_timer.c
@@ -0,0 +1,28 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2018 Philipp Hug <philipp@hug.cx>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include <arch/io.h>
#include <arch/encoding.h>
#include <console/console.h>
#include <stddef.h>
#include <timer.h>
#include <mcall.h>

void timer_monotonic_get(struct mono_time *mt)
{
if (HLS()->time == NULL)
die("time not set in HLS");
mono_time_set_usecs(mt, (long)read64((void *)(HLS()->time)));
}
6 changes: 6 additions & 0 deletions src/arch/riscv/bootblock.S
Expand Up @@ -24,6 +24,12 @@
.global _estack
.globl _start
_start:
csrr a0, mhartid
li a3, 0
beq a0, a3, _hart_zero
_hart_loop:
j _hart_loop
_hart_zero:

# The boot ROM may pass the following arguments to coreboot:
# a0: the value of mhartid
Expand Down
362 changes: 362 additions & 0 deletions src/arch/riscv/fp_asm.S
@@ -0,0 +1,362 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2018 HardenedLinux
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

/*
* This file define some function used to swap value between memory
* and float register. This will be used in misaligned access exception
* handling.
*/

#if defined(__riscv_flen)
#if __riscv_flen >= 32

.text

/* void read_f32(int regnum, uint32_t* v)
* regnum : which register want to read
* v : address to hold bits info of reading
*/
.align 1
.globl read_f32
read_f32:
la a2, .Lr32_t
andi a0, a0, 31
slli a0, a0, 1
add a0, a0, a2
lbu a0, 0(a0)
add a0, a0, a2
jr a0
.align 2
.Lr32_t:
.half .Lr32_f0 - .Lr32_t
.half .Lr32_f1 - .Lr32_t
.half .Lr32_f2 - .Lr32_t
.half .Lr32_f3 - .Lr32_t
.half .Lr32_f4 - .Lr32_t
.half .Lr32_f5 - .Lr32_t
.half .Lr32_f6 - .Lr32_t
.half .Lr32_f7 - .Lr32_t
.half .Lr32_f8 - .Lr32_t
.half .Lr32_f9 - .Lr32_t
.half .Lr32_f10 - .Lr32_t
.half .Lr32_f11 - .Lr32_t
.half .Lr32_f12 - .Lr32_t
.half .Lr32_f13 - .Lr32_t
.half .Lr32_f14 - .Lr32_t
.half .Lr32_f15 - .Lr32_t
.half .Lr32_f16 - .Lr32_t
.half .Lr32_f17 - .Lr32_t
.half .Lr32_f18 - .Lr32_t
.half .Lr32_f19 - .Lr32_t
.half .Lr32_f20 - .Lr32_t
.half .Lr32_f21 - .Lr32_t
.half .Lr32_f22 - .Lr32_t
.half .Lr32_f23 - .Lr32_t
.half .Lr32_f24 - .Lr32_t
.half .Lr32_f25 - .Lr32_t
.half .Lr32_f26 - .Lr32_t
.half .Lr32_f27 - .Lr32_t
.half .Lr32_f28 - .Lr32_t
.half .Lr32_f29 - .Lr32_t
.half .Lr32_f30 - .Lr32_t
.half .Lr32_f31 - .Lr32_t
#define read32(which) .Lr32_##which: fsw which, 0(a1); ret
read32(f0)
read32(f1)
read32(f2)
read32(f3)
read32(f4)
read32(f5)
read32(f6)
read32(f7)
read32(f8)
read32(f9)
read32(f10)
read32(f11)
read32(f12)
read32(f13)
read32(f14)
read32(f15)
read32(f16)
read32(f17)
read32(f18)
read32(f19)
read32(f20)
read32(f21)
read32(f22)
read32(f23)
read32(f24)
read32(f25)
read32(f26)
read32(f27)
read32(f28)
read32(f29)
read32(f30)
read32(f31)

/* void write_f32(int regnum, uint32_t* v)
* regnum: which register want to write
* v : address to hold bits info of writing
*/
.align 1
.globl write_f32
write_f32:
la a2, .Lw32_t
andi a0, a0, 31
slli a0, a0, 1
add a0, a0, a2
lbu a0, 0(a0)
add a0, a0, a2
jr a0
.align 2
.Lw32_t:
.half .Lw32_f0 - .Lw32_t
.half .Lw32_f1 - .Lw32_t
.half .Lw32_f2 - .Lw32_t
.half .Lw32_f3 - .Lw32_t
.half .Lw32_f4 - .Lw32_t
.half .Lw32_f5 - .Lw32_t
.half .Lw32_f6 - .Lw32_t
.half .Lw32_f7 - .Lw32_t
.half .Lw32_f8 - .Lw32_t
.half .Lw32_f9 - .Lw32_t
.half .Lw32_f10 - .Lw32_t
.half .Lw32_f11 - .Lw32_t
.half .Lw32_f12 - .Lw32_t
.half .Lw32_f13 - .Lw32_t
.half .Lw32_f14 - .Lw32_t
.half .Lw32_f15 - .Lw32_t
.half .Lw32_f16 - .Lw32_t
.half .Lw32_f17 - .Lw32_t
.half .Lw32_f18 - .Lw32_t
.half .Lw32_f19 - .Lw32_t
.half .Lw32_f20 - .Lw32_t
.half .Lw32_f21 - .Lw32_t
.half .Lw32_f22 - .Lw32_t
.half .Lw32_f23 - .Lw32_t
.half .Lw32_f24 - .Lw32_t
.half .Lw32_f25 - .Lw32_t
.half .Lw32_f26 - .Lw32_t
.half .Lw32_f27 - .Lw32_t
.half .Lw32_f28 - .Lw32_t
.half .Lw32_f29 - .Lw32_t
.half .Lw32_f30 - .Lw32_t
.half .Lw32_f31 - .Lw32_t
#define write32(which) .Lw32_##which: flw which, 0(a1); ret
write32(f0)
write32(f1)
write32(f2)
write32(f3)
write32(f4)
write32(f5)
write32(f6)
write32(f7)
write32(f8)
write32(f9)
write32(f10)
write32(f11)
write32(f12)
write32(f13)
write32(f14)
write32(f15)
write32(f16)
write32(f17)
write32(f18)
write32(f19)
write32(f20)
write32(f21)
write32(f22)
write32(f23)
write32(f24)
write32(f25)
write32(f26)
write32(f27)
write32(f28)
write32(f29)
write32(f30)
write32(f31)
#endif // __riscv_flen >= 32

#if __riscv_flen >= 64

.text

/* void read_f64(int regnum, uint64_t* v)
* regnum : which register want to read
* v : address to hold bits info of reading
*/
.align 1
.globl read_f64
read_f64:
la a2, .Lr64_t
andi a0, a0, 31
slli a0, a0, 1
add a0, a0, a2
lbu a0, 0(a0)
add a0, a0, a2
jr a0
.align 2
.Lr64_t:
.half .Lr64_f0 - .Lr64_t
.half .Lr64_f1 - .Lr64_t
.half .Lr64_f2 - .Lr64_t
.half .Lr64_f3 - .Lr64_t
.half .Lr64_f4 - .Lr64_t
.half .Lr64_f5 - .Lr64_t
.half .Lr64_f6 - .Lr64_t
.half .Lr64_f7 - .Lr64_t
.half .Lr64_f8 - .Lr64_t
.half .Lr64_f9 - .Lr64_t
.half .Lr64_f10 - .Lr64_t
.half .Lr64_f11 - .Lr64_t
.half .Lr64_f12 - .Lr64_t
.half .Lr64_f13 - .Lr64_t
.half .Lr64_f14 - .Lr64_t
.half .Lr64_f15 - .Lr64_t
.half .Lr64_f16 - .Lr64_t
.half .Lr64_f17 - .Lr64_t
.half .Lr64_f18 - .Lr64_t
.half .Lr64_f19 - .Lr64_t
.half .Lr64_f20 - .Lr64_t
.half .Lr64_f21 - .Lr64_t
.half .Lr64_f22 - .Lr64_t
.half .Lr64_f23 - .Lr64_t
.half .Lr64_f24 - .Lr64_t
.half .Lr64_f25 - .Lr64_t
.half .Lr64_f26 - .Lr64_t
.half .Lr64_f27 - .Lr64_t
.half .Lr64_f28 - .Lr64_t
.half .Lr64_f29 - .Lr64_t
.half .Lr64_f30 - .Lr64_t
.half .Lr64_f31 - .Lr64_t
#define read64(which) .Lr64_##which: fsd which, 0(a1); ret
read64(f0)
read64(f1)
read64(f2)
read64(f3)
read64(f4)
read64(f5)
read64(f6)
read64(f7)
read64(f8)
read64(f9)
read64(f10)
read64(f11)
read64(f12)
read64(f13)
read64(f14)
read64(f15)
read64(f16)
read64(f17)
read64(f18)
read64(f19)
read64(f20)
read64(f21)
read64(f22)
read64(f23)
read64(f24)
read64(f25)
read64(f26)
read64(f27)
read64(f28)
read64(f29)
read64(f30)
read64(f31)

/* void write_f64(int regnum, uint64_t* v)
* regnum: which register want to write
* v : address to hold bits info of writing
*/
.align 1
.globl write_f64
write_f64:
la a2, .Lw64_t
andi a0, a0, 31
slli a0, a0, 1
add a0, a0, a2
lbu a0, 0(a0)
add a0, a0, a2
jr a0
.align 2
.Lw64_t:
.half .Lw64_f0 - .Lw64_t
.half .Lw64_f1 - .Lw64_t
.half .Lw64_f2 - .Lw64_t
.half .Lw64_f3 - .Lw64_t
.half .Lw64_f4 - .Lw64_t
.half .Lw64_f5 - .Lw64_t
.half .Lw64_f6 - .Lw64_t
.half .Lw64_f7 - .Lw64_t
.half .Lw64_f8 - .Lw64_t
.half .Lw64_f9 - .Lw64_t
.half .Lw64_f10 - .Lw64_t
.half .Lw64_f11 - .Lw64_t
.half .Lw64_f12 - .Lw64_t
.half .Lw64_f13 - .Lw64_t
.half .Lw64_f14 - .Lw64_t
.half .Lw64_f15 - .Lw64_t
.half .Lw64_f16 - .Lw64_t
.half .Lw64_f17 - .Lw64_t
.half .Lw64_f18 - .Lw64_t
.half .Lw64_f19 - .Lw64_t
.half .Lw64_f20 - .Lw64_t
.half .Lw64_f21 - .Lw64_t
.half .Lw64_f22 - .Lw64_t
.half .Lw64_f23 - .Lw64_t
.half .Lw64_f24 - .Lw64_t
.half .Lw64_f25 - .Lw64_t
.half .Lw64_f26 - .Lw64_t
.half .Lw64_f27 - .Lw64_t
.half .Lw64_f28 - .Lw64_t
.half .Lw64_f29 - .Lw64_t
.half .Lw64_f30 - .Lw64_t
.half .Lw64_f31 - .Lw64_t
#define write64(which) .Lw64_##which: fld which, 0(a1); ret
write64(f0)
write64(f1)
write64(f2)
write64(f3)
write64(f4)
write64(f5)
write64(f6)
write64(f7)
write64(f8)
write64(f9)
write64(f10)
write64(f11)
write64(f12)
write64(f13)
write64(f14)
write64(f15)
write64(f16)
write64(f17)
write64(f18)
write64(f19)
write64(f20)
write64(f21)
write64(f22)
write64(f23)
write64(f24)
write64(f25)
write64(f26)
write64(f27)
write64(f28)
write64(f29)
write64(f30)
write64(f31)

#endif // __riscv_flen >= 64

#endif // defined(__riscv_flen)
6 changes: 6 additions & 0 deletions src/arch/riscv/include/arch/cpu.h
Expand Up @@ -51,5 +51,11 @@ static inline int supports_extension(char ext)
return read_csr(misa) & (1 << (ext - 'A'));
}

static inline int machine_xlen(void)
{
int mxl = (read_csr(misa) >> (__riscv_xlen - 2)) & 3;
return (1 << mxl) * 16;
}

struct cpu_info *cpu_info(void);
#endif /* __ARCH_CPU_H__ */
11 changes: 5 additions & 6 deletions src/arch/riscv/include/arch/exception.h
Expand Up @@ -32,8 +32,7 @@

#include <stdint.h>

typedef struct
{
typedef struct {
uintptr_t gpr[32];
uintptr_t status;
uintptr_t epc;
Expand All @@ -53,9 +52,9 @@ static inline void exception_init(void)
{
}

void trap_handler(trapframe* tf);
void handle_supervisor_call(trapframe* tf);
void handle_misaligned_load(trapframe *tf);
void handle_misaligned_store(trapframe *tf);
void redirect_trap(void);
void trap_handler(trapframe *tf);
void handle_supervisor_call(trapframe *tf);
void handle_misaligned(trapframe *tf);

#endif
4 changes: 3 additions & 1 deletion src/arch/riscv/include/arch/header.ld
Expand Up @@ -13,6 +13,8 @@
* GNU General Public License for more details.
*/

#include <rules.h>

/* We use ELF as output format. So that we can debug the code in some form. */
OUTPUT_ARCH(riscv)

Expand All @@ -21,7 +23,7 @@ PHDRS
to_load PT_LOAD;
}

#ifdef __BOOTBLOCK__
#if ENV_BOOTBLOCK || ENV_RAMSTAGE
ENTRY(_start)
#else
ENTRY(stage_entry)
Expand Down
4 changes: 3 additions & 1 deletion src/arch/riscv/include/arch/hlt.h
Expand Up @@ -11,7 +11,9 @@
* GNU General Public License for more details.
*/

static inline __attribute__((always_inline)) void hlt(void)
#include <compiler.h>

static __always_inline void hlt(void)
{
while (1);
}
24 changes: 18 additions & 6 deletions src/arch/riscv/include/arch/io.h
Expand Up @@ -14,36 +14,48 @@
#ifndef _ASM_IO_H
#define _ASM_IO_H

#include <endian.h>
#include <stdint.h>
#include <compiler.h>

static inline __attribute__((always_inline)) uint8_t read8(const volatile void *addr)
static __always_inline uint8_t read8(const volatile void *addr)
{
return *((volatile uint8_t *)(addr));
}

static inline __attribute__((always_inline)) uint16_t read16(const volatile void *addr)
static __always_inline uint16_t read16(const volatile void *addr)
{
return *((volatile uint16_t *)(addr));
}

static inline __attribute__((always_inline)) uint32_t read32(const volatile void *addr)
static __always_inline uint32_t read32(const volatile void *addr)
{
return *((volatile uint32_t *)(addr));
}

static inline __attribute__((always_inline)) void write8(volatile void *addr, uint8_t value)
static __always_inline uint64_t read64(const volatile void *addr)
{
return *((volatile uint64_t *)(addr));
}

static __always_inline void write8(volatile void *addr, uint8_t value)
{
*((volatile uint8_t *)(addr)) = value;
}

static inline __attribute__((always_inline)) void write16(volatile void *addr, uint16_t value)
static __always_inline void write16(volatile void *addr, uint16_t value)
{
*((volatile uint16_t *)(addr)) = value;
}

static inline __attribute__((always_inline)) void write32(volatile void *addr, uint32_t value)
static __always_inline void write32(volatile void *addr, uint32_t value)
{
*((volatile uint32_t *)(addr)) = value;
}

static __always_inline void write64(volatile void *addr, uint64_t value)
{
*((volatile uint64_t *)(addr)) = value;
}

#endif
14 changes: 14 additions & 0 deletions src/arch/riscv/include/arch/memlayout.h
Expand Up @@ -20,6 +20,20 @@

#define STACK(addr, size) REGION(stack, addr, size, 4096)

#if defined(__PRE_RAM__)
#define CAR_STACK(addr, size) \
REGION(car_stack, addr, size, 4K) \
ALIAS_REGION(car_stack, stack)
#define MEM_STACK(addr, size) \
REGION(mem_stack, addr, size, 4K)
#else
#define CAR_STACK(addr, size) \
REGION(car_stack, addr, size, 4K)
#define MEM_STACK(addr, size) \
REGION(mem_stack, addr, size, 4K) \
ALIAS_REGION(mem_stack, stack)
#endif

/* TODO: Need to add DMA_COHERENT region like on ARM? */

#endif /* __ARCH_MEMLAYOUT_H */
28 changes: 28 additions & 0 deletions src/arch/riscv/include/arch/smp/spinlock.h
@@ -1,6 +1,8 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2018 HardenedLinux.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
Expand All @@ -10,3 +12,29 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef ARCH_SMP_SPINLOCK_H
#define ARCH_SMP_SPINLOCK_H

#include <arch/encoding.h>
#include <arch/smp/atomic.h>

#define barrier() { asm volatile ("fence" ::: "memory"); }

typedef struct {
volatile atomic_t lock;
} spinlock_t;

static inline void spinlock_lock(spinlock_t *lock)
{
while (atomic_swap(&lock->lock, -1))
;
barrier();
}

static inline void spinlock_unlock(spinlock_t *lock)
{
barrier();
atomic_set(&lock->lock, 0);
}

#endif // ARCH_SMP_SPINLOCK_H
3 changes: 3 additions & 0 deletions src/arch/riscv/include/mcall.h
Expand Up @@ -61,6 +61,9 @@ typedef struct {

void hls_init(uint32_t hart_id); // need to call this before launching linux

/* This function is used to initialize HLS()->time/HLS()->timecmp */
void mtime_init(void);

#endif // __ASSEMBLER__

#endif
19 changes: 16 additions & 3 deletions src/arch/riscv/include/vm.h
Expand Up @@ -38,11 +38,11 @@
void mstatus_init(void); // need to setup mstatus so we know we have virtual memory


#define DEFINE_MPRV_READ(name, type, insn) \
#define DEFINE_MPRV_READ_FLAGS(name, type, insn, flags) \
static inline type name(type *p); \
static inline type name(type *p) \
{ \
size_t mprv = MSTATUS_MPRV; \
size_t mprv = flags; \
type value; \
asm ( \
"csrs mstatus, %1\n" \
Expand All @@ -53,6 +53,12 @@ void mstatus_init(void); // need to setup mstatus so we know we have virtual mem
return value; \
}

#define DEFINE_MPRV_READ(name, type, insn) \
DEFINE_MPRV_READ_FLAGS(name, type, insn, MSTATUS_MPRV)

#define DEFINE_MPRV_READ_MXR(name, type, insn) \
DEFINE_MPRV_READ_FLAGS(name, type, insn, MSTATUS_MPRV | MSTATUS_MXR)

#define DEFINE_MPRV_WRITE(name, type, insn) \
static inline void name(type *p, type value); \
static inline void name(type *p, type value) \
Expand Down Expand Up @@ -83,15 +89,22 @@ DEFINE_MPRV_READ(mprv_read_u32, uint32_t, lwu)
DEFINE_MPRV_READ(mprv_read_u64, uint64_t, ld)
DEFINE_MPRV_READ(mprv_read_long, long, ld)
DEFINE_MPRV_READ(mprv_read_ulong, unsigned long, ld)
DEFINE_MPRV_READ_MXR(mprv_read_mxr_u8, uint8_t, lbu)
DEFINE_MPRV_READ_MXR(mprv_read_mxr_u16, uint16_t, lhu)
DEFINE_MPRV_READ_MXR(mprv_read_mxr_u32, uint32_t, lwu)
DEFINE_MPRV_READ_MXR(mprv_read_mxr_u64, uint64_t, ld)
DEFINE_MPRV_READ_MXR(mprv_read_mxr_long, long, ld)
DEFINE_MPRV_READ_MXR(mprv_read_mxr_ulong, unsigned long, ld)
DEFINE_MPRV_WRITE(mprv_write_u8, uint8_t, sb)
DEFINE_MPRV_WRITE(mprv_write_u16, uint16_t, sh)
DEFINE_MPRV_WRITE(mprv_write_u32, uint32_t, sw)
DEFINE_MPRV_WRITE(mprv_write_u64, uint64_t, sd)
DEFINE_MPRV_WRITE(mprv_write_long, long, sd)
DEFINE_MPRV_WRITE(mprv_write_ulong, unsigned long, sd)

#undef DEFINE_MPRV_READ_FLAGS
#undef DEFINE_MPRV_READ
#undef DEFINE_MPRV_READ_MXR
#undef DEFINE_MPRV_WRITE


#endif
4 changes: 1 addition & 3 deletions src/arch/riscv/mcall.c
Expand Up @@ -40,9 +40,7 @@ void hls_init(uint32_t hart_id)
memset(HLS(), 0, sizeof(*HLS()));
HLS()->hart_id = hart_id;

/* Initialize these pointers with dummy values, for now */
HLS()->time = NULL;
HLS()->timecmp = NULL;
mtime_init();

printk(BIOS_SPEW, "Time is %p and timecmp is %p\n",
HLS()->time, HLS()->timecmp);
Expand Down
267 changes: 267 additions & 0 deletions src/arch/riscv/misaligned.c
@@ -0,0 +1,267 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2018 HardenedLinux
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include <stddef.h>
#include <stdint.h>
#include <vm.h>
#include <arch/exception.h>
#include <commonlib/helpers.h>

/* these functions are defined in src/arch/riscv/fp_asm.S */
#if defined(__riscv_flen)
#if __riscv_flen >= 32
extern void read_f32(int regnum, uint32_t *v);
extern void write_f32(int regnum, uint32_t *v);
#endif // __riscv_flen >= 32
#if __riscv_flen >= 64
extern void read_f64(int regnum, uint64_t *v);
extern void write_f64(int regnum, uint64_t *v);
#endif // __riscv_flen >= 64
#endif // defined(__riscv_flen)

/* This union makes it easy to read multibyte types by byte operations. */
union endian_buf {
uint8_t b[8];
uint16_t h[4];
uint32_t w[2];
uint64_t d[1];
uintptr_t v;
};

/* This struct hold info of load/store instruction */
struct memory_instruction_info {
/* opcode/mask used to identify instruction,
* (instruction_val) & mask == opcode */
uint32_t opcode;
uint32_t mask;
/* reg_shift/reg_mask/reg_addition used to get register number
* ((instruction_val >> reg_shift) & reg_mask) + reg_addition */
unsigned int reg_shift;
unsigned int reg_mask;
unsigned int reg_addition;
unsigned int is_fp : 1; /* mark as a float operation */
unsigned int is_load : 1; /* mark as a load operation */
unsigned int width : 8; /* Record the memory width of the operation */
unsigned int sign_extend : 1; /* mark need to be sign extended */
};

static struct memory_instruction_info insn_info[] = {
#if __riscv_xlen == 128
{ 0x00002000, 0x0000e003, 2, 7, 8, 0, 1, 16, 1}, // C.LQ
#else
{ 0x00002000, 0x0000e003, 2, 7, 8, 1, 1, 8, 0}, // C.FLD
#endif
{ 0x00004000, 0x0000e003, 2, 7, 8, 0, 1, 4, 1}, // C.LW
#if __riscv_xlen == 32
{ 0x00006000, 0x0000e003, 2, 7, 8, 1, 1, 4, 0}, // C.FLW
#else
{ 0x00006000, 0x0000e003, 2, 7, 8, 0, 1, 8, 1}, // C.LD
#endif

#if __riscv_xlen == 128
{ 0x0000a000, 0x0000e003, 2, 7, 8, 0, 0, 16, 0}, // C.SQ
#else
{ 0x0000a000, 0x0000e003, 2, 7, 8, 1, 0, 8, 0}, // C.FSD
#endif
{ 0x0000c000, 0x0000e003, 2, 7, 8, 0, 0, 4, 0}, // C.SW
#if __riscv_xlen == 32
{ 0x0000e000, 0x0000e003, 2, 7, 8, 1, 0, 4, 0}, // C.FSW
#else
{ 0x0000e000, 0x0000e003, 2, 7, 8, 0, 0, 8, 0}, // C.SD
#endif

#if __riscv_xlen == 128
{ 0x00002002, 0x0000e003, 7, 15, 0, 0, 1, 16, 1}, // C.LQSP
#else
{ 0x00002002, 0x0000e003, 7, 15, 0, 1, 1, 8, 0}, // C.FLDSP
#endif
{ 0x00004002, 0x0000e003, 7, 15, 0, 0, 1, 4, 1}, // C.LWSP
#if __riscv_xlen == 32
{ 0x00006002, 0x0000e003, 7, 15, 0, 1, 1, 4, 0}, // C.FLWSP
#else
{ 0x00006002, 0x0000e003, 7, 15, 0, 0, 1, 8, 1}, // C.LDSP
#endif

#if __riscv_xlen == 128
{ 0x0000a002, 0x0000e003, 2, 15, 0, 0, 0, 16, 0}, // C.SQSP
#else
{ 0x0000a002, 0x0000e003, 2, 15, 0, 1, 0, 8, 0}, // C.FSDSP
#endif
{ 0x0000c002, 0x0000e003, 2, 15, 0, 0, 0, 4, 0}, // C.SWSP
#if __riscv_xlen == 32
{ 0x0000e002, 0x0000e003, 2, 15, 0, 1, 0, 4, 0}, // C.FSWSP
#else
{ 0x0000e002, 0x0000e003, 2, 15, 0, 0, 0, 8, 0}, // C.SDSP
#endif

{ 0x00000003, 0x0000707f, 7, 15, 0, 0, 1, 1, 1}, // LB
{ 0x00001003, 0x0000707f, 7, 15, 0, 0, 1, 2, 1}, // LH
{ 0x00002003, 0x0000707f, 7, 15, 0, 0, 1, 4, 1}, // LW
#if __riscv_xlen > 32
{ 0x00003003, 0x0000707f, 7, 15, 0, 0, 1, 8, 1}, // LD
#endif
{ 0x00004003, 0x0000707f, 7, 15, 0, 0, 1, 1, 0}, // LBU
{ 0x00005003, 0x0000707f, 7, 15, 0, 0, 1, 2, 0}, // LHU
{ 0x00006003, 0x0000707f, 7, 15, 0, 0, 1, 4, 0}, // LWU

{ 0x00000023, 0x0000707f, 20, 15, 0, 0, 0, 1, 0}, // SB
{ 0x00001023, 0x0000707f, 20, 15, 0, 0, 0, 2, 0}, // SH
{ 0x00002023, 0x0000707f, 20, 15, 0, 0, 0, 4, 0}, // SW
#if __riscv_xlen > 32
{ 0x00003023, 0x0000707f, 20, 15, 0, 0, 0, 8, 0}, // SD
#endif

#if defined(__riscv_flen)
#if __riscv_flen >= 32
{ 0x00002007, 0x0000707f, 7, 15, 0, 1, 1, 4, 0}, // FLW
{ 0x00003007, 0x0000707f, 7, 15, 0, 1, 1, 8, 0}, // FLD
#endif // __riscv_flen >= 32

#if __riscv_flen >= 64
{ 0x00002027, 0x0000707f, 20, 15, 0, 1, 0, 4, 0}, // FSW
{ 0x00003027, 0x0000707f, 20, 15, 0, 1, 0, 8, 0}, // FSD
#endif // __riscv_flen >= 64
#endif // defined(__riscv_flen)
};

static struct memory_instruction_info *match_instruction(uintptr_t insn)
{
int i;
for (i = 0; i < ARRAY_SIZE(insn_info); i++)
if ((insn_info[i].mask & insn) == insn_info[i].opcode)
return &(insn_info[i]);
return NULL;
}


static int fetch_16bit_instruction(uintptr_t vaddr, uintptr_t *insn)
{
uint16_t ins = mprv_read_mxr_u16((uint16_t *)vaddr);
if (EXTRACT_FIELD(ins, 0x3) != 3) {
*insn = ins;
return 0;
}
return -1;
}

static int fetch_32bit_instruction(uintptr_t vaddr, uintptr_t *insn)
{
uint32_t l = (uint32_t)mprv_read_mxr_u16((uint16_t *)vaddr + 0);
uint32_t h = (uint32_t)mprv_read_mxr_u16((uint16_t *)vaddr + 2);
uint32_t ins = (h << 16) | l;
if ((EXTRACT_FIELD(ins, 0x3) == 3) &&
(EXTRACT_FIELD(ins, 0x1c) != 0x7)) {
*insn = ins;
return 0;
}
return -1;
}


void handle_misaligned(trapframe *tf)
{
uintptr_t insn = 0;
union endian_buf buff;

/* try to fetch 16/32 bits instruction */
if (fetch_16bit_instruction(tf->epc, &insn))
if (fetch_32bit_instruction(tf->epc, &insn))
redirect_trap();

/* matching instruction */
struct memory_instruction_info *match = match_instruction(insn);

if (!match) {
redirect_trap();
return;
}

int regnum;
regnum = ((insn >> match->reg_shift) & match->reg_mask);
regnum = regnum + match->reg_addition;
buff.v = 0;
if (match->is_load) {
/* load operation */

/* reading from memory by bytes prevents misaligned
* memory access */
for (int i = 0; i < match->width; i++) {
uint8_t *addr = (uint8_t *)(tf->badvaddr + i);
buff.b[i] = mprv_read_u8(addr);
}

/* sign extend for signed integer loading */
if (match->sign_extend)
if (buff.v >> (8 * match->width - 1))
buff.v |= -1 << (8 * match->width);

/* write to register */
if (match->is_fp) {
int done = 0;
#if defined(__riscv_flen)
#if __riscv_flen >= 32
/* single-precision floating-point */
if (match->width == 4) {
write_f32(regnum, buff.w);
done = 1;
}
#endif // __riscv_flen >= 32
#if __riscv_flen >= 64
/* double-precision floating-point */
if (match->width == 8) {
write_f64(regnum, buff.d);
done = 1;
}
#endif // __riscv_flen >= 64
#endif // defined(__riscv_flen)
if (!done)
redirect_trap();
} else {
tf->gpr[regnum] = buff.v;
}
} else {
/* store operation */

/* reading from register */
if (match->is_fp) {
int done = 0;
#if defined(__riscv_flen)
#if __riscv_flen >= 32
if (match->width == 4) {
read_f32(regnum, buff.w);
done = 1;
}
#endif // __riscv_flen >= 32
#if __riscv_flen >= 64
if (match->width == 8) {
read_f64(regnum, buff.d);
done = 1;
}
#endif // __riscv_flen >= 64
#endif // defined(__riscv_flen)
if (!done)
redirect_trap();
} else {
buff.v = tf->gpr[regnum];
}

/* writing to memory by bytes prevents misaligned
* memory access */
for (int i = 0; i < match->width; i++) {
uint8_t *addr = (uint8_t *)(tf->badvaddr + i);
mprv_write_u8(addr, buff.b[i]);
}
}
}
4 changes: 0 additions & 4 deletions src/arch/riscv/misc.c
Expand Up @@ -16,7 +16,3 @@
void init_timer(void)
{
}

void udelay(unsigned int n)
{
}
53 changes: 53 additions & 0 deletions src/arch/riscv/ramstage.S
@@ -0,0 +1,53 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2018 HardenedLinux
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include <arch/encoding.h>
#include <mcall.h>

.section ".text._start", "ax", %progbits
.globl _start
_start:
# initialize stack point for each hart
# and the stack must be page-aligned.
# 0xDEADBEEF used to check stack overflow
csrr a0, mhartid
la t0, _stack
slli t1, a0, RISCV_PGSHIFT
add t0, t0, t1
li t1, 0xDEADBEEF
sd t1, 0(t0)
li t1, RISCV_PGSIZE - HLS_SIZE
add sp, t0, t1

# initialize hart-local storage
csrr a0, mhartid
call hls_init

# initialize entry of interrupt/exception
la t0, trap_entry
csrw mtvec, t0

# clear any pending interrupts
csrwi mip, 0

call exit_car
# set up the mstatus register for VM
call mstatus_init
tail main

# These codes need to be implemented on a specific SoC
.weak exit_car
exit_car:
ret
76 changes: 14 additions & 62 deletions src/arch/riscv/trap_handler.c
Expand Up @@ -166,12 +166,9 @@ void trap_handler(trapframe *tf)
print_trap_information(tf);
break;
case CAUSE_MISALIGNED_LOAD:
print_trap_information(tf);
handle_misaligned_load(tf);
return;
case CAUSE_MISALIGNED_STORE:
print_trap_information(tf);
handle_misaligned_store(tf);
handle_misaligned(tf);
return;
default:
printk(BIOS_EMERG, "================================\n");
Expand All @@ -184,62 +181,17 @@ void trap_handler(trapframe *tf)
die("Can't recover from trap. Halting.\n");
}

static uint32_t fetch_instruction(uintptr_t vaddr) {
printk(BIOS_SPEW, "fetching instruction at 0x%016zx\n", (size_t)vaddr);
return mprv_read_u32((uint32_t *) vaddr);
}

void handle_misaligned_load(trapframe *tf) {
printk(BIOS_DEBUG, "Trapframe ptr: %p\n", tf);
uintptr_t faultingInstructionAddr = tf->epc;
insn_t faultingInstruction = fetch_instruction(faultingInstructionAddr);
printk(BIOS_DEBUG, "Faulting instruction: 0x%x\n", faultingInstruction);
insn_t widthMask = 0x7000;
insn_t memWidth = (faultingInstruction & widthMask) >> 12;
insn_t destMask = 0xF80;
insn_t destRegister = (faultingInstruction & destMask) >> 7;
printk(BIOS_DEBUG, "Width: %d bits\n", (1 << memWidth) * 8);
if (memWidth == 3) {
// load double, handle the issue
void* badAddress = (void*) tf->badvaddr;
uint64_t value = 0;
for (int i = 0; i < 8; i++) {
value <<= 8;
value += mprv_read_u8(badAddress+i);
}
tf->gpr[destRegister] = value;
} else {
// panic, this should not have happened
die("Code should not reach this path, misaligned on a non-64 bit store/load\n");
}

// return to where we came from
write_csr(mepc, read_csr(mepc) + 4);
}

void handle_misaligned_store(trapframe *tf) {
printk(BIOS_DEBUG, "Trapframe ptr: %p\n", tf);
uintptr_t faultingInstructionAddr = tf->epc;
insn_t faultingInstruction = fetch_instruction(faultingInstructionAddr);
printk(BIOS_DEBUG, "Faulting instruction: 0x%x\n", faultingInstruction);
insn_t widthMask = 0x7000;
insn_t memWidth = (faultingInstruction & widthMask) >> 12;
insn_t srcMask = 0x1F00000;
insn_t srcRegister = (faultingInstruction & srcMask) >> 20;
printk(BIOS_DEBUG, "Width: %d bits\n", (1 << memWidth) * 8);
if (memWidth == 3) {
// store double, handle the issue
void* badAddress = (void*) tf->badvaddr;
uint64_t value = tf->gpr[srcRegister];
for (int i = 0; i < 8; i++) {
mprv_write_u8(badAddress+i, value);
value >>= 8;
}
} else {
// panic, this should not have happened
die("Code should not reach this path, misaligned on a non-64 bit store/load\n");
}

// return to where we came from
write_csr(mepc, read_csr(mepc) + 4);
/* This function used to redirect trap to s-mode. */
void redirect_trap(void)
{
write_csr(sbadaddr, read_csr(mbadaddr));
write_csr(sepc, read_csr(mepc));
write_csr(scause, read_csr(mcause));
write_csr(mepc, read_csr(stvec));

uintptr_t status = read_csr(mstatus);
uintptr_t mpp = EXTRACT_FIELD(status, MSTATUS_MPP);
status = INSERT_FIELD(status, MSTATUS_MPP, 1);
status = INSERT_FIELD(status, MSTATUS_SPP, mpp & 1);
write_csr(mstatus, status);
}
13 changes: 7 additions & 6 deletions src/arch/riscv/virtual_memory.c
Expand Up @@ -14,6 +14,7 @@
* GNU General Public License for more details.
*/

#include <arch/cpu.h>
#include <arch/encoding.h>
#include <stdint.h>
#include <vm.h>
Expand Down Expand Up @@ -42,7 +43,6 @@ void mstatus_init(void)
uintptr_t ms = 0;

ms = INSERT_FIELD(ms, MSTATUS_FS, 3);
ms = INSERT_FIELD(ms, MSTATUS_XS, 3);
write_csr(mstatus, ms);

// clear any pending timer interrupts.
Expand All @@ -52,11 +52,12 @@ void mstatus_init(void)
// all other supervisor interrupts.
set_csr(mie, MIP_MTIP | MIP_STIP | MIP_SSIP);

// Delegate supervisor timer and other interrupts
// to supervisor mode.
set_csr(mideleg, MIP_STIP | MIP_SSIP);

set_csr(medeleg, delegate);
// Delegate supervisor timer and other interrupts to supervisor mode,
// if supervisor mode is supported.
if (supports_extension('S')) {
set_csr(mideleg, MIP_STIP | MIP_SSIP);
set_csr(medeleg, delegate);
}

// Enable all user/supervisor-mode counters using
// v1.10 register addresses.
Expand Down
2 changes: 2 additions & 0 deletions src/arch/x86/Makefile.inc
Expand Up @@ -145,6 +145,7 @@ $(objgenerated)/bootblock.ld: $$(filter-out $(call src-to-obj,bootblock,src/arch
cat $^ >> $@.tmp
mv $@.tmp $@

-include $(objgenerated)/bootblock.inc.d
$(objgenerated)/bootblock.inc: $(src)/arch/x86/$(subst ",,$(CONFIG_BOOTBLOCK_SOURCE)) $(objutil)/romcc/romcc $(OPTION_TABLE_H) $(KCONFIG_AUTOHEADER)
# The open quote in the subst messes with syntax highlighting. Fix it - ")
@printf " ROMCC $(subst $(obj)/,,$(@))\n"
Expand Down Expand Up @@ -291,6 +292,7 @@ ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpigen_dsm.c
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi_device.c
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi_pld.c
ramstage-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.c
ramstage-$(CONFIG_ACPI_BERT) += acpi_bert_storage.c
ramstage-y += boot.c
ramstage-y += c_start.S
ramstage-y += cbmem.c
Expand Down
23 changes: 23 additions & 0 deletions src/arch/x86/acpi.c
Expand Up @@ -958,6 +958,27 @@ void acpi_write_hest(acpi_hest_t *hest,
header->checksum = acpi_checksum((void *)hest, header->length);
}

/* ACPI 3.0b */
void acpi_write_bert(acpi_bert_t *bert, uintptr_t region, size_t length)
{
acpi_header_t *header = &(bert->header);

memset(bert, 0, sizeof(acpi_bert_t));

memcpy(header->signature, "BERT", 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);
header->length += sizeof(acpi_bert_t);
header->revision = get_acpi_table_revision(BERT);

bert->error_region = region;
bert->region_length = length;

/* Calculate checksums. */
header->checksum = acpi_checksum((void *)bert, header->length);
}

#if IS_ENABLED(CONFIG_COMMON_FADT)
void acpi_create_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt)
{
Expand Down Expand Up @@ -1296,6 +1317,8 @@ int get_acpi_table_revision(enum acpi_tables table)
return 1;
case NHLT:
return 5;
case BERT:
return 1;
default:
return -1;
}
Expand Down
570 changes: 570 additions & 0 deletions src/arch/x86/acpi_bert_storage.c

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/arch/x86/acpi_device.c
Expand Up @@ -166,6 +166,15 @@ const char *acpi_device_path_join(struct device *dev, const char *name)
return buf;
}

int acpi_device_status(const struct device *dev)
{
if (!dev->enabled)
return ACPI_STATUS_DEVICE_ALL_OFF;
if (dev->hidden)
return ACPI_STATUS_DEVICE_HIDDEN_ON;
return ACPI_STATUS_DEVICE_ALL_ON;
}

/* ACPI 6.1 section 6.4.3.6: Extended Interrupt Descriptor */
void acpi_device_write_interrupt(const struct acpi_irq *irq)
{
Expand Down
2 changes: 1 addition & 1 deletion src/arch/x86/acpigen.c
Expand Up @@ -1453,7 +1453,7 @@ void acpigen_write_rom(void *bios, const size_t length)
ASSERT(bios)
ASSERT(length)

/* Method (_ROM, 2, NotSerialized) */
/* Method (_ROM, 2, Serialized) */
acpigen_write_method_serialized("_ROM", 2);

/* OperationRegion("ROMS", SYSTEMMEMORY, current, length) */
Expand Down
70 changes: 70 additions & 0 deletions src/arch/x86/include/arch/acpi.h
Expand Up @@ -58,6 +58,8 @@
#include <rules.h>
#include <commonlib/helpers.h>
#include <device/device.h>
#include <uuid.h>
#include <cper.h>

#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */
#define ACPI_TABLE_CREATOR "COREBOOT" /* Must be exactly 8 bytes long! */
Expand Down Expand Up @@ -642,6 +644,73 @@ typedef struct acpi_hest_hen {
u32 error_threshold_win;
} __packed acpi_hest_hen_t;

/* BERT (Boot Error Record Table) */
typedef struct acpi_bert {
struct acpi_table_header header;
u32 region_length;
u64 error_region;
} __packed acpi_bert_t;

/* Generic Error Data Entry (ACPI spec v6.2-A, table 382) */
typedef struct acpi_hest_generic_data {
guid_t section_type;
u32 error_severity;
u16 revision;
u8 validation_bits;
u8 flags;
u32 data_length;
guid_t fru_id;
u8 fru_text[20];
/* error data */
} __packed acpi_hest_generic_data_t;

/* Generic Error Data Entry (ACPI spec v6.2-A, table 382) */
typedef struct acpi_hest_generic_data_v300 {
guid_t section_type;
u32 error_severity;
u16 revision;
u8 validation_bits;
u8 flags; /* see CPER Section Descriptor, Flags field */
u32 data_length;
guid_t fru_id;
u8 fru_text[20];
cper_timestamp_t timestamp;
/* error data */
} __packed acpi_hest_generic_data_v300_t;
#define HEST_GENERIC_ENTRY_V300 0x300

/* Both Generic Error Status & Generic Error Data Entry, Error Severity field */
#define ACPI_GENERROR_SEV_RECOVERABLE 0
#define ACPI_GENERROR_SEV_FATAL 1
#define ACPI_GENERROR_SEV_CORRECTED 2
#define ACPI_GENERROR_SEV_NONE 3

/* Generic Error Data Entry, Validation Bits field */
#define ACPI_GENERROR_VALID_FRUID BIT(0)
#define ACPI_GENERROR_VALID_FRUID_TEXT BIT(1)
#define ACPI_GENERROR_VALID_TIMESTAMP BIT(2)

/* Generic Error Status Block (ACPI spec v6.2-A, table 381) */
typedef struct acpi_generic_error_status {
u32 block_status;
u32 raw_data_offset; /* must follow any generic entries */
u32 raw_data_length;
u32 data_length; /* generic data */
u32 error_severity;
/* Generic Error Data structures, zero or more entries */
} __packed acpi_generic_error_status_t;

/* Generic Status Block, Block Status values */
#define GENERIC_ERR_STS_UNCORRECTABLE_VALID BIT(0)
#define GENERIC_ERR_STS_CORRECTABLE_VALID BIT(1)
#define GENERIC_ERR_STS_MULT_UNCORRECTABLE BIT(2)
#define GENERIC_ERR_STS_MULT_CORRECTABLE BIT(3)
#define GENERIC_ERR_STS_ENTRY_COUNT_SHIFT 4
#define GENERIC_ERR_STS_ENTRY_COUNT_MAX 0x3ff
#define GENERIC_ERR_STS_ENTRY_COUNT_MASK \
(GENERIC_ERR_STS_ENTRY_COUNT_MAX \
<< GENERIC_ERR_STS_ENTRY_COUNT_SHIFT)

typedef struct acpi_cstate {
u8 ctype;
u16 latency;
Expand Down Expand Up @@ -689,6 +758,7 @@ unsigned long acpi_fill_madt(unsigned long current);
unsigned long acpi_fill_mcfg(unsigned long current);
unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t *ivrs, unsigned long current);
void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id);
void acpi_write_bert(acpi_bert_t *bert, uintptr_t region, size_t length);
void acpi_create_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt);
#if IS_ENABLED(CONFIG_COMMON_FADT)
void acpi_fill_fadt(acpi_fadt_t *fadt);
Expand Down
1 change: 1 addition & 0 deletions src/arch/x86/include/arch/acpi_device.h
Expand Up @@ -66,6 +66,7 @@ const char *acpi_device_name(struct device *dev);
const char *acpi_device_path(struct device *dev);
const char *acpi_device_scope(struct device *dev);
const char *acpi_device_path_join(struct device *dev, const char *name);
int acpi_device_status(const struct device *dev);

/*
* ACPI Descriptor for extended Interrupt()
Expand Down
143 changes: 143 additions & 0 deletions src/arch/x86/include/arch/bert_storage.h
@@ -0,0 +1,143 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2018 Advanced Micro Devices, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#ifndef _BERT_STORAGE_H_
#define _BERT_STORAGE_H_

#include <stdint.h>
#include <arch/acpi.h>

/* Items in the BERT region
*
* * Each item begins with a Generic Error Status Block
* * Zero or more Generic Error Data Entries follow, and
* are associated with the Status Block
* * Each Generic Error Data Entry must be a certain type,
* as defined in the UEFI CPER appendix
* * Each type may allow zero or more additional sets of
* data, e.g. error descriptions, or processor contexts.
*
* In the example layout below, there are three BERT region
* entries. The first two are a single error. The third
* has two errors, with one providing a variable amount
* of additional information.
*
* +====================================================================+
* | Generic Error | Generic Error | Platform Memory Error |
* | Status | Data Entry | |
* |====================================================================|
* | Generic Error | Generic Error | Generic Processor Error |
* | Status | Data Entry | |
* |====================================================================|
* | Generic Error | Generic Error | IA32/X64 Processor Error |
* | Status | Data Entry | +----------------------------+
* | | | | Error Check Data |
* | | | +----------------------------+
* | | | | MSR Context |
* | | | +----------------------------+
* | | | | X64 Registers Context |
* | +-----------------+----+----------------------------+
* | | Generic Error | PCI Express Error |
* | | Data Entry | |
* +--------------------------------------------------------------------+
*/

/* Get implementation-specific reserved area for generating BERT info */
void bert_reserved_region(void **start, size_t *size);

/* Get the region where BERT error structures have been constructed for
* generating the ACPI table
*/
void bert_errors_region(void **start, size_t *size);

/* Get amount of available storage left for error info */
size_t bert_storage_remaining(void);
/* Find if errors were added, a BERT region is present, and ACPI table needed */
int bert_errors_present(void);

/* Get the number of entries accociated with status */
static inline size_t bert_entry_count(acpi_generic_error_status_t *status)
{
return (status->block_status & GENERIC_ERR_STS_ENTRY_COUNT_MASK)
>> GENERIC_ERR_STS_ENTRY_COUNT_SHIFT;
}

/* Increment the number of entries this status describes */
static inline void bert_bump_entry_count(acpi_generic_error_status_t *status)
{
int count;

count = bert_entry_count(status) + 1;
status->block_status &= ~GENERIC_ERR_STS_ENTRY_COUNT_MASK;
status->block_status |= count << GENERIC_ERR_STS_ENTRY_COUNT_SHIFT;
}

/* Find the address of the first Generic Data structure from its status entry */
static inline acpi_hest_generic_data_v300_t *acpi_hest_generic_data3(
acpi_generic_error_status_t *status)
{
return (acpi_hest_generic_data_v300_t *)
((u8 *)status + sizeof(*status));
}

/* Find the address of a Generic Data structure's CPER error record section */
#define section_of_acpientry(A, B) ((typeof(A))((u8 *)(B) + sizeof(*(B))))


/* Add a context to an existing IA32/X64-type error entry */
cper_ia32x64_context_t *new_cper_ia32x64_ctx(
acpi_generic_error_status_t *status,
cper_ia32x64_proc_error_section_t *x86err, int type, int num);

/* Helper to add an MSR context to an existing IA32/X64-type error entry */
cper_ia32x64_context_t *cper_new_ia32x64_context_msr(
acpi_generic_error_status_t *status,
cper_ia32x64_proc_error_section_t *x86err, u32 addr, int num);

/* Add check info to an existing IA32/X64-type error entry */
cper_ia32x64_proc_error_info_t *new_cper_ia32x64_check(
acpi_generic_error_status_t *status,
cper_ia32x64_proc_error_section_t *x86err,
enum cper_x86_check_type type);

/* Append a new ACPI Generic Error Data Entry plus CPER Error Section to an
* existing ACPI Generic Error Status Block. The caller is responsible for
* the setting the status and entry severity, as well as populating all fields
* of the error section.
*/
acpi_hest_generic_data_v300_t *bert_append_error_datasection(
acpi_generic_error_status_t *status, guid_t *guid);

/* Helper to append an ACPI Generic Error Data Entry plus a CPER Processor
* Generic Error Section. As many fields are populated as possible for the
* caller.
*/
acpi_hest_generic_data_v300_t *bert_append_genproc(
acpi_generic_error_status_t *status);

/* Helper to append an ACPI Generic Error Data Entry plus a CPER IA32/X64
* Processor Error Section. As many fields are populated as possible for the
* caller.
*/
acpi_hest_generic_data_v300_t *bert_append_ia32x64(
acpi_generic_error_status_t *status);

/* Add a new event to the BERT region. An event consists of an ACPI Error
* Status Block, a Generic Error Data Entry, and an associated CPER Error
* Section.
*/
acpi_generic_error_status_t *bert_new_event(guid_t *guid);

#endif /* _BERT_STORAGE_H_ */
1 change: 0 additions & 1 deletion src/arch/x86/include/arch/cpu.h
Expand Up @@ -242,7 +242,6 @@ static inline void get_fms(struct cpuinfo_x86 *c, uint32_t tfms)
#endif

#define asmlinkage __attribute__((regparm(0)))
#define alwaysinline inline __attribute__((always_inline))

#ifndef __ROMCC__
/*
Expand Down
4 changes: 3 additions & 1 deletion src/arch/x86/include/arch/hlt.h
Expand Up @@ -20,7 +20,9 @@ static void hlt(void)
__builtin_hlt();
}
#else
static inline __attribute__((always_inline)) void hlt(void)
#include <compiler.h>

static __always_inline void hlt(void)
{
asm("hlt");
}
Expand Down
47 changes: 24 additions & 23 deletions src/arch/x86/include/arch/io.h
Expand Up @@ -14,6 +14,7 @@
#ifndef _ASM_IO_H
#define _ASM_IO_H

#include <compiler.h>
#include <endian.h>
#include <stdint.h>
#include <rules.h>
Expand Down Expand Up @@ -156,52 +157,52 @@ static inline void insl(uint16_t port, void *addr, unsigned long count)
);
}

static inline __attribute__((always_inline)) uint8_t read8(
static __always_inline uint8_t read8(
const volatile void *addr)
{
return *((volatile uint8_t *)(addr));
}

static inline __attribute__((always_inline)) uint16_t read16(
static __always_inline uint16_t read16(
const volatile void *addr)
{
return *((volatile uint16_t *)(addr));
}

static inline __attribute__((always_inline)) uint32_t read32(
static __always_inline uint32_t read32(
const volatile void *addr)
{
return *((volatile uint32_t *)(addr));
}

#ifndef __ROMCC__
static inline __attribute__((always_inline)) uint64_t read64(
static __always_inline uint64_t read64(
const volatile void *addr)
{
return *((volatile uint64_t *)(addr));
}
#endif

static inline __attribute__((always_inline)) void write8(volatile void *addr,
static __always_inline void write8(volatile void *addr,
uint8_t value)
{
*((volatile uint8_t *)(addr)) = value;
}

static inline __attribute__((always_inline)) void write16(volatile void *addr,
static __always_inline void write16(volatile void *addr,
uint16_t value)
{
*((volatile uint16_t *)(addr)) = value;
}

static inline __attribute__((always_inline)) void write32(volatile void *addr,
static __always_inline void write32(volatile void *addr,
uint32_t value)
{
*((volatile uint32_t *)(addr)) = value;
}

#ifndef __ROMCC__
static inline __attribute__((always_inline)) void write64(volatile void *addr,
static __always_inline void write64(volatile void *addr,
uint64_t value)
{
*((volatile uint64_t *)(addr)) = value;
Expand Down Expand Up @@ -268,7 +269,7 @@ typedef u32 device_t;
#include <arch/pci_io_cfg.h>
#include <arch/pci_mmio_cfg.h>

static inline __attribute__((always_inline))
static __always_inline
uint8_t pci_read_config8(pci_devfn_t dev, unsigned int where)
{
if (IS_ENABLED(CONFIG_MMCONF_SUPPORT))
Expand All @@ -277,7 +278,7 @@ uint8_t pci_read_config8(pci_devfn_t dev, unsigned int where)
return pci_io_read_config8(dev, where);
}

static inline __attribute__((always_inline))
static __always_inline
uint16_t pci_read_config16(pci_devfn_t dev, unsigned int where)
{
if (IS_ENABLED(CONFIG_MMCONF_SUPPORT))
Expand All @@ -286,7 +287,7 @@ uint16_t pci_read_config16(pci_devfn_t dev, unsigned int where)
return pci_io_read_config16(dev, where);
}

static inline __attribute__((always_inline))
static __always_inline
uint32_t pci_read_config32(pci_devfn_t dev, unsigned int where)
{
if (IS_ENABLED(CONFIG_MMCONF_SUPPORT))
Expand All @@ -295,7 +296,7 @@ uint32_t pci_read_config32(pci_devfn_t dev, unsigned int where)
return pci_io_read_config32(dev, where);
}

static inline __attribute__((always_inline))
static __always_inline
void pci_write_config8(pci_devfn_t dev, unsigned int where, uint8_t value)
{
if (IS_ENABLED(CONFIG_MMCONF_SUPPORT))
Expand All @@ -304,7 +305,7 @@ void pci_write_config8(pci_devfn_t dev, unsigned int where, uint8_t value)
pci_io_write_config8(dev, where, value);
}

static inline __attribute__((always_inline))
static __always_inline
void pci_write_config16(pci_devfn_t dev, unsigned int where, uint16_t value)
{
if (IS_ENABLED(CONFIG_MMCONF_SUPPORT))
Expand All @@ -313,7 +314,7 @@ void pci_write_config16(pci_devfn_t dev, unsigned int where, uint16_t value)
pci_io_write_config16(dev, where, value);
}

static inline __attribute__((always_inline))
static __always_inline
void pci_write_config32(pci_devfn_t dev, unsigned int where, uint32_t value)
{
if (IS_ENABLED(CONFIG_MMCONF_SUPPORT))
Expand Down Expand Up @@ -365,62 +366,62 @@ static inline pci_devfn_t pci_locate_device_on_bus(unsigned int pci_id,
}

/* Generic functions for pnp devices */
static inline __attribute__((always_inline)) void pnp_write_config(
static __always_inline void pnp_write_config(
pnp_devfn_t dev, uint8_t reg, uint8_t value)
{
unsigned int port = dev >> 8;
outb(reg, port);
outb(value, port + 1);
}

static inline __attribute__((always_inline)) uint8_t pnp_read_config(
static __always_inline uint8_t pnp_read_config(
pnp_devfn_t dev, uint8_t reg)
{
unsigned int port = dev >> 8;
outb(reg, port);
return inb(port + 1);
}

static inline __attribute__((always_inline))
static __always_inline
void pnp_set_logical_device(pnp_devfn_t dev)
{
unsigned int device = dev & 0xff;
pnp_write_config(dev, 0x07, device);
}

static inline __attribute__((always_inline))
static __always_inline
void pnp_set_enable(pnp_devfn_t dev, int enable)
{
pnp_write_config(dev, 0x30, enable?0x1:0x0);
}

static inline __attribute__((always_inline))
static __always_inline
int pnp_read_enable(pnp_devfn_t dev)
{
return !!pnp_read_config(dev, 0x30);
}

static inline __attribute__((always_inline))
static __always_inline
void pnp_set_iobase(pnp_devfn_t dev, unsigned int index, unsigned int iobase)
{
pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
pnp_write_config(dev, index + 1, iobase & 0xff);
}

static inline __attribute__((always_inline))
static __always_inline
uint16_t pnp_read_iobase(pnp_devfn_t dev, unsigned int index)
{
return ((uint16_t)(pnp_read_config(dev, index)) << 8)
| pnp_read_config(dev, index + 1);
}

static inline __attribute__((always_inline))
static __always_inline
void pnp_set_irq(pnp_devfn_t dev, unsigned int index, unsigned int irq)
{
pnp_write_config(dev, index, irq);
}

static inline __attribute__((always_inline))
static __always_inline
void pnp_set_drq(pnp_devfn_t dev, unsigned int index, unsigned int drq)
{
pnp_write_config(dev, index, drq & 0xff);
Expand Down