1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/* Copyright 2015-2017 IBM Corp */
#include <endian.h>
#include <asm/unistd.h>
#ifndef __NR_switch_endian
#define __NR_switch_endian 363
#endif
/* a constant to use in the SI field of a little-endian D-form instruction */
#define le_si16(x) (((x & 0xff) << 24) | ((x & 0xff00) << 8))
.text
/*
* Call into a HBRT BE function
* Func desc (opd) will be in BE
* Use ldbrx to load from opd
*/
call_be:
/* Before we switch, we need to perform some ABI
* conversion. We are currently running LE with the
* new ABI v2. The GPR content is the same, we do
* need save/restore and adjust r2. At this point r11
* contain the OPD
*/
nop
nop
/* We first create a stack frame compatible with BE, we
* do a big one just in case... we save LR into our caller's
* frame and r2 in our own frame. This is a BE formatted
* frame so we store it as 40(r1), not 24(r1)
*/
stdu %r1,-128(%r1)
mflr %r0
std %r0,(128 + 16)(%r1)
std %r2,40(%r1)
/* Grab the target r2 and function pointer */
#if __BYTE_ORDER == __LITTLE_ENDIAN
ldbrx %r0, 0, %r11
li %r2, 8
ldbrx %r2, %r2, %r11
#else
ld %r0,0(%r11)
ld %r2,8(%r11)
#endif
mtlr %r0
#if __BYTE_ORDER == __LITTLE_ENDIAN
/* Switch to the "other endian" */
li %r0,__NR_switch_endian
sc
/* Branch to LR */
.long 0x2100804e /* (byteswapped blrl) */
/* Switch endian back */
.long 0x00000038 | le_si16(__NR_switch_endian)
/* byteswapped li %r0,__NR_switch_endian */
.long 0x02000044 /* byteswapped sc */
#else
bctrl
#endif
/* Recover our r2, LR, undo stack frame ... */
ld %r2,40(%r1)
ld %r0,(128+16)(%r1)
addi %r1,%r1,128
mtlr %r0
blr
#define CALL_THUNK(name, idx) \
.globl call_##name ;\
call_##name: ;\
ld %r11,hservice_runtime_fixed@got(%r2) ;\
ld %r11,(idx * 8)(%r11) ;\
b call_be
/* Instanciate call to HBRT thunks */
CALL_THUNK(cxxtestExecute, 1)
CALL_THUNK(get_lid_list, 2)
CALL_THUNK(occ_load, 3)
CALL_THUNK(occ_start, 4)
CALL_THUNK(occ_stop, 5)
CALL_THUNK(process_occ_error, 6)
CALL_THUNK(enable_attns, 7)
CALL_THUNK(disable_attns, 8)
CALL_THUNK(handle_attns, 9)
CALL_THUNK(process_occ_reset, 10)
CALL_THUNK(enable_occ_actuation, 11)
CALL_THUNK(apply_attr_override, 12)
CALL_THUNK(mfg_htmgt_pass_thru, 13)
CALL_THUNK(run_command, 14)
CALL_THUNK(verify_container, 15)
CALL_THUNK(sbe_message_passing, 16)
CALL_THUNK(load_pm_complex, 17)
CALL_THUNK(start_pm_complex, 18)
CALL_THUNK(reset_pm_complex, 19)
CALL_THUNK(get_ipoll_events, 20)
CALL_THUNK(firmware_notify, 21)
CALL_THUNK(prepare_hbrt_update, 22)
.globl call_hbrt_init
call_hbrt_init:
ld %r11,hbrt_entry@got(%r2)
b call_be
#if __BYTE_ORDER == __LITTLE_ENDIAN
/* Callback from HBRT, stack conversion and call into C code,
* we arrive here from the thunk macro with r11 containing the
* target function and r2 already set from the OPD.
*/
call_le:
/* Create a LE stack frame, save LR */
stdu %r1,-32(%r1)
mflr %r0
std %r0,(32+16)(%r1)
/* Branch to original function */
mtlr %r12
blrl
/* Restore stack and LR */
ld %r0,(32+16)(%r1)
addi %r1,%r1,32
mtlr %r0
/* Switch endian back to BE */
li %r0,__NR_switch_endian
sc
/* Return to BE */
.long 0x2000804e /* byteswapped blr */
/* Callback from HBRT. There is one entry point per function.
*
* We assume the proper r2 is already set via the OPD, so we grab our
* target function pointer in r12 and jump to call_le
*/
#define CALLBACK_THUNK(name) \
.pushsection ".text","ax" ;\
.globl name##_thunk ;\
name##_thunk: ;\
.long 0x00000038 | le_si16(__NR_switch_endian) ;\
/* byteswapped li %r0,__NR_switch_endian */ ;\
.long 0x02000044 /* byteswapped sc */ ;\
ld %r12,name@got(%r2) ;\
b call_le ;\
.popsection ;\
.pushsection ".data.thunk_opd","aw" ;\
1: .llong name##_thunk, .TOC., 0 ;\
.popsection ;\
.llong 1b
#else /* __BYTE_ORDER == __LITTLE_ENDIAN */
#define CALLBACK_THUNK(name) \
.llong name
#endif
#define DISABLED_THUNK(name) .llong 0x0
/* Here's the callback table generation. It creates the table and
* all the thunks for all the callbacks from HBRT to us
*/
.data
.globl hinterface
.globl __hinterface_start
__hinterface_start:
hinterface:
/* HBRT interface version */
.llong 1
/* Callout pointers */
CALLBACK_THUNK(hservice_puts)
CALLBACK_THUNK(hservice_assert)
CALLBACK_THUNK(hservice_set_page_execute)
CALLBACK_THUNK(hservice_malloc)
CALLBACK_THUNK(hservice_free)
CALLBACK_THUNK(hservice_realloc)
DISABLED_THUNK(hservice_send_error_log)
CALLBACK_THUNK(hservice_scom_read)
CALLBACK_THUNK(hservice_scom_write)
DISABLED_THUNK(hservice_lid_load)
DISABLED_THUNK(hservice_lid_unload)
CALLBACK_THUNK(hservice_get_reserved_mem)
CALLBACK_THUNK(hservice_wakeup)
CALLBACK_THUNK(hservice_nanosleep)
DISABLED_THUNK(hservice_report_occ_failure)
CALLBACK_THUNK(hservice_clock_gettime)
CALLBACK_THUNK(hservice_pnor_read)
CALLBACK_THUNK(hservice_pnor_write)
CALLBACK_THUNK(hservice_i2c_read)
CALLBACK_THUNK(hservice_i2c_write)
CALLBACK_THUNK(hservice_ipmi_msg)
CALLBACK_THUNK(hservice_memory_error)
CALLBACK_THUNK(hservice_get_interface_capabilities)
DISABLED_THUNK(hservice_map_phys_mem)
DISABLED_THUNK(hservice_unmap_phys_mem)
DISABLED_THUNK(hservice_hcode_scom_update)
CALLBACK_THUNK(hservice_firmware_request)
.globl __hinterface_pad
__hinterface_pad:
/* Reserved space for future growth */
.space 27*8,0
.globl __hinterface_end
__hinterface_end:
/* Eye catcher for debugging */
.llong 0xdeadbeef
|