| // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
| /* Copyright 2013-2019 IBM Corp. |
| * Copyright 2021 Stewart Smith |
| */ |
| |
| #ifndef __SKIBOOT_H |
| #define __SKIBOOT_H |
| |
| #include <compiler.h> |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <assert.h> |
| #include <errno.h> |
| #include <bitutils.h> |
| #include <types.h> |
| |
| #include <ccan/container_of/container_of.h> |
| #include <ccan/list/list.h> |
| #include <ccan/short_types/short_types.h> |
| #include <ccan/build_assert/build_assert.h> |
| #include <ccan/array_size/array_size.h> |
| #include <ccan/endian/endian.h> |
| #include <ccan/str/str.h> |
| |
| #include <libflash/blocklevel.h> |
| |
| #include <mem-map.h> |
| #include <op-panel.h> |
| #include <platform.h> |
| |
| /* Special ELF sections */ |
| #define __force_data __section(".force.data") |
| |
| struct mem_region; |
| extern struct mem_region *mem_region_next(struct mem_region *region); |
| |
| /* Misc linker script symbols */ |
| extern char _start[]; |
| extern char _head_end[]; |
| extern char _stext[]; |
| extern char _etext[]; |
| extern char __sym_map_end[]; |
| extern char _romem_end[]; |
| |
| #ifndef __TESTING__ |
| /* Readonly section start and end. */ |
| extern char __rodata_start[], __rodata_end[]; |
| |
| static inline bool is_rodata(const void *p) |
| { |
| return ((const char *)p >= __rodata_start && (const char *)p < __rodata_end); |
| } |
| #else |
| static inline bool is_rodata(const void *p) |
| { |
| return false; |
| } |
| #endif |
| |
| /* Console logging |
| * Update console_get_level() if you add here |
| */ |
| #define PR_EMERG 0 |
| #define PR_ALERT 1 |
| #define PR_CRIT 2 |
| #define PR_ERR 3 |
| #define PR_WARNING 4 |
| #define PR_NOTICE 5 |
| #define PR_PRINTF PR_NOTICE |
| #define PR_INFO 6 |
| #define PR_DEBUG 7 |
| #define PR_TRACE 8 |
| #define PR_INSANE 9 |
| |
| #ifndef pr_fmt |
| #define pr_fmt(fmt) fmt |
| #endif |
| |
| int vprlog(int log_level, const char *fmt, va_list ap); |
| void _prlog(int log_level, const char* fmt, ...) __attribute__((format (printf, 2, 3))); |
| #define prlog(l, f, ...) do { _prlog(l, pr_fmt(f), ##__VA_ARGS__); } while(0) |
| #define prerror(fmt...) do { prlog(PR_ERR, fmt); } while(0) |
| #define prlog_once(arg, ...) \ |
| ({ \ |
| static bool __prlog_once = false; \ |
| if (!__prlog_once) { \ |
| __prlog_once = true; \ |
| prlog(arg, ##__VA_ARGS__); \ |
| } \ |
| }) |
| |
| /* Location codes -- at most 80 chars with null termination */ |
| #define LOC_CODE_SIZE 80 |
| |
| /* Processor generation */ |
| enum proc_gen { |
| proc_gen_unknown, |
| proc_gen_p8, |
| proc_gen_p9, |
| proc_gen_p10, |
| }; |
| extern enum proc_gen proc_gen; |
| |
| extern bool lpar_per_core; |
| |
| extern unsigned int pcie_max_link_speed; |
| |
| /* Convert a 4-bit number to a hex char */ |
| extern char __attrconst tohex(uint8_t nibble); |
| |
| #ifndef __TEST__ |
| /* Bit position of the most significant 1-bit (LSB=0, MSB=63) */ |
| static inline int ilog2(unsigned long val) |
| { |
| int left_zeros; |
| |
| asm volatile ("cntlzd %0,%1" : "=r" (left_zeros) : "r" (val)); |
| |
| return 63 - left_zeros; |
| } |
| |
| static inline bool is_pow2(unsigned long val) |
| { |
| return val == (1ul << ilog2(val)); |
| } |
| #endif |
| |
| #define lo32(x) ((x) & 0xffffffff) |
| #define hi32(x) (((x) >> 32) & 0xffffffff) |
| |
| /* WARNING: _a *MUST* be a power of two */ |
| #define ALIGN_UP(_v, _a) (((_v) + (_a) - 1) & ~((_a) - 1)) |
| #define ALIGN_DOWN(_v, _a) ((_v) & ~((_a) - 1)) |
| |
| /* TCE alignment */ |
| #define TCE_SHIFT 12 |
| #define TCE_PSIZE (1ul << 12) |
| #define TCE_MASK (TCE_PSIZE - 1) |
| |
| /* Not the greatest variants but will do for now ... */ |
| #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
| #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
| |
| /* PCI Geographical Addressing */ |
| #define PCI_BUS_NUM(bdfn) (((bdfn) >> 8) & 0xff) |
| #define PCI_DEV(bdfn) (((bdfn) >> 3) & 0x1f) |
| #define PCI_FUNC(bdfn) ((bdfn) & 0x07) |
| |
| /* |
| * To help the FSP to distinguish between physical address and TCE mapped address. |
| * Also to help hostboot to distinguish physical and relative address. |
| */ |
| #define HRMOR_BIT (1ul << 63) |
| |
| /* Clean the stray high bit which the FSP inserts: we only have 52 bits real */ |
| static inline u64 cleanup_addr(u64 addr) |
| { |
| return addr & ((1ULL << 52) - 1); |
| } |
| |
| /* Start the kernel */ |
| extern void start_kernel(uint64_t entry, void* fdt, |
| uint64_t mem_top) __noreturn; |
| extern void start_kernel32(uint64_t entry, void* fdt, |
| uint64_t mem_top) __noreturn; |
| extern void start_kernel_secondary(uint64_t entry) __noreturn; |
| |
| /* Re-set r16 register with CPU pointer, based on stack (r1) value */ |
| extern void restore_cpu_ptr_r16(void); |
| /* Set r16 register with value in 'r16' parameter */ |
| extern void set_cpu_ptr_r16(uint64_t r16); |
| |
| /* Get description of machine from HDAT and create device-tree */ |
| extern int parse_hdat(bool is_opal); |
| |
| struct dt_node; |
| |
| /* Add /cpus/features node for boot environment that passes an fdt */ |
| extern void dt_add_cpufeatures(struct dt_node *root); |
| |
| /* Root of device tree. */ |
| extern struct dt_node *dt_root; |
| |
| /* Full skiboot version number (possibly includes gitid). */ |
| extern const char version[]; |
| |
| /* Debug support */ |
| extern char __sym_map_start[]; |
| extern char __sym_map_end[]; |
| extern size_t snprintf_symbol(char *buf, size_t len, uint64_t addr); |
| |
| /* Direct controls */ |
| extern void direct_controls_init(void); |
| extern int64_t opal_signal_system_reset(int cpu_nr); |
| |
| /* Fast reboot support */ |
| extern void disable_fast_reboot(const char *reason); |
| extern void add_fast_reboot_dt_entries(void); |
| extern void fast_reboot(void); |
| extern void __noreturn __secondary_cpu_entry(void); |
| extern void __noreturn load_and_boot_kernel(bool is_reboot); |
| extern void cleanup_local_tlb(void); |
| extern void cleanup_global_tlb(void); |
| extern void init_shared_sprs(void); |
| extern void init_replicated_sprs(void); |
| extern bool start_preload_kernel(void); |
| extern void copy_exception_vectors(void); |
| extern void copy_sreset_vector(void); |
| extern void copy_sreset_vector_fast_reboot(void); |
| extern void patch_traps(bool enable); |
| |
| /* Various probe routines, to replace with an initcall system */ |
| extern int preload_capp_ucode(void); |
| extern void preload_io_vpd(void); |
| extern void uart_init(void); |
| extern void mbox_init(void); |
| extern void early_uart_init(void); |
| extern void homer_init(void); |
| extern void add_cpu_idle_state_properties(void); |
| extern void lpc_rtc_init(void); |
| |
| /* flash support */ |
| struct flash_chip; |
| extern int flash_register(struct blocklevel_device *bl); |
| extern int flash_start_preload_resource(enum resource_id id, uint32_t subid, |
| void *buf, size_t *len); |
| extern int flash_resource_loaded(enum resource_id id, uint32_t idx); |
| extern bool flash_reserve(void); |
| extern void flash_release(void); |
| extern bool flash_unregister(void); |
| #define FLASH_SUBPART_ALIGNMENT 0x1000 |
| #define FLASH_SUBPART_HEADER_SIZE FLASH_SUBPART_ALIGNMENT |
| extern int flash_subpart_info(void *part_header, uint32_t header_len, |
| uint32_t part_size, uint32_t *part_actual, |
| uint32_t subid, uint32_t *offset, |
| uint32_t *size); |
| extern void flash_fw_version_preload(void); |
| extern void flash_dt_add_fw_version(void); |
| extern const char *flash_map_resource_name(enum resource_id id); |
| extern int flash_secboot_info(uint32_t *total_size); |
| extern int flash_secboot_read(void *dst, uint32_t src, uint32_t len); |
| extern int flash_secboot_write(uint32_t dst, void *src, uint32_t len); |
| |
| /* |
| * Decompression routines |
| * |
| * The below structure members are needed for the xz library routines, |
| * src: Source address (The compressed binary) |
| * src_size: Source size |
| * dst: Destination address (The memory area where the `src` will be |
| * decompressed) |
| * dst_size: Destination size |
| */ |
| struct xz_decompress { |
| void *dst; |
| void *src; |
| size_t dst_size; |
| size_t src_size; |
| /* The status of the decompress process: |
| - OPAL_PARTIAL: if the job is in progress |
| - OPAL_SUCCESS: if the job is successful |
| - OPAL_NO_MEM: memory allocation failure |
| - OPAL_PARAMETER: If any of the above (src, dst..) are invalid or |
| if xz decompress fails. In which case the caller should check the |
| xz_error for failure reason. |
| */ |
| int status; |
| int xz_error; |
| /* The decompression job, this will be freed if the caller uses |
| * `wait_xz_decompression` function, in any other case its the |
| * responsibility of caller to free the allocation job. */ |
| struct cpu_job *job; |
| }; |
| |
| extern void xz_start_decompress(struct xz_decompress *); |
| extern void wait_xz_decompress(struct xz_decompress *); |
| |
| /* NVRAM support */ |
| extern void nvram_init(void); |
| extern void nvram_read_complete(bool success); |
| |
| /* UART stuff */ |
| enum { |
| UART_CONSOLE_OPAL, |
| UART_CONSOLE_OS |
| }; |
| extern void uart_set_console_policy(int policy); |
| extern bool uart_enabled(void); |
| |
| /* PRD */ |
| extern void prd_psi_interrupt(uint32_t proc); |
| extern void prd_tmgt_interrupt(uint32_t proc); |
| extern void prd_occ_reset(uint32_t proc); |
| extern void prd_sbe_passthrough(uint32_t proc); |
| extern void prd_init(void); |
| extern void prd_register_reserved_memory(void); |
| extern void prd_fsp_occ_reset(uint32_t proc); |
| extern void prd_fsp_occ_load_start(u32 proc); |
| extern void prd_fw_resp_fsp_response(int status); |
| extern int prd_hbrt_fsp_msg_notify(void *data, u32 dsize); |
| |
| /* Flatten device-tree */ |
| extern void *create_dtb(const struct dt_node *root, bool exclusive); |
| |
| extern void nx_p9_rng_late_init(void); |
| |
| extern void fast_sleep_exit(void); |
| |
| /* Fallback fake RTC */ |
| extern void fake_rtc_init(void); |
| |
| /* Exceptions */ |
| struct stack_frame; |
| extern void exception_entry(struct stack_frame *stack); |
| extern void exception_entry_pm_sreset(void); |
| extern void __noreturn exception_entry_pm_mce(void); |
| |
| /* Assembly in head.S */ |
| extern void disable_machine_check(void); |
| extern void enable_machine_check(void); |
| extern unsigned int enter_p8_pm_state(bool winkle); |
| extern unsigned int enter_p9_pm_state(uint64_t psscr); |
| extern void enter_p9_pm_lite_state(uint64_t psscr); |
| extern uint32_t reset_patch_start; |
| extern uint32_t reset_patch_end; |
| extern uint32_t reset_fast_reboot_patch_start; |
| extern uint32_t reset_fast_reboot_patch_end; |
| |
| /* Fallback fake NVRAM */ |
| extern int fake_nvram_info(uint32_t *total_size); |
| extern int fake_nvram_start_read(void *dst, uint32_t src, uint32_t len); |
| extern int fake_nvram_write(uint32_t offset, void *src, uint32_t size); |
| |
| /* |
| * A bunch of hardware needs to be probed, sometimes in a particular order. |
| * Very simple dependency graph, with a even simpler way to resolve it. |
| * But it means we can now at link time choose what hardware we support. |
| * This struct should not be defined directly but with the macros. |
| */ |
| struct hwprobe { |
| const char *name; |
| void (*probe)(void); |
| |
| bool probed; |
| |
| /* NULL or NULL-terminated array of strings */ |
| const char **deps; |
| }; |
| |
| #define DEFINE_HWPROBE(__name, __probe) \ |
| static const struct hwprobe __used __section(".hwprobes") hwprobe_##__name = { \ |
| .name = #__name, \ |
| .probe = __probe, \ |
| .deps = NULL, \ |
| } |
| |
| #define DEFINE_HWPROBE_DEPS(__name, __probe, ...) \ |
| static const struct hwprobe __used __section(".hwprobes") hwprobe_##__name = { \ |
| .name = #__name, \ |
| .probe = __probe, \ |
| .deps = (const char *[]){ __VA_ARGS__, NULL}, \ |
| } |
| |
| extern struct hwprobe __hwprobes_start; |
| extern struct hwprobe __hwprobes_end; |
| |
| extern void probe_hardware(void); |
| |
| #endif /* __SKIBOOT_H */ |