#include #include #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