diff options
author | Dan Crowell <dcrowell@us.ibm.com> | 2017-10-01 16:09:56 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2018-03-29 12:03:50 -0400 |
commit | 90eaed6f430c88eb0127ce47671bd80b21f35433 (patch) | |
tree | 9bc4aaa5cfb416f0da69386fb595e92513e0d1b7 | |
parent | 284cebd97cf08d42ba2f4caa8779bf47494fcc20 (diff) | |
download | talos-hostboot-90eaed6f430c88eb0127ce47671bd80b21f35433.tar.gz talos-hostboot-90eaed6f430c88eb0127ce47671bd80b21f35433.zip |
Force checkstops for unhandled machine checks
Default MSR[ME]=0 during initial boot for bootloader and
hostboot kernel
Once the xscom address range has been mapped in, enable the
machine check handler to force a checkstop and set MSR[ME]=1
to allow regular machine check handling
CQ: SW401402
Change-Id: I104e39465e61b3b19d5c073e71271102711ae54f
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/47179
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: William G. Hoffa <wghoffa@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
-rw-r--r-- | src/bootloader/bl_start.S | 5 | ||||
-rwxr-xr-x | src/build/tools/listdeps.pl | 1 | ||||
-rw-r--r-- | src/include/kernel/machchk.H | 32 | ||||
-rw-r--r-- | src/include/kernel/syscalls.H | 5 | ||||
-rw-r--r-- | src/include/sys/misc.h | 12 | ||||
-rw-r--r-- | src/include/usr/xscom/xscomif.H | 11 | ||||
-rw-r--r-- | src/kernel/bltohbdatamgr.C | 8 | ||||
-rw-r--r-- | src/kernel/exception.C | 5 | ||||
-rw-r--r-- | src/kernel/machchk.C | 45 | ||||
-rw-r--r-- | src/kernel/start.S | 5 | ||||
-rw-r--r-- | src/kernel/syscall.C | 15 | ||||
-rw-r--r-- | src/lib/syscall_misc.C | 10 | ||||
-rw-r--r-- | src/usr/isteps/istep06/host_start_occ_xstop_handler.C | 57 | ||||
-rw-r--r-- | src/usr/xscom/xscom.C | 26 |
14 files changed, 201 insertions, 36 deletions
diff --git a/src/bootloader/bl_start.S b/src/bootloader/bl_start.S index 0110c2401..0780575d6 100644 --- a/src/bootloader/bl_start.S +++ b/src/bootloader/bl_start.S @@ -5,7 +5,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2015,2017 +# Contributors Listed Below - COPYRIGHT 2015,2018 # [+] Google Inc. # [+] International Business Machines Corp. # @@ -74,11 +74,10 @@ _start: ;// Set thread priority high. or 2,2,2 - ;// Clear MSR[TA] (bit 1) and enable MSR[ME] (bit 51). + ;// Clear MSR[TA] (bit 1) mfmsr r2 rldicl r2,r2,1,1 ;// Clear bit 1 - result [1-63,0] rotrdi r2,r2,1 ;// Rotate right 1 - result [0,63] - ori r2,r2,4096 ;// Set bit 51 ;// Set up SRR0 / SRR1 to enable new MSR. mtsrr1 r2 li r2, _start_postmsr@l diff --git a/src/build/tools/listdeps.pl b/src/build/tools/listdeps.pl index d3c9ce495..3561bb2f5 100755 --- a/src/build/tools/listdeps.pl +++ b/src/build/tools/listdeps.pl @@ -223,6 +223,7 @@ my $resident_modules = { "libsecureboot_trusted.so" => '1', "libsecureboot_base.so" => '1', "libscom.so" => '1', + "libxscom.so" => '1', }; # A list of the dependent libraries in each istep. diff --git a/src/include/kernel/machchk.H b/src/include/kernel/machchk.H index af4243807..aebef6235 100644 --- a/src/include/kernel/machchk.H +++ b/src/include/kernel/machchk.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -43,6 +45,34 @@ namespace Kernel * @return bool - True if MC successfully handled, false otherwise. */ bool handleSLB(task_t* t); + + /** + * Constants to define the FIR bit to use to force a checkstop + * for an unhandled machine check. + */ +#ifdef CONFIG_P9_SYSTEM + constexpr uint64_t MCHK_XSTOP_FIR_SCOM_ADDR = 0x05012000; + constexpr uint64_t MCHK_XSTOP_FIR_VALUE = 0x0000000100000000ull;//31 +#endif + + /** @fn setCheckstopData + * @brief Tells the kernel how to force a checkstop for unrecoverable + * machine checks + * @param[in] i_xstopAddr - XSCOM MMIO address of FIR to write + * @param[in] i_xstopData - Data to write into FIR to trigger xstop + * + * @return none + */ + void setCheckstopData(uint64_t i_xstopAddr, + uint64_t i_xstopData); + + /** @fn forceCheckstop + * @brief Force a checkstop if we know how in order to get better + * error isolation for cache/memory UEs + * + * @return none + */ + void forceCheckstop(); } } diff --git a/src/include/kernel/syscalls.H b/src/include/kernel/syscalls.H index 35c6a5fe8..c7a03d6b6 100644 --- a/src/include/kernel/syscalls.H +++ b/src/include/kernel/syscalls.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2010,2017 */ +/* Contributors Listed Below - COPYRIGHT 2010,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -123,6 +123,9 @@ namespace Systemcalls /** critassert() */ MISC_CRITASSERT, + /** set_mchk_data() */ + MISC_SETMCHKDATA, + SYSCALL_MAX }; diff --git a/src/include/sys/misc.h b/src/include/sys/misc.h index 6b57e7e4e..af44d7ce8 100644 --- a/src/include/sys/misc.h +++ b/src/include/sys/misc.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -248,6 +248,16 @@ int cpu_all_winkle(); */ void cpu_crit_assert(uint64_t i_failAddr); +/** @fn set_mchk_data + * @brief Tells the kernel how to force a checkstop for unrecoverable + * machine checks + * @param[in] i_xstopAddr - XSCOM MMIO address of FIR to write + * @param[in] i_xstopData - Data to write into FIR to trigger xstop + * + * @return none + */ +void set_mchk_data(uint64_t i_xstopAddr, uint64_t i_xstopData); + #ifdef __cplusplus } #endif diff --git a/src/include/usr/xscom/xscomif.H b/src/include/usr/xscom/xscomif.H index 1afdfafcb..65b7410f1 100644 --- a/src/include/usr/xscom/xscomif.H +++ b/src/include/usr/xscom/xscomif.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2017 */ +/* Contributors Listed Below - COPYRIGHT 2017,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -34,6 +34,15 @@ namespace XSCOM */ uint64_t get_master_bar( void ); +/** + * @brief Generate a fully-qualified MMIO address for a physical scom + * address, relative to the given processor target + * @param[in] i_proc - Processor + * @param[in] i_scomAddr - Physical scom address to convert + * @return uint64_t - MMIO address + */ +uint64_t generate_mmio_addr( TARGETING::Target* i_proc, + uint64_t i_scomAddr ); }; // namespace XSCOM diff --git a/src/kernel/bltohbdatamgr.C b/src/kernel/bltohbdatamgr.C index e33fab6ef..a0c89b034 100644 --- a/src/kernel/bltohbdatamgr.C +++ b/src/kernel/bltohbdatamgr.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2017 */ +/* Contributors Listed Below - COPYRIGHT 2017,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -145,7 +145,6 @@ printk("Version=%lX\n",i_data.version); // were set correctly, instead use BLTOHB_SECURE_OVERRIDES version. if( iv_data.version >= Bootloader::BLTOHB_SECURE_OVERRIDES ) { -printk("lpc=%lX, xscom=%lX\n", i_data.lpcBAR, i_data.xscomBAR ); kassert(i_data.lpcBAR>0); kassert(i_data.xscomBAR>0); iv_data.lpcBAR = i_data.lpcBAR; @@ -158,9 +157,10 @@ printk("lpc=%lX, xscom=%lX\n", i_data.lpcBAR, i_data.xscomBAR ); iv_data.xscomBAR = MMIO_GROUP0_CHIP0_XSCOM_BASE_ADDR; } + printk("lpc=%lX, xscom=%lX\n", i_data.lpcBAR, i_data.xscomBAR ); -printk("lpc=%lX, xscom=%lX, iv_data=%p\n", iv_data.lpcBAR, iv_data.xscomBAR, - static_cast<void *>(&iv_data) ); + printk("iv_lpc=%lX, iv_xscom=%lX, iv_data=%p\n", + iv_data.lpcBAR, iv_data.xscomBAR, static_cast<void *>(&iv_data) ); // Check if bootloader advertised the size of the structure it saw; // otherwise use the default padded size diff --git a/src/kernel/exception.C b/src/kernel/exception.C index 0ece19a63..cf2a35c81 100644 --- a/src/kernel/exception.C +++ b/src/kernel/exception.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2010,2017 */ +/* Contributors Listed Below - COPYRIGHT 2010,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -328,6 +328,7 @@ void kernel_execute_machine_check() t->tid, getPIR(), getSRR0(), getSRR1(), getDSISR(), getDAR()); MAGIC_INSTRUCTION(MAGIC_BREAK_ON_ERROR); + Kernel::MachineCheck::forceCheckstop(); kassert(false); } @@ -388,6 +389,7 @@ void kernel_execute_machine_check() t->tid, getPIR(), getSRR0(), getSRR1(), getDSISR(), getDAR()); MAGIC_INSTRUCTION(MAGIC_BREAK_ON_ERROR); + Kernel::MachineCheck::forceCheckstop(); TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED); } } @@ -425,3 +427,4 @@ void kernel_execute_unhandled_exception() termWriteSRC(TI_UNHANDLED_EX, KERNEL::RC_UNHANDLED_EX, exception); terminateExecuteTI(); } + diff --git a/src/kernel/machchk.C b/src/kernel/machchk.C index 79edf4240..2a96b5896 100644 --- a/src/kernel/machchk.C +++ b/src/kernel/machchk.C @@ -27,12 +27,20 @@ #include <kernel/vmmmgr.H> #include <sys/mmio.h> #include <arch/memorymap.H> +#include <arch/ppc.H> namespace Kernel { namespace MachineCheck { +//Keep track of the MMIO address that we can use to force a checkstop +static uint64_t* g_xstopRegPtr = nullptr; + +//Keep track of the data to write into the xstop reg +static uint64_t g_xstopRegValue = 0; + + bool handleLoadUE(task_t* t) { bool handled = false; @@ -132,5 +140,42 @@ bool handleSLB(task_t* t) } +/** + * @brief Tells the kernel how to force a checkstop for unrecoverable + * machine checks + */ +void setCheckstopData(uint64_t i_xstopAddr, uint64_t i_xstopData) +{ + g_xstopRegPtr = reinterpret_cast<uint64_t*>(i_xstopAddr + |VmmManager::FORCE_PHYS_ADDR); + g_xstopRegValue = i_xstopData; + printk( "Set MchChk Xstop: %p=%.16lX\n", g_xstopRegPtr, g_xstopRegValue ); + + // Now that the machine check handler can do the xscom we + // can set MSR[ME]=1 to enable the regular machine check + // handling + uint64_t l_msr = getMSR(); + l_msr |= 0x0000000000001000; //set bit 51 + setMSR(l_msr); +} + +/** + * @brief Force a checkstop if we know how in order to get better + * error isolation for cache/memory UEs + */ +void forceCheckstop() +{ + if( g_xstopRegPtr != nullptr ) + { + printk( "Forcing a xstop with %p = %.16lX\n", + g_xstopRegPtr, g_xstopRegValue ); + *g_xstopRegPtr = g_xstopRegValue; + } + else + { + printk( "Unable to force checkstop, No xstop reg set\n" ); + } +} + } } diff --git a/src/kernel/start.S b/src/kernel/start.S index 40ff3b0ed..979235276 100644 --- a/src/kernel/start.S +++ b/src/kernel/start.S @@ -33,11 +33,10 @@ _start: ;// Set thread priority high. or 2,2,2 - ;// Clear MSR[TA] (bit 1) and enable MSR[ME] (bit 51). + ;// Clear MSR[TA] (bit 1) mfmsr r2 rldicl r2,r2,1,1 ;// Clear bit 1 - result [1-63,0] rotrdi r2,r2,1 ;// Rotate right 1 - result [0,63] - ori r2,r2,4096 ;// Set bit 51 ;// Set up SRR0 / SRR1 to enable new MSR. mtsrr1 r2 li r2, _start_postmsr@l @@ -473,7 +472,7 @@ kernel_dispatch_task: stdcx. r0, TASK_CPUPTR, r1 ;// the CPU pointer in the task. mfmsr r2 ;// Get current MSR - ori r2,r2, 0xD030 ;// Enable MSR[EE,ME,PR,IR,DR]. + ori r2,r2, 0xC030 ;// Enable MSR[EE,PR,IR,DR]. rldicl r2,r2,50,1 ;// Clear ... rotldi r2,r2,14 ;// MSR[FP] ld r3, TASK_MSR_MASK(r1) ;// Load MSR mask. diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index 04c65eb10..9dc6bd720 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -45,6 +45,7 @@ #include <kernel/doorbell.H> #include <sys/sync.h> #include <errno.h> +#include <kernel/machchk.H> namespace KernelIpc { @@ -142,6 +143,7 @@ namespace Systemcalls void MmExtend(task_t *t); void MmLinearMap(task_t *t); void CritAssert(task_t *t); + void SetMchkData(task_t *t); syscall syscalls[] = @@ -185,6 +187,7 @@ namespace Systemcalls &MmExtend, // MM_EXTEND &MmLinearMap, // MM_LINEAR_MAP &CritAssert, // MISC_CRITASSERT + &SetMchkData, // MISC_SETMCHKDATA }; }; @@ -988,6 +991,18 @@ namespace Systemcalls CpuManager::critAssert(i_failAddr); } + /** + * @brief Tells the kernel how to force a checkstop for unrecoverable + * machine checks + * @param[in] t: the task calling the critical assert + */ + void SetMchkData(task_t* t) + { + uint64_t i_xstopAddr = (uint64_t)(TASK_GETARG0(t)); + uint64_t i_xstopData = (uint64_t)(TASK_GETARG1(t)); + + Kernel::MachineCheck::setCheckstopData(i_xstopAddr,i_xstopData); + } }; diff --git a/src/lib/syscall_misc.C b/src/lib/syscall_misc.C index dff702ddd..a2b4ab1e4 100644 --- a/src/lib/syscall_misc.C +++ b/src/lib/syscall_misc.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -137,3 +137,11 @@ void cpu_crit_assert(uint64_t i_failAddr) { _syscall1(MISC_CRITASSERT, reinterpret_cast<void*>(i_failAddr)); } + + +void set_mchk_data(uint64_t i_xstopAddr, uint64_t i_xstopData) +{ + _syscall2(MISC_SETMCHKDATA, + reinterpret_cast<void*>(i_xstopAddr), + reinterpret_cast<void*>(i_xstopData)); +} diff --git a/src/usr/isteps/istep06/host_start_occ_xstop_handler.C b/src/usr/isteps/istep06/host_start_occ_xstop_handler.C index 683041916..611dfd75b 100644 --- a/src/usr/isteps/istep06/host_start_occ_xstop_handler.C +++ b/src/usr/isteps/istep06/host_start_occ_xstop_handler.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -39,7 +39,10 @@ #ifdef CONFIG_BMC_IPMI #include <ipmi/ipmisensor.H> #endif - +#include <sys/misc.h> +#include <xscom/xscomif.H> +#include <initservice/initserviceif.H> +#include <kernel/machchk.H> namespace ISTEP_06 { @@ -47,12 +50,19 @@ void* host_start_occ_xstop_handler( void *io_pArgs ) { ISTEP_ERROR::IStepError l_stepError; + errlHndl_t l_err = nullptr; + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "host_start_occ_xstop_handler entry" ); + TARGETING::Target* masterproc = NULL; + TARGETING::targetService().masterProcChipTargetHandle(masterproc); + do { -// if ( Util::isSimicsRunning() ) break; //Skip if running in Simics + // If we have nothing external (FSP or OCC) to handle checkstops we are + // better off just crashing and having a chance to pull the HB + // traces off the system live TARGETING::Target * l_sys = nullptr; TARGETING::targetService().getTopLevelTarget( l_sys ); @@ -68,7 +78,7 @@ void* host_start_occ_xstop_handler( void *io_pArgs ) if ((l_mnfgFlags & TARGETING::MNFG_FLAG_SRC_TERM) && !(l_mnfgFlags & TARGETING::MNFG_FLAG_IMMEDIATE_HALT)) { - errlHndl_t l_err = nullptr; + l_err = nullptr; //If HB_VOLATILE MFG_TERM_REBOOT_ENABLE flag is set at this point //Create errorlog to terminate the boot. @@ -91,7 +101,6 @@ void* host_start_occ_xstop_handler( void *io_pArgs ) 0, true /*HB SW error*/ ); l_stepError.addErrorDetails(l_err); - ERRORLOG::errlCommit(l_err, ISTEP_COMP_ID); break; } @@ -111,7 +120,6 @@ void* host_start_occ_xstop_handler( void *io_pArgs ) TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, "Failed to enable BMC auto reboots...."); l_stepError.addErrorDetails(l_err); - ERRORLOG::errlCommit(l_err, HWPF_COMP_ID); break; } } @@ -119,11 +127,6 @@ void* host_start_occ_xstop_handler( void *io_pArgs ) #ifdef CONFIG_IPLTIME_CHECKSTOP_ANALYSIS - errlHndl_t l_errl = NULL; - - TARGETING::Target* masterproc = NULL; - TARGETING::targetService().masterProcChipTargetHandle(masterproc); - void* l_homerVirtAddrBase = reinterpret_cast<void*> (VmmManager::INITIAL_MEM_SIZE); uint64_t l_homerPhysAddrBase = mm_virt_to_phys(l_homerVirtAddrBase); @@ -133,33 +136,49 @@ void* host_start_occ_xstop_handler( void *io_pArgs ) " l_homerPhysAddrBase=0x%x, l_commonPhysAddr=0x%x", l_homerPhysAddrBase, l_commonPhysAddr); - l_errl = HBPM::loadPMComplex(masterproc, + // Load the OCC directly into SRAM and start it in a special mode + // that only handles checkstops + l_err = HBPM::loadPMComplex(masterproc, l_homerPhysAddrBase, l_commonPhysAddr, HBPM::PM_LOAD, true); - if(l_errl) + if(l_err) { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, "loadPMComplex failed"); - l_stepError.addErrorDetails(l_errl); - ERRORLOG::errlCommit(l_errl, HWPF_COMP_ID); + l_stepError.addErrorDetails(l_err); break; } - l_errl = HBOCC::startOCCFromSRAM(masterproc); - if(l_errl) + l_err = HBOCC::startOCCFromSRAM(masterproc); + if(l_err) { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, "startOCCFromSRAM failed"); - l_stepError.addErrorDetails(l_errl); - ERRORLOG::errlCommit(l_errl, HWPF_COMP_ID); + l_stepError.addErrorDetails(l_err); break; } #endif }while(0); + if(l_err) + { + ERRORLOG::errlCommit(l_err, HWPF_COMP_ID); + } + + // Now that the checkstop handler is running (or we don't have one), + // setup the machine check code to trigger a checkstop for UE + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, + "Enabling machine check handler to generate checkstops" ); + + uint64_t l_xstopXscom = XSCOM::generate_mmio_addr( masterproc, + Kernel::MachineCheck::MCHK_XSTOP_FIR_SCOM_ADDR ); + + set_mchk_data( l_xstopXscom, + Kernel::MachineCheck::MCHK_XSTOP_FIR_VALUE ); + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "host_start_occ_xstop_handler exit" ); diff --git a/src/usr/xscom/xscom.C b/src/usr/xscom/xscom.C index c9afe0273..a28897f8b 100644 --- a/src/usr/xscom/xscom.C +++ b/src/usr/xscom/xscom.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -866,5 +866,29 @@ uint64_t get_master_bar( void ) return mm_virt_to_phys(g_masterProcVirtAddr); } +/** + * @brief Generate a fully-qualified MMIO address for a physical scom + * address, relative to the given processor target + */ +uint64_t generate_mmio_addr( TARGETING::Target* i_proc, + uint64_t i_scomAddr ) +{ + uint64_t l_returnAddr = 0; + + // Get the target chip's physical mmio address + uint64_t l_XSComBaseAddr = + i_proc->getAttr<TARGETING::ATTR_XSCOM_BASE_ADDRESS>(); + + // Build the XSCom address (relative to group 0, chip 0) + XSComP9Address l_mmioAddr(i_scomAddr); + + // Get the offset + uint64_t l_offset = l_mmioAddr.offset(); + + // Compute value relative to target chip + l_returnAddr = l_XSComBaseAddr + l_offset; + + return l_returnAddr; +} } // end namespace |