210 lines
5.4 KiB
ArmAsm
210 lines
5.4 KiB
ArmAsm
#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
|
|
|