blob: 46355c033bce3f13b92ed865cb7633552cc57e86 [file] [log] [blame]
// 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