From d86cf0a0984786366af2a789dbdf1a1c98908a01 Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Mon, 6 Feb 2023 12:50:46 +0000 Subject: [PATCH 01/10] First draft support for interrupt handling - this also required some enhancements to schema and parser, to support function type declarations and to ensure correct content in docs and headers. --- api/C/include/csi.h | 11 + api/C/include/csi_bsp_csrs.h | 1 + api/C/include/csi_bsp_defs.h | 1 + api/C/include/csi_bsp_interrupts.h | 1 + api/C/include/csi_bsp_perip.h | 1 + api/C/include/csi_csrs.h | 1 + api/C/include/csi_defs.h | 59 ++++ api/C/include/csi_interrupts.h | 314 ++++++++++++++++++++++ api/C/include/rvm_csi.h | 17 ++ api/rvm-csi-spec.yaml | 414 ++++++++++++++++++++++++++++- chapter2.adoc | 4 + intro.adoc | 10 + spec-schema/parser/doc_gen.py | 31 ++- spec-schema/parser/header_gen.py | 49 +++- spec-schema/rvm-csi.schema.json | 17 +- 15 files changed, 919 insertions(+), 12 deletions(-) create mode 100644 api/C/include/csi.h create mode 100644 api/C/include/csi_bsp_csrs.h create mode 100644 api/C/include/csi_bsp_defs.h create mode 100644 api/C/include/csi_bsp_interrupts.h create mode 100644 api/C/include/csi_bsp_perip.h create mode 100644 api/C/include/csi_csrs.h create mode 100644 api/C/include/csi_defs.h create mode 100644 api/C/include/csi_interrupts.h create mode 100644 api/C/include/rvm_csi.h diff --git a/api/C/include/csi.h b/api/C/include/csi.h new file mode 100644 index 0000000..fd061ee --- /dev/null +++ b/api/C/include/csi.h @@ -0,0 +1,11 @@ +/* +* Top-level definition file for RVM-CSI API. Note: application writers do not include +* this file: user rvm_csi.h instead. +*/ + +#ifndef CSI_H +#define CSI_H + +#include "csi_interrupts.h" + +#endif /* CSI_H */ diff --git a/api/C/include/csi_bsp_csrs.h b/api/C/include/csi_bsp_csrs.h new file mode 100644 index 0000000..d37976c --- /dev/null +++ b/api/C/include/csi_bsp_csrs.h @@ -0,0 +1 @@ +/* PLACEHOLDER: replaced by content from BSP */ diff --git a/api/C/include/csi_bsp_defs.h b/api/C/include/csi_bsp_defs.h new file mode 100644 index 0000000..d37976c --- /dev/null +++ b/api/C/include/csi_bsp_defs.h @@ -0,0 +1 @@ +/* PLACEHOLDER: replaced by content from BSP */ diff --git a/api/C/include/csi_bsp_interrupts.h b/api/C/include/csi_bsp_interrupts.h new file mode 100644 index 0000000..d37976c --- /dev/null +++ b/api/C/include/csi_bsp_interrupts.h @@ -0,0 +1 @@ +/* PLACEHOLDER: replaced by content from BSP */ diff --git a/api/C/include/csi_bsp_perip.h b/api/C/include/csi_bsp_perip.h new file mode 100644 index 0000000..d37976c --- /dev/null +++ b/api/C/include/csi_bsp_perip.h @@ -0,0 +1 @@ +/* PLACEHOLDER: replaced by content from BSP */ diff --git a/api/C/include/csi_csrs.h b/api/C/include/csi_csrs.h new file mode 100644 index 0000000..930aa51 --- /dev/null +++ b/api/C/include/csi_csrs.h @@ -0,0 +1 @@ +/* PLACEHOLDER: to be replaced by content auto-generated by Sail model */ diff --git a/api/C/include/csi_defs.h b/api/C/include/csi_defs.h new file mode 100644 index 0000000..639d988 --- /dev/null +++ b/api/C/include/csi_defs.h @@ -0,0 +1,59 @@ +/* + * General-Purpose Definitions for use in CSI code + * + * This file is included prior to all other headers and contains general-purpose + * definitions which may be used by subsequent headers. + * + * Copyright (c) RISC-V International 2022. Creative Commons License. Auto- + * generated file: DO NOT EDIT + */ + +#ifndef CSI_DEFS_H +#define CSI_DEFS_H + +/* + * Return type for functions indicating status + */ +typedef enum { + CSI_SUCCESS = 0, + CSI_NOT_IMPLEMENTED = -1, + CSI_ERROR = -2, + CSI_NOT_INITIALIZED = -3, + CSI_OUT_OF_MEM = -4, +} csi_status_t; + +/* + * Enumerates all sources in the system that can give rise to a trap event. This + * enumeration should be treated as an integer which can have additional values + * beyond those enumerated here. A standard set of interrupt and exception sources + * are enumerated here, which exclude external sources. All external interrupt + * sources should be enumerated by the BSP within csi_bsp_interrupts.h; and their + * ennumerated values should follow on from CSI_NUM_STANDARD_TRAP_SOURCES. + * csi_bsp_interrupts.h must also define CSI_TOTAL_BSP_TRAP_SOURCES to indicate the + * total number of sources defined. User applications may then use values above + * this to enumerate user-defined software signals. Note that the actual + * enumerated values have no meaning beyond serving to uniquely identify the source + * of a trap event. + */ +typedef enum { + CSI_ENUM_NMI = 0, + CSI_ENUM_MACHINE_SW_INTERRUPT, + CSI_ENUM_MACHINE_TIMER_INTERRUPT, + CSI_ENUM_INSTRUCTION_ADDR_MISALIGNED_EXCEPTION, + CSI_ENUM_INSTRUCTION_ACCESS_FAULT_EXCEPTION, + CSI_ENUM_ILLEGAL_INSTRUCTION_EXCEPTION, + CSI_ENUM_BREAKPOINT_EXCEPTION, + CSI_ENUM_LOAD_ADDR_MISALIGNED_EXCEPTION, + CSI_ENUM_LOAD_ACCESS_FAULT_EXCEPTION, + CSI_ENUM_STORE_ADDR_MISALIGNED_EXCEPTION, + CSI_ENUM_STORE_ACCESS_FAULT_EXCEPTION, + CSI_ENUM_ECALL_FROM_UMODE, + CSI_ENUM_ECALL_FROM_MMODE, + CSI_ENUM_INST_PAGE_FAULT, + CSI_ENUM_LOAD_PAGE_FAULT, + CSI_ENUM_STORE_PAGE_FAULT, + CSI_NUM_STANDARD_TRAP_SOURCES, /* Must come last in this list */ +} csi_trap_source_t; + + +#endif /* CSI_DEFS_H */ diff --git a/api/C/include/csi_interrupts.h b/api/C/include/csi_interrupts.h new file mode 100644 index 0000000..1f9fb94 --- /dev/null +++ b/api/C/include/csi_interrupts.h @@ -0,0 +1,314 @@ +/* + * Trap Handling / Interrupt Support + * + * This module provides functionality for routing interrupts and registering + * handlers for traps. The BSP provides a base trap handler. Running the + * initialisation function csi_interrupts_init will put the address of this handler + * in the mtvec register. This base trap handler provides default exception + * handling, and calls any handlers registered by the user. It also provides + * functionality required by the RVM-CSI timer module. Systems using RVM-CSI may + * provide their own trap handling support, in which case csi_interrupts_init + * should not be called, and all functions in this module, and in the timer module, + * will be inoperative. + * + * Copyright (c) RISC-V International 2022. Creative Commons License. Auto- + * generated file: DO NOT EDIT + */ + +#ifndef CSI_INTERRUPTS_H +#define CSI_INTERRUPTS_H + +#include "csi_defs.h" + +/* + * Function prototype for the users trap handler (M-mode or U-mode) + * + * @param source: Enumerated interrupt source for which the handler was registered. + * @param isr_ctx: User's context pointer as supplied when the handler was + * registered. + * @param mtval: Contents of the mtval register associated with this trap. + */ +typedef void (csi_isr_t)(int source, void *isr_ctx, unsigned mtval); + + +/* + * Initialize interrupt and timer sub-system for this hart. Must be called before + * calling any other functions in this module. This function must run in machine + * mode. + * + * @param mctx: Pointer to an area of memory to be used as M-mode context space for + * the interrupt subsystem. The BSP will define a macro + * CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES which defines the minimum required size of + * this context space in bytes. Calling this function initializes the context + * space. + * @param mctx_size: Size of memory allocated at the mctx pointer in bytes. + * Allocating more than CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES may permit additional + * M-mode handlers to be registered. + * @param uctx: Pointer to an area of memory to be used as U-mode context space for + * the interrupt subsystem. The BSP will define a macro + * CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES which defines the minimum required size of + * this context space in bytes. Calling this function initializes the context + * space. + * @param uctx_size: Size of memory allocated at the uctx pointer in bytes. + * Allocating more than CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES may permit additional + * U-mode handlers to be registered. + * @return : Status of initialisation operation + */ +csi_status_t csi_interrupts_init(void *mctx, unsigned mctx_size, void *uctx, unsigned uctx_size); + +/* + * Un-initialize the interrupt and timer sub-system. After calling this function, + * the memory allocated for the contexts may be freed, and no other functions in + * this module may be called. This function must run in machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @return : Status of uninitialisation operation + */ +csi_status_t csi_interrupts_uninit(void *mctx); + +/* + * This function is run from U-mode to obtain the U-mode context pointer previously + * passed into csi_interrupts_init for the current hart. + * + * @return : context pointer, or null pointer if inapplicable. + */ +void * get_interrupts_u_ctx(void); + +/* + * Registers a user-supplied function (isr) that will be called in M-mode by the + * base trap handler on receipt of a trap arising from from the source signal. + * isr_ctx is a parameter that will be passed into the user's ISR along with the + * signal number and mtval contents. This function transparently deals with + * routing the desired signal to the hart and enabling the interrupt. This + * function must run in machine mode. Running this function with a NULL pointer + * for the isr parameter will un-register a previously registered handler. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param isr: Pointer to the user's handler function; or NULL pointer to un- + * register a handler. + * @param isr_ctx: Pointer to the user's context. This will be passed into the + * handler function when called. + * @param source: Enumerated interrupt / exception source. This must be one of the + * enumerations from csi_trap_source_t, or a value from the BSP (extending the + * enumerations in csi_trap_source_t) enumerating a platform-specific external + * interrupt source. + * @return : Status of ISR registration operation. CSI_ERROR will be returned if + * the source parameter is invalid. CSI_NOT_INITIALIZED will be returned if + * csi_interrupts_init has not been called prior to calling this function, or if + * csi_interrupts_uninit was called prior to calling this function. CSI_OUT_OF_MEM + * will be returned if the number of handlers registered exceeds that supported by + * the context size. + */ +csi_status_t csi_register_m_isr(void *mctx, csi_isr_t *isr, void *isr_ctx, int source); + +/* + * Registers a user-supplied function (isr) that will be called in U-mode by the + * base trap handler on receipt of a trap arising from from the source signal. + * isr_ctx is a parameter that will be passed into the user's ISR along with the + * signal number and mtval contents. This function transparently deals with + * routing the desired signal to the hart and enabling the interrupt. This + * function must run in user mode. Running this function with a NULL pointer for + * the isr parameter will un-register a previously registered handler. + * + * @param uctx: U-mode context pointer previously initialised by + * csi_interrupts_init. + * @param isr: Pointer to the user's handler function; or NULL pointer to un- + * register a handler + * @param isr_ctx: Pointer to the user's context. This will be passed into the + * handler function when called. + * @param source: Enumerated interrupt / exception source. This must be one of the + * enumerations from csi_trap_source_t, or a value from the BSP (extending the + * enumerations in csi_trap_source_t) enumerating a platform-specific external + * interrupt source. + * @return : Status of ISR registration operation. CSI_ERROR will be returned if + * the source parameter is invalid, or if the requested source has not been enabled + * for u-mode handling by first running csi_set_umode_trap_permissions . + * CSI_NOT_INITIALIZED will be returned if csi_interrupts_init has not been called + * prior to calling this function, or if csi_interrupts_uninit was called prior to + * calling this function. CSI_OUT_OF_MEM will be returned if the number of handlers + * registered exceeds that supported by the context size. + */ +csi_status_t csi_register_u_isr(void *uctx, csi_isr_t *isr, void *isr_ctx, int source); + +/* + * Disable a trap source. This function must be run in machine mode. Note that + * this only gates an interrupting signal within the interrupt control logic. + * Device drivers may offer separate controls for turning their interrupts on and + * off at source. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param source: Enumerated interrupt / exception source. This must be one of the + * enumerations from csi_trap_source_t, or a value from the BSP (extending the + * enumerations in csi_trap_source_t) enumerating a platform-specific external + * interrupt source. + * @return : Status of disable operation. CSI_ERROR will be returned if the source + * parameter is invalid. + */ +csi_status_t csi_disable_m_trap_source(void *mctx, int source); + +/* + * Enable a trap source. This function must be run in machine mode. Note that + * this only gates an interrupting signal within the interrupt control logic. + * Device drivers may offer separate controls for turning their interrupts on and + * off at source. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param source: Enumerated interrupt / exception source. This must be one of the + * enumerations from csi_trap_source_t, or a value from the BSP (extending the + * enumerations in csi_trap_source_t) enumerating a platform-specific external + * interrupt source. + * @return : Status of enable operation. CSI_ERROR will be returned if the source + * parameter is invalid. + */ +csi_status_t csi_enable_m_trap_source(void *mctx, int source); + +/* + * Disable handling of a trap arising from a particular source. This function must + * be run in user mode. It will only have an effect if a user-mode handler has + * previously been registered for the selected source. Note this only disables the + * running of the handler. Device drivers may offer separate controls for turning + * their interrupts on and off at source. + * + * @param uctx: U-mode context pointer previously initialised by + * csi_interrupts_init. + * @param source: Enumerated interrupt / exception source. This must be one of the + * enumerations from csi_trap_source_t, or a value from the BSP (extending the + * enumerations in csi_trap_source_t) enumerating a platform-specific external + * interrupt source. + * @return : Status of disable operation. CSI_ERROR will be returned if the source + * parameter is invalid. + */ +csi_status_t csi_disable_u_trap_source(void *uctx, int source); + +/* + * Enable handling of a trap arising from a particular source. This function must + * be run in user mode. It will only have an effect if a user-mode handler has + * previously been registered for the selected source. Note this only enables the + * running of the handler. Device drivers may offer separate controls for turning + * their interrupts on and off at source. + * + * @param uctx: U-mode context pointer previously initialised by + * csi_interrupts_init. + * @param source: Enumerated interrupt / exception source. This must be one of the + * enumerations from csi_trap_source_t, or a value from the BSP (extending the + * enumerations in csi_trap_source_t) enumerating a platform-specific external + * interrupt source. + * @return : Status of enable operation. CSI_ERROR will be returned if the source + * parameter is invalid. + */ +csi_status_t csi_enable_u_trap_source(void *uctx, int source); + +/* + * Enable or disable 3 classes of interrupts for this hart. Must be run in machine + * mode. + * + * @param int_enables: Set bit 3 to enable software interrupts. Set bit 7 to + * enable timer interrupts. Set bit 11 to enable external interrupts. Setting + * these bits to zero will disable each interrupt source respectively. All other + * bits should be left at zero. + * @return : Integer in the same format as int_enables, reflecting the previous + * value of int_enables prior to the change. This may be stored and passed back + * into another call to csi_set_interrupt_enables in order to restore the previous + * interrupt enables state. + */ +unsigned csi_set_interrupt_enables(unsigned int_enables); + +/* + * Informs the interrupt subsystem whether a given signal is allowed to be handled + * in user mode. This function must be run in machine mode. Any signals for which + * this function is not run will not be permitted to be handled in U-mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param source: Enumerated interrupt / exception source. This must be one of the + * enumerations from csi_trap_source_t, or a value from the BSP (extending the + * enumerations in csi_trap_source_t) enumerating a platform-specific external + * interrupt source. + * @param permitted: True if user mode is permitted to register a handler for this + * trap source. False if not permitted. + * @return : Status of permissions setting operation. CSI_ERROR will be returned + * if the source parameter is invalid. + */ +csi_status_t csi_set_umode_trap_permissions(void *mctx, int source, bool permitted); + +/* + * Allocates a signal number for software use. The signal number must be outside + * the range currently reserved by the BSP, otherwise an error is raised. When + * raised, the signal will be routed to the specified hart ID. Must be run in + * machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param signal: Source enumeration for this signal. A unique number >= + * CSI_TOTAL_BSP_TRAP_SOURCES must be chosen. + * @param hartid: ID of the hart to which this signal will be routed. + * @return : Status of operation. CSI_ERROR will be returned if the source + * parameter is invalid. + */ +csi_status_t csi_define_sw_signal(void *mctx, int signal, int hartid); + +/* + * Raises a software signal, previously defined using csi_define_sw_signal. Must + * be run in machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param signal: Source enumeration for this signal. + * @return : Status of operation. CSI_ERROR will be returned if the specified + * signal is not software-raisable. + */ +csi_status_t csi_raise_signal(void *mctx, int signal); + +/* + * Set priority for an external interrupt source. Priorities range from 0 to + * CSI_MAX_INTERRUPT_PRIORITY, where 0 indicates "never interrupt", and 1 is the + * lowest subsequent priority level. This function must be run in machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param signal: Source enumeration for this signal. + * @param priority: priority level. + * @return : Status of operation. CSI_ERROR will be returned if the request is + * invalid. + */ +csi_status_t csi_set_irq_priority(void *mctx, int signal, int priority); + +/* + * Get priority of an external interrupt source. Must be run in machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param signal: Source enumeration for this signal. + * @return : priority level (resulting from calls to csi_set_irq_priority). -1 + * will be returned if the request is invalid. + */ +int csi_get_irq_priority(void *mctx, int signal); + +/* + * Set a priority threshold below which external interrupts will be masked. Must + * be run in machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param threshold: Priority threshold for external interrupts. + * @return : Status of operation. CSI_ERROR will be returned if the request is + * invalid. + */ +csi_status_t csi_set_irq_priority_thresh(void *mctx, int threshold); + +/* + * Get the current priority threshold for external interrupts + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @return : Priority threshold, or -1 if priority thresholds unsupported, or on + * error. + */ +int csi_get_irq_priority_thresh(void *mctx); + + +#endif /* CSI_INTERRUPTS_H */ diff --git a/api/C/include/rvm_csi.h b/api/C/include/rvm_csi.h new file mode 100644 index 0000000..f7d247d --- /dev/null +++ b/api/C/include/rvm_csi.h @@ -0,0 +1,17 @@ +/* +* Top-level include file for RVM-CSI Hardware Abstraction Layer. This is the only +* header to be included in the user's application. +*/ + +#ifndef RVM_CSI_H +#define RVM_CSI_H + +#include "csi_defs.h" /* Standard definitions for use in other headers */ +#include "csi_csrs.h" /* Standard RISC-V CSR addresses and bitfields */ +#include "csi_bsp_csrs.h" /* Custom CSR addresses and bitfields supplied by BSP */ +#include "csi_bsp_perip.h" /* Peripheral register addresses and bitfields supplied by BSP */ +#include "csi_bsp_interrupts.h" /* Enumeration of external interrupt sources supplied by BSP */ +#include "csi_bsp_defs.h" /* Other macro definitions supplied by BSP */ +#include "csi.h" /* The platform-agnostic RVM-CSI API */ + +#endif /* RVM_CSI_H */ diff --git a/api/rvm-csi-spec.yaml b/api/rvm-csi-spec.yaml index 0b9f40f..486fb29 100644 --- a/api/rvm-csi-spec.yaml +++ b/api/rvm-csi-spec.yaml @@ -25,4 +25,416 @@ modules: value: -1 - name: CSI_ERROR value: -2 - + - name: CSI_NOT_INITIALIZED + value: -3 + - name: CSI_OUT_OF_MEM + value: -4 + - name: csi_trap_source_t + description: > + Enumerates all sources in the system that can give rise to a trap event. This enumeration should + be treated as an integer which can have additional values beyond those enumerated here. A standard + set of interrupt and exception sources are enumerated here, which exclude external sources. All + external interrupt sources should be enumerated by the BSP within csi_bsp_interrupts.h; and their + ennumerated values should follow on from CSI_NUM_STANDARD_TRAP_SOURCES. csi_bsp_interrupts.h must + also define CSI_TOTAL_BSP_TRAP_SOURCES to indicate the total number of sources defined. User + applications may then use values above this to enumerate user-defined software signals. Note that + the actual enumerated values have no meaning beyond serving to uniquely identify the source of a + trap event. + type: enum + enum-members: + - name: CSI_ENUM_NMI + value: 0 + - name: CSI_ENUM_MACHINE_SW_INTERRUPT + - name: CSI_ENUM_MACHINE_TIMER_INTERRUPT + - name: CSI_ENUM_INSTRUCTION_ADDR_MISALIGNED_EXCEPTION + - name: CSI_ENUM_INSTRUCTION_ACCESS_FAULT_EXCEPTION + - name: CSI_ENUM_ILLEGAL_INSTRUCTION_EXCEPTION + - name: CSI_ENUM_BREAKPOINT_EXCEPTION + - name: CSI_ENUM_LOAD_ADDR_MISALIGNED_EXCEPTION + - name: CSI_ENUM_LOAD_ACCESS_FAULT_EXCEPTION + - name: CSI_ENUM_STORE_ADDR_MISALIGNED_EXCEPTION + - name: CSI_ENUM_STORE_ACCESS_FAULT_EXCEPTION + - name: CSI_ENUM_ECALL_FROM_UMODE + - name: CSI_ENUM_ECALL_FROM_MMODE + - name: CSI_ENUM_INST_PAGE_FAULT + - name: CSI_ENUM_LOAD_PAGE_FAULT + - name: CSI_ENUM_STORE_PAGE_FAULT + - name: CSI_NUM_STANDARD_TRAP_SOURCES + description: Must come last in this list + - name: Trap Handling / Interrupt Support + description: > + This module provides functionality for routing interrupts and registering handlers for traps. + The BSP provides a base trap handler. Running the initialisation function csi_interrupts_init will + put the address of this handler in the mtvec register. This base trap handler provides default + exception handling, and calls any handlers registered by the user. It also provides functionality + required by the RVM-CSI timer module. Systems using RVM-CSI may provide their own trap handling + support, in which case csi_interrupts_init should not be called, and all functions in this module, + and in the timer module, will be inoperative. + notes: + - There will be at most one instance of the trap handling and interrupt subsystem per hart. + c-specific: false + c-filename: csi_interrupts.h + c-include-files: + - filename: csi_defs.h + system-header: false + c-type-declarations: + - name: csi_isr_t + description: Function prototype for the users trap handler (M-mode or U-mode) + type: function + func-typedef-retval: void + func-typedef-params: + - name: source + description: > + Enumerated interrupt source for which the handler was registered. + type: int + - name: isr_ctx + description: User's context pointer as supplied when the handler was registered. + type: void * + - name: mtval + description: Contents of the mtval register associated with this trap. + type: unsigned + functions: + - name: csi_interrupts_init + description: > + Initialize interrupt and timer sub-system for this hart. Must be called before calling any other functions + in this module. This function must run in machine mode. + c-params: + - name: mctx + description: > + Pointer to an area of memory to be used as M-mode context space for the interrupt subsystem. The BSP will + define a macro CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES which defines the minimum required size of this context space in + bytes. Calling this function initializes the context space. + type: void * + - name: mctx_size + description: > + Size of memory allocated at the mctx pointer in bytes. Allocating more than CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES may + permit additional M-mode handlers to be registered. + type: unsigned + - name: uctx + description: > + Pointer to an area of memory to be used as U-mode context space for the interrupt subsystem. The BSP will + define a macro CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES which defines the minimum required size of this context space in + bytes. Calling this function initializes the context space. + type: void * + - name: uctx_size + description: > + Size of memory allocated at the uctx pointer in bytes. Allocating more than CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES may + permit additional U-mode handlers to be registered. + type: unsigned + c-return-value: + description: Status of initialisation operation + type: csi_status_t + - name: csi_interrupts_uninit + description: > + Un-initialize the interrupt and timer sub-system. After calling this function, the memory allocated + for the contexts may be freed, and no other functions in this module may be called. This function + must run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + c-return-value: + description: Status of uninitialisation operation + type: csi_status_t + - name: get_interrupts_u_ctx + description: > + This function is run from U-mode to obtain the U-mode context pointer previously passed into csi_interrupts_init + for the current hart. + c-return-value: + description: context pointer, or null pointer if inapplicable. + type: void * + - name: csi_register_m_isr + description: > + Registers a user-supplied function (isr) that will be called in M-mode by the base trap handler on receipt of a + trap arising from from the source signal. isr_ctx is a parameter that will be passed into the user's ISR + along with the signal number and mtval contents. This function transparently deals with routing the desired signal + to the hart and enabling the interrupt. This function must run in machine mode. Running this function with a NULL + pointer for the isr parameter will un-register a previously registered handler. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: isr + description: > + Pointer to the user's handler function; or NULL pointer to un-register a handler. + type: csi_isr_t * + - name: isr_ctx + description: > + Pointer to the user's context. This will be passed into the handler function when called. + type: void * + - name: source + description: > + Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or + a value from the BSP (extending the enumerations in csi_trap_source_t) enumerating a platform-specific + external interrupt source. + type: int + c-return-value: + description: > + Status of ISR registration operation. CSI_ERROR will be returned if the source parameter is + invalid. CSI_NOT_INITIALIZED will be returned if csi_interrupts_init has not been called prior to calling this + function, or if csi_interrupts_uninit was called prior to calling this function. CSI_OUT_OF_MEM will be + returned if the number of handlers registered exceeds that supported by the context size. + type: csi_status_t + - name: csi_register_u_isr + description: > + Registers a user-supplied function (isr) that will be called in U-mode by the base trap handler on receipt of a + trap arising from from the source signal. isr_ctx is a parameter that will be passed into the user's ISR + along with the signal number and mtval contents. This function transparently deals with routing the desired signal + to the hart and enabling the interrupt. This function must run in user mode. Running this function with a NULL + pointer for the isr parameter will un-register a previously registered handler. + c-params: + - name: uctx + description: > + U-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: isr + description: > + Pointer to the user's handler function; or NULL pointer to un-register a handler + type: csi_isr_t * + - name: isr_ctx + description: > + Pointer to the user's context. This will be passed into the handler function when called. + type: void * + - name: source + description: > + Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or + a value from the BSP (extending the enumerations in csi_trap_source_t) enumerating a platform-specific + external interrupt source. + type: int + c-return-value: + description: > + Status of ISR registration operation. CSI_ERROR will be returned if the source parameter is + invalid, or if the requested source has not been enabled for u-mode handling by first running + csi_set_umode_trap_permissions . CSI_NOT_INITIALIZED will be returned if csi_interrupts_init has not been + called prior to calling this function, or if csi_interrupts_uninit was called prior to calling this + function. CSI_OUT_OF_MEM will be returned if the number of handlers registered exceeds that supported by + the context size. + type: csi_status_t + - name: csi_disable_m_trap_source + description: > + Disable a trap source. This function must be run in machine mode. Note that this only gates an interrupting + signal within the interrupt control logic. Device drivers may offer separate controls for turning their + interrupts on and off at source. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: source + description: > + Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or + a value from the BSP (extending the enumerations in csi_trap_source_t) enumerating a platform-specific + external interrupt source. + type: int + c-return-value: + description: > + Status of disable operation. CSI_ERROR will be returned if the source parameter is + invalid. + type: csi_status_t + - name: csi_enable_m_trap_source + description: > + Enable a trap source. This function must be run in machine mode. Note that this only gates an interrupting + signal within the interrupt control logic. Device drivers may offer separate controls for turning their + interrupts on and off at source. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: source + description: > + Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or + a value from the BSP (extending the enumerations in csi_trap_source_t) enumerating a platform-specific + external interrupt source. + type: int + c-return-value: + description: > + Status of enable operation. CSI_ERROR will be returned if the source parameter is + invalid. + type: csi_status_t + - name: csi_disable_u_trap_source + description: > + Disable handling of a trap arising from a particular source. This function must be run in user mode. + It will only have an effect if a user-mode handler has previously been registered for the selected source. + Note this only disables the running of the handler. Device drivers may offer separate controls for turning their + interrupts on and off at source. + c-params: + - name: uctx + description: > + U-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: source + description: > + Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or + a value from the BSP (extending the enumerations in csi_trap_source_t) enumerating a platform-specific + external interrupt source. + type: int + c-return-value: + description: > + Status of disable operation. CSI_ERROR will be returned if the source parameter is + invalid. + type: csi_status_t + - name: csi_enable_u_trap_source + description: > + Enable handling of a trap arising from a particular source. This function must be run in user mode. + It will only have an effect if a user-mode handler has previously been registered for the selected source. + Note this only enables the running of the handler. Device drivers may offer separate controls for turning their + interrupts on and off at source. + c-params: + - name: uctx + description: > + U-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: source + description: > + Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or + a value from the BSP (extending the enumerations in csi_trap_source_t) enumerating a platform-specific + external interrupt source. + type: int + c-return-value: + description: > + Status of enable operation. CSI_ERROR will be returned if the source parameter is + invalid. + type: csi_status_t + - name: csi_set_interrupt_enables + description: Enable or disable 3 classes of interrupts for this hart. Must be run in machine mode. + c-params: + - name: int_enables + description: > + Set bit 3 to enable software interrupts. Set bit 7 to enable timer interrupts. Set bit 11 to enable + external interrupts. Setting these bits to zero will disable each interrupt source respectively. All + other bits should be left at zero. + type: unsigned + c-return-value: + description: > + Integer in the same format as int_enables, reflecting the previous value of int_enables prior to the + change. This may be stored and passed back into another call to csi_set_interrupt_enables in order + to restore the previous interrupt enables state. + type: unsigned + - name: csi_set_umode_trap_permissions + description: > + Informs the interrupt subsystem whether a given signal is allowed to be handled in user mode. This function + must be run in machine mode. Any signals for which this function is not run will not be permitted to be + handled in U-mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: source + description: > + Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or + a value from the BSP (extending the enumerations in csi_trap_source_t) enumerating a platform-specific + external interrupt source. + type: int + - name: permitted + description: > + True if user mode is permitted to register a handler for this trap source. False if not permitted. + type: bool + c-return-value: + description: > + Status of permissions setting operation. CSI_ERROR will be returned if the source parameter is + invalid. + type: csi_status_t + - name: csi_define_sw_signal + description: > + Allocates a signal number for software use. The signal number must be outside the range currently + reserved by the BSP, otherwise an error is raised. When raised, the signal will be routed to the + specified hart ID. Must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: signal + description: > + Source enumeration for this signal. A unique number >= CSI_TOTAL_BSP_TRAP_SOURCES must be chosen. + type: int + - name: hartid + description: > + ID of the hart to which this signal will be routed. + type: int + c-return-value: + description: > + Status of operation. CSI_ERROR will be returned if the source parameter is invalid. + type: csi_status_t + - name: csi_raise_signal + description: > + Raises a software signal, previously defined using csi_define_sw_signal. Must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: signal + description: > + Source enumeration for this signal. + type: int + c-return-value: + description: > + Status of operation. CSI_ERROR will be returned if the specified signal is not software-raisable. + type: csi_status_t + - name: csi_set_irq_priority + description: > + Set priority for an external interrupt source. Priorities range from 0 to CSI_MAX_INTERRUPT_PRIORITY, + where 0 indicates "never interrupt", and 1 is the lowest subsequent priority level. + This function must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: signal + description: > + Source enumeration for this signal. + type: int + - name: priority + description: priority level. + type: int + c-return-value: + description: > + Status of operation. CSI_ERROR will be returned if the request is invalid. + type: csi_status_t + - name: csi_get_irq_priority + description: > + Get priority of an external interrupt source. Must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: signal + description: > + Source enumeration for this signal. + type: int + c-return-value: + description: priority level (resulting from calls to csi_set_irq_priority). -1 will be returned if + the request is invalid. + type: int + - name: csi_set_irq_priority_thresh + description: > + Set a priority threshold below which external interrupts will be masked. Must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: threshold + description: Priority threshold for external interrupts. + type: int + c-return-value: + description: > + Status of operation. CSI_ERROR will be returned if the request is invalid. + type: csi_status_t + - name: csi_get_irq_priority_thresh + description: Get the current priority threshold for external interrupts + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + c-return-value: + description: Priority threshold, or -1 if priority thresholds unsupported, or on error. + type: int diff --git a/chapter2.adoc b/chapter2.adoc index 6f5a3f3..45a1a79 100644 --- a/chapter2.adoc +++ b/chapter2.adoc @@ -96,6 +96,9 @@ that follow on from the interrupt numbers in csi_defs.h. The numerical values of these enumerations bear no relationship to hardware; they are simply unique numbers assigned arbitrarily to the interrupt sources, allowing them to be indexed by the software. The enumerations are prefixed INT_. +csi_bsp_interrupts.h should also define CSI_MAX_INTERRUPT_PRIORITY which defines the number of of non-zero interrupt +priorities available. + === Global Definitions Set By Application Writers The following macros may be defined globally by application writers, in order to change the behaviour of the underlying BSP code: @@ -118,3 +121,4 @@ CSI_LOG_INFO. See documentation of these macros for details. |=== include::auto-gen/modules/csi_defs_h.adoc[] +include::auto-gen/modules/csi_interrupts_h.adoc[] diff --git a/intro.adoc b/intro.adoc index 656972c..7bddcbf 100644 --- a/intro.adoc +++ b/intro.adoc @@ -44,3 +44,13 @@ indexterm:[Application Writers] functionality in the API. (This could also be implemented within a language runtime). indexterm:[Board Support Pack] indexterm:[BSP] +=== Assumed Features of Underlying Hardware + +==== Privilege Levels + +We assume that systems targeted by RVM-CSI will require either Machine-mode only, or Machine mode + User mode. +No functionality is provided to target Hypervisor, Supervisor or VS privilege modes. + +==== Virtual Memory + +RVM-CSI does not support virtual addressing. diff --git a/spec-schema/parser/doc_gen.py b/spec-schema/parser/doc_gen.py index 9ecd453..2ed809c 100644 --- a/spec-schema/parser/doc_gen.py +++ b/spec-schema/parser/doc_gen.py @@ -33,7 +33,13 @@ def format_adoc_type_declaration(declaration): out_str += heading_marker(4) + "Values\n" for member in declaration['enum-members']: - out_str += "*" + member['name'] + "*\n\n" + out_str += "*" + member['name'] + "*" + if 'value' in member.keys(): + out_str += " = " + str(member['value']) + out_str += "\n" + if 'description' in member.keys(): + out_str += member['description'] + "\n" + out_str += "\n" if c_type == "struct": out_str += heading_marker(4) + "Members\n" @@ -44,7 +50,24 @@ def format_adoc_type_declaration(declaration): if member_type[-1] == '*': # pointer delimiter = "" out_str += member_type + delimiter + member['name'] + "\n\n" - + + if c_type == "function": + out_str += heading_marker(4) + "Parameters\n" + if 'func-typedef-params' in declaration.keys(): + for param in declaration['func-typedef-params']: + param_type = param['type'] + param_name = param['name'] + if param_type[-1] == '*': # pointer + param_type = param_type.rstrip('* ') + param_name = "*" + param_name + out_str += param_type + " `" + param_name + "` - " + param['description'] + "\n\n" + + if 'notes' in param.keys(): + out_str += format_text_from_array(param['notes']) + out_str += "\n" + else: + out_str += "Function takes no parameters\n\n" + return out_str def format_adoc_function(function, module_type_list): @@ -100,7 +123,9 @@ def generate_c_module_adoc(module, out_dir, module_sub_dir, adoc_optimization): filename = module['c-filename'].lower().replace('.','_') + ".adoc" out_file = pathlib.Path(out_dir, module_sub_dir, filename) - out_str = "[#title]\n" + out_str = "indexterm:[" + module['c-filename'] + "]\n\n" + if adoc_optimization == 'html': + out_str += "[#title]\n" out_str += heading_marker(1) + module['c-filename'] + " - " + module['name'] + "\n" out_str += ":toc:\n" diff --git a/spec-schema/parser/header_gen.py b/spec-schema/parser/header_gen.py index 6cdf26a..d01fa44 100644 --- a/spec-schema/parser/header_gen.py +++ b/spec-schema/parser/header_gen.py @@ -61,8 +61,16 @@ def indent(): return " " # indent 4 spaces out_str = "" - - # values can be "struct", "enum", "int", "unsigned" + if 'description' in declaration.keys(): + out_str += "/*\n " + out_str += format_c_comment_lines(declaration['description']) + if 'func-typedef-params' in declaration.keys(): + out_str += "*\n " + for param in declaration['func-typedef-params']: + out_str += format_c_comment_lines("@param " + param['name'] + ": " + param['description']) + out_str += "*/\n" + + # values can be "struct", "enum", "int", "unsigned", "function" c_type = declaration['type'] if c_type == "int": out_str += "typedef int " + declaration['name'] + ";\n" @@ -75,10 +83,13 @@ def indent(): for member in declaration['enum-members']: out_str += indent() + member['name'] if 'value' in member.keys(): - out_str += " = " + str(member['value']) - out_str += ",\n" # trailing comma should be valid for modern compilers + out_str += " = " + str(member['value']) + out_str += "," # trailing comma should be valid for modern compilers + if 'description' in member.keys(): + out_str += " /* " + member['description'] + " */" + out_str += "\n" out_str += "} " + declaration['name'] + ";\n" - + elif c_type == "struct": out_str += "typedef struct {\n" for member in declaration['struct-members']: @@ -89,7 +100,25 @@ def indent(): out_str += indent() + member_type + delimiter + member['name'] + ";\n" out_str += "} " + declaration['name'] + ";\n" - + + elif c_type == "function": + retval = "void" + params = "void" + if 'func-typedef-retval' in declaration.keys(): + retval = declaration['func-typedef-retval'] + if 'func-typedef-params' in declaration.keys(): + params = '' + for param in declaration['func-typedef-params']: + param_type = param['type'] + param_name = param['name'] + if param_type[-1] == '*': + # pointer types - present with spacing as "int *a" + param_type = param_type.rstrip('* ') + param_name = "*" + param_name + params += param_type + " " + param_name + ", " + params = params.rstrip(", ") # Get rid of last comma/space + out_str += "typedef " + retval + " (" + declaration['name'] + ")(" + params + ");\n" + else: raise('undefined C type definition') # Should not be possible to reach here @@ -108,7 +137,13 @@ def format_c_function(function): out_str = "/*\n " out_str += format_c_comment_lines(function['description']) - + out_str += "*\n " + if 'c-params' in function.keys(): + for param in function['c-params']: + out_str += format_c_comment_lines("@param " + param['name'] + ": " + param['description']) + if 'c-return-value' in function.keys(): + out_str += format_c_comment_lines("@return " + ": " + function['c-return-value']['description']) + # Close comment out_str += "*/\n" diff --git a/spec-schema/rvm-csi.schema.json b/spec-schema/rvm-csi.schema.json index f81d211..075ce07 100644 --- a/spec-schema/rvm-csi.schema.json +++ b/spec-schema/rvm-csi.schema.json @@ -99,7 +99,7 @@ "c-type": { "description": "C type", "type": "string", - "enum": ["struct", "enum", "int", "unsigned"] + "enum": ["struct", "enum", "int", "unsigned", "function"] }, "c-type-prefix": { "description": "C type prefix (const, static, inline etc.)", @@ -134,6 +134,10 @@ "value": { "description": "C enum member value", "type": "integer" + }, + "description": { + "description": "Enumerated value description", + "type": "string" } } }, @@ -171,6 +175,17 @@ "items": { "$ref": "#/definitions/c-enum-entry" } + }, + "func-typedef-retval": { + "description": "Function return value for typedef", + "type": "string" + }, + "func-typedef-params": { + "description": "Function parameter list for typedef (note the list may be absent, in which case there is a single void parameter)", + "type": "array", + "items": { + "$ref": "#/definitions/c-function-param" + } } } }, From 313f438a7dd4f06a6fe1c9e6baec6009b609f133 Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Tue, 7 Feb 2023 13:00:45 +0000 Subject: [PATCH 02/10] Add timer support, and improve documentation. --- api/C/include/csi_bsp_interrupts.h | 10 +++ api/C/include/csi_defs.h | 4 +- api/C/include/csi_interrupts.h | 112 +++++++++++++++++++++----- api/rvm-csi-spec.yaml | 121 +++++++++++++++++++++++++---- chapter2.adoc | 12 ++- spec-schema/parser/doc_gen.py | 5 +- spec-schema/parser/header_gen.py | 5 ++ 7 files changed, 229 insertions(+), 40 deletions(-) diff --git a/api/C/include/csi_bsp_interrupts.h b/api/C/include/csi_bsp_interrupts.h index d37976c..a4897c0 100644 --- a/api/C/include/csi_bsp_interrupts.h +++ b/api/C/include/csi_bsp_interrupts.h @@ -1 +1,11 @@ /* PLACEHOLDER: replaced by content from BSP */ + +#ifndef CSI_BSP_INTERRUPTS_H +#define CSI_BSP_INTERRUPTS_H + +// Context structure for a timeout +typedef struct { + int placeholder; +} csi_timeout_t; + +#endif // CSI_BSP_INTERRUPTS_H diff --git a/api/C/include/csi_defs.h b/api/C/include/csi_defs.h index 639d988..3bbed13 100644 --- a/api/C/include/csi_defs.h +++ b/api/C/include/csi_defs.h @@ -1,8 +1,8 @@ /* * General-Purpose Definitions for use in CSI code * - * This file is included prior to all other headers and contains general-purpose - * definitions which may be used by subsequent headers. + * This file is included from rvm_csi.h prior to all other headers and contains + * general-purpose definitions which may be used by subsequent headers. * * Copyright (c) RISC-V International 2022. Creative Commons License. Auto- * generated file: DO NOT EDIT diff --git a/api/C/include/csi_interrupts.h b/api/C/include/csi_interrupts.h index 1f9fb94..4acf4ca 100644 --- a/api/C/include/csi_interrupts.h +++ b/api/C/include/csi_interrupts.h @@ -1,15 +1,19 @@ /* - * Trap Handling / Interrupt Support + * Trap Handling / Interrupt and Timer Support * * This module provides functionality for routing interrupts and registering - * handlers for traps. The BSP provides a base trap handler. Running the - * initialisation function csi_interrupts_init will put the address of this handler - * in the mtvec register. This base trap handler provides default exception - * handling, and calls any handlers registered by the user. It also provides - * functionality required by the RVM-CSI timer module. Systems using RVM-CSI may - * provide their own trap handling support, in which case csi_interrupts_init - * should not be called, and all functions in this module, and in the timer module, - * will be inoperative. + * handlers for traps, controlling the system timer, and managing timed events. The + * BSP provides a base trap handler. Running the initialisation function + * csi_interrupts_init will put the address of this handler in the mtvec register. + * This base trap handler provides default exception handling, and calls any + * handlers registered by the user. Systems using RVM-CSI may provide their own + * trap handling support, in which case csi_interrupts_init should not be called, + * and all functions in this module will be inoperative. + * + * There will be at most one instance of the trap handling and interrupt subsystem + * per hart. + * The base trap handler will attempt to inform users of unhandled exceptions via + * the RVM-CSI console API. Other unhandled interrupts will be ignored. * * Copyright (c) RISC-V International 2022. Creative Commons License. Auto- * generated file: DO NOT EDIT @@ -19,9 +23,10 @@ #define CSI_INTERRUPTS_H #include "csi_defs.h" +#include "csi_bsp_interrupts.h" /* - * Function prototype for the users trap handler (M-mode or U-mode) + * Function prototype for the user's trap handler (M-mode or U-mode) * * @param source: Enumerated interrupt source for which the handler was registered. * @param isr_ctx: User's context pointer as supplied when the handler was @@ -30,11 +35,22 @@ */ typedef void (csi_isr_t)(int source, void *isr_ctx, unsigned mtval); +/* + * Function prototype for the user's timeout callback function (M-mode or U-mode) + * + * @param handle: Handle for this timeout instance, as passed into csi_set_timeout + * @param callback_context: Context pointer that was passed into csi_set_timeout + */ +typedef void (csi_timeout_callback_t)(csi_timeout_t *handle, void *callback_context); + /* * Initialize interrupt and timer sub-system for this hart. Must be called before * calling any other functions in this module. This function must run in machine - * mode. + * mode. Following initialization, all interrupt sources (except exceptions and + * NMI) are disabled. To enable a source, first register a handler, using + * csi_register_m_isr or csi_register_u_isr; then enable the source with + * csi_enable_m_trap_source or csi_enable_u_trap_source. * * @param mctx: Pointer to an area of memory to be used as M-mode context space for * the interrupt subsystem. The BSP will define a macro @@ -261,10 +277,10 @@ csi_status_t csi_define_sw_signal(void *mctx, int signal, int hartid); * @return : Status of operation. CSI_ERROR will be returned if the specified * signal is not software-raisable. */ -csi_status_t csi_raise_signal(void *mctx, int signal); +csi_status_t csi_raise_sw_signal(void *mctx, int signal); /* - * Set priority for an external interrupt source. Priorities range from 0 to + * Set priority for an interrupt source. Priorities range from 0 to * CSI_MAX_INTERRUPT_PRIORITY, where 0 indicates "never interrupt", and 1 is the * lowest subsequent priority level. This function must be run in machine mode. * @@ -278,7 +294,7 @@ csi_status_t csi_raise_signal(void *mctx, int signal); csi_status_t csi_set_irq_priority(void *mctx, int signal, int priority); /* - * Get priority of an external interrupt source. Must be run in machine mode. + * Get priority of an interrupt source. Must be run in machine mode. * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. @@ -289,19 +305,19 @@ csi_status_t csi_set_irq_priority(void *mctx, int signal, int priority); int csi_get_irq_priority(void *mctx, int signal); /* - * Set a priority threshold below which external interrupts will be masked. Must - * be run in machine mode. + * Set a priority threshold below which interrupts will be masked. Must be run in + * machine mode. * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. - * @param threshold: Priority threshold for external interrupts. + * @param threshold: Priority threshold. * @return : Status of operation. CSI_ERROR will be returned if the request is * invalid. */ csi_status_t csi_set_irq_priority_thresh(void *mctx, int threshold); /* - * Get the current priority threshold for external interrupts + * Get the current priority threshold for interrupts * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. @@ -310,5 +326,65 @@ csi_status_t csi_set_irq_priority_thresh(void *mctx, int threshold); */ int csi_get_irq_priority_thresh(void *mctx); +/* + * Force an external interrupt (e.g. for testing purposes). Must be run in machine + * mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param signal: Source enumeration for this signal. + */ +void csi_force_ext_irq(void *mctx, int signal); + +/* + * RISC-V hardware has a single timer implemented as a counter running at some + * defined frequency, and a compare register. An interrupt is generated when the + * count hits the compare register value. This function configures the timer and + * compare register to produce a regular timer interrupt at the configured tick + * rate, and enables a handler within the BSP to service those interrupts. This + * base timer handler can then service multiple timed events that may be configured + * using csi_set_timeout. This function must be run in machine mode. Care must be + * taken since the timer services all harts in the system, so this function can + * affect the operation of code on other harts. + * + * @param tick_period_us: Timer tick period in microseconds. Longer tick periods + * put less load on the system (due to servicing interrupts), but limit the + * accuracy of any timed events. Passing a value of 0 for the tick period disables + * the timer and turns off timer interrupts. + * @return : Status of operation. CSI_ERROR will be returned if the request is + * invalid. + */ +csi_status_t csi_timer_config(unsigned tick_period_us); + +/* + * Registers a callback function (callback) which will be called after a period set + * by timeout_ticks unless cancelled with cs_cancel_timeout(). callback_context + * will be passed into the user's callback function. The structure pointed to by + * handle will be initialised by this function and used as a handle for this + * timeout instance. This function may be run in either machine mode or user mode. + * + * @param handle: Handle for this timeout instance. The structure declaration + * csi_timeout_t is published by the BSP in csi_bsp_interrupts.h but should be + * considered private to the BSP. Application code instantiates this structure and + * passes in a pointer to it. + * @param callback: Pointer to the users callback function, to be called when the + * timeout expires. + * @param callback_context: Pointer to the user's context space, which will be + * passed into the callback function. + * @param timeout_ticks: Timeout period in ticks (configured by csi_timer_config) + * @return : Status of operation. + */ +csi_status_t csi_set_timeout(csi_timeout_t *handle, csi_timeout_callback_t *callback, void *callback_context, int timeout_ticks); + +/* + * Cancels a timeout previously configured with csi_set_timeout, using the + * associated handle. Cancelling a timer that has already expired is not an error. + * + * @param handle: handle for this timeout instance, previously initialised with + * csi_set_timeout + * @return : Status of operation. + */ +csi_status_t csi_cancel_timeout(csi_timeout_t *handle); + #endif /* CSI_INTERRUPTS_H */ diff --git a/api/rvm-csi-spec.yaml b/api/rvm-csi-spec.yaml index 486fb29..583830e 100644 --- a/api/rvm-csi-spec.yaml +++ b/api/rvm-csi-spec.yaml @@ -10,8 +10,8 @@ top-heading-level: 2 modules: - name: General-Purpose Definitions for use in CSI code description: > - This file is included prior to all other headers and contains general-purpose definitions which - may be used by subsequent headers. + This file is included from rvm_csi.h prior to all other headers and contains general-purpose + definitions which may be used by subsequent headers. c-specific: true c-filename: csi_defs.h c-type-declarations: @@ -61,25 +61,31 @@ modules: - name: CSI_ENUM_STORE_PAGE_FAULT - name: CSI_NUM_STANDARD_TRAP_SOURCES description: Must come last in this list - - name: Trap Handling / Interrupt Support + - name: Trap Handling / Interrupt and Timer Support description: > - This module provides functionality for routing interrupts and registering handlers for traps. + This module provides functionality for routing interrupts and registering handlers for traps, + controlling the system timer, and managing timed events. The BSP provides a base trap handler. Running the initialisation function csi_interrupts_init will put the address of this handler in the mtvec register. This base trap handler provides default - exception handling, and calls any handlers registered by the user. It also provides functionality - required by the RVM-CSI timer module. Systems using RVM-CSI may provide their own trap handling - support, in which case csi_interrupts_init should not be called, and all functions in this module, - and in the timer module, will be inoperative. + exception handling, and calls any handlers registered by the user. + Systems using RVM-CSI may provide their own trap handling + support, in which case csi_interrupts_init should not be called, and all functions in this module + will be inoperative. notes: - There will be at most one instance of the trap handling and interrupt subsystem per hart. + - > + The base trap handler will attempt to inform users of unhandled exceptions via the RVM-CSI console + API. Other unhandled interrupts will be ignored. c-specific: false c-filename: csi_interrupts.h c-include-files: - filename: csi_defs.h system-header: false + - filename: csi_bsp_interrupts.h + system-header: false c-type-declarations: - name: csi_isr_t - description: Function prototype for the users trap handler (M-mode or U-mode) + description: Function prototype for the user's trap handler (M-mode or U-mode) type: function func-typedef-retval: void func-typedef-params: @@ -93,11 +99,26 @@ modules: - name: mtval description: Contents of the mtval register associated with this trap. type: unsigned + - name: csi_timeout_callback_t + description: Function prototype for the user's timeout callback function (M-mode or U-mode) + type: function + func-typedef-retval: void + func-typedef-params: + - name: handle + description: Handle for this timeout instance, as passed into csi_set_timeout + type: csi_timeout_t * + - name: callback_context + description: > + Context pointer that was passed into csi_set_timeout + type: void * functions: - name: csi_interrupts_init description: > Initialize interrupt and timer sub-system for this hart. Must be called before calling any other functions - in this module. This function must run in machine mode. + in this module. This function must run in machine mode. Following initialization, all interrupt sources + (except exceptions and NMI) are disabled. To enable a source, first register a handler, using + csi_register_m_isr or csi_register_u_isr; then enable the source with csi_enable_m_trap_source or + csi_enable_u_trap_source. c-params: - name: mctx description: > @@ -360,7 +381,7 @@ modules: description: > Status of operation. CSI_ERROR will be returned if the source parameter is invalid. type: csi_status_t - - name: csi_raise_signal + - name: csi_raise_sw_signal description: > Raises a software signal, previously defined using csi_define_sw_signal. Must be run in machine mode. c-params: @@ -378,7 +399,7 @@ modules: type: csi_status_t - name: csi_set_irq_priority description: > - Set priority for an external interrupt source. Priorities range from 0 to CSI_MAX_INTERRUPT_PRIORITY, + Set priority for an interrupt source. Priorities range from 0 to CSI_MAX_INTERRUPT_PRIORITY, where 0 indicates "never interrupt", and 1 is the lowest subsequent priority level. This function must be run in machine mode. c-params: @@ -399,7 +420,7 @@ modules: type: csi_status_t - name: csi_get_irq_priority description: > - Get priority of an external interrupt source. Must be run in machine mode. + Get priority of an interrupt source. Must be run in machine mode. c-params: - name: mctx description: > @@ -415,21 +436,21 @@ modules: type: int - name: csi_set_irq_priority_thresh description: > - Set a priority threshold below which external interrupts will be masked. Must be run in machine mode. + Set a priority threshold below which interrupts will be masked. Must be run in machine mode. c-params: - name: mctx description: > M-mode context pointer previously initialised by csi_interrupts_init. type: void * - name: threshold - description: Priority threshold for external interrupts. + description: Priority threshold. type: int c-return-value: description: > Status of operation. CSI_ERROR will be returned if the request is invalid. type: csi_status_t - name: csi_get_irq_priority_thresh - description: Get the current priority threshold for external interrupts + description: Get the current priority threshold for interrupts c-params: - name: mctx description: > @@ -438,3 +459,71 @@ modules: c-return-value: description: Priority threshold, or -1 if priority thresholds unsupported, or on error. type: int + - name: csi_force_ext_irq + description: Force an external interrupt (e.g. for testing purposes). Must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: signal + description: > + Source enumeration for this signal. + type: int + - name: csi_timer_config + description: > + RISC-V hardware has a single timer implemented as a counter running at some defined frequency, + and a compare register. An interrupt is generated when the count hits the compare register value. + This function configures the timer and compare register to produce a regular timer interrupt at + the configured tick rate, and enables a handler within the BSP to service those interrupts. This base timer + handler can then service multiple timed events that may be configured using csi_set_timeout. + This function must be run in machine mode. Care must be taken since the timer services all harts + in the system, so this function can affect the operation of code on other harts. + c-params: + - name: tick_period_us + description: > + Timer tick period in microseconds. Longer tick periods put less load on the system (due to + servicing interrupts), but limit the accuracy of any timed events. Passing a value of 0 for the + tick period disables the timer and turns off timer interrupts. + type: unsigned + c-return-value: + description: > + Status of operation. CSI_ERROR will be returned if the request is invalid. + type: csi_status_t + - name: csi_set_timeout + description: > + Registers a callback function (callback) which will be called after a period set by timeout_ticks + unless cancelled with cs_cancel_timeout(). callback_context will be passed into the user's callback + function. The structure pointed to by handle will be initialised by this function and used as a + handle for this timeout instance. This function may be run in either machine mode or user mode. + c-params: + - name: handle + description: > + Handle for this timeout instance. The structure declaration csi_timeout_t is published + by the BSP in csi_bsp_interrupts.h but should be considered private to the BSP. Application + code instantiates this structure and passes in a pointer to it. + type: csi_timeout_t * + - name: callback + description: Pointer to the users callback function, to be called when the timeout expires. + type: csi_timeout_callback_t * + - name: callback_context + description: Pointer to the user's context space, which will be passed into the callback function. + type: void * + - name: timeout_ticks + description: Timeout period in ticks (configured by csi_timer_config) + type: int + c-return-value: + description: Status of operation. + type: csi_status_t + - name: csi_cancel_timeout + description: > + Cancels a timeout previously configured with csi_set_timeout, using the associated handle. + Cancelling a timer that has already expired is not an error. + c-params: + - name: handle + description: handle for this timeout instance, previously initialised with csi_set_timeout + type: csi_timeout_t * + c-return-value: + description: Status of operation. + type: csi_status_t + \ No newline at end of file diff --git a/chapter2.adoc b/chapter2.adoc index 45a1a79..1a15193 100644 --- a/chapter2.adoc +++ b/chapter2.adoc @@ -96,8 +96,16 @@ that follow on from the interrupt numbers in csi_defs.h. The numerical values of these enumerations bear no relationship to hardware; they are simply unique numbers assigned arbitrarily to the interrupt sources, allowing them to be indexed by the software. The enumerations are prefixed INT_. -csi_bsp_interrupts.h should also define CSI_MAX_INTERRUPT_PRIORITY which defines the number of of non-zero interrupt -priorities available. +csi_bsp_interrupts.h should also define the following macros and types: + +[cols="3,2,6",options="header"] +|=== +|Definition|Type|Purpose +|CSI_MAX_INTERRUPT_PRIORITY|Macro|Number of of non-zero interrupt priorities available +|CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES|Macro|Miniumum size of M-mode context space for interrupt sub-system +|CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES|Macro|Miniumum size of U-mode context space for interrupt sub-system +|csi_timeout_t|struct|Context structure associated with a timeout +|=== === Global Definitions Set By Application Writers diff --git a/spec-schema/parser/doc_gen.py b/spec-schema/parser/doc_gen.py index 2ed809c..c4d968c 100644 --- a/spec-schema/parser/doc_gen.py +++ b/spec-schema/parser/doc_gen.py @@ -135,8 +135,9 @@ def generate_c_module_adoc(module, out_dir, module_sub_dir, adoc_optimization): out_str += heading_marker(2) + "Notes\n" if 'notes' in module.keys(): - out_str += format_text_from_array(module['notes']) - out_str += "\n" + for note in module['notes']: + out_str += note + out_str += "\n\n" if 'c-specific-notes' in module.keys(): out_str += format_text_from_array(module['c-specific-notes']) diff --git a/spec-schema/parser/header_gen.py b/spec-schema/parser/header_gen.py index d01fa44..980ee30 100644 --- a/spec-schema/parser/header_gen.py +++ b/spec-schema/parser/header_gen.py @@ -191,6 +191,11 @@ def generate_c(api_definition, out_dir): out_str += format_c_comment_lines(module['description']) out_str += "*\n " + + if 'notes' in module.keys(): + for note in module['notes']: + out_str += format_c_comment_lines(note) + out_str += "*\n " out_str += format_c_comment_lines(api_definition['boilerplate']) From c7ea8255beaab085d3769b44194af74f02d9f788 Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Tue, 7 Feb 2023 22:26:03 +0000 Subject: [PATCH 03/10] Get rid of user mode context and switch to use of a handle. Add u-mode functions for raising signals and setting timeouts Split timer config into 2 functions --- api/C/include/csi_defs.h | 9 ++ api/C/include/csi_interrupts.h | 157 ++++++++++++++++++++----------- api/rvm-csi-spec.yaml | 166 +++++++++++++++++++++++---------- chapter2.adoc | 1 - 4 files changed, 231 insertions(+), 102 deletions(-) diff --git a/api/C/include/csi_defs.h b/api/C/include/csi_defs.h index 3bbed13..7c18eda 100644 --- a/api/C/include/csi_defs.h +++ b/api/C/include/csi_defs.h @@ -55,5 +55,14 @@ typedef enum { CSI_NUM_STANDARD_TRAP_SOURCES, /* Must come last in this list */ } csi_trap_source_t; +/* + * Interrupt enable bits in the mie CSR + */ +typedef enum { + CSI_SW_INTERRUPTS_ENABLE = 8, + CSI_TIMER_INTERRUPTS_ENABLE = 128, + CSI_EXT_INTERRUPTS_ENABLE = 2048, +} csi_interrupt_enables_t; + #endif /* CSI_DEFS_H */ diff --git a/api/C/include/csi_interrupts.h b/api/C/include/csi_interrupts.h index 4acf4ca..1a823f7 100644 --- a/api/C/include/csi_interrupts.h +++ b/api/C/include/csi_interrupts.h @@ -38,10 +38,11 @@ typedef void (csi_isr_t)(int source, void *isr_ctx, unsigned mtval); /* * Function prototype for the user's timeout callback function (M-mode or U-mode) * - * @param handle: Handle for this timeout instance, as passed into csi_set_timeout + * @param timeout_handle: Handle for this timeout instance, as passed into + * csi_set_timeout * @param callback_context: Context pointer that was passed into csi_set_timeout */ -typedef void (csi_timeout_callback_t)(csi_timeout_t *handle, void *callback_context); +typedef void (csi_timeout_callback_t)(csi_timeout_t *timeout_handle, void *callback_context); /* @@ -60,17 +61,9 @@ typedef void (csi_timeout_callback_t)(csi_timeout_t *handle, void *callback_cont * @param mctx_size: Size of memory allocated at the mctx pointer in bytes. * Allocating more than CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES may permit additional * M-mode handlers to be registered. - * @param uctx: Pointer to an area of memory to be used as U-mode context space for - * the interrupt subsystem. The BSP will define a macro - * CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES which defines the minimum required size of - * this context space in bytes. Calling this function initializes the context - * space. - * @param uctx_size: Size of memory allocated at the uctx pointer in bytes. - * Allocating more than CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES may permit additional - * U-mode handlers to be registered. * @return : Status of initialisation operation */ -csi_status_t csi_interrupts_init(void *mctx, unsigned mctx_size, void *uctx, unsigned uctx_size); +csi_status_t csi_interrupts_init(void *mctx, unsigned mctx_size); /* * Un-initialize the interrupt and timer sub-system. After calling this function, @@ -84,12 +77,14 @@ csi_status_t csi_interrupts_init(void *mctx, unsigned mctx_size, void *uctx, uns csi_status_t csi_interrupts_uninit(void *mctx); /* - * This function is run from U-mode to obtain the U-mode context pointer previously - * passed into csi_interrupts_init for the current hart. + * This function is run from U-mode to obtain a handle that can be used to + * reference the interrupt sub-system for the current hart. (This will usually be + * the address of mctx as passed into csi_interrupts_init, which can be de- + * referenced by M-mode code but not U-mode). * - * @return : context pointer, or null pointer if inapplicable. + * @return : IRQ system handle, or 0 if inapplicable. */ -void * get_interrupts_u_ctx(void); +unsigned get_interrupts_u_handle(void); /* * Registers a user-supplied function (isr) that will be called in M-mode by the @@ -126,10 +121,13 @@ csi_status_t csi_register_m_isr(void *mctx, csi_isr_t *isr, void *isr_ctx, int s * signal number and mtval contents. This function transparently deals with * routing the desired signal to the hart and enabling the interrupt. This * function must run in user mode. Running this function with a NULL pointer for - * the isr parameter will un-register a previously registered handler. + * the isr parameter will un-register a previously registered handler. Note that + * before registering a user mode handler for a source, + * csi_set_umode_trap_permissions must have been run (from machine mode) in order + * to enable handling of the trap in U-mode. * - * @param uctx: U-mode context pointer previously initialised by - * csi_interrupts_init. + * @param irq_system_handle: Handle for the interrupt sub-system on this hart, + * obtained by running get_interrupts_u_handle * @param isr: Pointer to the user's handler function; or NULL pointer to un- * register a handler * @param isr_ctx: Pointer to the user's context. This will be passed into the @@ -146,7 +144,7 @@ csi_status_t csi_register_m_isr(void *mctx, csi_isr_t *isr, void *isr_ctx, int s * calling this function. CSI_OUT_OF_MEM will be returned if the number of handlers * registered exceeds that supported by the context size. */ -csi_status_t csi_register_u_isr(void *uctx, csi_isr_t *isr, void *isr_ctx, int source); +csi_status_t csi_register_u_isr(unsigned irq_system_handle, csi_isr_t *isr, void *isr_ctx, int source); /* * Disable a trap source. This function must be run in machine mode. Note that @@ -189,8 +187,8 @@ csi_status_t csi_enable_m_trap_source(void *mctx, int source); * running of the handler. Device drivers may offer separate controls for turning * their interrupts on and off at source. * - * @param uctx: U-mode context pointer previously initialised by - * csi_interrupts_init. + * @param irq_system_handle: Handle for the interrupt sub-system on this hart, + * obtained by running get_interrupts_u_handle * @param source: Enumerated interrupt / exception source. This must be one of the * enumerations from csi_trap_source_t, or a value from the BSP (extending the * enumerations in csi_trap_source_t) enumerating a platform-specific external @@ -198,7 +196,7 @@ csi_status_t csi_enable_m_trap_source(void *mctx, int source); * @return : Status of disable operation. CSI_ERROR will be returned if the source * parameter is invalid. */ -csi_status_t csi_disable_u_trap_source(void *uctx, int source); +csi_status_t csi_disable_u_trap_source(unsigned irq_system_handle, int source); /* * Enable handling of a trap arising from a particular source. This function must @@ -207,8 +205,8 @@ csi_status_t csi_disable_u_trap_source(void *uctx, int source); * running of the handler. Device drivers may offer separate controls for turning * their interrupts on and off at source. * - * @param uctx: U-mode context pointer previously initialised by - * csi_interrupts_init. + * @param irq_system_handle: Handle for the interrupt sub-system on this hart, + * obtained by running get_interrupts_u_handle * @param source: Enumerated interrupt / exception source. This must be one of the * enumerations from csi_trap_source_t, or a value from the BSP (extending the * enumerations in csi_trap_source_t) enumerating a platform-specific external @@ -216,16 +214,17 @@ csi_status_t csi_disable_u_trap_source(void *uctx, int source); * @return : Status of enable operation. CSI_ERROR will be returned if the source * parameter is invalid. */ -csi_status_t csi_enable_u_trap_source(void *uctx, int source); +csi_status_t csi_enable_u_trap_source(unsigned irq_system_handle, int source); /* * Enable or disable 3 classes of interrupts for this hart. Must be run in machine * mode. * - * @param int_enables: Set bit 3 to enable software interrupts. Set bit 7 to - * enable timer interrupts. Set bit 11 to enable external interrupts. Setting - * these bits to zero will disable each interrupt source respectively. All other - * bits should be left at zero. + * @param int_enables: This word will be written directly to the mie CSR in order + * to control whether software interrupts, timer interrupts and external interrupts + * are enabled. To enable all 3 classes of interrupts, pass a value of + * CSI_SW_INTERRUPTS_ENABLE | CSI_TIMER_INTERRUPTS_ENABLE | + * CSI_EXT_INTERRUPTS_ENABLE. To disable all interrupts, pass a value of 0. * @return : Integer in the same format as int_enables, reflecting the previous * value of int_enables prior to the change. This may be stored and passed back * into another call to csi_set_interrupt_enables in order to restore the previous @@ -277,7 +276,20 @@ csi_status_t csi_define_sw_signal(void *mctx, int signal, int hartid); * @return : Status of operation. CSI_ERROR will be returned if the specified * signal is not software-raisable. */ -csi_status_t csi_raise_sw_signal(void *mctx, int signal); +csi_status_t csi_raise_m_sw_signal(void *mctx, int signal); + +/* + * Raises a software signal, previously defined using csi_define_sw_signal. Must + * be run in user mode. User-mode permissions for the selected signal must have + * been set by previously running csi_set_umode_trap_permissions. + * + * @param irq_system_handle: Handle for the interrupt sub-system on this hart, + * obtained by running get_interrupts_u_handle + * @param signal: Source enumeration for this signal. + * @return : Status of operation. CSI_ERROR will be returned if the specified + * signal is not software-raisable. + */ +csi_status_t csi_raise_u_sw_signal(unsigned irq_system_handle, int signal); /* * Set priority for an interrupt source. Priorities range from 0 to @@ -317,7 +329,7 @@ int csi_get_irq_priority(void *mctx, int signal); csi_status_t csi_set_irq_priority_thresh(void *mctx, int threshold); /* - * Get the current priority threshold for interrupts + * Get the current priority threshold for interrupts Must be run in machine mode. * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. @@ -337,54 +349,91 @@ int csi_get_irq_priority_thresh(void *mctx); void csi_force_ext_irq(void *mctx, int signal); /* - * RISC-V hardware has a single timer implemented as a counter running at some - * defined frequency, and a compare register. An interrupt is generated when the - * count hits the compare register value. This function configures the timer and - * compare register to produce a regular timer interrupt at the configured tick - * rate, and enables a handler within the BSP to service those interrupts. This - * base timer handler can then service multiple timed events that may be configured - * using csi_set_timeout. This function must be run in machine mode. Care must be - * taken since the timer services all harts in the system, so this function can - * affect the operation of code on other harts. + * Set the frequency of the system timer. Note that there is typically a single + * timer for all harts in the system, so this function can affect the operation of + * other harts. The timer will be compared against a compare register for each + * hart in order to produce a regular timer interrupt at a tick rate configured + * using csi_set_timer_tick, which is used for timing purposes. This function must + * run in machine mode. + * + * @param timer_freq_mhz: System timer frequency in MHz + * @return : Status of operation. CSI_ERROR will be returned if the request is + * invalid. + */ +csi_status_t csi_timer_config(unsigned timer_freq_mhz); + +/* + * This function causes the BSP to register a base handler for timer interrupts and + * to control the value of the mtimecmp register in order to produce a regular + * timer tick interrupt at the requested frequency. This base timer handler can + * then service multiple timed events that may be configured using csi_set_timeout. + * This function must be run in machine mode. * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. * @param tick_period_us: Timer tick period in microseconds. Longer tick periods * put less load on the system (due to servicing interrupts), but limit the - * accuracy of any timed events. Passing a value of 0 for the tick period disables - * the timer and turns off timer interrupts. + * accuracy of any timed events. Passing a value of 0 for the tick period turns off + * timer interrupts. * @return : Status of operation. CSI_ERROR will be returned if the request is * invalid. */ -csi_status_t csi_timer_config(unsigned tick_period_us); +csi_status_t csi_set_timer_tick(void *mctx, unsigned tick_period_us); /* * Registers a callback function (callback) which will be called after a period set * by timeout_ticks unless cancelled with cs_cancel_timeout(). callback_context * will be passed into the user's callback function. The structure pointed to by - * handle will be initialised by this function and used as a handle for this - * timeout instance. This function may be run in either machine mode or user mode. + * timeout_handle will be initialised by this function and used as a handle for + * this timeout instance. This function must be run in machine mode. * - * @param handle: Handle for this timeout instance. The structure declaration - * csi_timeout_t is published by the BSP in csi_bsp_interrupts.h but should be - * considered private to the BSP. Application code instantiates this structure and - * passes in a pointer to it. + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param timeout_handle: Handle for this timeout instance. The structure + * declaration csi_timeout_t is published by the BSP in csi_bsp_interrupts.h but + * should be considered private to the BSP. Application code instantiates this + * structure and passes in a pointer to it. * @param callback: Pointer to the users callback function, to be called when the * timeout expires. * @param callback_context: Pointer to the user's context space, which will be * passed into the callback function. - * @param timeout_ticks: Timeout period in ticks (configured by csi_timer_config) + * @param timeout_ticks: Timeout period in ticks (configured by csi_set_timer_tick) * @return : Status of operation. */ -csi_status_t csi_set_timeout(csi_timeout_t *handle, csi_timeout_callback_t *callback, void *callback_context, int timeout_ticks); +csi_status_t csi_set_m_timeout(void *mctx, csi_timeout_t *timeout_handle, csi_timeout_callback_t *callback, void *callback_context, int timeout_ticks); + +/* + * Registers a callback function (callback) which will be called after a period set + * by timeout_ticks unless cancelled with cs_cancel_timeout(). callback_context + * will be passed into the user's callback function. The structure pointed to by + * timeout_handle will be initialised by this function and used as a handle for + * this timeout instance. This function must be run in user mode. + * + * @param irq_system_handle: Handle for the interrupt sub-system on this hart, + * obtained by running get_interrupts_u_handle + * @param timeout_handle: Handle for this timeout instance. The structure + * declaration csi_timeout_t is published by the BSP in csi_bsp_interrupts.h but + * should be considered private to the BSP. Application code instantiates this + * structure and passes in a pointer to it. + * @param callback: Pointer to the users callback function, to be called when the + * timeout expires. + * @param callback_context: Pointer to the user's context space, which will be + * passed into the callback function. + * @param timeout_ticks: Timeout period in ticks (configured by csi_set_timer_tick) + * @return : Status of operation. + */ +csi_status_t csi_set_u_timeout(unsigned irq_system_handle, csi_timeout_t *timeout_handle, csi_timeout_callback_t *callback, void *callback_context, int timeout_ticks); /* * Cancels a timeout previously configured with csi_set_timeout, using the * associated handle. Cancelling a timer that has already expired is not an error. + * This function may be run in either machine mode or user mode. * - * @param handle: handle for this timeout instance, previously initialised with - * csi_set_timeout + * @param timeout_handle: handle for this timeout instance, previously initialised + * with csi_set_timeout * @return : Status of operation. */ -csi_status_t csi_cancel_timeout(csi_timeout_t *handle); +csi_status_t csi_cancel_timeout(csi_timeout_t *timeout_handle); #endif /* CSI_INTERRUPTS_H */ diff --git a/api/rvm-csi-spec.yaml b/api/rvm-csi-spec.yaml index 583830e..e9d092b 100644 --- a/api/rvm-csi-spec.yaml +++ b/api/rvm-csi-spec.yaml @@ -61,6 +61,16 @@ modules: - name: CSI_ENUM_STORE_PAGE_FAULT - name: CSI_NUM_STANDARD_TRAP_SOURCES description: Must come last in this list + - name: csi_interrupt_enables_t + description: Interrupt enable bits in the mie CSR + type: enum + enum-members: + - name: CSI_SW_INTERRUPTS_ENABLE + value: 8 + - name: CSI_TIMER_INTERRUPTS_ENABLE + value: 128 + - name: CSI_EXT_INTERRUPTS_ENABLE + value: 2048 - name: Trap Handling / Interrupt and Timer Support description: > This module provides functionality for routing interrupts and registering handlers for traps, @@ -104,7 +114,7 @@ modules: type: function func-typedef-retval: void func-typedef-params: - - name: handle + - name: timeout_handle description: Handle for this timeout instance, as passed into csi_set_timeout type: csi_timeout_t * - name: callback_context @@ -131,17 +141,6 @@ modules: Size of memory allocated at the mctx pointer in bytes. Allocating more than CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES may permit additional M-mode handlers to be registered. type: unsigned - - name: uctx - description: > - Pointer to an area of memory to be used as U-mode context space for the interrupt subsystem. The BSP will - define a macro CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES which defines the minimum required size of this context space in - bytes. Calling this function initializes the context space. - type: void * - - name: uctx_size - description: > - Size of memory allocated at the uctx pointer in bytes. Allocating more than CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES may - permit additional U-mode handlers to be registered. - type: unsigned c-return-value: description: Status of initialisation operation type: csi_status_t @@ -158,13 +157,14 @@ modules: c-return-value: description: Status of uninitialisation operation type: csi_status_t - - name: get_interrupts_u_ctx + - name: get_interrupts_u_handle description: > - This function is run from U-mode to obtain the U-mode context pointer previously passed into csi_interrupts_init - for the current hart. + This function is run from U-mode to obtain a handle that can be used to reference the interrupt sub-system + for the current hart. (This will usually be the address of mctx as passed into csi_interrupts_init, which + can be de-referenced by M-mode code but not U-mode). c-return-value: - description: context pointer, or null pointer if inapplicable. - type: void * + description: IRQ system handle, or 0 if inapplicable. + type: unsigned - name: csi_register_m_isr description: > Registers a user-supplied function (isr) that will be called in M-mode by the base trap handler on receipt of a @@ -204,12 +204,14 @@ modules: trap arising from from the source signal. isr_ctx is a parameter that will be passed into the user's ISR along with the signal number and mtval contents. This function transparently deals with routing the desired signal to the hart and enabling the interrupt. This function must run in user mode. Running this function with a NULL - pointer for the isr parameter will un-register a previously registered handler. + pointer for the isr parameter will un-register a previously registered handler. Note that before registering + a user mode handler for a source, csi_set_umode_trap_permissions must have been run (from machine mode) in order + to enable handling of the trap in U-mode. c-params: - - name: uctx + - name: irq_system_handle description: > - U-mode context pointer previously initialised by csi_interrupts_init. - type: void * + Handle for the interrupt sub-system on this hart, obtained by running get_interrupts_u_handle + type: unsigned - name: isr description: > Pointer to the user's handler function; or NULL pointer to un-register a handler @@ -282,10 +284,10 @@ modules: Note this only disables the running of the handler. Device drivers may offer separate controls for turning their interrupts on and off at source. c-params: - - name: uctx + - name: irq_system_handle description: > - U-mode context pointer previously initialised by csi_interrupts_init. - type: void * + Handle for the interrupt sub-system on this hart, obtained by running get_interrupts_u_handle + type: unsigned - name: source description: > Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or @@ -304,10 +306,10 @@ modules: Note this only enables the running of the handler. Device drivers may offer separate controls for turning their interrupts on and off at source. c-params: - - name: uctx + - name: irq_system_handle description: > - U-mode context pointer previously initialised by csi_interrupts_init. - type: void * + Handle for the interrupt sub-system on this hart, obtained by running get_interrupts_u_handle + type: unsigned - name: source description: > Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or @@ -324,9 +326,10 @@ modules: c-params: - name: int_enables description: > - Set bit 3 to enable software interrupts. Set bit 7 to enable timer interrupts. Set bit 11 to enable - external interrupts. Setting these bits to zero will disable each interrupt source respectively. All - other bits should be left at zero. + This word will be written directly to the mie CSR in order to control whether software interrupts, + timer interrupts and external interrupts are enabled. To enable all 3 classes of interrupts, + pass a value of CSI_SW_INTERRUPTS_ENABLE | CSI_TIMER_INTERRUPTS_ENABLE | CSI_EXT_INTERRUPTS_ENABLE. To + disable all interrupts, pass a value of 0. type: unsigned c-return-value: description: > @@ -381,7 +384,7 @@ modules: description: > Status of operation. CSI_ERROR will be returned if the source parameter is invalid. type: csi_status_t - - name: csi_raise_sw_signal + - name: csi_raise_m_sw_signal description: > Raises a software signal, previously defined using csi_define_sw_signal. Must be run in machine mode. c-params: @@ -397,6 +400,24 @@ modules: description: > Status of operation. CSI_ERROR will be returned if the specified signal is not software-raisable. type: csi_status_t + - name: csi_raise_u_sw_signal + description: > + Raises a software signal, previously defined using csi_define_sw_signal. Must be run in user mode. + User-mode permissions for the selected signal must have been set by previously running + csi_set_umode_trap_permissions. + c-params: + - name: irq_system_handle + description: > + Handle for the interrupt sub-system on this hart, obtained by running get_interrupts_u_handle + type: unsigned + - name: signal + description: > + Source enumeration for this signal. + type: int + c-return-value: + description: > + Status of operation. CSI_ERROR will be returned if the specified signal is not software-raisable. + type: csi_status_t - name: csi_set_irq_priority description: > Set priority for an interrupt source. Priorities range from 0 to CSI_MAX_INTERRUPT_PRIORITY, @@ -450,7 +471,7 @@ modules: Status of operation. CSI_ERROR will be returned if the request is invalid. type: csi_status_t - name: csi_get_irq_priority_thresh - description: Get the current priority threshold for interrupts + description: Get the current priority threshold for interrupts Must be run in machine mode. c-params: - name: mctx description: > @@ -472,32 +493,53 @@ modules: type: int - name: csi_timer_config description: > - RISC-V hardware has a single timer implemented as a counter running at some defined frequency, - and a compare register. An interrupt is generated when the count hits the compare register value. - This function configures the timer and compare register to produce a regular timer interrupt at - the configured tick rate, and enables a handler within the BSP to service those interrupts. This base timer - handler can then service multiple timed events that may be configured using csi_set_timeout. - This function must be run in machine mode. Care must be taken since the timer services all harts - in the system, so this function can affect the operation of code on other harts. + Set the frequency of the system timer. Note that there is typically a single timer for all + harts in the system, so this function can affect the operation of other harts. The timer will + be compared against a compare register for each hart in order to produce a regular timer + interrupt at a tick rate configured using csi_set_timer_tick, which is used for timing purposes. + This function must run in machine mode. + c-params: + - name: timer_freq_mhz + description: > + System timer frequency in MHz + type: unsigned + c-return-value: + description: > + Status of operation. CSI_ERROR will be returned if the request is invalid. + type: csi_status_t + - name: csi_set_timer_tick + description: > + This function causes the BSP to register a base handler for timer interrupts and to control the + value of the mtimecmp register in order to produce a regular timer tick interrupt at the + requested frequency. This base timer handler can then service multiple timed events that may + be configured using csi_set_timeout. This function must be run in machine mode. c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * - name: tick_period_us description: > Timer tick period in microseconds. Longer tick periods put less load on the system (due to servicing interrupts), but limit the accuracy of any timed events. Passing a value of 0 for the - tick period disables the timer and turns off timer interrupts. + tick period turns off timer interrupts. type: unsigned c-return-value: description: > Status of operation. CSI_ERROR will be returned if the request is invalid. type: csi_status_t - - name: csi_set_timeout + - name: csi_set_m_timeout description: > Registers a callback function (callback) which will be called after a period set by timeout_ticks unless cancelled with cs_cancel_timeout(). callback_context will be passed into the user's callback - function. The structure pointed to by handle will be initialised by this function and used as a - handle for this timeout instance. This function may be run in either machine mode or user mode. + function. The structure pointed to by timeout_handle will be initialised by this function and used as a + handle for this timeout instance. This function must be run in machine mode. c-params: - - name: handle + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: timeout_handle description: > Handle for this timeout instance. The structure declaration csi_timeout_t is published by the BSP in csi_bsp_interrupts.h but should be considered private to the BSP. Application @@ -510,17 +552,47 @@ modules: description: Pointer to the user's context space, which will be passed into the callback function. type: void * - name: timeout_ticks - description: Timeout period in ticks (configured by csi_timer_config) + description: Timeout period in ticks (configured by csi_set_timer_tick) type: int c-return-value: description: Status of operation. - type: csi_status_t + type: csi_status_t + - name: csi_set_u_timeout + description: > + Registers a callback function (callback) which will be called after a period set by timeout_ticks + unless cancelled with cs_cancel_timeout(). callback_context will be passed into the user's callback + function. The structure pointed to by timeout_handle will be initialised by this function and used as a + handle for this timeout instance. This function must be run in user mode. + c-params: + - name: irq_system_handle + description: > + Handle for the interrupt sub-system on this hart, obtained by running get_interrupts_u_handle + type: unsigned + - name: timeout_handle + description: > + Handle for this timeout instance. The structure declaration csi_timeout_t is published + by the BSP in csi_bsp_interrupts.h but should be considered private to the BSP. Application + code instantiates this structure and passes in a pointer to it. + type: csi_timeout_t * + - name: callback + description: Pointer to the users callback function, to be called when the timeout expires. + type: csi_timeout_callback_t * + - name: callback_context + description: Pointer to the user's context space, which will be passed into the callback function. + type: void * + - name: timeout_ticks + description: Timeout period in ticks (configured by csi_set_timer_tick) + type: int + c-return-value: + description: Status of operation. + type: csi_status_t - name: csi_cancel_timeout description: > Cancels a timeout previously configured with csi_set_timeout, using the associated handle. Cancelling a timer that has already expired is not an error. + This function may be run in either machine mode or user mode. c-params: - - name: handle + - name: timeout_handle description: handle for this timeout instance, previously initialised with csi_set_timeout type: csi_timeout_t * c-return-value: diff --git a/chapter2.adoc b/chapter2.adoc index 1a15193..a5ce3b7 100644 --- a/chapter2.adoc +++ b/chapter2.adoc @@ -103,7 +103,6 @@ csi_bsp_interrupts.h should also define the following macros and types: |Definition|Type|Purpose |CSI_MAX_INTERRUPT_PRIORITY|Macro|Number of of non-zero interrupt priorities available |CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES|Macro|Miniumum size of M-mode context space for interrupt sub-system -|CSI_INTERRUPT_UCTX_MIN_SIZE_BYTES|Macro|Miniumum size of U-mode context space for interrupt sub-system |csi_timeout_t|struct|Context structure associated with a timeout |=== From 237874098e78af10b8a353f29a4c290923b0a8e8 Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Tue, 7 Feb 2023 22:56:10 +0000 Subject: [PATCH 04/10] Add csi_read_mtime --- api/C/include/csi_interrupts.h | 10 ++++++++++ api/rvm-csi-spec.yaml | 10 +++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/api/C/include/csi_interrupts.h b/api/C/include/csi_interrupts.h index 1a823f7..1b511be 100644 --- a/api/C/include/csi_interrupts.h +++ b/api/C/include/csi_interrupts.h @@ -435,5 +435,15 @@ csi_status_t csi_set_u_timeout(unsigned irq_system_handle, csi_timeout_t *timeou */ csi_status_t csi_cancel_timeout(csi_timeout_t *timeout_handle); +/* + * Read the current timer value. This function can be called from M-mode or + * U-mode. However, on systems where the timer is not directly readable from + * U-mode, the function will have to ECALL to M-mode to make the read, which will + * likely make the value innaccurate due to the delay incurred by this. + * + * @return : Current timer value + */ +long long csi_read_mtime(void); + #endif /* CSI_INTERRUPTS_H */ diff --git a/api/rvm-csi-spec.yaml b/api/rvm-csi-spec.yaml index e9d092b..f391429 100644 --- a/api/rvm-csi-spec.yaml +++ b/api/rvm-csi-spec.yaml @@ -598,4 +598,12 @@ modules: c-return-value: description: Status of operation. type: csi_status_t - \ No newline at end of file + - name: csi_read_mtime + description: > + Read the current timer value. This function can be called from M-mode or U-mode. However, + on systems where the timer is not directly readable from U-mode, the function will have to + ECALL to M-mode to make the read, which will likely make the value innaccurate due to the + delay incurred by this. + c-return-value: + description: Current timer value + type: long long From 7930bfd7664e1227ff71bee42e2e2e60e24bc455 Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Wed, 8 Feb 2023 16:53:00 +0000 Subject: [PATCH 05/10] Change SSoT for csi_csrs.h Note on thread-safety Get parser unit test working again --- api/C/include/csi_interrupts.h | 8 ++++++++ api/rvm-csi-spec.yaml | 6 ++++++ chapter2.adoc | 14 +++++--------- spec-schema/parser/header_gen.py | 2 +- spec-schema/parser/test_data/simple.rvm-csi.yaml | 2 ++ 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/api/C/include/csi_interrupts.h b/api/C/include/csi_interrupts.h index 1b511be..a24862f 100644 --- a/api/C/include/csi_interrupts.h +++ b/api/C/include/csi_interrupts.h @@ -12,9 +12,17 @@ * * There will be at most one instance of the trap handling and interrupt subsystem * per hart. + * * The base trap handler will attempt to inform users of unhandled exceptions via * the RVM-CSI console API. Other unhandled interrupts will be ignored. * + * BSP implementations of the functions within this module should be thread-safe. + * The use of separate context spaces for each hart protects against multiple cores + * simultaneously running a function. To ensure that the code is reentrant in + * systems with multiple software-scheduled threads, the implementation should turn + * off interrupts temporarily, to prevent re-scheduling, while accessing data + * within the context space, as required. + * * Copyright (c) RISC-V International 2022. Creative Commons License. Auto- * generated file: DO NOT EDIT */ diff --git a/api/rvm-csi-spec.yaml b/api/rvm-csi-spec.yaml index f391429..45f7545 100644 --- a/api/rvm-csi-spec.yaml +++ b/api/rvm-csi-spec.yaml @@ -86,6 +86,12 @@ modules: - > The base trap handler will attempt to inform users of unhandled exceptions via the RVM-CSI console API. Other unhandled interrupts will be ignored. + - > + BSP implementations of the functions within this module should be thread-safe. The use of separate + context spaces for each hart protects against multiple cores simultaneously running a function. + To ensure that the code is reentrant in systems with multiple software-scheduled threads, the + implementation should turn off interrupts temporarily, to prevent re-scheduling, while accessing + data within the context space, as required. c-specific: false c-filename: csi_interrupts.h c-include-files: diff --git a/chapter2.adoc b/chapter2.adoc index a5ce3b7..c61ab75 100644 --- a/chapter2.adoc +++ b/chapter2.adoc @@ -65,15 +65,11 @@ in csi_bsp_defs.h or in the same header as the associated initialisation functio ==== CSRs (Control and Status Registers) -Standard RISC-V CSRs are defined in https://github.com/riscv-software-src/riscv-isa-sim/blob/master/riscv/encoding.h. -However this is an internal file forming part of the Spike simulator; and such files cannot be treated as forming a -public API; they are likely subject to backwards-incompatible changes. - -Instead, the true "Source of Truth" for this information should be considered to be the RISC-V SAIL model. -csi_csrs.h, forming part of the API, is auto-generated from the SAIL model (a version of which forms a submodule -of the RVM-CSI specification repo). This header file lists all standard CSR indeces and bit masks / shifts. -In this file, CSR indeces are prefixed CSR_. Bit shifts for fields within CSRs are prefixed CSR_SHIFT_, and -masks for bitfields are prefixed CSR_MASK_. +csi_csrs.h lists indeces and bitfield information for all the standard RISC-V CSRs. This file will be +auto-generated from the repo https://github.com/riscv/riscv-opcodes, which acts as a Single Source of Truth +for this information. Accordingly, the contents will align with +https://github.com/riscv-software-src/riscv-isa-sim/blob/master/riscv/encoding.h (which forms part of the +spike simulator). In addition, csi_bsp_csrs.h should enumerate all custom CSR names, addresses and bit-fields in a similar way. Custom CSR indeces are prefixed CCSR_. Bit shifts for fields within custom CSRs are prefixed CCSR_SHIFT_, and diff --git a/spec-schema/parser/header_gen.py b/spec-schema/parser/header_gen.py index 980ee30..c6000ff 100644 --- a/spec-schema/parser/header_gen.py +++ b/spec-schema/parser/header_gen.py @@ -195,7 +195,7 @@ def generate_c(api_definition, out_dir): if 'notes' in module.keys(): for note in module['notes']: out_str += format_c_comment_lines(note) - out_str += "*\n " + out_str += "*\n " out_str += format_c_comment_lines(api_definition['boilerplate']) diff --git a/spec-schema/parser/test_data/simple.rvm-csi.yaml b/spec-schema/parser/test_data/simple.rvm-csi.yaml index 2595a16..7776123 100644 --- a/spec-schema/parser/test_data/simple.rvm-csi.yaml +++ b/spec-schema/parser/test_data/simple.rvm-csi.yaml @@ -4,6 +4,8 @@ c-documentation-title: RVM-CSI API boilerplate: > Copyright (c) RISC-V International 2022. Creative Commons License +adoc-optimization: html +top-heading-level: 0 notes: - This is an example YAML used to demonstrate validation against the schema, rvm-csi.schema.json. - It does not reflect the real API specification, but the real specification will have similar form. From f5c6785f6c2de02d924e3d822b70751bb4d87696 Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Fri, 17 Feb 2023 16:46:15 +0000 Subject: [PATCH 06/10] - add new API functions csi_set_interrupt_level, csi_get_interrupt_level, csi_set_interrupt_level_thresh, csi_get_interrupt_level_thresh, csi_register_raw_interrupt_handler, csi_register_raw_exception_handler. - Add parameters to init function for U-mode and M-mode stack spaces. - Further explanatory text and corrections. --- api/C/include/csi_defs.h | 3 +- api/C/include/csi_interrupts.h | 160 ++++++++++++++++++++++++++---- api/rvm-csi-spec.yaml | 174 ++++++++++++++++++++++++++++++--- chapter2.adoc | 14 ++- 4 files changed, 314 insertions(+), 37 deletions(-) diff --git a/api/C/include/csi_defs.h b/api/C/include/csi_defs.h index 7c18eda..3cb3ad0 100644 --- a/api/C/include/csi_defs.h +++ b/api/C/include/csi_defs.h @@ -33,7 +33,8 @@ typedef enum { * total number of sources defined. User applications may then use values above * this to enumerate user-defined software signals. Note that the actual * enumerated values have no meaning beyond serving to uniquely identify the source - * of a trap event. + * of a trap event. They are not intended to map onto values in the mcause + * register. */ typedef enum { CSI_ENUM_NMI = 0, diff --git a/api/C/include/csi_interrupts.h b/api/C/include/csi_interrupts.h index a24862f..279bb63 100644 --- a/api/C/include/csi_interrupts.h +++ b/api/C/include/csi_interrupts.h @@ -3,12 +3,12 @@ * * This module provides functionality for routing interrupts and registering * handlers for traps, controlling the system timer, and managing timed events. The - * BSP provides a base trap handler. Running the initialisation function - * csi_interrupts_init will put the address of this handler in the mtvec register. - * This base trap handler provides default exception handling, and calls any - * handlers registered by the user. Systems using RVM-CSI may provide their own - * trap handling support, in which case csi_interrupts_init should not be called, - * and all functions in this module will be inoperative. + * BSP provides base trap handler functionality, which is installed when the + * initialization function csi_interrupts_init is called. This base trap handling + * code provides save and restore of register context, performs default exception + * handling, and calls any handlers registered by the user. Systems using RVM-CSI + * may provide their own trap handling support, in which case csi_interrupts_init + * should not be called, and all functions in this module will be inoperative. * * There will be at most one instance of the trap handling and interrupt subsystem * per hart. @@ -16,6 +16,15 @@ * The base trap handler will attempt to inform users of unhandled exceptions via * the RVM-CSI console API. Other unhandled interrupts will be ignored. * + * The base trap handler will deal with saving and restoring all registers which + * would normally be used by compiled C code without the use of special compiler + * intrinsics (the exact register set is platform-dependent and may be documented + * by the BSP). Other registers manipulated by the user's handler (such as + * platform-specific CSRs etc.) should be saved and restored by that handler. + * + * It is the responsibility of the user's handler to clear down the source of any + * interrupt that it is handling, prior to returning. + * * BSP implementations of the functions within this module should be thread-safe. * The use of separate context spaces for each hart protects against multiple cores * simultaneously running a function. To ensure that the code is reentrant in @@ -23,6 +32,9 @@ * off interrupts temporarily, to prevent re-scheduling, while accessing data * within the context space, as required. * + * BSPs should use vectored interrupts where possible; although to save memory, + * handlers for many different mcause values may share code. + * * Copyright (c) RISC-V International 2022. Creative Commons License. Auto- * generated file: DO NOT EDIT */ @@ -69,14 +81,22 @@ typedef void (csi_timeout_callback_t)(csi_timeout_t *timeout_handle, void *callb * @param mctx_size: Size of memory allocated at the mctx pointer in bytes. * Allocating more than CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES may permit additional * M-mode handlers to be registered. + * @param mstack: Pointer to an area of memory to be used as M-mode stack space for + * the interrupt subsystem. This parameter may be NULL in which case the stack of + * the interrupted thread will be used. + * @param mstack_size: Size of memory allocated at the mstack pointer in bytes. + * @param ustack: Pointer to an area of memory to be used as U-mode stack space for + * the interrupt subsystem. This parameter may be NULL in which case U-mode + * handlers will not be supported. + * @param ustack_size: Size of memory allocated at the ustack pointer in bytes. * @return : Status of initialisation operation */ -csi_status_t csi_interrupts_init(void *mctx, unsigned mctx_size); +csi_status_t csi_interrupts_init(void *mctx, unsigned mctx_size, void *mstack, unsigned mstack_size, void *ustack, unsigned ustack_size); /* * Un-initialize the interrupt and timer sub-system. After calling this function, - * the memory allocated for the contexts may be freed, and no other functions in - * this module may be called. This function must run in machine mode. + * the memory allocated for the context and stacks may be freed, and no other + * functions in this module may be called. This function must run in machine mode. * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. @@ -101,7 +121,10 @@ unsigned get_interrupts_u_handle(void); * signal number and mtval contents. This function transparently deals with * routing the desired signal to the hart and enabling the interrupt. This * function must run in machine mode. Running this function with a NULL pointer - * for the isr parameter will un-register a previously registered handler. + * for the isr parameter will un-register a previously registered handler. NOTE: + * there can only be one handler registered for any given signal. Re-running this + * function to register a second handler for a signal will replace the previous, + * and is not an error. * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. @@ -132,7 +155,9 @@ csi_status_t csi_register_m_isr(void *mctx, csi_isr_t *isr, void *isr_ctx, int s * the isr parameter will un-register a previously registered handler. Note that * before registering a user mode handler for a source, * csi_set_umode_trap_permissions must have been run (from machine mode) in order - * to enable handling of the trap in U-mode. + * to enable handling of the trap in U-mode. NOTE: there can only be one handler + * registered for any given signal. Re-running this function to register a second + * handler for a signal will replace the previous, and is not an error. * * @param irq_system_handle: Handle for the interrupt sub-system on this hart, * obtained by running get_interrupts_u_handle @@ -302,14 +327,18 @@ csi_status_t csi_raise_u_sw_signal(unsigned irq_system_handle, int signal); /* * Set priority for an interrupt source. Priorities range from 0 to * CSI_MAX_INTERRUPT_PRIORITY, where 0 indicates "never interrupt", and 1 is the - * lowest subsequent priority level. This function must be run in machine mode. + * lowest subsequent priority level. Where supported, priorities determine the + * order in which simultaneous interrupts at the same privilege level are handled. + * They are also compared against the threshold set using + * csi_set_irq_priority_thresh, to determine if an interrupt will be masked. This + * function must be run in machine mode. * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. * @param signal: Source enumeration for this signal. - * @param priority: priority level. - * @return : Status of operation. CSI_ERROR will be returned if the request is - * invalid. + * @param priority: priority for this source. + * @return : Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be + * returned as appropriate will be returned if the request is invalid. */ csi_status_t csi_set_irq_priority(void *mctx, int signal, int priority); @@ -319,8 +348,8 @@ csi_status_t csi_set_irq_priority(void *mctx, int signal, int priority); * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. * @param signal: Source enumeration for this signal. - * @return : priority level (resulting from calls to csi_set_irq_priority). -1 - * will be returned if the request is invalid. + * @return : Priority (resulting from calls to csi_set_irq_priority). -1 will be + * returned if the request is invalid. */ int csi_get_irq_priority(void *mctx, int signal); @@ -331,8 +360,8 @@ int csi_get_irq_priority(void *mctx, int signal); * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. * @param threshold: Priority threshold. - * @return : Status of operation. CSI_ERROR will be returned if the request is - * invalid. + * @return : Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be + * returned as appropriate will be returned if the request is invalid. */ csi_status_t csi_set_irq_priority_thresh(void *mctx, int threshold); @@ -356,6 +385,99 @@ int csi_get_irq_priority_thresh(void *mctx); */ void csi_force_ext_irq(void *mctx, int signal); +/* + * Set interrupt level for a source, if supported. Higher-level interrupts will + * preempt lower-level interrupts at the same privilege level. Levels range from 0 + * to CSI_MAX_INTERRUPT_LEVEL, where level 0 represents regular execution outside + * of an interrupt handler. Must be run in machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param signal: Source enumeration for this signal. + * @param level: interrupt level. + * @return : Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be + * returned as appropriate if the request is invalid. + */ +csi_status_t csi_set_interrupt_level(void *mctx, int signal, int level); + +/* + * Get level of an interrupt source. Must be run in machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param signal: Source enumeration for this signal. + * @return : interrupt level (resulting from calls to csi_set_interrupt_level). -1 + * will be returned if the request is invalid. + */ +int csi_get_interrupt_level(void *mctx, int signal); + +/* + * Set an interrupt threshold level for this hart, if supported. Must be run in + * machine mode. While processing an interrupt at a given level, the effective + * interrupt level is the maximum of the level threshold, set by this function, and + * the level associated with the current interrupt. Therefore this function can be + * called to temporarily raise the level during a piece of critical code, thereby + * preventing preemption by interrupts with a certain range of levels; while the + * "correct" interrupt level can be restored by setting level threshold to 0. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param level_thresh: Interrupt level threshold. + * @return : Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be + * returned as appropriate if the request is invalid. + */ +csi_status_t csi_set_interrupt_level_thresh(void *mctx, int level_thresh); + +/* + * Get interrupt threshold level for this hart. Must be run in machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @return : interrupt level threshold (resulting from calls to + * csi_set_interrupt_level_thresh). -1 will be returned if the request is invalid. + */ +int csi_get_interrupt_level_thresh(void *mctx); + +/* + * This function may optionally be run by users who want to supply their own fast + * interrupt handling function to be inserted directly into the vector table + * (thereby bypassing the RVM-CSI base trap handler in handling a given mcause). + * It must be run in machine mode. Note that in this case the user's function must + * deal with save and restore of register context (whereas this is not necessary + * for handlers registered using csi_register_m_isr). + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param mcause: mcause register value (LSBs) which will result in a jump into + * this handler + * @param handler: Pointer to the user's handler function. If this is NULL, any + * function previously registered using csi_register_raw_interrupt_handler will be + * unregistered and the relevant signals will go back to being handled by the base + * trap handler in the BSP. + * @return : Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be + * returned as appropriate if the request is invalid. + */ +csi_status_t csi_register_raw_interrupt_handler(void *mctx, unsigned mcause, void *handler); + +/* + * This function may optionally be run by users who want to supply their own fast + * exception handling function to be inserted directly into the mtvec register + * (thereby bypassing the RVM-CSI base trap handler in handling exceptions). It + * must be run in machine mode. Note that in this case the user's function must + * deal with save and restore of register context (whereas this is not necessary + * for handlers registered using csi_register_m_isr). + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param handler: Pointer to the user's handler function. If this is NULL, any + * function previously registered using csi_register_raw_exception_handler will be + * unregistered and exeptions will go back to being handled by the base trap + * handler in the BSP. + * @return : Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be + * returned as appropriate if the request is invalid. + */ +csi_status_t csi_register_raw_exception_handler(void *mctx, void *handler); + /* * Set the frequency of the system timer. Note that there is typically a single * timer for all harts in the system, so this function can affect the operation of diff --git a/api/rvm-csi-spec.yaml b/api/rvm-csi-spec.yaml index 45f7545..f6d8fc7 100644 --- a/api/rvm-csi-spec.yaml +++ b/api/rvm-csi-spec.yaml @@ -39,7 +39,7 @@ modules: also define CSI_TOTAL_BSP_TRAP_SOURCES to indicate the total number of sources defined. User applications may then use values above this to enumerate user-defined software signals. Note that the actual enumerated values have no meaning beyond serving to uniquely identify the source of a - trap event. + trap event. They are not intended to map onto values in the mcause register. type: enum enum-members: - name: CSI_ENUM_NMI @@ -75,9 +75,9 @@ modules: description: > This module provides functionality for routing interrupts and registering handlers for traps, controlling the system timer, and managing timed events. - The BSP provides a base trap handler. Running the initialisation function csi_interrupts_init will - put the address of this handler in the mtvec register. This base trap handler provides default - exception handling, and calls any handlers registered by the user. + The BSP provides base trap handler functionality, which is installed when the initialization function + csi_interrupts_init is called. This base trap handling code provides save and restore of register context, + performs default exception handling, and calls any handlers registered by the user. Systems using RVM-CSI may provide their own trap handling support, in which case csi_interrupts_init should not be called, and all functions in this module will be inoperative. @@ -86,12 +86,23 @@ modules: - > The base trap handler will attempt to inform users of unhandled exceptions via the RVM-CSI console API. Other unhandled interrupts will be ignored. + - > + The base trap handler will deal with saving and restoring all registers which would normally be used + by compiled C code without the use of special compiler intrinsics (the exact register set is platform-dependent + and may be documented by the BSP). Other registers manipulated by the user's handler (such as + platform-specific CSRs etc.) should be saved and restored by that handler. + - > + It is the responsibility of the user's handler to clear down the source of any interrupt that it is + handling, prior to returning. - > BSP implementations of the functions within this module should be thread-safe. The use of separate context spaces for each hart protects against multiple cores simultaneously running a function. To ensure that the code is reentrant in systems with multiple software-scheduled threads, the implementation should turn off interrupts temporarily, to prevent re-scheduling, while accessing data within the context space, as required. + - > + BSPs should use vectored interrupts where possible; although to save memory, handlers + for many different mcause values may share code. c-specific: false c-filename: csi_interrupts.h c-include-files: @@ -147,13 +158,31 @@ modules: Size of memory allocated at the mctx pointer in bytes. Allocating more than CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES may permit additional M-mode handlers to be registered. type: unsigned + - name: mstack + description: > + Pointer to an area of memory to be used as M-mode stack space for the interrupt subsystem. This parameter may + be NULL in which case the stack of the interrupted thread will be used. + type: void * + - name: mstack_size + description: > + Size of memory allocated at the mstack pointer in bytes. + type: unsigned + - name: ustack + description: > + Pointer to an area of memory to be used as U-mode stack space for the interrupt subsystem. This parameter may + be NULL in which case U-mode handlers will not be supported. + type: void * + - name: ustack_size + description: > + Size of memory allocated at the ustack pointer in bytes. + type: unsigned c-return-value: description: Status of initialisation operation type: csi_status_t - name: csi_interrupts_uninit description: > Un-initialize the interrupt and timer sub-system. After calling this function, the memory allocated - for the contexts may be freed, and no other functions in this module may be called. This function + for the context and stacks may be freed, and no other functions in this module may be called. This function must run in machine mode. c-params: - name: mctx @@ -177,7 +206,9 @@ modules: trap arising from from the source signal. isr_ctx is a parameter that will be passed into the user's ISR along with the signal number and mtval contents. This function transparently deals with routing the desired signal to the hart and enabling the interrupt. This function must run in machine mode. Running this function with a NULL - pointer for the isr parameter will un-register a previously registered handler. + pointer for the isr parameter will un-register a previously registered handler. NOTE: there can only be one + handler registered for any given signal. Re-running this function to register a second handler for a signal + will replace the previous, and is not an error. c-params: - name: mctx description: > @@ -212,7 +243,8 @@ modules: to the hart and enabling the interrupt. This function must run in user mode. Running this function with a NULL pointer for the isr parameter will un-register a previously registered handler. Note that before registering a user mode handler for a source, csi_set_umode_trap_permissions must have been run (from machine mode) in order - to enable handling of the trap in U-mode. + to enable handling of the trap in U-mode. NOTE: there can only be one handler registered for any given signal. + Re-running this function to register a second handler for a signal will replace the previous, and is not an error. c-params: - name: irq_system_handle description: > @@ -427,7 +459,10 @@ modules: - name: csi_set_irq_priority description: > Set priority for an interrupt source. Priorities range from 0 to CSI_MAX_INTERRUPT_PRIORITY, - where 0 indicates "never interrupt", and 1 is the lowest subsequent priority level. + where 0 indicates "never interrupt", and 1 is the lowest subsequent priority level. Where supported, + priorities determine the order in which simultaneous interrupts at the same privilege level are + handled. They are also compared against the threshold set using csi_set_irq_priority_thresh, + to determine if an interrupt will be masked. This function must be run in machine mode. c-params: - name: mctx @@ -439,11 +474,11 @@ modules: Source enumeration for this signal. type: int - name: priority - description: priority level. + description: priority for this source. type: int c-return-value: description: > - Status of operation. CSI_ERROR will be returned if the request is invalid. + Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be returned as appropriate will be returned if the request is invalid. type: csi_status_t - name: csi_get_irq_priority description: > @@ -458,7 +493,7 @@ modules: Source enumeration for this signal. type: int c-return-value: - description: priority level (resulting from calls to csi_set_irq_priority). -1 will be returned if + description: Priority (resulting from calls to csi_set_irq_priority). -1 will be returned if the request is invalid. type: int - name: csi_set_irq_priority_thresh @@ -474,7 +509,7 @@ modules: type: int c-return-value: description: > - Status of operation. CSI_ERROR will be returned if the request is invalid. + Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be returned as appropriate will be returned if the request is invalid. type: csi_status_t - name: csi_get_irq_priority_thresh description: Get the current priority threshold for interrupts Must be run in machine mode. @@ -497,6 +532,121 @@ modules: description: > Source enumeration for this signal. type: int + - name: csi_set_interrupt_level + description: > + Set interrupt level for a source, if supported. Higher-level interrupts will preempt lower-level + interrupts at the same privilege level. Levels range from 0 to CSI_MAX_INTERRUPT_LEVEL, where level 0 + represents regular execution outside of an interrupt handler. + Must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: signal + description: > + Source enumeration for this signal. + type: int + - name: level + description: interrupt level. + type: int + c-return-value: + description: > + Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be returned as appropriate if the request is invalid. + type: csi_status_t + - name: csi_get_interrupt_level + description: > + Get level of an interrupt source. Must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: signal + description: > + Source enumeration for this signal. + type: int + c-return-value: + description: interrupt level (resulting from calls to csi_set_interrupt_level). -1 will be returned if + the request is invalid. + type: int + - name: csi_set_interrupt_level_thresh + description: > + Set an interrupt threshold level for this hart, if supported. Must be run in machine mode. + While processing an interrupt at a given level, the effective interrupt level is the maximum of the level + threshold, set by this function, and the level associated with the current interrupt. Therefore this function + can be called to temporarily raise the level during a piece of critical code, thereby preventing preemption by + interrupts with a certain range of levels; while the "correct" interrupt level can be restored by setting + level threshold to 0. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: level_thresh + description: Interrupt level threshold. + type: int + c-return-value: + description: > + Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be returned as appropriate if the request is invalid. + type: csi_status_t + - name: csi_get_interrupt_level_thresh + description: > + Get interrupt threshold level for this hart. Must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + c-return-value: + description: interrupt level threshold (resulting from calls to csi_set_interrupt_level_thresh). -1 will be returned if + the request is invalid. + type: int + - name: csi_register_raw_interrupt_handler + description: > + This function may optionally be run by users who want to supply their own fast interrupt handling function + to be inserted directly into the vector table (thereby bypassing the RVM-CSI base trap handler in handling a given + mcause). It must be run in machine mode. Note that in this case the user's function must deal with save and restore + of register context (whereas this is not necessary for handlers registered using csi_register_m_isr). + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: mcause + description: mcause register value (LSBs) which will result in a jump into this handler + type: unsigned + - name: handler + description: > + Pointer to the user's handler function. If this is NULL, any function previously registered using + csi_register_raw_interrupt_handler will be unregistered and the relevant signals will go back to being handled + by the base trap handler in the BSP. + type: void * + c-return-value: + description: > + Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be returned as appropriate if the request is invalid. + type: csi_status_t + - name: csi_register_raw_exception_handler + description: > + This function may optionally be run by users who want to supply their own fast exception handling function + to be inserted directly into the mtvec register (thereby bypassing the RVM-CSI base trap handler in handling + exceptions). It must be run in machine mode. Note that in this case the user's function must deal with save and restore + of register context (whereas this is not necessary for handlers registered using csi_register_m_isr). + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: handler + description: > + Pointer to the user's handler function. If this is NULL, any function previously registered using + csi_register_raw_exception_handler will be unregistered and exeptions will go back to being handled + by the base trap handler in the BSP. + type: void * + c-return-value: + description: > + Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be returned as appropriate if the request is invalid. + type: csi_status_t - name: csi_timer_config description: > Set the frequency of the system timer. Note that there is typically a single timer for all diff --git a/chapter2.adoc b/chapter2.adoc index c61ab75..0d92fa5 100644 --- a/chapter2.adoc +++ b/chapter2.adoc @@ -65,14 +65,14 @@ in csi_bsp_defs.h or in the same header as the associated initialisation functio ==== CSRs (Control and Status Registers) -csi_csrs.h lists indeces and bitfield information for all the standard RISC-V CSRs. This file will be +csi_csrs.h lists indices and bitfield information for all the standard RISC-V CSRs. This file will be auto-generated from the repo https://github.com/riscv/riscv-opcodes, which acts as a Single Source of Truth for this information. Accordingly, the contents will align with https://github.com/riscv-software-src/riscv-isa-sim/blob/master/riscv/encoding.h (which forms part of the spike simulator). In addition, csi_bsp_csrs.h should enumerate all custom CSR names, addresses and bit-fields in a similar way. -Custom CSR indeces are prefixed CCSR_. Bit shifts for fields within custom CSRs are prefixed CCSR_SHIFT_, and +Custom CSR indices are prefixed CCSR_. Bit shifts for fields within custom CSRs are prefixed CCSR_SHIFT_, and masks for bitfields within custom CSRs are prefixed CCSR_MASK_. ==== Peripheral Registers @@ -97,11 +97,15 @@ csi_bsp_interrupts.h should also define the following macros and types: [cols="3,2,6",options="header"] |=== |Definition|Type|Purpose -|CSI_MAX_INTERRUPT_PRIORITY|Macro|Number of of non-zero interrupt priorities available -|CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES|Macro|Miniumum size of M-mode context space for interrupt sub-system -|csi_timeout_t|struct|Context structure associated with a timeout +|CSI_MAX_INTERRUPT_PRIORITY|Macro|Number of of non-zero interrupt priorities available. +|CSI_MAX_INTERRUPT_LEVEL|Macro|Number of non-zero interrupt levels available, or 0 if interrupt levels are not supported. +|CSI_INTERRUPT_MCTX_MIN_SIZE_BYTES|Macro|Minimum size of M-mode context space for interrupt sub-system. +|csi_timeout_t|struct|Context structure associated with a timeout. |=== +(Note: interrupt priorities determine the order in which simultaneous interrupts at a given privilege level are handled, +while interrupt levels determine which interrupts can preempt others, if supported: see interrupts module for details). + === Global Definitions Set By Application Writers The following macros may be defined globally by application writers, in order to change the behaviour of the underlying BSP code: From eb355e11eee8dcb5a572fa29ca25d3f879081519 Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Fri, 17 Feb 2023 19:28:24 +0000 Subject: [PATCH 07/10] Improvements to formatting of documentation (no change of functionality in this commit) --- api/C/include/csi_defs.h | 48 ++++++++++----------- api/rvm-csi-spec.yaml | 24 +++++++++++ chapter2.adoc | 2 +- spec-schema/parser/doc_gen.py | 41 ++++++++++++++---- spec-schema/parser/header_gen.py | 62 ++++----------------------- spec-schema/parser/parser_common.py | 65 +++++++++++++++++++++++++++++ 6 files changed, 156 insertions(+), 86 deletions(-) create mode 100644 spec-schema/parser/parser_common.py diff --git a/api/C/include/csi_defs.h b/api/C/include/csi_defs.h index 3cb3ad0..f47d7d6 100644 --- a/api/C/include/csi_defs.h +++ b/api/C/include/csi_defs.h @@ -15,11 +15,11 @@ * Return type for functions indicating status */ typedef enum { - CSI_SUCCESS = 0, - CSI_NOT_IMPLEMENTED = -1, - CSI_ERROR = -2, - CSI_NOT_INITIALIZED = -3, - CSI_OUT_OF_MEM = -4, + CSI_SUCCESS = 0, /* Operation completed successfully */ + CSI_NOT_IMPLEMENTED = -1, /* Functionality not implemented */ + CSI_ERROR = -2, /* Generic error code */ + CSI_NOT_INITIALIZED = -3, /* Sub-system not correctly initialised, operation failed. */ + CSI_OUT_OF_MEM = -4, /* Out-of-memory error */ } csi_status_t; /* @@ -37,22 +37,22 @@ typedef enum { * register. */ typedef enum { - CSI_ENUM_NMI = 0, - CSI_ENUM_MACHINE_SW_INTERRUPT, - CSI_ENUM_MACHINE_TIMER_INTERRUPT, - CSI_ENUM_INSTRUCTION_ADDR_MISALIGNED_EXCEPTION, - CSI_ENUM_INSTRUCTION_ACCESS_FAULT_EXCEPTION, - CSI_ENUM_ILLEGAL_INSTRUCTION_EXCEPTION, - CSI_ENUM_BREAKPOINT_EXCEPTION, - CSI_ENUM_LOAD_ADDR_MISALIGNED_EXCEPTION, - CSI_ENUM_LOAD_ACCESS_FAULT_EXCEPTION, - CSI_ENUM_STORE_ADDR_MISALIGNED_EXCEPTION, - CSI_ENUM_STORE_ACCESS_FAULT_EXCEPTION, - CSI_ENUM_ECALL_FROM_UMODE, - CSI_ENUM_ECALL_FROM_MMODE, - CSI_ENUM_INST_PAGE_FAULT, - CSI_ENUM_LOAD_PAGE_FAULT, - CSI_ENUM_STORE_PAGE_FAULT, + CSI_ENUM_NMI = 0, /* Non-maskable exception (hardware error) */ + CSI_ENUM_MACHINE_SW_INTERRUPT, /* Machine mode software interrupt */ + CSI_ENUM_MACHINE_TIMER_INTERRUPT, /* Machine mode timer interrupt */ + CSI_ENUM_INSTRUCTION_ADDR_MISALIGNED_EXCEPTION, /* Instruction misaligned exception */ + CSI_ENUM_INSTRUCTION_ACCESS_FAULT_EXCEPTION, /* Instruction access fault exception */ + CSI_ENUM_ILLEGAL_INSTRUCTION_EXCEPTION, /* Illegal instruction exception */ + CSI_ENUM_BREAKPOINT_EXCEPTION, /* Breakpoint exception */ + CSI_ENUM_LOAD_ADDR_MISALIGNED_EXCEPTION, /* Load address misaligned exception */ + CSI_ENUM_LOAD_ACCESS_FAULT_EXCEPTION, /* Load access fault exception */ + CSI_ENUM_STORE_ADDR_MISALIGNED_EXCEPTION, /* Store address misaligned exception */ + CSI_ENUM_STORE_ACCESS_FAULT_EXCEPTION, /* Store access fault exception */ + CSI_ENUM_ECALL_FROM_UMODE, /* ECALL from User mode */ + CSI_ENUM_ECALL_FROM_MMODE, /* ECALL from Machine mode */ + CSI_ENUM_INST_PAGE_FAULT, /* Instruction page-fault */ + CSI_ENUM_LOAD_PAGE_FAULT, /* Load page-fault */ + CSI_ENUM_STORE_PAGE_FAULT, /* Store page-fault */ CSI_NUM_STANDARD_TRAP_SOURCES, /* Must come last in this list */ } csi_trap_source_t; @@ -60,9 +60,9 @@ typedef enum { * Interrupt enable bits in the mie CSR */ typedef enum { - CSI_SW_INTERRUPTS_ENABLE = 8, - CSI_TIMER_INTERRUPTS_ENABLE = 128, - CSI_EXT_INTERRUPTS_ENABLE = 2048, + CSI_SW_INTERRUPTS_ENABLE = 8, /* Software interrupts enable bit index */ + CSI_TIMER_INTERRUPTS_ENABLE = 128, /* Timer interrupts enable bit index */ + CSI_EXT_INTERRUPTS_ENABLE = 2048, /* External interrupts enable bit index */ } csi_interrupt_enables_t; diff --git a/api/rvm-csi-spec.yaml b/api/rvm-csi-spec.yaml index f6d8fc7..b451a59 100644 --- a/api/rvm-csi-spec.yaml +++ b/api/rvm-csi-spec.yaml @@ -21,14 +21,19 @@ modules: enum-members: - name: CSI_SUCCESS value: 0 + description: Operation completed successfully - name: CSI_NOT_IMPLEMENTED value: -1 + description: Functionality not implemented - name: CSI_ERROR value: -2 + description: Generic error code - name: CSI_NOT_INITIALIZED value: -3 + description: Sub-system not correctly initialised, operation failed. - name: CSI_OUT_OF_MEM value: -4 + description: Out-of-memory error - name: csi_trap_source_t description: > Enumerates all sources in the system that can give rise to a trap event. This enumeration should @@ -44,21 +49,37 @@ modules: enum-members: - name: CSI_ENUM_NMI value: 0 + description: Non-maskable exception (hardware error) - name: CSI_ENUM_MACHINE_SW_INTERRUPT + description: Machine mode software interrupt - name: CSI_ENUM_MACHINE_TIMER_INTERRUPT + description: Machine mode timer interrupt - name: CSI_ENUM_INSTRUCTION_ADDR_MISALIGNED_EXCEPTION + description: Instruction misaligned exception - name: CSI_ENUM_INSTRUCTION_ACCESS_FAULT_EXCEPTION + description: Instruction access fault exception - name: CSI_ENUM_ILLEGAL_INSTRUCTION_EXCEPTION + description: Illegal instruction exception - name: CSI_ENUM_BREAKPOINT_EXCEPTION + description: Breakpoint exception - name: CSI_ENUM_LOAD_ADDR_MISALIGNED_EXCEPTION + description: Load address misaligned exception - name: CSI_ENUM_LOAD_ACCESS_FAULT_EXCEPTION + description: Load access fault exception - name: CSI_ENUM_STORE_ADDR_MISALIGNED_EXCEPTION + description: Store address misaligned exception - name: CSI_ENUM_STORE_ACCESS_FAULT_EXCEPTION + description: Store access fault exception - name: CSI_ENUM_ECALL_FROM_UMODE + description: ECALL from User mode - name: CSI_ENUM_ECALL_FROM_MMODE + description: ECALL from Machine mode - name: CSI_ENUM_INST_PAGE_FAULT + description: Instruction page-fault - name: CSI_ENUM_LOAD_PAGE_FAULT + description: Load page-fault - name: CSI_ENUM_STORE_PAGE_FAULT + description: Store page-fault - name: CSI_NUM_STANDARD_TRAP_SOURCES description: Must come last in this list - name: csi_interrupt_enables_t @@ -67,10 +88,13 @@ modules: enum-members: - name: CSI_SW_INTERRUPTS_ENABLE value: 8 + description: Software interrupts enable bit index - name: CSI_TIMER_INTERRUPTS_ENABLE value: 128 + description: Timer interrupts enable bit index - name: CSI_EXT_INTERRUPTS_ENABLE value: 2048 + description: External interrupts enable bit index - name: Trap Handling / Interrupt and Timer Support description: > This module provides functionality for routing interrupts and registering handlers for traps, diff --git a/chapter2.adoc b/chapter2.adoc index 0d92fa5..6cbed56 100644 --- a/chapter2.adoc +++ b/chapter2.adoc @@ -94,7 +94,7 @@ arbitrarily to the interrupt sources, allowing them to be indexed by the softwar csi_bsp_interrupts.h should also define the following macros and types: -[cols="3,2,6",options="header"] +[cols="4,2,6",options="header"] |=== |Definition|Type|Purpose |CSI_MAX_INTERRUPT_PRIORITY|Macro|Number of of non-zero interrupt priorities available. diff --git a/spec-schema/parser/doc_gen.py b/spec-schema/parser/doc_gen.py index c4d968c..9155981 100644 --- a/spec-schema/parser/doc_gen.py +++ b/spec-schema/parser/doc_gen.py @@ -1,4 +1,5 @@ import pathlib +from parser_common import format_c_function_prototype, format_c_function_typedef, format_c_enum_typedef def heading_marker(level): '''Add a heading marker at given level relative to the top level as defined by the @@ -30,16 +31,28 @@ def format_adoc_type_declaration(declaration): out_str += declaration['description'] + "\n\n" if c_type == "enum": + out_str += ''' +[source, c] +---- +''' + out_str += format_c_enum_typedef(declaration, False) + out_str += "----\n\n" + out_str += heading_marker(4) + "Values\n" - + out_str += ''' +[cols="6,6",options="header"] +|=== +|Value|Description +''' for member in declaration['enum-members']: - out_str += "*" + member['name'] + "*" - if 'value' in member.keys(): - out_str += " = " + str(member['value']) - out_str += "\n" + out_str += '|' + member['name'] +'|' if 'description' in member.keys(): out_str += member['description'] + "\n" - out_str += "\n" + else: + out_str += "\n" + out_str += ''' +|=== +''' if c_type == "struct": out_str += heading_marker(4) + "Members\n" @@ -51,7 +64,13 @@ def format_adoc_type_declaration(declaration): delimiter = "" out_str += member_type + delimiter + member['name'] + "\n\n" - if c_type == "function": + if c_type == "function": + out_str += ''' +[source, c] +---- +''' + out_str += format_c_function_typedef(declaration) + out_str += "----\n\n" out_str += heading_marker(4) + "Parameters\n" if 'func-typedef-params' in declaration.keys(): for param in declaration['func-typedef-params']: @@ -85,6 +104,14 @@ def format_param_type(type,types_defined_by_module): return type out_str = heading_marker(3) + function['name'] + "\n" + + out_str += ''' +[source, c] +---- +''' + out_str += format_c_function_prototype(function) + out_str += "----\n\n" + out_str += function['description'] + "\n\n" out_str += heading_marker(4) + "Return\n" diff --git a/spec-schema/parser/header_gen.py b/spec-schema/parser/header_gen.py index c6000ff..b136690 100644 --- a/spec-schema/parser/header_gen.py +++ b/spec-schema/parser/header_gen.py @@ -1,4 +1,5 @@ import textwrap, pathlib +from parser_common import format_c_function_prototype, format_c_function_typedef, indent, format_c_enum_typedef def format_c_comment_lines(input_string): ''' Takes a string as input. @@ -57,9 +58,6 @@ def format_c_type_prefix_list(prefix_list): return out_str def format_c_type_declaration(declaration): - def indent(): - return " " # indent 4 spaces - out_str = "" if 'description' in declaration.keys(): out_str += "/*\n " @@ -79,16 +77,7 @@ def indent(): out_str += "typedef unsigned int " + declaration['name'] + ";\n" elif c_type == "enum": - out_str += "typedef enum {\n" - for member in declaration['enum-members']: - out_str += indent() + member['name'] - if 'value' in member.keys(): - out_str += " = " + str(member['value']) - out_str += "," # trailing comma should be valid for modern compilers - if 'description' in member.keys(): - out_str += " /* " + member['description'] + " */" - out_str += "\n" - out_str += "} " + declaration['name'] + ";\n" + out_str += format_c_enum_typedef(declaration, True) elif c_type == "struct": out_str += "typedef struct {\n" @@ -102,22 +91,7 @@ def indent(): out_str += "} " + declaration['name'] + ";\n" elif c_type == "function": - retval = "void" - params = "void" - if 'func-typedef-retval' in declaration.keys(): - retval = declaration['func-typedef-retval'] - if 'func-typedef-params' in declaration.keys(): - params = '' - for param in declaration['func-typedef-params']: - param_type = param['type'] - param_name = param['name'] - if param_type[-1] == '*': - # pointer types - present with spacing as "int *a" - param_type = param_type.rstrip('* ') - param_name = "*" + param_name - params += param_type + " " + param_name + ", " - params = params.rstrip(", ") # Get rid of last comma/space - out_str += "typedef " + retval + " (" + declaration['name'] + ")(" + params + ");\n" + out_str += format_c_function_typedef(declaration) else: raise('undefined C type definition') # Should not be possible to reach here @@ -146,31 +120,11 @@ def format_c_function(function): # Close comment out_str += "*/\n" - - return_type = "void" - if 'c-return-value' in function.keys(): - return_type = function['c-return-value']['type'] - - out_str += return_type + " " + function['name'] + "(" - if 'c-params' in function.keys(): - for param in function['c-params']: - - param_type = param['type'] - param_name = param['name'] - if param_type[-1] == '*': - # pointer types - present with spacing as "int *a" - param_type = param_type.rstrip('* ') - param_name = "*" + param_name - - out_str += param_type + " " + param_name + ", " - - out_str = out_str.rstrip(", ") # Get rid of last comma/space - - else: - out_str += "void" - - out_str +=");\n" - return out_str + + # Write out the function prototype + out_str += format_c_function_prototype(function) + + return out_str def generate_c(api_definition, out_dir): ''' Top level function which iterates through each of the modules in the api definition diff --git a/spec-schema/parser/parser_common.py b/spec-schema/parser/parser_common.py new file mode 100644 index 0000000..f58999d --- /dev/null +++ b/spec-schema/parser/parser_common.py @@ -0,0 +1,65 @@ +def indent(): + '''Insert standard-size indentation for C code''' + return " " # indent 4 spaces + +def format_c_function_prototype(function): + '''Format a function prototype as a string, from fields extracted from yaml''' + return_type = "void" + if 'c-return-value' in function.keys(): + return_type = function['c-return-value']['type'] + + out_str = return_type + " " + function['name'] + "(" + if 'c-params' in function.keys(): + for param in function['c-params']: + + param_type = param['type'] + param_name = param['name'] + if param_type[-1] == '*': + # pointer types - present with spacing as "int *a" + param_type = param_type.rstrip('* ') + param_name = "*" + param_name + + out_str += param_type + " " + param_name + ", " + + out_str = out_str.rstrip(", ") # Get rid of last comma/space + + else: + out_str += "void" + + out_str +=");\n" + return out_str + +def format_c_function_typedef(declaration): + '''Format a function type declaration as a string''' + retval = "void" + params = "void" + if 'func-typedef-retval' in declaration.keys(): + retval = declaration['func-typedef-retval'] + if 'func-typedef-params' in declaration.keys(): + params = '' + for param in declaration['func-typedef-params']: + param_type = param['type'] + param_name = param['name'] + if param_type[-1] == '*': + # pointer types - present with spacing as "int *a" + param_type = param_type.rstrip('* ') + param_name = "*" + param_name + params += param_type + " " + param_name + ", " + params = params.rstrip(", ") # Get rid of last comma/space + out_str = "typedef " + retval + " (" + declaration['name'] + ")(" + params + ");\n" + return out_str + +def format_c_enum_typedef(declaration, include_comments): + '''Format an enum type declaration as a string''' + out_str = "typedef enum {\n" + for member in declaration['enum-members']: + out_str += indent() + member['name'] + if 'value' in member.keys(): + out_str += " = " + str(member['value']) + out_str += "," # trailing comma should be valid for modern compilers + if include_comments: + if 'description' in member.keys(): + out_str += " /* " + member['description'] + " */" + out_str += "\n" + out_str += "} " + declaration['name'] + ";\n" + return out_str From 94d9ba49684406bb9532179489d5945bc9839fa5 Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Wed, 22 Feb 2023 14:18:14 +0000 Subject: [PATCH 08/10] - Add csi_set_preemption - Add priority argument to csi_set_m_timeout and csi_set_u_timeout - Improve explanatory text --- api/C/include/csi_interrupts.h | 44 +++++++++++++++++++++++++++------- api/rvm-csi-spec.yaml | 40 +++++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/api/C/include/csi_interrupts.h b/api/C/include/csi_interrupts.h index 279bb63..ee34bf5 100644 --- a/api/C/include/csi_interrupts.h +++ b/api/C/include/csi_interrupts.h @@ -386,10 +386,11 @@ int csi_get_irq_priority_thresh(void *mctx); void csi_force_ext_irq(void *mctx, int signal); /* - * Set interrupt level for a source, if supported. Higher-level interrupts will - * preempt lower-level interrupts at the same privilege level. Levels range from 0 - * to CSI_MAX_INTERRUPT_LEVEL, where level 0 represents regular execution outside - * of an interrupt handler. Must be run in machine mode. + * Set interrupt level for a source. If preemption has been enabled using + * csi_set_preemption, then higher-level interrupts will preempt lower-level + * interrupts at the same privilege level (if supported by the hardware). Levels + * range from 0 to CSI_MAX_INTERRUPT_LEVEL, where level 0 represents regular + * execution outside of an interrupt handler. Must be run in machine mode. * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. @@ -419,6 +420,8 @@ int csi_get_interrupt_level(void *mctx, int signal); * called to temporarily raise the level during a piece of critical code, thereby * preventing preemption by interrupts with a certain range of levels; while the * "correct" interrupt level can be restored by setting level threshold to 0. + * Note: preemption must be enabled using csi_set_preemption for this to take + * effect. * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. @@ -461,9 +464,9 @@ csi_status_t csi_register_raw_interrupt_handler(void *mctx, unsigned mcause, voi /* * This function may optionally be run by users who want to supply their own fast - * exception handling function to be inserted directly into the mtvec register - * (thereby bypassing the RVM-CSI base trap handler in handling exceptions). It - * must be run in machine mode. Note that in this case the user's function must + * exception handling function to be inserted directly into the base of the vector + * table (thereby bypassing the RVM-CSI base trap handler in handling exceptions). + * It must be run in machine mode. Note that in this case the user's function must * deal with save and restore of register context (whereas this is not necessary * for handlers registered using csi_register_m_isr). * @@ -478,6 +481,21 @@ csi_status_t csi_register_raw_interrupt_handler(void *mctx, unsigned mcause, voi */ csi_status_t csi_register_raw_exception_handler(void *mctx, void *handler); +/* + * When any trap is first taken, the mie bit within mstatus reverts to 0, thereby + * disabling interrupts until it is set to 1. By default, the base trap handler + * leaves this bit at 0 until just before interrupt handling completes, thereby + * preventing preemption. This function may optionally be run to modify this + * behaviour and thus allow preemption. This function must be run in machine mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param preemption_enabled: Set true to enable preemption, false to disable. + * @return : Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be + * returned as appropriate if the request is invalid. + */ +csi_status_t csi_set_preemption(void *mctx, bool preemption_enabled); + /* * Set the frequency of the system timer. Note that there is typically a single * timer for all harts in the system, so this function can affect the operation of @@ -528,9 +546,13 @@ csi_status_t csi_set_timer_tick(void *mctx, unsigned tick_period_us); * @param callback_context: Pointer to the user's context space, which will be * passed into the callback function. * @param timeout_ticks: Timeout period in ticks (configured by csi_set_timer_tick) + * @param priority: Priority for this timeout, used to determine the callback to be + * called if two callbacks fall due on the same timer tick. Higher numbers + * indicate higher priority. A single priority scheme is shared between M-mode and + * U-mode callbacks. * @return : Status of operation. */ -csi_status_t csi_set_m_timeout(void *mctx, csi_timeout_t *timeout_handle, csi_timeout_callback_t *callback, void *callback_context, int timeout_ticks); +csi_status_t csi_set_m_timeout(void *mctx, csi_timeout_t *timeout_handle, csi_timeout_callback_t *callback, void *callback_context, int timeout_ticks, int priority); /* * Registers a callback function (callback) which will be called after a period set @@ -550,9 +572,13 @@ csi_status_t csi_set_m_timeout(void *mctx, csi_timeout_t *timeout_handle, csi_ti * @param callback_context: Pointer to the user's context space, which will be * passed into the callback function. * @param timeout_ticks: Timeout period in ticks (configured by csi_set_timer_tick) + * @param priority: Priority for this timeout, used to determine the callback to be + * called if two callbacks fall due on the same timer tick. Higher numbers + * indicate higher priority. A single priority scheme is shared between M-mode and + * U-mode callbacks. * @return : Status of operation. */ -csi_status_t csi_set_u_timeout(unsigned irq_system_handle, csi_timeout_t *timeout_handle, csi_timeout_callback_t *callback, void *callback_context, int timeout_ticks); +csi_status_t csi_set_u_timeout(unsigned irq_system_handle, csi_timeout_t *timeout_handle, csi_timeout_callback_t *callback, void *callback_context, int timeout_ticks, int priority); /* * Cancels a timeout previously configured with csi_set_timeout, using the diff --git a/api/rvm-csi-spec.yaml b/api/rvm-csi-spec.yaml index b451a59..86da721 100644 --- a/api/rvm-csi-spec.yaml +++ b/api/rvm-csi-spec.yaml @@ -558,8 +558,9 @@ modules: type: int - name: csi_set_interrupt_level description: > - Set interrupt level for a source, if supported. Higher-level interrupts will preempt lower-level - interrupts at the same privilege level. Levels range from 0 to CSI_MAX_INTERRUPT_LEVEL, where level 0 + Set interrupt level for a source. If preemption has been enabled using csi_set_preemption, then + higher-level interrupts will preempt lower-level interrupts at the same privilege level (if supported + by the hardware). Levels range from 0 to CSI_MAX_INTERRUPT_LEVEL, where level 0 represents regular execution outside of an interrupt handler. Must be run in machine mode. c-params: @@ -601,7 +602,7 @@ modules: threshold, set by this function, and the level associated with the current interrupt. Therefore this function can be called to temporarily raise the level during a piece of critical code, thereby preventing preemption by interrupts with a certain range of levels; while the "correct" interrupt level can be restored by setting - level threshold to 0. + level threshold to 0. Note: preemption must be enabled using csi_set_preemption for this to take effect. c-params: - name: mctx description: > @@ -653,7 +654,7 @@ modules: - name: csi_register_raw_exception_handler description: > This function may optionally be run by users who want to supply their own fast exception handling function - to be inserted directly into the mtvec register (thereby bypassing the RVM-CSI base trap handler in handling + to be inserted directly into the base of the vector table (thereby bypassing the RVM-CSI base trap handler in handling exceptions). It must be run in machine mode. Note that in this case the user's function must deal with save and restore of register context (whereas this is not necessary for handlers registered using csi_register_m_isr). c-params: @@ -671,6 +672,25 @@ modules: description: > Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be returned as appropriate if the request is invalid. type: csi_status_t + - name: csi_set_preemption + description: > + When any trap is first taken, the mie bit within mstatus reverts to 0, thereby disabling interrupts until it is set + to 1. By default, the base trap handler leaves this bit at 0 until just before interrupt handling completes, thereby + preventing preemption. This function may optionally be run to modify this behaviour and thus allow preemption. + This function must be run in machine mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: preemption_enabled + description: > + Set true to enable preemption, false to disable. + type: bool + c-return-value: + description: > + Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be returned as appropriate if the request is invalid. + type: csi_status_t - name: csi_timer_config description: > Set the frequency of the system timer. Note that there is typically a single timer for all @@ -734,6 +754,12 @@ modules: - name: timeout_ticks description: Timeout period in ticks (configured by csi_set_timer_tick) type: int + - name: priority + description: > + Priority for this timeout, used to determine the callback to be called if two callbacks + fall due on the same timer tick. Higher numbers indicate higher priority. A single priority + scheme is shared between M-mode and U-mode callbacks. + type: int c-return-value: description: Status of operation. type: csi_status_t @@ -763,6 +789,12 @@ modules: - name: timeout_ticks description: Timeout period in ticks (configured by csi_set_timer_tick) type: int + - name: priority + description: > + Priority for this timeout, used to determine the callback to be called if two callbacks + fall due on the same timer tick. Higher numbers indicate higher priority. A single priority + scheme is shared between M-mode and U-mode callbacks. + type: int c-return-value: description: Status of operation. type: csi_status_t From c0d0a6a7caeb724430676c4d7923d1cb7e6a3181 Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Wed, 8 Mar 2023 14:52:41 +0000 Subject: [PATCH 09/10] Add csi_route_interrupt Add U-mode version of raw interrupt handling --- api/C/include/csi_interrupts.h | 62 ++++++++++++++++++++++++++++-- api/rvm-csi-spec.yaml | 65 ++++++++++++++++++++++++++++++-- spec-schema/parser/doc_gen.py | 5 ++- spec-schema/parser/header_gen.py | 5 +++ 4 files changed, 128 insertions(+), 9 deletions(-) diff --git a/api/C/include/csi_interrupts.h b/api/C/include/csi_interrupts.h index ee34bf5..e471335 100644 --- a/api/C/include/csi_interrupts.h +++ b/api/C/include/csi_interrupts.h @@ -441,18 +441,72 @@ csi_status_t csi_set_interrupt_level_thresh(void *mctx, int level_thresh); */ int csi_get_interrupt_level_thresh(void *mctx); +/* + * This function may optionally be used to route an interrupt source to the hart. + * This is only required if using csi_register_raw_m_interrupt_handler or + * csi_register_raw_m_interrupt_handler to register a "raw" handler. Otherwise, + * this routing functionality is performed within csi_register_m_isr or + * csi_register_u_isr, and this function should not be run. If run, it must be run + * in M-mode. + * + * @param mctx: M-mode context pointer previously initialised by + * csi_interrupts_init. + * @param source: Enumerated interrupt / exception source. This must be one of the + * enumerations from csi_trap_source_t, or a value from the BSP (extending the + * enumerations in csi_trap_source_t) enumerating a platform-specific external + * interrupt source. + */ +void csi_route_interrupt(void *mctx, int source); + /* * This function may optionally be run by users who want to supply their own fast - * interrupt handling function to be inserted directly into the vector table + * M-mode interrupt handling function to be inserted directly into the vector table * (thereby bypassing the RVM-CSI base trap handler in handling a given mcause). * It must be run in machine mode. Note that in this case the user's function must * deal with save and restore of register context (whereas this is not necessary * for handlers registered using csi_register_m_isr). * + * Many systems without CLIC (Core Local Interrrupt Controller) functionality may + * chose not to implement this function. If it is implemented on such systems, + * then there may be severe restrictions around its functionality, particularly on + * placement of the user's handler in memory. Some CLINT-based systems may not be + * able to implement this functionality due to restrictions on writing to code + * memory. Consult the BSP documentation for details. + * * @param mctx: M-mode context pointer previously initialised by * csi_interrupts_init. - * @param mcause: mcause register value (LSBs) which will result in a jump into - * this handler + * @param exccode: Exception code (mcause register LSBs) which will result in a + * jump into this handler + * @param handler: Pointer to the user's handler function. If this is NULL, any + * function previously registered using csi_register_raw_interrupt_handler will be + * unregistered and the relevant signals will go back to being handled by the base + * trap handler in the BSP. + * @return : Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be + * returned as appropriate if the request is invalid. + */ +csi_status_t csi_register_raw_m_interrupt_handler(void *mctx, unsigned exccode, void *handler); + +/* + * This function may optionally be run by users who want to supply their own fast + * U-mode interrupt handling function to be inserted directly into the vector table + * (thereby bypassing the RVM-CSI base trap handler in handling a given mcause). + * It must be run in user mode. Note that in this case the user's function must + * deal with save and restore of register context (whereas this is not necessary + * for handlers registered using csi_register_m_isr). + * + * It will not normally be possible to support this functionality on systems + * without CLIC (Core Local Interrrupt Controller) functionality, since delegation + * of interrupts directly to U-mode has been removed (for CLINT mode) from later + * editions of the RISC-V ISA. If it is implemented on such systems, then there + * may be severe restrictions around its functionality, particularly on placement + * of the user's handler in memory. Some CLINT-based systems may not be able to + * implement this functionality due to restrictions on writing to code memory. + * Consult the BSP documentation for details. + * + * @param irq_system_handle: Handle for the interrupt sub-system on this hart, + * obtained by running get_interrupts_u_handle + * @param exccode: Exception code (mcause register LSBs) which will result in a + * jump into this handler * @param handler: Pointer to the user's handler function. If this is NULL, any * function previously registered using csi_register_raw_interrupt_handler will be * unregistered and the relevant signals will go back to being handled by the base @@ -460,7 +514,7 @@ int csi_get_interrupt_level_thresh(void *mctx); * @return : Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be * returned as appropriate if the request is invalid. */ -csi_status_t csi_register_raw_interrupt_handler(void *mctx, unsigned mcause, void *handler); +csi_status_t csi_register_raw_u_interrupt_handler(unsigned irq_system_handle, unsigned exccode, void *handler); /* * This function may optionally be run by users who want to supply their own fast diff --git a/api/rvm-csi-spec.yaml b/api/rvm-csi-spec.yaml index 86da721..815daf3 100644 --- a/api/rvm-csi-spec.yaml +++ b/api/rvm-csi-spec.yaml @@ -627,19 +627,76 @@ modules: description: interrupt level threshold (resulting from calls to csi_set_interrupt_level_thresh). -1 will be returned if the request is invalid. type: int - - name: csi_register_raw_interrupt_handler + + + - name: csi_route_interrupt description: > - This function may optionally be run by users who want to supply their own fast interrupt handling function + This function may optionally be used to route an interrupt source to the hart. This is only required if using + csi_register_raw_m_interrupt_handler or csi_register_raw_m_interrupt_handler to register a "raw" handler. Otherwise, + this routing functionality is performed within csi_register_m_isr or csi_register_u_isr, and this function should + not be run. If run, it must be run in M-mode. + c-params: + - name: mctx + description: > + M-mode context pointer previously initialised by csi_interrupts_init. + type: void * + - name: source + description: > + Enumerated interrupt / exception source. This must be one of the enumerations from csi_trap_source_t, or + a value from the BSP (extending the enumerations in csi_trap_source_t) enumerating a platform-specific + external interrupt source. + type: int + - name: csi_register_raw_m_interrupt_handler + description: > + This function may optionally be run by users who want to supply their own fast M-mode interrupt handling function to be inserted directly into the vector table (thereby bypassing the RVM-CSI base trap handler in handling a given mcause). It must be run in machine mode. Note that in this case the user's function must deal with save and restore of register context (whereas this is not necessary for handlers registered using csi_register_m_isr). + notes: + - > + Many systems without CLIC (Core Local Interrrupt Controller) functionality may chose not to implement this function. If it + is implemented on such systems, then there may be severe restrictions around its functionality, particularly on + placement of the user's handler in memory. Some CLINT-based systems may not be able to implement this functionality + due to restrictions on writing to code memory. Consult the BSP documentation for details. c-params: - name: mctx description: > M-mode context pointer previously initialised by csi_interrupts_init. type: void * - - name: mcause - description: mcause register value (LSBs) which will result in a jump into this handler + - name: exccode + description: Exception code (mcause register LSBs) which will result in a jump into this handler + type: unsigned + - name: handler + description: > + Pointer to the user's handler function. If this is NULL, any function previously registered using + csi_register_raw_interrupt_handler will be unregistered and the relevant signals will go back to being handled + by the base trap handler in the BSP. + type: void * + c-return-value: + description: > + Status of operation. CSI_ERROR or CSI_NOT_IMPLEMENTED will be returned as appropriate if the request is invalid. + type: csi_status_t + - name: csi_register_raw_u_interrupt_handler + description: > + This function may optionally be run by users who want to supply their own fast U-mode interrupt handling function + to be inserted directly into the vector table (thereby bypassing the RVM-CSI base trap handler in handling a given + mcause). It must be run in user mode. Note that in this case the user's function must deal with save and restore + of register context (whereas this is not necessary for handlers registered using csi_register_m_isr). + notes: + - > + It will not normally be possible to support this functionality on systems without CLIC (Core Local Interrrupt + Controller) functionality, since delegation of interrupts directly to U-mode has been removed (for CLINT mode) from + later editions of the RISC-V ISA. If it is implemented on such systems, then there may be severe restrictions + around its functionality, particularly on placement of the user's handler in memory. Some CLINT-based systems + may not be able to implement this functionality due to restrictions on writing to code memory. Consult the BSP + documentation for details. + c-params: + - name: irq_system_handle + description: > + Handle for the interrupt sub-system on this hart, obtained by running get_interrupts_u_handle + type: unsigned + - name: exccode + description: Exception code (mcause register LSBs) which will result in a jump into this handler type: unsigned - name: handler description: > diff --git a/spec-schema/parser/doc_gen.py b/spec-schema/parser/doc_gen.py index 9155981..48bff1c 100644 --- a/spec-schema/parser/doc_gen.py +++ b/spec-schema/parser/doc_gen.py @@ -113,7 +113,10 @@ def format_param_type(type,types_defined_by_module): out_str += "----\n\n" out_str += function['description'] + "\n\n" - + if 'notes' in function.keys(): + for note in function['notes']: + out_str += note + "\n\n" + out_str += heading_marker(4) + "Return\n" if 'c-return-value' in function.keys(): diff --git a/spec-schema/parser/header_gen.py b/spec-schema/parser/header_gen.py index b136690..7df1f61 100644 --- a/spec-schema/parser/header_gen.py +++ b/spec-schema/parser/header_gen.py @@ -112,6 +112,11 @@ def format_c_function(function): out_str += format_c_comment_lines(function['description']) out_str += "*\n " + if 'notes' in function.keys(): + for note in function['notes']: + out_str += format_c_comment_lines(note) + out_str += "*\n " + if 'c-params' in function.keys(): for param in function['c-params']: out_str += format_c_comment_lines("@param " + param['name'] + ": " + param['description']) From 8b692fccee7b2fd2ddd5fee8e9306b3a4a81a9ca Mon Sep 17 00:00:00 2001 From: Chris Owen Date: Wed, 22 Mar 2023 10:59:05 +0000 Subject: [PATCH 10/10] Improve doc generation to include more cross-referencing links. Also revise some of the introductory text. No change to functionality. --- chapter2.adoc | 2 +- intro.adoc | 19 ++++++++---- spec-schema/parser/doc_gen.py | 55 +++++++++++++++++++++-------------- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/chapter2.adoc b/chapter2.adoc index 6cbed56..b54f376 100644 --- a/chapter2.adoc +++ b/chapter2.adoc @@ -31,7 +31,7 @@ This header is part of the API definition, and includes several further header f |=== |Header|Supplied by|Contents |csi_defs.h|API|Definitions which may be used by the BSP-supplied headers (such as return codes etc.) -|csi_csrs.h|API|Standard CSR definitions, auto-generated from the RISC-V SAIL model +|csi_csrs.h|API|Standard CSR definitions (auto-generated according to the RISC-V spec) |csi_bsp_csrs.h|BSP|Custom CSR definitions |csi_bsp_perip.h|BSP|Peripheral register definitions |csi_bsp_interrupts.h|BSP|Enumeration of interrupt sources in the system diff --git a/intro.adoc b/intro.adoc index 7bddcbf..58835bb 100644 --- a/intro.adoc +++ b/intro.adoc @@ -4,16 +4,19 @@ RVM-CSI (Risc-V eMbedded - Common Software Interface) has been defined with the aim of facilitating the portability of source code across different embedded platforms. -RVM refers to a class of _platforms_ and _profiles_ which RISC-V International intends to define. A _profile_ defines a +RVM refers to a class of _platforms_ and _profiles_ which RISC-V International originally intended to define. A _profile_ defines a specific base ISA, plus ISA extensions and any options applicable within those ISA extensions. A _platform_ comprises a profile plus further specifications for non-ISA features (such as interrupt controllers etc.). -Although no RVM platform or profile has yet been specified at time of writing, the initial specification of RVM-CSI -will have no dependency on certain features being present in the platform (beyond the base ISA). Any run-time -functionality that depends on certain hardware characteristics can either a) report the absence of the required -functionality and hence be non-functional, or b) emulate the required functionality in software. +The motivation behind defining these profiles and platforms is to constrain the features of a RISC-V platform in order to +make it easier to write software that is portable between platforms. This is most important in the application +processor space, where binary distributions need to be created that will work on platforms from multiple vendors. +Hence most focus in this area has been on the RVA (application processor) platforms. -Therefore, a single Common Software Interface should serve to cover all defined RVM platforms going forward. +In the embedded space, there is no longer an intention, at least in the near future at time of writing, to define the +RVM platforms and profiles. Rather, since we assume that software will be built for a specific embedded platform, we +can deal with the problem of software portability by creating a software layer that abstracts the features of the platform. +Hence the motivation behind RVM-CSI. In constructing systems for RVM platforms, we assume the following: @@ -31,6 +34,10 @@ _Board Support Packs_ (BSPs) conforming to this API, and application writers can in order to create portable code. * The format of Board Support Packs. +The API aims to have no dependency on certain features being present in the platform (beyond the base ISA). Any run-time +functionality that depends on certain hardware characteristics can either a) report the absence of the required +functionality and hence be non-functional, or b) emulate the required functionality in software. + While the first version of the specification deals with a C language API, future enhancements may encompass other languages. Implementations in different languages will share common function names and descriptions wherever possible. diff --git a/spec-schema/parser/doc_gen.py b/spec-schema/parser/doc_gen.py index 48bff1c..de52c24 100644 --- a/spec-schema/parser/doc_gen.py +++ b/spec-schema/parser/doc_gen.py @@ -18,6 +18,12 @@ def format_text_from_array(input_array): out_str += "\n" return out_str +def preprocess_links(text, linked_sections): + '''Searches text for matches within linked_sections, and replaces with links''' + for s in linked_sections: + text = text.replace(s, '<<' + s + ', ' + s + '>>') + return text + def format_adoc_type_declaration(declaration): ''' Builds adoc level 3 & 4 section for supplied type declaration. Returns this as a string. @@ -26,7 +32,7 @@ def format_adoc_type_declaration(declaration): # values can be "struct", "enum", "int", "unsigned" c_type = declaration['type'] - out_str = "[#type_" + declaration['name'] + "]\n" + out_str = "[#" + declaration['name'] + "]\n" out_str += heading_marker(3) + c_type + " *" + declaration['name'] + "*\n" out_str += declaration['description'] + "\n\n" @@ -89,21 +95,14 @@ def format_adoc_type_declaration(declaration): return out_str -def format_adoc_function(function, module_type_list): +def format_adoc_function(function, linked_sections): ''' Builds adoc level 3 & 4 section for supplied function declaration. Second parameter is a list of types declared within this module which is used to create cross-references. Returns function adoc string. ''' - - def format_param_type(type,types_defined_by_module): - ''' If parameter type is defined within module then render this as a cross-reference''' - if type in types_defined_by_module: - return "<>" # Adoc cross-reference to type - else: - return type - out_str = heading_marker(3) + function['name'] + "\n" + out_str = heading_marker(3) + function['name'] + '[[' + function['name'] + ']]' "\n" out_str += ''' [source, c] @@ -112,15 +111,16 @@ def format_param_type(type,types_defined_by_module): out_str += format_c_function_prototype(function) out_str += "----\n\n" - out_str += function['description'] + "\n\n" + out_str += preprocess_links(function['description'], linked_sections) + "\n\n" if 'notes' in function.keys(): for note in function['notes']: - out_str += note + "\n\n" + out_str += preprocess_links(note, linked_sections) + "\n\n" out_str += heading_marker(4) + "Return\n" if 'c-return-value' in function.keys(): - out_str += "`" + function['c-return-value']['type'] + "` - " + function['c-return-value']['description'] + "\n\n" + out_str += "`" + function['c-return-value']['type'] + "` - " + \ + preprocess_links(function['c-return-value']['description'], linked_sections) + "\n\n" out_str += heading_marker(4) + "Parameters\n" @@ -133,7 +133,8 @@ def format_param_type(type,types_defined_by_module): param_type = param_type.rstrip('* ') param_name = "*" + param_name - out_str += format_param_type(param_type, module_type_list) + " `" + param_name + "` - " + param['description'] + "\n\n" + out_str += preprocess_links(param_type, linked_sections) + " `" + param_name + "` - " + \ + preprocess_links(param['description'],linked_sections) + "\n\n" if 'notes' in param.keys(): out_str += format_text_from_array(param['notes']) @@ -144,7 +145,7 @@ def format_param_type(type,types_defined_by_module): return out_str -def generate_c_module_adoc(module, out_dir, module_sub_dir, adoc_optimization): +def generate_c_module_adoc(module, out_dir, module_sub_dir, adoc_optimization, linked_sections): ''' Builds adoc file for a module. Inputs are the module definition and the output directory & sub directory for the adoc file. @@ -159,35 +160,33 @@ def generate_c_module_adoc(module, out_dir, module_sub_dir, adoc_optimization): out_str += heading_marker(1) + module['c-filename'] + " - " + module['name'] + "\n" out_str += ":toc:\n" - out_str += module['description'] + "\n\n" + out_str += preprocess_links(module['description'], linked_sections) + "\n\n" if 'notes' in module.keys() or 'c-specific-notes' in module.keys(): out_str += heading_marker(2) + "Notes\n" if 'notes' in module.keys(): for note in module['notes']: - out_str += note + out_str += preprocess_links(note, linked_sections) out_str += "\n\n" if 'c-specific-notes' in module.keys(): - out_str += format_text_from_array(module['c-specific-notes']) + out_str += preprocess_links(format_text_from_array(module['c-specific-notes']), linked_sections) out_str += "\n" # Add type declarations - types_provided_by_module = [] # used to create link between function params and types, if possible if 'c-type-declarations' in module.keys(): out_str += heading_marker(2) + "Types\n" for type_declaration in module['c-type-declarations']: out_str += format_adoc_type_declaration(type_declaration) out_str += "\n" - types_provided_by_module.append(type_declaration['name']) out_str += "\n" # Add function declarations if 'functions' in module.keys(): out_str += heading_marker(2) + "Functions\n" for function in module['functions']: - out_str += format_adoc_function(function, types_provided_by_module) + out_str += format_adoc_function(function, linked_sections) out_str += "\n" out_str += "\n" @@ -224,6 +223,18 @@ def generate_c_adoc(api_definition, out_dir): global top_heading_level top_heading_level = api_definition['top-heading-level'] + # Get a set of function and macro names, we will create links where these are + # referred to. + linked_sections = [] + for module in api_definition['modules']: + if 'functions' in module.keys(): + for function in module['functions']: + linked_sections.append(function['name']) + if 'c-type-declarations' in module.keys(): + for dec in module['c-type-declarations']: + linked_sections.append(dec['name']) + + # Create document as a string out_str = "[#title]\n" out_str += heading_marker(1) + api_definition['c-documentation-title'] + "\n" @@ -240,7 +251,7 @@ def generate_c_adoc(api_definition, out_dir): for module in api_definition['modules']: # Generate docs for module - this will be a new file # Returns [c filename, module name, adoc filename] - module_links = generate_c_module_adoc(module, out_dir, module_sub_dir, api_definition['adoc-optimization']) + module_links = generate_c_module_adoc(module, out_dir, module_sub_dir, api_definition['adoc-optimization'], linked_sections) # Add link to a table of contents module_file_wth_path = pathlib.Path(module_sub_dir, module_links[2])