diff --git a/.gitignore b/.gitignore index 8e11e9aa..82e64a99 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ *.mk /return_pass /return_fail +*.specs diff --git a/Makefile.am b/Makefile.am index 6371577f..01747c66 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,20 +8,39 @@ %.c: mee/machine/@MACHINE_NAME@.h %.S: mee/machine/@MACHINE_NAME@.h %.o: mee/machine/@MACHINE_NAME@.h +%.c: riscv__menv__mee.specs +%.S: riscv__menv__mee.specs +%.o: riscv__menv__mee.specs +%.c: riscv__mmachine__@MACHINE_NAME@.specs +%.S: riscv__mmachine__@MACHINE_NAME@.specs +%.o: riscv__mmachine__@MACHINE_NAME@.specs # Every test depends on the generated linker script. -$(check_PROGRAMS): mee-@MACHINE_NAME@.lds +$(check_PROGRAMS): riscv__mmachine__@MACHINE_NAME@.lds # Every test depends on the freshly-compiled library. -$(check_PROGRAMS): libmee-@MACHINE_NAME@.a +$(check_PROGRAMS): libriscv__mmachine__@MACHINE_NAME@.a # Generates a linker script that's more reasonable that whatever GCC's default # is. ldsdir = $(libdir) -lds_DATA = mee-@MACHINE_NAME@.lds -mee-@MACHINE_NAME@.lds: @LDSCRIPT_GENERATOR@ @MACHINE_NAME@.dtb +lds_DATA = riscv__mmachine__@MACHINE_NAME@.lds +riscv__mmachine__@MACHINE_NAME@.lds: @LDSCRIPT_GENERATOR@ @MACHINE_NAME@.dtb $< --dtb $(filter %.dtb,$^) --linker $@ +# Generates a SPEC file that sets a reasonable set of default options for this +# build. +specdir = $(libdir) +spec_DATA = + +spec_DATA += riscv__mmachine__@MACHINE_NAME@.specs +riscv__mmachine__@MACHINE_NAME@.specs: @SPECS_GENERATOR@ @MACHINE_NAME@.dtb + $< --dtb $(filter %.dtb,$^) --specs $@ --prefix @prefix@ --machine @MACHINE_NAME@ + +spec_DATA += riscv__menv__mee.specs +riscv__menv__mee.specs: riscv__menv__mee.specs.in + cat $^ > $@ + # In order to generate code that's actually compatible with a machine we must # pass the march and mabi arguments to GCC that coorespond to the hardware. # This is handled by generating a makefile fragment, including it, and then @@ -45,6 +64,7 @@ nobase_include_HEADERS = \ mee/compiler.h \ mee/clock.h \ mee/io.h \ + mee/machine.h \ mee/shutdown.h \ mee/tty.h \ mee/uart.h @@ -64,14 +84,12 @@ mee/machine/@MACHINE_NAME@.h: @MEE_HEADER_GENERATOR@ @MACHINE_NAME@.dtb # Everything in here is compiled into a single library, which contains all the # source files in the project. It's named for one specific machine, which GCC # uses to select the target machine that this MEE implementation points at. -lib_LIBRARIES = libmee-@MACHINE_NAME@.a +lib_LIBRARIES = libriscv__mmachine__@MACHINE_NAME@.a -libmee_@MACHINE_NAME@_a_CFLAGS = -mmee-machine=@MACHINE_NAME@ -libmee_@MACHINE_NAME@_a_CFLAGS += -ffunction-sections -fdata-sections -libmee_@MACHINE_NAME@_a_CFLAGS += -march=$(FRAMEWORK_BOARD_DTS_MARCH) -mabi=$(FRAMEWORK_BOARD_DTS_MABI) -libmee_@MACHINE_NAME@_a_CCASFLAGS = $(libmee_@MACHINE_NAME@_a_CFLAGS) -DASSEMBLY +libriscv__mmachine__@MACHINE_NAME@_a_CFLAGS = -menv=mee -mmachine=@MACHINE_NAME@ +libriscv__mmachine__@MACHINE_NAME@_a_CCASFLAGS = -menv=mee -mmachine=@MACHINE_NAME@ -libmee_@MACHINE_NAME@_a_SOURCES = \ +libriscv__mmachine__@MACHINE_NAME@_a_SOURCES = \ src/drivers/fixed-clock.c \ src/drivers/sifive,fe310-g000,hfrosc.c \ src/drivers/sifive,fe310-g000,hfxosc.c \ @@ -92,37 +110,28 @@ check_PROGRAMS = # The simplest possible pair of tests: one that passes and one that fails check_PROGRAMS += return_pass return_pass_SOURCES = test/return_pass.c -return_pass_CFLAGS = -mmee-machine=@MACHINE_NAME@ -return_pass_CFLAGS += -ffunction-sections -fdata-sections -return_pass_CFLAGS += -march=$(FRAMEWORK_BOARD_DTS_MARCH) -mabi=$(FRAMEWORK_BOARD_DTS_MABI) +return_pass_CFLAGS = -menv=mee -mmachine=@MACHINE_NAME@ return_pass_LDFLAGS = -L. -Wl,--gc-sections -Wl,-Map=return_pass.map check_PROGRAMS += return_fail return_fail_SOURCES = test/return_fail.c -return_fail_CFLAGS = -mmee-machine=@MACHINE_NAME@ -return_fail_CFLAGS += -ffunction-sections -fdata-sections -return_fail_CFLAGS += -march=$(FRAMEWORK_BOARD_DTS_MARCH) -mabi=$(FRAMEWORK_BOARD_DTS_MABI) +return_fail_CFLAGS = -menv=mee -mmachine=@MACHINE_NAME@ return_fail_LDFLAGS = -L. -Wl,--gc-sections -Wl,-Map=return_fail.map # A simple "Hello, World!" program that directly uses the MEE interface to # print to the serial terminal. check_PROGRAMS += hello hello_SOURCES = test/hello.c -hello_CFLAGS = -mmee-machine=@MACHINE_NAME@ -hello_CFLAGS += -ffunction-sections -fdata-sections -hello_CFLAGS += -march=$(FRAMEWORK_BOARD_DTS_MARCH) -mabi=$(FRAMEWORK_BOARD_DTS_MABI) +hello_CFLAGS = -menv=mee -mmachine=@MACHINE_NAME@ hello_LDFLAGS = -L. -Wl,--gc-sections -Wl,-Map=hello.map check_PROGRAMS += pll_set_hz pll_set_hz_SOURCES = test/pll_set_hz.c -pll_set_hz_CFLAGS = -mmee-machine=@MACHINE_NAME@ -pll_set_hz_CFLAGS += -ffunction-sections -fdata-sections -pll_set_hz_CFLAGS += -march=$(FRAMEWORK_BOARD_DTS_MARCH) -mabi=$(FRAMEWORK_BOARD_DTS_MABI) +pll_set_hz_CFLAGS = -menv=mee -mmachine=@MACHINE_NAME@ pll_set_hz_LDFLAGS = -L. -Wl,--gc-sections -Wl,-Map=pll_set_hz.map # Extra clean targets clean-local: -rm -rf @MACHINE_NAME@.mk -rm -rf mee/machine/@MACHINE_NAME@.h @MACHINE_NAME@.dtb mee-@MACHINE_NAME@.lds - -rm -rf return_pass.map return_fail.map - -rm -rf hello.map + -rm -rf *.map *.specs diff --git a/README.md b/README.md index 1faf6442..dacadb4c 100644 --- a/README.md +++ b/README.md @@ -6,69 +6,3 @@ This repository provides a MEE that is designed to run on SiFive's Freedom platform devices. As the MEE runs at machine mode it's not designed with binary compatibility in mind but is instead tailored to a specific machine. - -## Describing a Target Machine - -The MEE is not natively self-hosting and is therefor designed to be -cross compiled for a target machine. This target machine is described -by a device tree file, which is then provided to the MEE's build scripts -in order to parameterize it for the target machine. - -## MEE Interface - -The whole point of the MEE is to define an interface against which -portable programs can be written. Since this is machine-mode software -the degree of portability is very limited, but nontheless some about of -portability can reasonably be achieved. Specifically, that means - -* The existence of devices can be statically probed. -* Devices exist behind a well-defined API that abstracts away their - physical addresses. - -This allows portable software to be written against the MEE that will -run on all SiFive systems that are capable of meeting its requirements. - -### Internal Symbols vs Public Symbols - -Any symbol beginning with `__mee_` is internal to the MEE and must not -be called or defined by user code. Symbols beginning with `mee_` are -public interfaces and can be considered to be a stable API. The best -documentation for most of these symbols are found in the code, but some -is listed below. - -As the MEE is desgined for bare-metal development there is no stable ABI. - -### Pre-C Environment - -The MEE handles entering the C library's start routine, which is defined -by the symbol `_start`. This symbol must be defined by the C library in -order to allow the MEE to do anything meaningful. - -The MEE follows the standard RISC-V bootloader ABI when calling -`_start`: - -* `a0` contains the hart ID. -* `a1` contains a pointer to the machine description. The MEE always - sets this to NULL, as machines are described staticly. -* `a2` contains a callback that should be called from within the child - environment after it has initialized itself. The MEE always sets this - to NULL, as initialization is performed using constructors. - -This can be described as a the C function `void _start(long hartid, -unsigned char *dtb, void (*after_init)(void))'. Note that the MEE does -not initialize a C environment and therefor this cannot actually be a C -function -- for example, there may not be a stack. - -### Special Sections - -Many special sections are utilized by this MEE implementation in order -to allow compact code to be generated while still providing API -guarntees. These sections are all named such that standard linker -scripts will produce the correct answer, albeit at some performance or -code size cost. A list of interesting sections is described below: - -* `.text.mee.nop`: Every sub-section in here will consist of exactly the - same C function: `int func(...) { return -1; }`. Functions that look - like this are frequently weakly referenced in order to provide default - implementations of MBI functionality that cannot be implemented on the - given target. diff --git a/configure.ac b/configure.ac index 83ea264c..bcaace81 100644 --- a/configure.ac +++ b/configure.ac @@ -139,6 +139,24 @@ AS_IF([test "x$MAKEATTRIBUTES_GENERATOR" != "xno"], [AC_MSG_ERROR([Unable to find freedom-makeattributes-generator, either place it in PATH or try the --with-makeattributes-generator argument.])] ) +# Allows users to specify a path to freedom-mee_specs-generator, which +# generates GCC spec files to control the compilation of MEE based targets. +AC_ARG_WITH([mee_specs-generator], + [AS_HELP_STRING([--with-mee_specs-generator=PATH], [Use the given path to freedom-mee_specs-generator])], + [], + [with_mee_specs_generator=check] +) + +AC_ARG_VAR(SPECS_GENERATOR, [The absolute path of the freedom-mee_specs-generator]) +AS_IF([test "x$with_mee_specs_generator" == "xcheck"], + [AC_PATH_PROG(SPECS_GENERATOR, freedom-mee_specs-generator, [no])], + [SPECS_GENERATOR=$with_mee_specs_generator] +) +AS_IF([test "x$SPECS_GENERATOR" != "xno"], + [AC_SUBST([SPECS_GENERATOR], "$SPECS_GENERATOR")], + [AC_MSG_ERROR([Unable to find freedom-mee_specs-generator, either place it in PATH or try the --with-mee_specs-generator argument.])] +) + # Generates the remainder of the build system. AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/doc/mee-spec.md b/doc/mee-spec.md new file mode 100644 index 00000000..5af5976e --- /dev/null +++ b/doc/mee-spec.md @@ -0,0 +1,145 @@ +# MEE Specification + +The MEE is designed to provide a source-level compatibility for +bare-metal code between platforms. This specification defines the +publicly available API. The intent is that this API is stable so users +can rely on it not changing, but we're not going to make any guarantees +about it until our 1.0.0 release. + +Note that the MEE does not define an ABI -- specifically that means that +binaries will not be compatible between different versions of the MBI, +or between different platforms. + +## User API + +The core of the MEE is a C API that is designed to allow programmers to +write portable bare-metal embedded code. + +Any symbol beginning with `__mee_` is internal to the MEE and must not +be called or defined by user code. Symbols beginning with `mee_` are +public interfaces and can be considered to be a stable API. The best +documentation for most of these symbols are found in the code, but some +is listed below. + +### Clock Interface + +The clock interface allows for controlling the rate of various clocks in +the system. Clocks are defined by a pointer to a `struct mee_clock`, the +contents of which is implementation defined. Users of the clock +interface must call the functions defined below in order to interact +with a `struct mee_clock *`. + +Note that no mechanism for obtaining a pointer to a `struct mee_clock` +has been defined, making it impossible to call any of these functions +without invoking implementation-defined behavior. + +#### `long mee_clock_get_rate_hz(const struct mee_clock *clock)` + +Returns the clock rate of the given clock, in Hz. + +#### `long mee_clock_set_rate_hz(const struct mee_clock *clock, long hz)` + +Attempts to set the rate of the given clock to the given value, in Hz. +Returns the rate the given clock was actually set to, which may be +different than the requested rate. There are no hard requirements on +what clock rates can be set, but it's expected that a best effort +approach is taken to match the caller's desired clock rate. + +#### `void mee_clock_register_rate_change_callback(struct mee_clock *clk, int (*cb)(struct mee_clock *, void *), void *priv)` + +Registers a function (and an associated opaque data block) that will be +called whenever the giver clock's rate has been changed. This function +will be called after the driver-specific clock frequency changing code +has returned, but before the caller of `mee_clock_set_rate_hz()` has +been returned to. + +It's not guaranteed that the given clock's rate will have actually +changed every time the given function is called, but it's guaranteed +that the given function will be called every time the given clock's rate +has been changed. + +### Power Control Interface + +The MEE defines a mechanism to control the power state of a given +machine. The interface is currently quite simple: it's just the +`mee_shutdown()` function. + +#### `void mee_shutdown(int code) __attribute__((noreturn))` + +Terminates execution of this program, attempting to pass the given code +to whomever may be looking. The code `0` indicates success, while all +other codes indicate failure. The exact mechanism by which execution +terminates is implementation defined, but some examples include: + +* Spinning in an infinite loop. +* Printing the return code to standard out and spinning in an infinite + loop. +* Toggling an external I/O to disable the power to the core. +* Poking through a hole to the host that's providing this environment + and indicating success or failure. + +### TTY Interface + +The MEE provides an terminal interface. This interface is designed to +provide a simple mechanism for getting text-based data outside of the +MEE -- in other words, it's designed to be used to implement C library +functions like `printf()`. + +#### `int mee_tty_putc(unsigned char c);` + +Writes the given character to the default terminal, returning 0 on +success or -1 on failure. + +### UART Interface + +The UART interface allows users of the MEE to control + +Note that there is no mechanism for obtaining a pointer to a `struct +mee_uart` without invoking implementation-defined behavior, thus making +calling any of these functions impossible. + +#### `int mee_uart_init(struct mee_uart *uart)` + +Initializes the given UART. This must be called exactly once before any +other function on this UART can be called. It is invalid to initialize +a UART more than once. + +#### `int mee_uart_putc(struct mee_uart *uart, unsigned char c)` + +Writes the given character to the given UART, returning 0 on success and +-1 on failure. + +#### `int mee_uart_getc(struct mee_uart *uart, unsigned char *c)` + +Reads a character from the given UART, storing it at the given character +pointer. This returns 0 on success and -1 on failure. + +#### `int mee_uart_get_baud_rate(struct mee_uart *uart)` + +Obtains the baud rate of the given UART, or `-1` to signify an error. + +#### `int mee_uart_set_baud_rate(struct mee_uart *uart, int baud_rate)` + +Sets the baud rate of the given UART. Returns 0 on success, or -1 on +failure. Failure to set the baud rate can render the UART unusable +until a subsequent coll to `mee_uart_set_baud_rate()` returns success. + +### C Startup Interface + +The MEE handles entering the C library's start routine, which is defined +by the symbol `_start`. This symbol must be defined by the C library in +order to allow the MEE to do anything meaningful. + +The MEE follows the standard RISC-V bootloader ABI when calling +`_start`: + +* `a0` contains the hart ID. +* `a1` contains a pointer to the machine description. The MEE always + sets this to NULL, as machines are described statically. +* `a2` contains a callback that should be called from within the child + environment after it has initialized itself. + +This can be described as a the C function `void _start(long hartid, +unsigned char *dtb, void (*after_init)(void))'. Note that the MEE does +not initialize a C environment and therefor this cannot actually be a C +function -- for example, there may not be a stack. diff --git a/mee/compiler.h b/mee/compiler.h index e8a7b83f..5e31258f 100644 --- a/mee/compiler.h +++ b/mee/compiler.h @@ -4,11 +4,11 @@ #ifndef MEE__COMPILER_H #define MEE__COMPILER_H -#define MEE_DECLARE_VTABLE(type) \ - asm(".weak " #type); \ - const struct type type \ +#define __MEE_DECLARE_VTABLE(type) \ + asm(".weak " #type); \ + const struct type type \ -#define MEE_GET_FIELD(reg, mask) \ +#define __MEE_GET_FIELD(reg, mask) \ (((reg) & (mask)) / ((mask) & ~((mask) << 1))) static inline long abs(long val) diff --git a/mee/drivers/fixed-clock.h b/mee/drivers/fixed-clock.h index dacc3e7d..ecc6176d 100644 --- a/mee/drivers/fixed-clock.h +++ b/mee/drivers/fixed-clock.h @@ -16,7 +16,7 @@ struct __mee_driver_vtable_fixed_clock { long __mee_driver_fixed_clock_get_rate_hz(const struct mee_clock *gclk); long __mee_driver_fixed_clock_set_rate_hz(struct mee_clock *gclk, long target_hz); -MEE_DECLARE_VTABLE(__mee_driver_vtable_fixed_clock) = { +__MEE_DECLARE_VTABLE(__mee_driver_vtable_fixed_clock) = { .clock.get_rate_hz = __mee_driver_fixed_clock_get_rate_hz, .clock.set_rate_hz = __mee_driver_fixed_clock_set_rate_hz, }; diff --git a/mee/drivers/sifive,fe310-g000,hfrosc.h b/mee/drivers/sifive,fe310-g000,hfrosc.h index e16030f7..66a55555 100644 --- a/mee/drivers/sifive,fe310-g000,hfrosc.h +++ b/mee/drivers/sifive,fe310-g000,hfrosc.h @@ -16,7 +16,7 @@ struct __mee_driver_vtable_sifive_fe310_g000_hfrosc { struct __mee_clock_vtable clock; }; -MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_fe310_g000_hfrosc) = { +__MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_fe310_g000_hfrosc) = { .clock.get_rate_hz = &__mee_driver_sifive_fe310_g000_hfrosc_get_rate_hz, .clock.set_rate_hz = &__mee_driver_sifive_fe310_g000_hfrosc_set_rate_hz, }; diff --git a/mee/drivers/sifive,fe310-g000,hfxosc.h b/mee/drivers/sifive,fe310-g000,hfxosc.h index 3703725d..04c0a120 100644 --- a/mee/drivers/sifive,fe310-g000,hfxosc.h +++ b/mee/drivers/sifive,fe310-g000,hfxosc.h @@ -14,7 +14,7 @@ struct __mee_driver_vtable_sifive_fe310_g000_hfxosc { struct __mee_clock_vtable clock; }; -MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_fe310_g000_hfxosc) = { +__MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_fe310_g000_hfxosc) = { .clock.get_rate_hz = __mee_driver_sifive_fe310_g000_hfxosc_get_rate_hz, .clock.set_rate_hz = __mee_driver_sifive_fe310_g000_hfxosc_set_rate_hz, }; diff --git a/mee/drivers/sifive,fe310-g000,pll.h b/mee/drivers/sifive,fe310-g000,pll.h index 625ace1e..12701cf2 100644 --- a/mee/drivers/sifive,fe310-g000,pll.h +++ b/mee/drivers/sifive,fe310-g000,pll.h @@ -18,7 +18,7 @@ struct __mee_driver_vtable_sifive_fe310_g000_pll { struct __mee_clock_vtable clock; }; -MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_fe310_g000_pll) = { +__MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_fe310_g000_pll) = { .init = __mee_driver_sifive_fe310_g000_pll_init, .clock.get_rate_hz = __mee_driver_sifive_fe310_g000_pll_get_rate_hz, .clock.set_rate_hz = __mee_driver_sifive_fe310_g000_pll_set_rate_hz, diff --git a/mee/drivers/sifive,fe310-g000,prci.h b/mee/drivers/sifive,fe310-g000,prci.h index 04d12694..37a2493e 100644 --- a/mee/drivers/sifive,fe310-g000,prci.h +++ b/mee/drivers/sifive,fe310-g000,prci.h @@ -17,7 +17,7 @@ struct __mee_driver_vtable_sifive_fe310_g000_prci { long (*set_reg)(const struct __mee_driver_sifive_fe310_g000_prci *, long offset, long value); }; -MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_fe310_g000_prci) = { +__MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_fe310_g000_prci) = { .get_reg = __mee_driver_sifive_fe310_g000_prci_get_reg, .set_reg = __mee_driver_sifive_fe310_g000_prci_set_reg, }; diff --git a/mee/drivers/sifive,gpio0.h b/mee/drivers/sifive,gpio0.h index ecb0f7a8..723f5213 100644 --- a/mee/drivers/sifive,gpio0.h +++ b/mee/drivers/sifive,gpio0.h @@ -14,7 +14,7 @@ struct __mee_driver_vtable_sifive_gpio0 { long (*enable_io)(const struct __mee_driver_sifive_gpio0 *, long source, long dest); }; -MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_gpio0) = { +__MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_gpio0) = { .enable_io = __mee_driver_sifive_gpio0_enable_io, }; diff --git a/mee/drivers/sifive,test0.h b/mee/drivers/sifive,test0.h index 1dbe3e76..199348b0 100644 --- a/mee/drivers/sifive,test0.h +++ b/mee/drivers/sifive,test0.h @@ -8,19 +8,19 @@ #include struct __mee_driver_vtable_sifive_test0 { - const struct mee_shutdown_vtable shutdown; + const struct __mee_shutdown_vtable shutdown; }; struct __mee_driver_sifive_test0; -void __mee_driver_sifive_test0_exit(const struct mee_shutdown *test, int code) __attribute__((noreturn)); +void __mee_driver_sifive_test0_exit(const struct __mee_shutdown *test, int code) __attribute__((noreturn)); -MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_test0) = { +__MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_test0) = { .shutdown.exit = &__mee_driver_sifive_test0_exit, }; struct __mee_driver_sifive_test0 { - struct mee_shutdown shutdown; + struct __mee_shutdown shutdown; const struct __mee_driver_vtable_sifive_test0 *vtable; const unsigned long base; const unsigned long size; diff --git a/mee/drivers/sifive,uart0.h b/mee/drivers/sifive,uart0.h index 7f4a8f31..6c04656f 100644 --- a/mee/drivers/sifive,uart0.h +++ b/mee/drivers/sifive,uart0.h @@ -22,7 +22,7 @@ int __mee_driver_sifive_uart0_getc(struct mee_uart *uart, unsigned char *c); int __mee_driver_sifive_uart0_get_baud_rate(struct mee_uart *guart); int __mee_driver_sifive_uart0_set_baud_rate(struct mee_uart *guart, int baud_rate); -MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_uart0) = { +__MEE_DECLARE_VTABLE(__mee_driver_vtable_sifive_uart0) = { .uart.init = __mee_driver_sifive_uart0_init, .uart.putc = __mee_driver_sifive_uart0_putc, .uart.getc = __mee_driver_sifive_uart0_getc, diff --git a/mee/io.h b/mee/io.h index 2cd8b9e7..37160525 100644 --- a/mee/io.h +++ b/mee/io.h @@ -5,18 +5,18 @@ #define MEE__IO_H /* This macro enforces that the compiler will not elide the given access. */ -#define MEE_ACCESS_ONCE(x) (*(typeof(*x) volatile *)(x)) +#define __MEE_ACCESS_ONCE(x) (*(typeof(*x) volatile *)(x)) /* Allows users to specify arbitrary fences. */ -#define MEE_IO_FENCE(pred, succ) __asm__ volatile ("fence " #pred "," #succ ::: "memory"); +#define __MEE_IO_FENCE(pred, succ) __asm__ volatile ("fence " #pred "," #succ ::: "memory"); /* Types that explicitly describe an address as being used for memory-mapped - * IO. These should only be accessed via MEE_ACCESS_ONCE. */ -typedef unsigned char mee_io_u8; -typedef unsigned short mee_io_u16; -typedef unsigned int mee_io_u32; + * IO. These should only be accessed via __MEE_ACCESS_ONCE. */ +typedef unsigned char __mee_io_u8; +typedef unsigned short __mee_io_u16; +typedef unsigned int __mee_io_u32; #if __riscv_xlen >= 64 -typedef unsigned long mee_io_u64; +typedef unsigned long __mee_io_u64; #endif #endif diff --git a/mee/machine.h b/mee/machine.h new file mode 100644 index 00000000..a1d18c93 --- /dev/null +++ b/mee/machine.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2018 SiFive, Inc */ + +#ifndef __MEE_MACHINE_HEADER +#error "The toolchain must define __MEE_MACHINE_HEADER" +#endif + +#include __MEE_MACHINE_HEADER diff --git a/mee/shutdown.h b/mee/shutdown.h index ee9732c6..9113c519 100644 --- a/mee/shutdown.h +++ b/mee/shutdown.h @@ -4,18 +4,18 @@ #ifndef MEE__SHUTDOWN_H #define MEE__SHUTDOWN_H -struct mee_shutdown; +struct __mee_shutdown; -struct mee_shutdown_vtable { - void (*exit)(const struct mee_shutdown *sd, int code) __attribute__((noreturn)); +struct __mee_shutdown_vtable { + void (*exit)(const struct __mee_shutdown *sd, int code) __attribute__((noreturn)); }; -struct mee_shutdown { - const struct mee_shutdown_vtable *vtable; +struct __mee_shutdown { + const struct __mee_shutdown_vtable *vtable; }; -inline void mee_shutdown_exit(const struct mee_shutdown *sd, int code) __attribute__((noreturn)); -inline void mee_shutdown_exit(const struct mee_shutdown *sd, int code) { sd->vtable->exit(sd, code); } +inline void __mee_shutdown_exit(const struct __mee_shutdown *sd, int code) __attribute__((noreturn)); +inline void __mee_shutdown_exit(const struct __mee_shutdown *sd, int code) { sd->vtable->exit(sd, code); } /* The public MEE shutdown interface, which allows us to turn off the machine * when posible. */ diff --git a/riscv__menv__mee.specs.in b/riscv__menv__mee.specs.in new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/riscv__menv__mee.specs.in @@ -0,0 +1 @@ + diff --git a/src/drivers/sifive,fe310-g000,pll.c b/src/drivers/sifive,fe310-g000,pll.c index d0367949..a7dbae34 100644 --- a/src/drivers/sifive,fe310-g000,pll.c +++ b/src/drivers/sifive,fe310-g000,pll.c @@ -146,19 +146,19 @@ static void mee_sifive_fe310_g000_pll_init(void) { #endif /* __MEE_DT_SIFIVE_FE310_G000__PLL_HANDLE */ void __mee_driver_sifive_fe310_g000_pll_init(struct __mee_driver_sifive_fe310_g000_pll *pll) { - mee_io_u32 *pllcfg = (mee_io_u32 *) (pll->config_base->base + pll->config_offset); + __mee_io_u32 *pllcfg = (__mee_io_u32 *) (pll->config_base->base + pll->config_offset); /* If the PLL clock has had a pre_rate_change_callback configured, call it */ if(pll->clock.pre_rate_change_callback != NULL) pll->clock.pre_rate_change_callback(pll->clock.pre_rate_change_callback_priv); /* If we're running off of the PLL, switch off before we start configuring it*/ - if((MEE_ACCESS_ONCE(pllcfg) & PLL_SEL) == 0) - MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL); + if((__MEE_ACCESS_ONCE(pllcfg) & PLL_SEL) == 0) + __MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL); /* Make sure we're running off of the external oscillator for stability */ if(pll->pllref != NULL) - MEE_ACCESS_ONCE(pllcfg) |= PLL_REFSEL; + __MEE_ACCESS_ONCE(pllcfg) |= PLL_REFSEL; /* Configure the PLL to run at the requested init frequency. * Using the vtable instead of the user API because we want to control @@ -178,33 +178,33 @@ long __mee_driver_sifive_fe310_g000_pll_get_rate_hz(const struct mee_clock *cloc /* At the end of the PLL there's one big mux: it either selects the HFROSC * (bypassing the PLL entirely) or uses the PLL. */ - if (MEE_GET_FIELD(cfg, PLL_SEL) == 0) + if (__MEE_GET_FIELD(cfg, PLL_SEL) == 0) return mee_clock_get_rate_hz(clk->pllsel0); /* There's a clock mux before the PLL that selects between the HFROSC adn * the HFXOSC as the PLL's input clock. */ - long ref_hz = mee_clock_get_rate_hz(MEE_GET_FIELD(cfg, PLL_REFSEL) ? clk->pllref : clk->pllsel0); + long ref_hz = mee_clock_get_rate_hz(__MEE_GET_FIELD(cfg, PLL_REFSEL) ? clk->pllref : clk->pllsel0); /* It's possible to bypass the PLL, which is an internal bpyass. This * still obays the PLL's input clock mu. */ - if (MEE_GET_FIELD(cfg, PLL_BYPASS)) + if (__MEE_GET_FIELD(cfg, PLL_BYPASS)) return ref_hz; /* Logically the PLL is a three stage div-mul-div. */ - long div_r = MEE_GET_FIELD(cfg, PLL_R) + 1; - long mul_f = 2 * (MEE_GET_FIELD(cfg, PLL_F) + 1); - if (MEE_GET_FIELD(cfg, PLL_Q) == 0) + long div_r = __MEE_GET_FIELD(cfg, PLL_R) + 1; + long mul_f = 2 * (__MEE_GET_FIELD(cfg, PLL_F) + 1); + if (__MEE_GET_FIELD(cfg, PLL_Q) == 0) return -1; - long div_q = 1 << MEE_GET_FIELD(cfg, PLL_Q); + long div_q = 1 << __MEE_GET_FIELD(cfg, PLL_Q); /* In addition to the dividers inherent in the PLL, there's an additional * clock divider that lives after the PLL and lets us pick a more * interesting range of frequencies. */ long pllout = (((ref_hz / div_r) * mul_f) / div_q); - if (MEE_GET_FIELD(div, DIV_1)) + if (__MEE_GET_FIELD(div, DIV_1)) return pllout; - return pllout / (2 * (MEE_GET_FIELD(div, DIV_DIV) + 1)); + return pllout / (2 * (__MEE_GET_FIELD(div, DIV_DIV) + 1)); } /* Find a valid configuration for the PLL which is closest to the desired @@ -240,57 +240,57 @@ static int find_closest_config(long ref_hz, long rate) } /* Configure the PLL and wait for it to lock */ -static void configure_pll(mee_io_u32 *pllcfg, mee_io_u32 *plloutdiv, struct pll_config_t *config) +static void configure_pll(__mee_io_u32 *pllcfg, __mee_io_u32 *plloutdiv, struct pll_config_t *config) { - MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_R); - MEE_ACCESS_ONCE(pllcfg) |= PLL_R_SHIFT(config->r); + __MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_R); + __MEE_ACCESS_ONCE(pllcfg) |= PLL_R_SHIFT(config->r); - MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_F); - MEE_ACCESS_ONCE(pllcfg) |= PLL_F_SHIFT(config->f); + __MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_F); + __MEE_ACCESS_ONCE(pllcfg) |= PLL_F_SHIFT(config->f); - MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_Q); - MEE_ACCESS_ONCE(pllcfg) |= PLL_Q_SHIFT(config->q); + __MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_Q); + __MEE_ACCESS_ONCE(pllcfg) |= PLL_Q_SHIFT(config->q); if(config->d < 0) { /* disable final divider */ - MEE_ACCESS_ONCE(plloutdiv) |= DIV_1; + __MEE_ACCESS_ONCE(plloutdiv) |= DIV_1; - MEE_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV); - MEE_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(1); + __MEE_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV); + __MEE_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(1); } else { - MEE_ACCESS_ONCE(plloutdiv) &= ~(DIV_1); + __MEE_ACCESS_ONCE(plloutdiv) &= ~(DIV_1); - MEE_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV); - MEE_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(config->d); + __MEE_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV); + __MEE_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(config->d); } - MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_BYPASS); + __MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_BYPASS); /* Wait for PLL to lock */ - while((MEE_ACCESS_ONCE(pllcfg) & PLL_LOCK) == 0) ; + while((__MEE_ACCESS_ONCE(pllcfg) & PLL_LOCK) == 0) ; } long __mee_driver_sifive_fe310_g000_pll_set_rate_hz(struct mee_clock *clock, long rate) { struct __mee_driver_sifive_fe310_g000_pll *clk = (void *)clock; - mee_io_u32 *pllcfg = (mee_io_u32 *) (clk->config_base->base + clk->config_offset); - mee_io_u32 *plloutdiv = (mee_io_u32 *) (clk->divider_base->base + clk->divider_offset); + __mee_io_u32 *pllcfg = (__mee_io_u32 *) (clk->config_base->base + clk->config_offset); + __mee_io_u32 *plloutdiv = (__mee_io_u32 *) (clk->divider_base->base + clk->divider_offset); /* We can't modify the PLL if coreclk is driven by it, so switch it off */ - if (MEE_ACCESS_ONCE(pllcfg) & PLL_SEL) - MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL); + if (__MEE_ACCESS_ONCE(pllcfg) & PLL_SEL) + __MEE_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL); /* There's a clock mux before the PLL that selects between the HFROSC and * the HFXOSC as the PLL's input clock. */ - long ref_hz = mee_clock_get_rate_hz(MEE_ACCESS_ONCE(pllcfg) & PLL_REFSEL ? clk->pllref : clk->pllsel0); + long ref_hz = mee_clock_get_rate_hz(__MEE_ACCESS_ONCE(pllcfg) & PLL_REFSEL ? clk->pllref : clk->pllsel0); /* if the desired rate is within 75%-125% of the input clock, bypass the PLL */ if((ref_hz * 3 / 4) <= rate && (ref_hz * 5 / 4) >= rate) { - MEE_ACCESS_ONCE(pllcfg) |= PLL_BYPASS; + __MEE_ACCESS_ONCE(pllcfg) |= PLL_BYPASS; } else { @@ -302,12 +302,12 @@ long __mee_driver_sifive_fe310_g000_pll_set_rate_hz(struct mee_clock *clock, lon else { /* unable to find a valid configuration */ - MEE_ACCESS_ONCE(pllcfg) |= PLL_BYPASS; + __MEE_ACCESS_ONCE(pllcfg) |= PLL_BYPASS; } } /* Enable the PLL */ - MEE_ACCESS_ONCE(pllcfg) |= PLL_SEL; + __MEE_ACCESS_ONCE(pllcfg) |= PLL_SEL; return __mee_driver_sifive_fe310_g000_pll_get_rate_hz(clock); } diff --git a/src/drivers/sifive,fe310-g000,prci.c b/src/drivers/sifive,fe310-g000,prci.c index 3f38d518..a65453ba 100644 --- a/src/drivers/sifive,fe310-g000,prci.c +++ b/src/drivers/sifive,fe310-g000,prci.c @@ -4,9 +4,9 @@ #include long __mee_driver_sifive_fe310_g000_prci_get_reg(const struct __mee_driver_sifive_fe310_g000_prci *prci, long offset) { - return MEE_ACCESS_ONCE((mee_io_u32 *)(prci->base + offset)); + return __MEE_ACCESS_ONCE((__mee_io_u32 *)(prci->base + offset)); } long __mee_driver_sifive_fe310_g000_prci_set_reg(const struct __mee_driver_sifive_fe310_g000_prci *prci, long offset, long value) { - return MEE_ACCESS_ONCE((mee_io_u32 *)(prci->base + offset)) = value; + return __MEE_ACCESS_ONCE((__mee_io_u32 *)(prci->base + offset)) = value; } diff --git a/src/drivers/sifive,gpio0.c b/src/drivers/sifive,gpio0.c index 54a0a54d..284b41d1 100644 --- a/src/drivers/sifive,gpio0.c +++ b/src/drivers/sifive,gpio0.c @@ -9,6 +9,6 @@ long __mee_driver_sifive_gpio0_enable_io(const struct __mee_driver_sifive_gpio0 *gpio, long source, long dest) { - MEE_ACCESS_ONCE((mee_io_u32 *)(gpio->base + GPIO_IOF_SEL)) &= ~source; - MEE_ACCESS_ONCE((mee_io_u32 *)(gpio->base + GPIO_IOF_EN)) |= dest; + __MEE_ACCESS_ONCE((__mee_io_u32 *)(gpio->base + GPIO_IOF_SEL)) &= ~source; + __MEE_ACCESS_ONCE((__mee_io_u32 *)(gpio->base + GPIO_IOF_EN)) |= dest; } diff --git a/src/drivers/sifive,test0.c b/src/drivers/sifive,test0.c index 462b978b..d989b04c 100644 --- a/src/drivers/sifive,test0.c +++ b/src/drivers/sifive,test0.c @@ -7,11 +7,11 @@ #define FINISHER_OFFSET 0 -void __mee_driver_sifive_test0_exit(const struct mee_shutdown *sd, int code) +void __mee_driver_sifive_test0_exit(const struct __mee_shutdown *sd, int code) { const struct __mee_driver_sifive_test0 *test = (void *)sd; uint32_t out = (code << 16) + (code == 0 ? 0x5555 : 0x3333); while (1) { - MEE_ACCESS_ONCE((mee_io_u32 *)(test->base + FINISHER_OFFSET)) = out; + __MEE_ACCESS_ONCE((__mee_io_u32 *)(test->base + FINISHER_OFFSET)) = out; } } diff --git a/src/drivers/sifive,uart0.c b/src/drivers/sifive,uart0.c index 22477c5d..74cf5aa7 100644 --- a/src/drivers/sifive,uart0.c +++ b/src/drivers/sifive,uart0.c @@ -30,8 +30,8 @@ #define UART_TXWM (1 << 0) #define UART_REG(offset) (((unsigned long)(((struct __mee_driver_sifive_uart0 *)(uart))->control_base) + offset)) -#define UART_REGB(offset) (MEE_ACCESS_ONCE((mee_io_u8 *)UART_REG(offset))) -#define UART_REGW(offset) (MEE_ACCESS_ONCE((mee_io_u32 *)UART_REG(offset))) +#define UART_REGB(offset) (__MEE_ACCESS_ONCE((__mee_io_u8 *)UART_REG(offset))) +#define UART_REGW(offset) (__MEE_ACCESS_ONCE((__mee_io_u32 *)UART_REG(offset))) int __mee_driver_sifive_uart0_putc(struct mee_uart *uart, unsigned char c) { diff --git a/src/shutdown.c b/src/shutdown.c index 1f3570ed..3d9107aa 100644 --- a/src/shutdown.c +++ b/src/shutdown.c @@ -1,14 +1,15 @@ /* Copyright 2018 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ +#include #include -extern inline void mee_shutdown_exit(const struct mee_shutdown *sd, int code); +extern inline void __mee_shutdown_exit(const struct __mee_shutdown *sd, int code); #if defined(__MEE_DT_SHUTDOWN_HANDLE) void mee_shutdown(int code) { - mee_shutdown_exit(__MEE_DT_SHUTDOWN_HANDLE, code); + __mee_shutdown_exit(__MEE_DT_SHUTDOWN_HANDLE, code); } #else # warning "There is no defined shutdown mechanism, mee_shutdown() will spin." diff --git a/src/tty.c b/src/tty.c index 703e5e49..ede6ecf2 100644 --- a/src/tty.c +++ b/src/tty.c @@ -2,6 +2,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include +#include #if defined(__MEE_DT_STDOUT_UART_HANDLE) /* This implementation serves as a small shim that interfaces with the first diff --git a/test/pll_set_hz.c b/test/pll_set_hz.c index 4f01db74..50542bea 100644 --- a/test/pll_set_hz.c +++ b/test/pll_set_hz.c @@ -8,6 +8,7 @@ #define PLL_MAX_OUT 320000000 void main() { +#ifdef __MEE_DT_SIFIVE_FE310_G000_PLL_HANDLE struct mee_clock * pll = __ME_DT_SIFIVE_FE310_G000_PLL_HANDLE; printf("Test harness for FE310-G000 PLL Set Frequency\n\n"); @@ -24,4 +25,7 @@ void main() { } printf("--- Complete ---\n"); +#else + printf("Unable to run fe310-g000 PLL test case as there is no PLL\n"); +#endif }