| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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__ */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,3 +28,7 @@ config ARCH_ROMSTAGE_RISCV | |
| config ARCH_RAMSTAGE_RISCV | ||
| bool | ||
| default n | ||
|
|
||
| config RISCV_USE_ARCH_TIMER | ||
| bool | ||
| default n | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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))); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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]); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,3 @@ | |
| void init_timer(void) | ||
| { | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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_ */ |