123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- /* Copyright 2018 SiFive, Inc */
- /* SPDX-License-Identifier: Apache-2.0 */
- /*! @file cpu.h
- * @brief API for accessing CPU capabilities.
- */
- #ifndef METAL__CPU_H
- #define METAL__CPU_H
- #include <stdint.h>
- #include <metal/interrupt.h>
- struct metal_cpu;
- /*!
- * @brief Function signature for exception handlers
- */
- typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode);
- struct metal_cpu_vtable {
- unsigned long long (*mcycle_get)(struct metal_cpu *cpu);
- unsigned long long (*timebase_get)(struct metal_cpu *cpu);
- unsigned long long (*mtime_get)(struct metal_cpu *cpu);
- int (*mtimecmp_set)(struct metal_cpu *cpu, unsigned long long time);
- struct metal_interrupt* (*tmr_controller_interrupt)(struct metal_cpu *cpu);
- int (*get_tmr_interrupt_id)(struct metal_cpu *cpu);
- struct metal_interrupt* (*sw_controller_interrupt)(struct metal_cpu *cpu);
- int (*get_sw_interrupt_id)(struct metal_cpu *cpu);
- int (*set_sw_ipi)(struct metal_cpu *cpu, int hartid);
- int (*clear_sw_ipi)(struct metal_cpu *cpu, int hartid);
- int (*get_msip)(struct metal_cpu *cpu, int hartid);
- struct metal_interrupt* (*controller_interrupt)(struct metal_cpu *cpu);
- int (*exception_register)(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
- int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc);
- uintptr_t (*get_epc)(struct metal_cpu *cpu);
- int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc);
- };
- /*! @brief A device handle for a CPU hart
- */
- struct metal_cpu {
- const struct metal_cpu_vtable *vtable;
- };
- /*! @brief Get a reference to a CPU hart
- *
- * @param hartid The ID of the desired CPU hart
- * @return A pointer to the CPU device handle
- */
- struct metal_cpu* metal_cpu_get(unsigned int hartid);
- /*! @brief Get the hartid of the CPU hart executing this function
- *
- * @return The hartid of the current CPU hart */
- int metal_cpu_get_current_hartid(void);
- /*! @brief Get the number of CPU harts
- *
- * @return The number of CPU harts */
- int metal_cpu_get_num_harts(void);
- /*! @brief Get the CPU cycle count timer value
- *
- * Get the value of the cycle count timer for a given CPU
- *
- * @param cpu The CPU device handle
- * @return The value of the CPU cycle count timer
- */
- __inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
- { return cpu->vtable->mcycle_get(cpu); }
- /*! @brief Get the timebase of the CPU
- *
- * Get the value of the timebase of the cycle count timer
- *
- * @param cpu The CPU device handle
- * @return The value of the cycle count timer timebase
- */
- __inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
- { return cpu->vtable->timebase_get(cpu); }
- /*! @brief Get the value of the mtime RTC
- *
- * Get the value of the mtime real-time clock. The CPU interrupt controller
- * must be initialized before this function is called or the return value
- * will be 0.
- *
- * @param cpu The CPU device handle
- * @return The value of mtime, or 0 if failure
- */
- __inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
- { return cpu->vtable->mtime_get(cpu); }
- /*! @brief Set the value of the RTC mtimecmp RTC
- *
- * Set the value of the mtime real-time clock compare register. The CPU
- * interrupt controller must be initialized before this function is called
- * or the return value will be -1;
- *
- * @param cpu The CPU device handle
- * @param time The value to set the compare register to
- * @return The value of mtimecmp or -1 if error
- */
- __inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
- { return cpu->vtable->mtimecmp_set(cpu, time); }
- /*! @brief Get a reference to RTC timer interrupt controller
- *
- * Get a reference to the interrupt controller for the real-time clock interrupt.
- * The controller returned by this function must be initialized before any interrupts
- * are registered or enabled with it.
- *
- * @param cpu The CPU device handle
- * @return A pointer to the timer interrupt handle
- */
- __inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
- { return cpu->vtable->tmr_controller_interrupt(cpu); }
- /*! @brief Get the RTC timer interrupt id
- *
- * Get the interrupt ID of the real-time clock interrupt
- *
- * @param cpu The CPU device handle
- * @return The timer interrupt ID
- */
- __inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
- { return cpu->vtable->get_tmr_interrupt_id(cpu); }
- /*! @brief Get a reference to the software interrupt controller
- *
- * Get a reference to the interrupt controller for the software/inter-process
- * interrupt. The controller returned by this function must be initialized before
- * any interrupts are registered or enabled with it.
- *
- * @param cpu The CPU device handle
- * @return A pointer to the software interrupt handle
- */
- __inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
- { return cpu->vtable->sw_controller_interrupt(cpu); }
- /*! @brief Get the software interrupt id
- *
- * Get the interrupt ID for the software/inter-process interrupt
- *
- * @param cpu The CPU device handle
- * @return the software interrupt ID
- */
- __inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
- { return cpu->vtable->get_sw_interrupt_id(cpu); }
- /*!
- * @brief Set the inter-process interrupt for a hart
- *
- * Trigger a software/inter-process interrupt for a hart. The CPU interrupt
- * controller for the CPU handle passed to this function must be initialized
- * before this function is called.
- *
- * @param cpu The CPU device handle
- * @param hartid The CPU hart ID to be interrupted
- * @return 0 upon success
- */
- __inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
- { return cpu->vtable->set_sw_ipi(cpu, hartid); }
- /*!
- * @brief Clear the inter-process interrupt for a hart
- *
- * Clear the software/inter-process interrupt for a hart. The CPU interrupt
- * controller for the CPU handle passed to this function must be initialized
- * before this function is called.
- *
- * @param cpu The CPU device handle
- * @param hartid The CPU hart ID to clear
- * @return 0 upon success
- */
- __inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
- { return cpu->vtable->clear_sw_ipi(cpu, hartid); }
- /*!
- * @brief Get the value of MSIP for the given hart
- *
- * Get the value of the machine software interrupt pending bit for
- * the given hart. The CPU interrupt controller for the CPU handle passed
- * as argument to this function must be initialized before this function
- * is called.
- *
- * @param cpu the CPU device handle
- * @param hartid The CPU hart to read
- * @return 0 upon success
- */
- __inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
- { return cpu->vtable->get_msip(cpu, hartid); }
- /*!
- * @brief Get the interrupt controller for the CPU
- *
- * Get the CPU interrupt controller. The controller returned by this
- * function must be initialized before any interrupts are registered
- * or enabled and before any exception handlers are registered with
- * this CPU.
- *
- * @param cpu The CPU device handle
- * @return The handle for the CPU interrupt controller
- */
- __inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
- { return cpu->vtable->controller_interrupt(cpu); }
- /*!
- * @brief Register an exception handler
- *
- * Register an exception handler for the CPU. The CPU interrupt controller must be initialized
- * before this function is called.
- *
- * @param cpu The CPU device handle
- * @param ecode The exception code to register a handler for
- * @param handler Callback function for the exception handler
- * @return 0 upon success
- */
- __inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
- { return cpu->vtable->exception_register(cpu, ecode, handler); }
- /*!
- * @brief Get the length of an instruction in bytes
- *
- * Get the length of an instruction in bytes.
- *
- * On RISC-V platforms, this is useful for detecting whether an instruction is
- * compressed (2 bytes long) or uncompressed (4 bytes long).
- *
- * This function is useful in conjuction with `metal_cpu_get_exception_pc()`
- * and `metal_cpu_set_exception_pc()` in order to cause the exception handler to
- * return execution after the faulting instruction.
- *
- * @param cpu The CPU device handle
- * @param epc The address of the instruction to measure
- * @return the length of the instruction in bytes
- */
- __inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
- { return cpu->vtable->get_ilen(cpu, epc); }
- /*!
- * @brief Get the program counter of the current exception.
- *
- * This function must be called within an exception handler. The behavior is
- * undefined outside of an exception handler.
- *
- * @param cpu The CPU device handle
- * @return The value of the program counter at the time of the exception
- */
- __inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu)
- { return cpu->vtable->get_epc(cpu); }
- /*!
- * @brief Set the exception program counter
- *
- * This function must be called within an exception handler. The behavior
- * is undefined outside of an exception handler.
- *
- * This function can be used to cause an exception handler to return execution
- * to an address other than the one that caused the exception.
- *
- * @param cpu the CPU device handle
- * @param epc The address to set the exception program counter to
- * @return 0 upon success
- */
- __inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
- { return cpu->vtable->set_epc(cpu, epc); }
- #endif
|