* Copyright 2010-2017 Intel Corporation.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
* as published by the Free Software Foundation.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* Disclaimer: The codes contained in these modules may be specific to
* the Intel Software Development Platform codenamed Knights Ferry,
* and the Intel product codenamed Knights Corner, and are not backward
* compatible with other Intel products. Additionally, Intel will NOT
* support the codes or instruction set in future products.
* Intel offers no warranty of any kind regarding the code. This code is
* licensed on an "AS IS" basis and Intel is not obligated to provide
* any support, assistance, installation, training, or other services
* of any kind. Intel is also not obligated to provide any updates,
* enhancements or extensions. Intel specifically disclaims any warranty
* of merchantability, non-infringement, fitness for any particular
* purpose, and any other warranty.
* Further, Intel disclaims all liability of any kind, including but
* not limited to liability for infringement of any proprietary rights,
* relating to the use of the code, even if Intel is notified of the
* possibility of such liability. Except as expressly stated in an Intel
* license agreement provided with this code and agreed upon with Intel,
* no license, express or implied, by estoppel or otherwise, to any
* intellectual property rights is granted herein.
* Contains code to handle trace_capture syscall, stop all cpus
* and dump their state, then dump all physical memeory.
#include "trace_capture.h"
#define BARRIER(epd, string) { \
printk("%s\n", string); \
if ((err = scif_send(epd, &control_msg, sizeof(control_msg), 1)) <= 0) { \
pr_crit("%s:%s:%d scif_send failed with err %ld\n", __FILE__, __FUNCTION__, __LINE__, err); \
if ((err = scif_recv(epd, &control_msg, sizeof(control_msg), 1)) <= 0) { \
pr_crit("%s:%s:%d scif_recv failed with err %ld\n", __FILE__, __FUNCTION__, __LINE__, err); \
/* SPU privileged gates (per specification) */
#define SPU_SPBA_OFFSET 0x1000 /* offset of Privileged gates in SPU MMIO */
#define SPU_XQ_SIZE 0x040
#define SPU_XQ_BASE 0x080
#define SPU_XQ_INDEX 0x0C0
#define SPU_CONTROL 0x100
#define SPU_SAMPLER_BASE 0x140
#define SPU_ABORT_STATUS 0x1C0
#define SPU_FLUSH_STATUS 0x240
#define SPU_INVALPG_4K 0x280
#define SPU_INVALPG_64K 0x2C0
#define SPU_INVALPG_2M 0x300
#define SPU_SOFT_RESET 0x3C0
#define SPU_PMU_EVENT_SEL 0x400
#define SPU_CONTROL2 0x440
#define SPU_CONTROL3 0x480
#define SPU_MEM_BW_LIMIT 0x4C0 // This is 64 bit register
#define SPU_TCU_CREDITS 0x700
#define SPU_ALT_FER 0x840
#define SPU_MATCH_ACTION 0x880
#define SPU_COUNTER0_SET 0x500
#define SPU_COUNTER1_SET 0x540
#define SPU_COUNTER2_SET 0x580
#define SPU_COUNTER3_SET 0x5C0
#define SPU_COUNTER4_SET 0x600
#define SPU_COUNTER5_SET 0x640
#define SPU_COUNTER6_SET 0x680
#define SPU_COUNTER7_SET 0x6C0
#define CBOX_SPU_PA_MSR 0x0000017E
#define CBOX_SPU_SAMPLER_BIND_MSR 0x0000017F
#define MSR_SF_MASK 0xc0000084 /* syscall flags mask */
#define MSR_FSBASE 0xc0000100 /* base address of the %fs "segment" */
#define MSR_GSBASE 0xc0000101 /* base address of the %gs "segment" */
#define MSR_KGSBASE 0xc0000102 /* base address of the kernel %gs */
// MSR's defined in the trace file sent during REQs
// Are these all valid for L1OM??
#define X86_CR_APICBASE 0x1b
#define MIC_CR_SPUBASE 0x1c
#define IA32_CR_MISC 0x1a0
#define WMT_CR_LASTBRANCH_0 0x1db
#define WMT_CR_LASTBRANCH_1 0x1dc
#define X86_CR_MTRRphysMask0 0x201
#define X86_CR_MTRRphysMask1 0x203
#define X86_CR_MTRRphysMask2 0x205
#define X86_CR_MTRRphysMask3 0x207
#define X86_CR_MTRRphysMask4 0x209
#define X86_CR_MTRRphysMask5 0x20b
#define X86_CR_MTRRphysMask6 0x20d
#define X86_CR_MTRRphysMask7 0x20f
#define IA32_CR_PAT 0x277
#define IA32_MTRR_DEF_TYPE 0x2ff
#define VMX_MSR_BASE 0x480
#define VMX_MSR_BASE_PLUS_1 0x481
#define VMX_MSR_BASE_PLUS_2 0x482
#define VMX_MSR_BASE_PLUS_3 0x483
#define VMX_MSR_BASE_PLUS_4 0x484
#define VMX_MSR_BASE_PLUS_5 0x485
#define VMX_MSR_BASE_PLUS_6 0x486
#define VMX_MSR_BASE_PLUS_7 0x487
#define VMX_MSR_BASE_PLUS_8 0x488
#define VMX_MSR_BASE_PLUS_9 0x489
#define X86_CR_MTRRdefType 0x2ff
#define X86_CR_MTRRcap 0xfe
#define X86_CR_MTRRphysBase0 0x200
#define X86_CR_MTRRphysBase1 0x202
#define X86_CR_MTRRphysBase2 0x204
#define X86_CR_MTRRphysBase3 0x206
#define X86_CR_MTRRphysBase4 0x208
#define X86_CR_MTRRphysBase5 0x20a
#define X86_CR_MTRRphysBase6 0x20c
#define X86_CR_MTRRphysBase7 0x20e
#define X86_CR_MTRRfix64K_00000 0x250
#define X86_CR_MTRRfix16K_80000 0x258
#define X86_CR_MTRRfix16K_A0000 0x259
#define X86_CR_MTRRfix4K_C0000 0x268
#define X86_CR_MTRRfix4K_C8000 0x269
#define X86_CR_MTRRfix4K_D0000 0x26a
#define X86_CR_MTRRfix4K_D8000 0x26b
#define X86_CR_MTRRfix4K_E0000 0x26c
#define X86_CR_MTRRfix4K_E8000 0x26d
#define X86_CR_MTRRfix4K_F0000 0x26e
#define X86_CR_MTRRfix4K_F8000 0x26f
#define IA32_APIC_BASE 0x1b
#define IA32_TIME_STAMP_COUNTER 0x10
#define IA32_PerfCntr0 0x20
#define IA32_PerfCntr1 0x21
#define IA32_PerfCntr2 0x22
#define IA32_PerfCntr3 0x23
#define PerfFilteredCntr0 0x24
#define PerfFilteredCntr1 0x25
#define PerfFilteredCntr2 0x26
#define PerfFilteredCntr3 0x27
#define IA32_PerfEvtSel0 0x28
#define IA32_PerfEvtSel1 0x29
#define IA32_PerfEvtSel2 0x2a
#define IA32_PerfEvtSel3 0x2b
#define PerfFilterMask 0x2c
#define IA32_PERF_GLOBAL_STATUS 0x2d
#define IA32_PERF_GLOBAL_OVF_CONTROL 0x2e
#define IA32_PERF_GLOBAL_CTRL 0x2f
#define IA32_MCG_CTL 0x17b
#define IA32_MC0_CTRL 0x400
#define IA32_MC0_STAT 0x401
#define IA32_MC0_ADDR 0x402
#define IA32_MC0_MISC 0x403
#define IA32_MC1_CTRL 0x404
#define IA32_MC1_STAT 0x405
#define IA32_MC1_ADDR 0x406
#define IA32_MC1_MISC 0x407
#define SYSCALL_FLAG_MASK 0xc0000084
// Kernel virtual address to physical page at 0xfee03000
// This is created by an ioremap outside of interrupt context.
static uint8_t *spu_addr
;
static char *SegRegNames
[MAX_SEG_REG
] = {"CS","DS","ES","SS", "FS","GS","LDTR","TR"};
//static struct i387_fxsave_struct fpu;
struct mictc_segment_reg segment
;
struct vpustate_struct vpustate
;
struct i387_fxsave_struct fpu
;
struct mictc_trace
*trace
;
// fxsave definition copied from fpu.c
//#define mictc_fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr)))
#define mictc_fxsave(addr) __asm __volatile("fxsave (%0)" : "=a" (addr) : [fx] "a" (addr))
// Spinlock to serialize access in IPI handler
static DEFINE_SPINLOCK(mictc_lock
);
// Used to count the cpus waiting
static atomic_t cpus_stopped
= ATOMIC_INIT(0);
// Used to count the cpus released
static atomic_t cpus_released
= ATOMIC_INIT(0);
//static scif_epd_t mictc_endp_cmd;
static scif_epd_t mictc_endp_data
;
// SCIF ports - temp hack; move to scif.h
#define MICTC_SCIF_PORT_DATA 300
// Used to prevent concurent access into the same device .
static int Device_Open
= 0;
//static char print_string_buf[PS_BUF_SIZE] = "";
#define print_str(fmt, ...) \
snprintf(print_string_buf, PS_BUF_SIZE, fmt, ##__VA_ARGS__); \
print_string(print_string_buf); \
//#define printk(fmt, ...) print_str(fmt, ##__VA_ARGS__)
//#define pr_crit(fmt, ...) print_str(fmt, ##__VA_ARGS__)
#define cli __asm (" cli\n")
#define sti __asm (" sti\n")
// Debug code to display low 16 bits of eflags register.
{unsigned long kernel_eflags; \
raw_local_save_flags(kernel_eflags); \
printk("%s:%d eflags %lx\n", __FUNCTION__, __LINE__, kernel_eflags); \
// Find another definition of this in some .h file
mictc_cpuid(u_int ax
, u_int
*p
)
: "=a" (p
[0]), "=b" (p
[1]), "=c" (p
[2]), "=d" (p
[3])
uint32_t get_dr(int regno
)
unsigned long val
= 0; /* Damn you, gcc! */
asm("mov %%db0, %0" :"=r" (val
));
asm("mov %%db1, %0" :"=r" (val
));
asm("mov %%db2, %0" :"=r" (val
));
asm("mov %%db3, %0" :"=r" (val
));
asm("mov %%db4, %0" :"=r" (val
));
asm("mov %%db5, %0" :"=r" (val
));
asm("mov %%db6, %0" :"=r" (val
));
asm("mov %%db7, %0" :"=r" (val
));
static inline void mictc_store_ldt(u16
*dtr
)
asm volatile("sldt %0":"=m" (*dtr
));
static inline void mictc_store_tr(u16
*dtr
)
asm volatile("str %0":"=m" (*dtr
));
static inline void read_gdt_entry(struct desc_struct
*gdt
, int entry
,
size
= sizeof(struct desc_struct
);
memcpy(desc
, &gdt
[entry
], size
);
#if 0 // Helpful for debug
{ u64
*p
= (u64
*)&gdt
[entry
];
printk("GDT[entry] = %p %llx %llx\n", &gdt
[entry
], p
[0], p
[1]);
static inline void __get_tss_desc(unsigned cpu
, unsigned int entry
, void *dest
)
struct desc_struct
*d
= get_cpu_gdt_table(cpu
);
read_gdt_entry(d
, entry
, dest
, DESC_TSS
);
#define get_tss_desc(cpu, addr) __get_tss_desc(cpu, GDT_ENTRY_TSS, addr)
static inline void __get_seg_desc(unsigned cpu
, unsigned int entry
, void *dest
)
struct desc_struct
*d
= get_cpu_gdt_table(cpu
);
read_gdt_entry(d
, entry
, dest
, 0);
#define get_seg_desc(cpu, seg, addr) __get_seg_desc(cpu, ((seg & 0xffff) >> 3), addr)
// Redefine rdmsr to work like BSD.
//#define rdmsr(msr) tc_msr((msr))
uint64_t tc_rdmsr(uint32_t msrid
)
rdmsr(msrid
, lower
, upper
);
return (uint64_t)upper
<< 32 | lower
;
// Number of Retries before it is assumed that the Host will not respond
#define TRACE_CAPTURE_TIMEOUT 50000000
static void *g_traceBufferAllocated
;
// Global variable used by initiator to wait for everyone to complete trace captures
//static volatile u32 g_smpTraceCaptureWait;
// Global variable to keep track of how much data we are writing to the shared buffer
static volatile u64 g_sizeXferred
= 0;
static s64 g_triggerFound
= -1;
static volatile u64
*g_traceBufferStatusOffset
= NULL
;
static volatile u64
*g_traceBufferSizeOffset
= NULL
;
static volatile u32
*g_traceBufferDataOffset
= 0;
static volatile u32
*g_traceBufferTriggerOffset
= NULL
;
// This is an array of trigger numbers. The value TRACE_EOL is ignored.
static u32 g_traceTriggers
[TRACE_TRIGGER_MAX
];
static u32 g_traceCurrentTrigger
;
static long scif_offset_xml
;
//static long scif_offset_xml_dst;
static long scif_offset_mem
;
static long scif_offset_dst
;
#if MIC_TRACE_CAPTURE_MEMORY_TEST
static volatile u64
*g_traceBufferChecksumOffset
= NULL
;
// The maximum size allowed for a DMA transfer is 1MB - 4K. The size of this array
// is 1MB to allow this to be used as the dst memory while dumping entire GDDR
// For Debug purposes only.
static u32 g_dstMemoryDump
[4096/sizeof(u32
)] __attribute__ ((aligned(4096)));
#define TRACE_SPRINTF(...) \
(g_sizeXferred += sprintf(((char*)g_traceBufferDataOffset + g_sizeXferred), __VA_ARGS__))
#define ADD_SPU_REG_TO_HEADER(x) \
TRACE_SPRINTF("\t\t\t\t<reg offset=\"0x%x\">\n\t\t\t\t\t<name>%s</name>\n\t\t\t\t</reg>\n", (x), #x)
#define ADD_MSR_TO_HEADER(x) \
TRACE_SPRINTF("\t\t\t\t<reg addr=\"0x%x\"/>\n", (x))
#define TRACE_SPRINTF_MSR(x) \
TRACE_SPRINTF("\t\t\t\t<reg addr=\"0x%x\">0x%llx</reg>\n", (x), tc_rdmsr((x)))
#define TRACE_SPRINTF_SPU(x) \
TRACE_SPRINTF("\t\t\t\t<reg offset=\"0x%x\">0x%llx</reg>\n", (x), *(volatile u64*)((u8*)spu_addr + (x)))
#define TRACE_SPRINTF_VECTOR(x, vpu) \
PrintVector((u8*)&(vpu), (x))
//------------------------------------------------------------------------------
// FUNCTION: mictc_trace_capture_prep_SPU_header
// Perform all the tasks related to preparing the SPU Trace Header
mictc_trace_capture_prep_SPU_header(void)
TRACE_SPRINTF("\t\t\t<spu>\n");
ADD_SPU_REG_TO_HEADER(SPU_XQ_SIZE
);
ADD_SPU_REG_TO_HEADER(SPU_XQ_BASE
);
ADD_SPU_REG_TO_HEADER(SPU_XQ_INDEX
);
ADD_SPU_REG_TO_HEADER(SPU_CONTROL
);
ADD_SPU_REG_TO_HEADER(SPU_SAMPLER_BASE
);
ADD_SPU_REG_TO_HEADER(SPU_PMU_EVENT_SEL
);
ADD_SPU_REG_TO_HEADER(SPU_CONTROL2
);
ADD_SPU_REG_TO_HEADER(SPU_CONTROL3
);
TRACE_SPRINTF("\t\t\t</spu>\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_trace_capture_prep_cpuid_header
// Perform all the tasks related to preparing the CPUID Trace Header
mictc_trace_capture_prep_cpuid_header(void)
TRACE_SPRINTF("\t\t\t<cpuid>\n");
for (i
= 0; i
< 0x4; i
++)
TRACE_SPRINTF("\t\t\t\t<reg eax=\"0x%x\">0x%x-0x%x-0x%x-0x%x</reg>\n",
i
, regs
[0], regs
[1], regs
[2], regs
[3]);
TRACE_SPRINTF("\t\t\t</cpuid>\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_trace_capture_prep_msr_header
// Perform all the tasks related to preparing the MSR Trace Header
mictc_trace_capture_prep_msr_header(void)
TRACE_SPRINTF("\t\t\t<msr>\n");
ADD_MSR_TO_HEADER(P6_CR_TSC
);
ADD_MSR_TO_HEADER(X86_CR_APICBASE
);
ADD_MSR_TO_HEADER(CBOX_SPU_PA_MSR
);
ADD_MSR_TO_HEADER(SPU_BASE
);
ADD_MSR_TO_HEADER(CBOX_SPU_SAMPLER_BIND_MSR
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysMask0
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysMask1
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysMask2
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysMask3
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysMask4
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysMask5
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysMask6
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysMask7
);
ADD_MSR_TO_HEADER(MSR_EFER
);
ADD_MSR_TO_HEADER(MSR_SF_MASK
);
ADD_MSR_TO_HEADER(MSR_FSBASE
);
ADD_MSR_TO_HEADER(MSR_GSBASE
);
ADD_MSR_TO_HEADER(X86_CR_MTRRdefType
);
ADD_MSR_TO_HEADER(X86_CR_MTRRcap
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysBase2
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysBase0
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysBase1
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysBase3
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysBase4
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysBase5
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysBase6
);
ADD_MSR_TO_HEADER(X86_CR_MTRRphysBase7
);
ADD_MSR_TO_HEADER(LSTAR
);
ADD_MSR_TO_HEADER(MSR_KGSBASE
);
// The following MSR's are currently ifdef'd out
// because LarrySim barfs on these.
// We might need these later.
ADD_MSR_TO_HEADER(X86_CR_MTRRfix64K_00000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix16K_80000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix16K_A0000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix4K_C0000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix4K_C8000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix4K_D0000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix4K_D8000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix4K_E0000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix4K_E8000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix4K_F0000
);
ADD_MSR_TO_HEADER(X86_CR_MTRRfix4K_F8000
);
ADD_MSR_TO_HEADER(P5_MC_ADDR
);
ADD_MSR_TO_HEADER(P5_MC_TYPE
);
ADD_MSR_TO_HEADER(MSR_TR1
);
ADD_MSR_TO_HEADER(MSR_TR2
);
ADD_MSR_TO_HEADER(MSR_TR3
);
ADD_MSR_TO_HEADER(MSR_TR4
);
ADD_MSR_TO_HEADER(MSR_TR5
);
ADD_MSR_TO_HEADER(MSR_TR6
);
ADD_MSR_TO_HEADER(MSR_TR7
);
ADD_MSR_TO_HEADER(MSR_TR9
);
ADD_MSR_TO_HEADER(MSR_TR10
);
ADD_MSR_TO_HEADER(MSR_TR11
);
ADD_MSR_TO_HEADER(MSR_TR12
);
ADD_MSR_TO_HEADER(IA32_APIC_BASE
);
ADD_MSR_TO_HEADER(IA32_TIME_STAMP_COUNTER
);
ADD_MSR_TO_HEADER(IA32_PerfCntr0
);
ADD_MSR_TO_HEADER(IA32_PerfCntr1
);
ADD_MSR_TO_HEADER(IA32_PerfCntr2
);
ADD_MSR_TO_HEADER(IA32_PerfCntr3
);
ADD_MSR_TO_HEADER(PerfFilteredCntr0
);
ADD_MSR_TO_HEADER(PerfFilteredCntr1
);
ADD_MSR_TO_HEADER(PerfFilteredCntr2
);
ADD_MSR_TO_HEADER(PerfFilteredCntr3
);
ADD_MSR_TO_HEADER(IA32_PerfEvtSel0
);
ADD_MSR_TO_HEADER(IA32_PerfEvtSel1
);
ADD_MSR_TO_HEADER(IA32_PerfEvtSel2
);
ADD_MSR_TO_HEADER(IA32_PerfEvtSel3
);
ADD_MSR_TO_HEADER(PerfFilterMask
);
ADD_MSR_TO_HEADER(IA32_PERF_GLOBAL_STATUS
);
ADD_MSR_TO_HEADER(IA32_PERF_GLOBAL_OVF_CONTROL
);
ADD_MSR_TO_HEADER(IA32_PERF_GLOBAL_CTRL
);
ADD_MSR_TO_HEADER(IA32_MCG_CTL
);
ADD_MSR_TO_HEADER(IA32_MC0_CTRL
);
ADD_MSR_TO_HEADER(IA32_MC0_STAT
);
ADD_MSR_TO_HEADER(IA32_MC0_ADDR
);
ADD_MSR_TO_HEADER(IA32_MC0_MISC
);
ADD_MSR_TO_HEADER(IA32_MC1_CTRL
);
ADD_MSR_TO_HEADER(IA32_MC1_STAT
);
ADD_MSR_TO_HEADER(IA32_MC1_ADDR
);
ADD_MSR_TO_HEADER(IA32_MC1_MISC
);
ADD_MSR_TO_HEADER(SYSCALL_FLAG_MASK
);
ADD_MSR_TO_HEADER(X86_PAT
);
TRACE_SPRINTF("\t\t\t</msr>\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_prep_header
// Perform all the tasks related to preparing the Trace Header
TRACE_SPRINTF("<?xml version=\"1.0\" standalone=\"yes\"?>\n");
TRACE_SPRINTF("<arch_data>\n");
TRACE_SPRINTF("<!-- The format of this file is defined in https://cpu-sim.intel.com/twiki/bin/view/CpuSim/TraceFileFormats. -->\n");
TRACE_SPRINTF("\t<header>\n");
TRACE_SPRINTF("\t\t<format_version>1.0</format_version>\n");
TRACE_SPRINTF("\t\t<creation_date>Nov 19 2009</creation_date>\n");
TRACE_SPRINTF("\t\t<arch_xml_ver>1.1</arch_xml_ver>\n");
TRACE_SPRINTF("\t\t<arch_xml_date>Oct 21 2009</arch_xml_date>\n");
TRACE_SPRINTF("\t\t<created_by>archlib</created_by>\n");
TRACE_SPRINTF("\t\t<comment>Warnings! This is based on the state available in archlib.</comment>\n");
TRACE_SPRINTF("\t\t<comment> This state dump is primarily good for capturing frequently used architectural register state.</comment>\n");
TRACE_SPRINTF("\t\t<comment> Support for CPUId, MSRs, APIC, and x87 state is currently incomplete.</comment>\n");
TRACE_SPRINTF("\t\t<comment> There is no support for state not specifically modeled in archlib.</comment>\n");
TRACE_SPRINTF("\t\t<comment> Have also noticed inconsistencies in the final value of the RFLAGS reg.</comment>\n");
if (g_triggerFound
!= -1)
TRACE_SPRINTF("\t\t<comment> This capture is generated for HOST BASED TRIGGER # %lld.</comment>\n", g_triggerFound
);
TRACE_SPRINTF("\t</header>\n");
TRACE_SPRINTF("\t<cpu_definition>\n");
TRACE_SPRINTF("\t\t<num_cpus>%d</num_cpus>\n", num_online_cpus());
TRACE_SPRINTF("<!-- the number of \"cpu\" definitions must correspond to the \"num_cpus\" data item -->\n");
for (i
= 0; i
< num_online_cpus(); i
++)
TRACE_SPRINTF("\t\t<cpu num=\"%d\">\n", i
);
// SPU is not supported in Linux
if (always_false
) mictc_trace_capture_prep_SPU_header();
mictc_trace_capture_prep_cpuid_header();
mictc_trace_capture_prep_msr_header();
TRACE_SPRINTF("\t\t</cpu>\n");
TRACE_SPRINTF("\t</cpu_definition>\n");
TRACE_SPRINTF("\t<platform_definition>\n");
TRACE_SPRINTF("\t\t<physical_memory/>\n");
TRACE_SPRINTF("\t</platform_definition>\n");
TRACE_SPRINTF("\t<cpu_state>\n");
TRACE_SPRINTF("<!-- the number of \"cpu\" definitions must correspond to the \"num_cpus\" data item -->\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_capture_general_purpose_reg
// Capture all general purpose registers.
mictc_capture_general_purpose_reg(struct pt_regs
*regs
)
// printk("starting reg dump regs=%llx\n", (uint64_t)regs);
printk("Null pointer found. cpu %d %s\n", smp_processor_id(), current
->comm
);
TRACE_SPRINTF("\t\t\t<general>\n");
TRACE_SPRINTF("\t\t\t\t<reg name=\"RAX\">0x%lx</reg>\n", regs
->ax
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"RBX\">0x%lx</reg>\n", regs
->bx
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"RCX\">0x%lx</reg>\n", regs
->cx
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"RDX\">0x%lx</reg>\n", regs
->dx
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"RBP\">0x%lx</reg>\n", regs
->bp
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"RSP\">0x%lx</reg>\n", regs
->sp
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"RSI\">0x%lx</reg>\n", regs
->si
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"RDI\">0x%lx</reg>\n", regs
->di
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"R8\">0x%lx</reg>\n", regs
->r8
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"R9\">0x%lx</reg>\n", regs
->r9
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"R10\">0x%lx</reg>\n", regs
->r10
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"R11\">0x%lx</reg>\n", regs
->r11
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"R12\">0x%lx</reg>\n", regs
->r12
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"R13\">0x%lx</reg>\n", regs
->r13
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"R14\">0x%lx</reg>\n", regs
->r14
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"R15\">0x%lx</reg>\n", regs
->r15
);
// In cases where a CPU is halted and is woken up from halt by the trace capture IPI
// we want to report the RIP as the one pointing to the halt instruction itself
// and not the one on the trap frame. This is to avoid the condition where the simulator-run
// for these halted CPUs ends up running extra cycles (before going back idle)
// which would not happen under actual conditions. Problem reported by Jason S.
//// if(regs->tf_rip == (register_t)ExitIdle)
//// TRACE_SPRINTF("\t\t\t\t<reg name=\"RIP\">0x%lx</reg>\n", regs->ip-1);
TRACE_SPRINTF("\t\t\t\t<reg name=\"RIP\">0x%lx</reg>\n", regs
->ip
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"RFLAGS\">0x%lx</reg>\n", regs
->flags
);
TRACE_SPRINTF("\t\t\t</general>\n");
// printk("ending reg dump\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_capture_segment_reg
// Capture all segment registers.
mictc_capture_segment_reg(struct mictc_segment_reg
*segment
, struct pt_regs
*regs
)
struct mictc_seg
*segreg
;
// printk("Segment registers on cpu %d\n", smp_processor_id());
// This is only useful during initial development.
printk("Null pointer found. cpu %d %s\n", smp_processor_id(), current
->comm
);
segment
->cs
.selector
= (u16
)regs
->cs
;
segment
->ss
.selector
= (u16
)regs
->ss
;
if (ISPL(regs
->tf_cs
) == SEL_KPL
&& curthread
->td_pcb
->pcb_ds
== 0x0) {
// Specifically required for kernel IDLE thread
asm("movl %%ds,%0" : "=r" (v
)); segment
->ds
.selector
= v
;
asm("movl %%es,%0" : "=r" (v
)); segment
->es
.selector
= v
;
segment
->fs
.selector
= current
->thread
.fs
;
segment
->gs
.selector
= current
->thread
.gs
;
mictc_store_tr(&(segment
->tr
.selector
));
get_tss_desc(smp_processor_id(), &(segment
->tr
.desc
));
mictc_store_ldt(&(segment
->ldtr
.selector
));
// LDT is not used, so zeros will be printed.
TRACE_SPRINTF("\t\t\t<segment>\n");
segreg
= (struct mictc_seg
*)&(segment
->cs
);
for(i
=0; i
< MAX_SEG_REG
; i
++) {
if (strcmp(SegRegNames
[i
], "GS") == 0) {
segreg
->base
= tc_rdmsr(MSR_KGSBASE
);
if (strcmp(SegRegNames
[i
], "FS") == 0) {
segreg
->base
= tc_rdmsr(MSR_FSBASE
);
// Fill in the segment descriptor for cs to gs
get_seg_desc(smp_processor_id(), segreg
->selector
, &(segreg
->desc
));
TRACE_SPRINTF("\t\t\t\t<reg name=\"%s\">\n",SegRegNames
[i
]);
if (i
> 5) { // LDT and TSS
struct mictc_tss
*segreg1
=(struct mictc_tss
*)segreg
;
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"base\">0x%llx</attr>\n", ((uint64_t)segreg1
->desc
.base3
<< 32) | (uint64_t)((segreg1
->desc
.base2
<< 24) | (segreg1
->desc
.base1
<< 16) | segreg1
->desc
.base0
));
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"limit\">0x%x</attr>\n", (segreg1
->desc
.limit1
<< 16) | segreg1
->desc
.limit0
);
TRACE_SPRINTF("\t\t\t\t\t<selector>0x%x</selector>\n", segreg1
->selector
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"G\">0x%x</attr>\n", segreg1
->desc
.g
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"DB\">0x%x</attr>\n", 0); // double word of base and limit
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"L\">0x%x</attr>\n", 0);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"AVL\">0x0</attr>\n");//AVL bit not populated in the gdt[] array
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"P\">0x%x</attr>\n", segreg1
->desc
.p
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"DPL\">0x%x</attr>\n", segreg1
->desc
.dpl
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"S\">0x%x</attr>\n", segreg1
->desc
.type
& 0x10 ? 1 : 0); //The S bit (descriptor type) is clubbed along with the ssd_type element.
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"TYPE\">0x%x</attr>\n", (segreg1
->desc
.type
& 0xf));
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"base\">0x%llx</attr>\n", segreg
->base
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"base\">0x%x</attr>\n", (segreg
->desc
.base2
<< 24) | (segreg
->desc
.base1
<< 16) |segreg
->desc
.base0
);
if (segreg
->desc
.l
) segreg
->desc
.a
= 0;
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"limit\">0x%x</attr>\n", (segreg
->desc
.limit
<< 16) | segreg
->desc
.limit0
);
TRACE_SPRINTF("\t\t\t\t\t<selector>0x%x</selector>\n", segreg
->selector
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"G\">0x%x</attr>\n", segreg
->desc
.g
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"DB\">0x%x</attr>\n", segreg
->desc
.a
& 1); // double word of base and limit
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"L\">0x%x</attr>\n", segreg
->desc
.l
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"AVL\">0x0</attr>\n");//AVL bit not populated in the gdt[] array
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"P\">0x%x</attr>\n", segreg
->desc
.p
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"DPL\">0x%x</attr>\n", segreg
->desc
.dpl
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"S\">0x%x</attr>\n", segreg
->desc
.type
& 0x10 ? 1 : 0); //The S bit (descriptor type) is clubbed along with the ssd_type element.
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"TYPE\">0x%x</attr>\n", (segreg
->desc
.type
& 0xf));
TRACE_SPRINTF("\t\t\t\t</reg>\n");
TRACE_SPRINTF("\t\t\t\t<reg name=\"GDTR\">\n");
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"base\">0x%lx</attr>\n", gdtr
.address
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"limit\">0x%x</attr>\n", gdtr
.size
);
TRACE_SPRINTF("\t\t\t\t</reg>\n");
TRACE_SPRINTF("\t\t\t\t<reg name=\"IDTR\">\n");
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"base\">0x%lx</attr>\n", idtr
.address
);
TRACE_SPRINTF("\t\t\t\t\t<attr name=\"limit\">0x%x</attr>\n", idtr
.size
);
TRACE_SPRINTF("\t\t\t\t</reg>\n");
TRACE_SPRINTF("\t\t\t</segment>\n");
// printk("End of mictc_capture_segment_reg\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_capture_debug_reg
// Capture all debug registers.
mictc_capture_debug_reg(void)
TRACE_SPRINTF("\t\t\t<debug>\n");
TRACE_SPRINTF("\t\t\t\t<reg name=\"DR0\">0x%x</reg>\n", get_dr(0));
TRACE_SPRINTF("\t\t\t\t<reg name=\"DR1\">0x%x</reg>\n", get_dr(1));
TRACE_SPRINTF("\t\t\t\t<reg name=\"DR2\">0x%x</reg>\n", get_dr(2));
TRACE_SPRINTF("\t\t\t\t<reg name=\"DR3\">0x%x</reg>\n", get_dr(3));
// TRACE_SPRINTF("\t\t\t\t<reg name=\"DR4\">0x%x</reg>\n", get_dr(4));
// TRACE_SPRINTF("\t\t\t\t<reg name=\"DR5\">0x%x</reg>\n", get_dr(5));
TRACE_SPRINTF("\t\t\t\t<reg name=\"DR6\">0x%x</reg>\n", get_dr(6));
TRACE_SPRINTF("\t\t\t\t<reg name=\"DR7\">0x%x</reg>\n", get_dr(7));
TRACE_SPRINTF("\t\t\t</debug>\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_capture_control_reg
// Capture all control registers.
mictc_capture_control_reg(void)
TRACE_SPRINTF("\t\t\t<control>\n");
TRACE_SPRINTF("\t\t\t\t<reg name=\"CR0\">0x%lx</reg>\n", (read_cr0()) & 0xffffffff);
TRACE_SPRINTF("\t\t\t\t<reg name=\"CR2\">0x%lx</reg>\n", read_cr2());
TRACE_SPRINTF("\t\t\t\t<reg name=\"CR3\">0x%lx</reg>\n", read_cr3());
TRACE_SPRINTF("\t\t\t\t<reg name=\"CR4\">0x%lx</reg>\n", (read_cr4()) & 0xffffffff);
TRACE_SPRINTF("\t\t\t\t<reg name=\"CR8\">0x%lx</reg>\n", read_cr8());
TRACE_SPRINTF("\t\t\t</control>\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_capture_SPU_reg
// Capture all SPU registers.
mictc_capture_SPU_reg(void)
// FIXME - The SPU is not setup currently in Linux
TRACE_SPRINTF("\t\t\t<spu>\n");
TRACE_SPRINTF_SPU(SPU_XQ_SIZE
);
TRACE_SPRINTF_SPU(SPU_XQ_BASE
);
TRACE_SPRINTF_SPU(SPU_XQ_INDEX
);
TRACE_SPRINTF_SPU(SPU_CONTROL
);
TRACE_SPRINTF_SPU(SPU_SAMPLER_BASE
);
TRACE_SPRINTF_SPU(SPU_PMU_EVENT_SEL
);
TRACE_SPRINTF_SPU(SPU_CONTROL2
);
TRACE_SPRINTF_SPU(SPU_CONTROL3
);
TRACE_SPRINTF("\t\t\t</spu>\n");
//------------------------------------------------------------------------------
PrintVector(u8
*res_mem
, int reg_num
)
TRACE_SPRINTF("\t\t\t\t<reg name=\"V%d\">0x"
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x</reg>\n",
res_mem
[63], res_mem
[62], res_mem
[61], res_mem
[60], res_mem
[59], res_mem
[58], res_mem
[57], res_mem
[56],
res_mem
[55], res_mem
[54], res_mem
[53], res_mem
[52], res_mem
[51], res_mem
[50], res_mem
[49], res_mem
[48],
res_mem
[47], res_mem
[46], res_mem
[45], res_mem
[44], res_mem
[43], res_mem
[42], res_mem
[41], res_mem
[40],
res_mem
[39], res_mem
[38], res_mem
[37], res_mem
[36], res_mem
[35], res_mem
[34], res_mem
[33], res_mem
[32],
res_mem
[31], res_mem
[30], res_mem
[29], res_mem
[28], res_mem
[27], res_mem
[26], res_mem
[25], res_mem
[24],
res_mem
[23], res_mem
[22], res_mem
[21], res_mem
[20], res_mem
[19], res_mem
[18], res_mem
[17], res_mem
[16],
res_mem
[15], res_mem
[14], res_mem
[13], res_mem
[12], res_mem
[11], res_mem
[10], res_mem
[9], res_mem
[8],
res_mem
[7], res_mem
[6], res_mem
[5], res_mem
[4], res_mem
[3], res_mem
[2], res_mem
[1], res_mem
[0]);
//------------------------------------------------------------------------------
// FUNCTION: PrintFPRegister
// Prints 10 byte FP register contents
PrintFPRegister(u8
*res_mem
, int reg_num
)
TRACE_SPRINTF("\t\t\t\t<reg name=\"FR%d\">0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x</reg>\n",
#define VSTORED_DISP32_EAX(v, disp32) " vstored %%v" #v "," #disp32 "(%%rax)\n"
#define VKSTORE_DISP32_EAX(k, disp32) \
" vkmov %%k" #k ",%%ebx\n" \
" movw %%bx, " #disp32 "(%%rax)\n"
#define STVXCSR_DISP32_EAX(disp32) " stvxcsr " #disp32 "(%%rax)\n"
#define VSTORED_DISP32_EAX(v, disp32) " vpackstorelps %%zmm" #v "," #disp32 "(%%rax)\n"
#define VKSTORE_DISP32_EAX(k, disp32) \
" kmov %%k" #k ",%%ebx\n" \
" movw %%bx, " #disp32 "(%%rax)\n"
#define STVXCSR_DISP32_EAX(disp32) " stmxcsr " #disp32 "(%%rax)\n"
static inline void save_vpu(struct vpustate_struct
*vpustate
)
VSTORED_DISP32_EAX(0, 0x00)
VSTORED_DISP32_EAX(1, 0x40)
VSTORED_DISP32_EAX(2, 0x80)
VSTORED_DISP32_EAX(3, 0xc0)
VSTORED_DISP32_EAX(4, 0x100)
VSTORED_DISP32_EAX(5, 0x140)
VSTORED_DISP32_EAX(6, 0x180)
VSTORED_DISP32_EAX(7, 0x1c0)
VSTORED_DISP32_EAX(8, 0x200)
VSTORED_DISP32_EAX(9, 0x240)
VSTORED_DISP32_EAX(10, 0x280)
VSTORED_DISP32_EAX(11, 0x2c0)
VSTORED_DISP32_EAX(12, 0x300)
VSTORED_DISP32_EAX(13, 0x340)
VSTORED_DISP32_EAX(14, 0x380)
VSTORED_DISP32_EAX(15, 0x3c0)
VSTORED_DISP32_EAX(16, 0x400)
VSTORED_DISP32_EAX(17, 0x440)
VSTORED_DISP32_EAX(18, 0x480)
VSTORED_DISP32_EAX(19, 0x4c0)
VSTORED_DISP32_EAX(20, 0x500)
VSTORED_DISP32_EAX(21, 0x540)
VSTORED_DISP32_EAX(22, 0x580)
VSTORED_DISP32_EAX(23, 0x5c0)
VSTORED_DISP32_EAX(24, 0x600)
VSTORED_DISP32_EAX(25, 0x640)
VSTORED_DISP32_EAX(26, 0x680)
VSTORED_DISP32_EAX(27, 0x6c0)
VSTORED_DISP32_EAX(28, 0x700)
VSTORED_DISP32_EAX(29, 0x740)
VSTORED_DISP32_EAX(30, 0x780)
VSTORED_DISP32_EAX(31, 0x7c0)
VKSTORE_DISP32_EAX(0, 0x800)
VKSTORE_DISP32_EAX(1, 0x802)
VKSTORE_DISP32_EAX(2, 0x804)
VKSTORE_DISP32_EAX(3, 0x806)
VKSTORE_DISP32_EAX(4, 0x808)
VKSTORE_DISP32_EAX(5, 0x80a)
VKSTORE_DISP32_EAX(6, 0x80c)
VKSTORE_DISP32_EAX(7, 0x80e)
STVXCSR_DISP32_EAX(0x810)
: "=m" (vpustate
) : [fx
] "a" (vpustate
) : "ebx"
//------------------------------------------------------------------------------
// FUNCTION: mictc_capture_vector_reg
// Capture all vector registers.
mictc_capture_vector_reg(struct vpustate_struct
*vpustate
)
// printk("vpustate = %p\n", vpustate);
TRACE_SPRINTF("\t\t\t<vpu>\n");
TRACE_SPRINTF("\t\t\t\t<reg name=\"K0\">0x%x</reg>\n", vpustate
->k
[0]);
TRACE_SPRINTF("\t\t\t\t<reg name=\"K1\">0x%x</reg>\n", vpustate
->k
[1]);
TRACE_SPRINTF("\t\t\t\t<reg name=\"K2\">0x%x</reg>\n", vpustate
->k
[2]);
TRACE_SPRINTF("\t\t\t\t<reg name=\"K3\">0x%x</reg>\n", vpustate
->k
[3]);
TRACE_SPRINTF("\t\t\t\t<reg name=\"K4\">0x%x</reg>\n", vpustate
->k
[4]);
TRACE_SPRINTF("\t\t\t\t<reg name=\"K5\">0x%x</reg>\n", vpustate
->k
[5]);
TRACE_SPRINTF("\t\t\t\t<reg name=\"K6\">0x%x</reg>\n", vpustate
->k
[6]);
TRACE_SPRINTF("\t\t\t\t<reg name=\"K7\">0x%x</reg>\n", vpustate
->k
[7]);
TRACE_SPRINTF_VECTOR(0, vpustate
->vector_space
[0]);
TRACE_SPRINTF_VECTOR(1, vpustate
->vector_space
[16]);
TRACE_SPRINTF_VECTOR(2, vpustate
->vector_space
[32]);
TRACE_SPRINTF_VECTOR(3, vpustate
->vector_space
[48]);
TRACE_SPRINTF_VECTOR(4, vpustate
->vector_space
[64]);
TRACE_SPRINTF_VECTOR(5, vpustate
->vector_space
[80]);
TRACE_SPRINTF_VECTOR(6, vpustate
->vector_space
[96]);
TRACE_SPRINTF_VECTOR(7, vpustate
->vector_space
[112]);
TRACE_SPRINTF_VECTOR(8, vpustate
->vector_space
[128]);
TRACE_SPRINTF_VECTOR(9, vpustate
->vector_space
[144]);
TRACE_SPRINTF_VECTOR(10, vpustate
->vector_space
[160]);
TRACE_SPRINTF_VECTOR(11, vpustate
->vector_space
[176]);
TRACE_SPRINTF_VECTOR(12, vpustate
->vector_space
[192]);
TRACE_SPRINTF_VECTOR(13, vpustate
->vector_space
[208]);
TRACE_SPRINTF_VECTOR(14, vpustate
->vector_space
[224]);
TRACE_SPRINTF_VECTOR(15, vpustate
->vector_space
[240]);
TRACE_SPRINTF_VECTOR(16, vpustate
->vector_space
[256]);
TRACE_SPRINTF_VECTOR(17, vpustate
->vector_space
[272]);
TRACE_SPRINTF_VECTOR(18, vpustate
->vector_space
[288]);
TRACE_SPRINTF_VECTOR(19, vpustate
->vector_space
[304]);
TRACE_SPRINTF_VECTOR(20, vpustate
->vector_space
[320]);
TRACE_SPRINTF_VECTOR(21, vpustate
->vector_space
[336]);
TRACE_SPRINTF_VECTOR(22, vpustate
->vector_space
[352]);
TRACE_SPRINTF_VECTOR(23, vpustate
->vector_space
[368]);
TRACE_SPRINTF_VECTOR(24, vpustate
->vector_space
[384]);
TRACE_SPRINTF_VECTOR(25, vpustate
->vector_space
[400]);
TRACE_SPRINTF_VECTOR(26, vpustate
->vector_space
[416]);
TRACE_SPRINTF_VECTOR(27, vpustate
->vector_space
[432]);
TRACE_SPRINTF_VECTOR(28, vpustate
->vector_space
[448]);
TRACE_SPRINTF_VECTOR(29, vpustate
->vector_space
[464]);
TRACE_SPRINTF_VECTOR(30, vpustate
->vector_space
[480]);
TRACE_SPRINTF_VECTOR(31, vpustate
->vector_space
[496]);
TRACE_SPRINTF("\t\t\t\t<reg name=\"VXCSR\">0x%x</reg>\n", vpustate
->vxcsr
);
TRACE_SPRINTF("\t\t\t</vpu>\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_capture_FPU_reg
// Capture all FPU registers.
mictc_capture_FPU_reg(struct i387_fxsave_struct
*fpu
)
Get FPU contents from the registers instead of the PCB.
fxsave on L1OM saves only the x87 FPU registers and not the SSE2 and MMX registers.
For format of the data below refer Intel 64 and IA-32 Arch. SDM Vol 2A Instr Set Ref A-M
TRACE_SPRINTF("\t\t\t<fp>\n");
TRACE_SPRINTF("\t\t\t\t<reg name=\"CW\">0x%x</reg>\n", fpu
->cwd
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"SW\">0x%x</reg>\n", fpu
->swd
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"TW\">0x%x</reg>\n", (fpu
->twd
));
TRACE_SPRINTF("\t\t\t\t<reg name=\"FCS\">0x%x</reg>\n", (fpu
->fcs
& 0xffff));
TRACE_SPRINTF("\t\t\t\t<reg name=\"OPCODE\">0x%x</reg>\n", fpu
->fop
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"FDS\">0x%x</reg>\n", (fpu
->fos
& 0xffff));
TRACE_SPRINTF("\t\t\t\t<reg name=\"FIP\">0x%x</reg>\n", fpu
->fip
);
TRACE_SPRINTF("\t\t\t\t<reg name=\"DATAOP\">0x%x</reg>\n", (fpu
->foo
));
PrintFPRegister((u8
*)&(fpu
->st_space
[0]), 0);
PrintFPRegister((u8
*)&(fpu
->st_space
[4]), 1);
PrintFPRegister((u8
*)&(fpu
->st_space
[8]), 2);
PrintFPRegister((u8
*)&(fpu
->st_space
[12]), 3);
PrintFPRegister((u8
*)&(fpu
->st_space
[16]), 4);
PrintFPRegister((u8
*)&(fpu
->st_space
[20]), 5);
PrintFPRegister((u8
*)&(fpu
->st_space
[24]), 6);
PrintFPRegister((u8
*)&(fpu
->st_space
[28]), 7);
TRACE_SPRINTF("\t\t\t</fp>\n");
printk("00 %08x %08x\n", ((u32
*)fpu
)[0], ((u32
*)fpu
)[1]);
printk("08 %08x %08x\n", ((u32
*)fpu
)[2], ((u32
*)fpu
)[3]);
printk("10 %08x %08x\n", ((u32
*)fpu
)[4], ((u32
*)fpu
)[5]);
printk("18 %08x %08x\n", ((u32
*)fpu
)[6], ((u32
*)fpu
)[7]);
printk("20 %08x %08x\n", ((u32
*)fpu
)[8], ((u32
*)fpu
)[9]);
printk("28 %08x %08x\n", ((u32
*)fpu
)[10], ((u32
*)fpu
)[11]);
printk("30 %08x %08x\n", ((u32
*)fpu
)[12], ((u32
*)fpu
)[13]);
printk("38 %08x %08x\n", ((u32
*)fpu
)[14], ((u32
*)fpu
)[15]);
printk("40 %08x %08x\n", ((u32
*)fpu
)[16], ((u32
*)fpu
)[17]);
printk("48 %08x %08x\n", ((u32
*)fpu
)[18], ((u32
*)fpu
)[19]);
printk("50 %08x %08x\n", ((u32
*)fpu
)[20], ((u32
*)fpu
)[21]);
printk("58 %08x %08x\n", ((u32
*)fpu
)[22], ((u32
*)fpu
)[23]);
printk("60 %08x %08x\n", ((u32
*)fpu
)[24], ((u32
*)fpu
)[25]);
printk("68 %08x %08x\n", ((u32
*)fpu
)[26], ((u32
*)fpu
)[27]);
printk("70 %08x %08x\n", ((u32
*)fpu
)[28], ((u32
*)fpu
)[29]);
printk("78 %08x %08x\n", ((u32
*)fpu
)[30], ((u32
*)fpu
)[31]);
printk("80 %08x %08x\n", ((u32
*)fpu
)[32], ((u32
*)fpu
)[33]);
printk("88 %08x %08x\n", ((u32
*)fpu
)[34], ((u32
*)fpu
)[35]);
printk("90 %08x %08x\n", ((u32
*)fpu
)[36], ((u32
*)fpu
)[37]);
printk("98 %08x %08x\n", ((u32
*)fpu
)[38], ((u32
*)fpu
)[39]);
//------------------------------------------------------------------------------
// FUNCTION: mictc_capture_MSR
// u32 me_cpu = PCPU_GET(cpuid);
//msr->msrMIC_CR_SPUBASE = tc_rdmsr(MIC_CR_SPUBASE);
//msr->msrIA32_CR_MISC = tc_rdmsr(IA32_CR_MISC);
//msr->msrWMT_CR_LASTBRANCH_0 = tc_rdmsr(WMT_CR_LASTBRANCH_0);
//msr->msrWMT_CR_LASTBRANCH_1 = tc_rdmsr(WMT_CR_LASTBRANCH_1);
msr
->msrVMX_MSR_BASE
= tc_rdmsr(VMX_MSR_BASE
);
msr
->msrVMX_MSR_BASE_PLUS_1
= tc_rdmsr(VMX_MSR_BASE_PLUS_1
);
msr
->msrVMX_MSR_BASE_PLUS_2
= tc_rdmsr(VMX_MSR_BASE_PLUS_2
);
msr
->msrVMX_MSR_BASE_PLUS_3
= tc_rdmsr(VMX_MSR_BASE_PLUS_3
);
msr
->msrVMX_MSR_BASE_PLUS_4
= tc_rdmsr(VMX_MSR_BASE_PLUS_4
);
msr
->msrVMX_MSR_BASE_PLUS_5
= tc_rdmsr(VMX_MSR_BASE_PLUS_5
);
msr
->msrVMX_MSR_BASE_PLUS_6
= tc_rdmsr(VMX_MSR_BASE_PLUS_6
);
msr
->msrVMX_MSR_BASE_PLUS_7
= tc_rdmsr(VMX_MSR_BASE_PLUS_7
);
msr
->msrVMX_MSR_BASE_PLUS_8
= tc_rdmsr(VMX_MSR_BASE_PLUS_8
);
msr
->msrVMX_MSR_BASE_PLUS_9
= tc_rdmsr(VMX_MSR_BASE_PLUS_9
);
msr
->msrTIME
= tc_rdmsr(TIME
);
msr
->msrPINFO
= tc_rdmsr(PINFO
);
TRACE_SPRINTF("\t\t\t<msr>\n");
TRACE_SPRINTF_MSR(P6_CR_TSC
);
TRACE_SPRINTF_MSR(X86_CR_APICBASE
);
TRACE_SPRINTF_MSR(CBOX_SPU_PA_MSR
);
// This is being added since it is included in the ITP dump as well.
TRACE_SPRINTF("\t\t\t\t<reg addr=\"0x%x\">0x%llx</reg>\n", SPU_BASE
, (tc_rdmsr(CBOX_SPU_PA_MSR
) & 0x7fffffffffffffff) + 0x1000);
TRACE_SPRINTF_MSR(CBOX_SPU_SAMPLER_BIND_MSR
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysMask0
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysMask1
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysMask2
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysMask3
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysMask4
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysMask5
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysMask6
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysMask7
);
TRACE_SPRINTF_MSR(MSR_EFER
& ~0x800); // Force bit 11 to 0
TRACE_SPRINTF_MSR(MSR_SF_MASK
);
TRACE_SPRINTF_MSR(MSR_FSBASE
);
TRACE_SPRINTF_MSR(MSR_GSBASE
);
TRACE_SPRINTF_MSR(X86_CR_MTRRcap
);
TRACE_SPRINTF_MSR(X86_CR_MTRRdefType
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysBase2
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysBase0
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysBase1
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysBase3
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysBase4
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysBase5
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysBase6
);
TRACE_SPRINTF_MSR(X86_CR_MTRRphysBase7
);
TRACE_SPRINTF_MSR(LSTAR
);
// MSR_KGSBASE needs some special handling.
// On Silicon when a thread transitions from Ring 3->Ring 0 the
// first instruction it executes is swapgs which swaps the value
// of the current GSBase (which could be 0x0) with the value in
// MSR_KGSBASE to get to the per cpu data structure and onwards to the kernel stack.
// On Silicon, when the same thread transitions from Ring 0->Ring 3 MSR_KGSBASE gets
// the right value as a result of another swapgs on the way back.
// Where Trace Capture differs from Silicon is that we take a snapshot while executing
// in Ring 0 (when MSR_KGSBASE could be 0x0) but the first instruction
// which executes on LarrySim is a Ring 3 instruction.
// On the first syscall in LarrySim when it executes a swapgs it sees a MSR_KGSBASE value of 0x0.
// LarrySim cannot get to the kernel stack and we correctly hit a double fault (Bang!).
// The correct fix is to ensure that LarrySim sees a correct value of
// MSR_KGSBASE when it is provided a snapshot.
// TRACE_SPRINTF("\t\t\t\t<reg addr=\"0x%x\">0x%lx</reg>\n", MSR_KGSBASE, &__pcpu[me_cpu]);
// The following MSR's are currently ifdef'd out
// because LarrySim barfs on these.
// We might need these later.
TRACE_SPRINTF_MSR(X86_CR_MTRRfix64K_00000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix16K_80000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix16K_A0000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix4K_C0000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix4K_C8000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix4K_D0000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix4K_D8000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix4K_E0000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix4K_E8000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix4K_F0000
);
TRACE_SPRINTF_MSR(X86_CR_MTRRfix4K_F8000
);
TRACE_SPRINTF_MSR(P5_MC_ADDR
);
TRACE_SPRINTF_MSR(P5_MC_TYPE
);
TRACE_SPRINTF_MSR(MSR_TR1
);
TRACE_SPRINTF_MSR(MSR_TR2
);
TRACE_SPRINTF_MSR(MSR_TR3
);
TRACE_SPRINTF_MSR(MSR_TR4
);
TRACE_SPRINTF_MSR(MSR_TR5
);
TRACE_SPRINTF_MSR(MSR_TR6
);
TRACE_SPRINTF_MSR(MSR_TR7
);
TRACE_SPRINTF_MSR(MSR_TR9
);
TRACE_SPRINTF_MSR(MSR_TR10
);
TRACE_SPRINTF_MSR(MSR_TR11
);
TRACE_SPRINTF_MSR(MSR_TR12
);
TRACE_SPRINTF_MSR(IA32_APIC_BASE
);
TRACE_SPRINTF_MSR(IA32_TIME_STAMP_COUNTER
);
TRACE_SPRINTF_MSR(IA32_PerfCntr0
);
TRACE_SPRINTF_MSR(IA32_PerfCntr1
);
TRACE_SPRINTF_MSR(IA32_PerfCntr2
);
TRACE_SPRINTF_MSR(IA32_PerfCntr3
);
TRACE_SPRINTF_MSR(PerfFilteredCntr0
);
TRACE_SPRINTF_MSR(PerfFilteredCntr1
);
TRACE_SPRINTF_MSR(PerfFilteredCntr2
);
TRACE_SPRINTF_MSR(PerfFilteredCntr3
);
TRACE_SPRINTF_MSR(IA32_PerfEvtSel0
);
TRACE_SPRINTF_MSR(IA32_PerfEvtSel1
);
TRACE_SPRINTF_MSR(IA32_PerfEvtSel2
);
TRACE_SPRINTF_MSR(IA32_PerfEvtSel3
);
TRACE_SPRINTF_MSR(PerfFilterMask
);
TRACE_SPRINTF_MSR(IA32_PERF_GLOBAL_STATUS
);
TRACE_SPRINTF_MSR(IA32_PERF_GLOBAL_OVF_CONTROL
);
TRACE_SPRINTF_MSR(IA32_PERF_GLOBAL_CTRL
);
TRACE_SPRINTF_MSR(IA32_MCG_CTL
);
TRACE_SPRINTF_MSR(IA32_MC0_CTRL
);
TRACE_SPRINTF_MSR(IA32_MC0_STAT
);
TRACE_SPRINTF_MSR(IA32_MC0_ADDR
);
TRACE_SPRINTF_MSR(IA32_MC0_MISC
);
TRACE_SPRINTF_MSR(IA32_MC1_CTRL
);
TRACE_SPRINTF_MSR(IA32_MC1_STAT
);
TRACE_SPRINTF_MSR(IA32_MC1_ADDR
);
TRACE_SPRINTF_MSR(IA32_MC1_MISC
);
TRACE_SPRINTF_MSR(SYSCALL_FLAG_MASK
);
TRACE_SPRINTF_MSR(X86_PAT
);
TRACE_SPRINTF("\t\t\t</msr>\n");
//u64 rdtsccount = 0, dmasetuptime = 0, dmacomptime=0, hostacktime=0;
#if MIC_TRACE_CAPTURE_MEMORY_TEST
// Local function to count the number of bytes in a U32
// This is only used for the memory test.
static U32
AddBytes(U32 add
)
for (int i
=0; i
< sizeof(U32
); i
++)
//------------------------------------------------------------------------------
// FUNCTION: mictc_capture_memory
// Trace Capture IPI Handler
mictc_capture_memory(void)
long total_transfered
= 0;
// Transfer a full buffer.
for (i
= 0; total_transfered
< (max_pfn
<< PAGE_SHIFT
); i
++) {
printk("before scif_writeto, i = %ld\n", i
);
// Transfer any remainder
if ((max_pfn
<< PAGE_SHIFT
) - total_transfered
< MICTC_MEM_BUFFER_SIZE
) {
long remainder
= ((uint64_t)max_pfn
<< PAGE_SHIFT
) % MICTC_MEM_BUFFER_SIZE
;
printk("Writing %ld bytes, max_pfn = %ld\n", remainder
, max_pfn
);
if ((err
= scif_writeto(mictc_endp_data
, scif_offset_mem
+ (i
* MICTC_MEM_BUFFER_SIZE
),
remainder
, scif_offset_dst
, 0)) < 0) {
pr_crit("%s:%s:%d scif_writeto failed with error %ld\n", __FILE__
, __FUNCTION__
, __LINE__
, err
);
total_transfered
+= remainder
;
g_sizeXferred
= remainder
;
if ((err
= scif_writeto(mictc_endp_data
, scif_offset_mem
+ (i
* MICTC_MEM_BUFFER_SIZE
),
MICTC_MEM_BUFFER_SIZE
, scif_offset_dst
, 0)) < 0) {
pr_crit("%s:%s:%d scif_writeto failed with error %ld\n", __FILE__
, __FUNCTION__
, __LINE__
, err
);
total_transfered
+= MICTC_MEM_BUFFER_SIZE
;
g_sizeXferred
= MICTC_MEM_BUFFER_SIZE
;
*g_traceBufferSizeOffset
= g_sizeXferred
;
printk("before fence\n");
err
= scif_fence_signal(mictc_endp_data
, (off_t
)scif_offset_xml
+ TRACE_STATUS_OFFSET
,
TRACE_PAGE_READY
, 0, 0, SCIF_FENCE_INIT_SELF
| SCIF_SIGNAL_LOCAL
);
printk("scif_fence_signal failed. err = %ld\n", err
);
printk("TRACE_PAGE_READY %lld bytes\n", g_sizeXferred
);
printk("waiting for TRACE_HOST_READY\n");
while (*g_traceBufferStatusOffset
!= TRACE_HOST_READY
) {
if (delay_count
== TRACE_CAPTURE_TIMEOUT
) {
printk("Memory Dump Timeout. Host did not update @physAddr 0x%lx\n", i
<< PAGE_SHIFT
);
*g_traceBufferSizeOffset
= 0;
*g_traceBufferStatusOffset
= TRACE_MEM_COMPLETE
;
while (*g_traceBufferStatusOffset
!= TRACE_COMPLETE
) {
if (delay_count
== TRACE_CAPTURE_TIMEOUT
) {
printk("Trace completion timeout.\n");
//------------------------------------------------------------------------------
// FUNCTION: mictc_trace_capture
// Perform all the tasks related to Trace Capture
// for a particular Hardware Thread.
// The tasks currently include:
// General purpose registers
// Note: The SPU is not setup in Linux.
// PARAMETERS: regs - pointer to the task's registers
mictc_trace_capture(struct pt_regs
*regs
)
// printk("Entering mictc_trace_capture on cpu %d, for process = %s\n", smp_processor_id(), current->comm);
// Logic to let threads in one by one in order
while (atomic_read(&cpus_stopped
) != smp_processor_id()) {
//STH touch_nmi_watchdog();
if (smp_processor_id() == 0)
// CPU0 is responsible for preparing the
TRACE_SPRINTF("\t\t<cpu num=\"%d\">\n", smp_processor_id());
mictc_capture_general_purpose_reg(regs
);
mictc_capture_segment_reg(&(trace
->segment
), regs
);
mictc_capture_debug_reg();
mictc_capture_control_reg();
mictc_capture_vector_reg(&(trace
->vpustate
));
//STH touch_nmi_watchdog(); // Just to be safe
// The SPU is not setup currently in Linux
if (always_false
) mictc_capture_SPU_reg();
mictc_capture_FPU_reg(&(trace
->fpu
));
// printk("In mictc_trace_capture on cpu %d, after MSRs\n", smp_processor_id());
TRACE_SPRINTF("\t\t</cpu>\n");
// Each core should flush their caches
// as the initiator is going to take a memory
// Not required since DMA should snoop the caches.
// printk("In mictc_trace_capture on cpu %d, before check for last cpu\n", smp_processor_id());
if (smp_processor_id() == (num_online_cpus() - 1))
// The last CPU is responsible for preparing the
// Trace Capture Trailer.
TRACE_SPRINTF("\t</cpu_state>\n");
TRACE_SPRINTF("</arch_data>\n");
// Update the size as the Host App needs this information.
*g_traceBufferSizeOffset
= g_sizeXferred
;
// Update the status for the Host App. The CPU register state has been written by all
// the hardware threads. The host app polls for this status.
*g_traceBufferStatusOffset
= TRACE_REG_COMPLETE
;
printk("Completed Arch Dump. Now Beginning Memory Dump. Be patient (~1 min is ETA)..\n");
while (*g_traceBufferStatusOffset
!= TRACE_GET_FILE
)
if (delay_count
== TRACE_CAPTURE_TIMEOUT
)
printk("Arch Dump Timeout. Host did not update status.\n");
printk("%s out of wait loop.\n", __FUNCTION__
);
// printk("Exiting mictc_trace_capture on cpu %d\n", smp_processor_id());
// Starting point for trace_capture.
mictc_start_capture(void)
struct scif_portID portID_data
;
printk("Starting tracecapture on cpu %d. Taking lock.\n", smp_processor_id());
if (!(g_traceBufferAllocated
= kmalloc(MICTC_XML_BUFFER_SIZE
, GFP_KERNEL
))) {
pr_crit("%s:%s:%d kmalloc failed failed with ENOMEM\n", __FILE__
, __FUNCTION__
, __LINE__
);
pr_crit("%s:%s:%d kmalloc returned %llx\n", __FILE__
, __FUNCTION__
, __LINE__
, (uint64_t)g_traceBufferAllocated
);
g_traceBufferStatusOffset
= (u64
*)((u64
)g_traceBufferAllocated
+ TRACE_STATUS_OFFSET
);
g_traceBufferSizeOffset
= (u64
*)((u64
)g_traceBufferAllocated
+ TRACE_SIZE_OFFSET
);
g_traceBufferDataOffset
= (u32
*)((u64
)g_traceBufferAllocated
+ TRACE_DATA_OFFSET
);
g_traceBufferTriggerOffset
= (u32
*)((u64
)g_traceBufferAllocated
+ TRACE_TRIGGER_OFFSET
);
*g_traceBufferStatusOffset
= TRACE_DATA
;
#if MIC_TRACE_CAPTURE_MEMORY_TEST
g_traceBufferChecksumOffset
= (u64
*)((u64
)g_traceBufferAllocated
+ TRACE_CHECKSUM_OFFSET
);
if (!(trace
= (struct mictc_trace
*)kmalloc(sizeof(struct mictc_trace
), GFP_KERNEL
))) {
pr_crit("%s:%s:%d kmalloc failed failed with ENOMEM\n", __FILE__
, __FUNCTION__
, __LINE__
);
pr_crit("%s:%s:%d kmalloc returned %llx\n", __FILE__
, __FUNCTION__
, __LINE__
, (uint64_t)trace
);
memset(trace
, 0, sizeof(struct mictc_trace
));
pr_crit("g_traceBufferStatusOffset %llx\n", (uint64_t)g_traceBufferStatusOffset
);
pr_crit("g_traceBufferSizeOffset %llx\n", (uint64_t)g_traceBufferSizeOffset
);
pr_crit("g_traceBufferDataOffset %llx\n", (uint64_t)g_traceBufferDataOffset
);
if (!(mictc_endp_data
= scif_open())) {
pr_crit("%s:%s:%d scif_open failed with ENOMEM\n", __FILE__
, __FUNCTION__
, __LINE__
);
if ((ret
= scif_bind(mictc_endp_data
, MICTC_SCIF_PORT_DATA
)) < 0) {
pr_crit("%s:%s:%d scif_bind failed with error %ld\n", __FILE__
, __FUNCTION__
, __LINE__
, ret
);
portID_data
.port
= MICTC_SCIF_PORT_DATA
;
if ((ret
= scif_connect(mictc_endp_data
, &portID_data
)) < 0) {
pr_crit("%s:%s:%d scif_connect failed with error %ld\n", __FILE__
, __FUNCTION__
, __LINE__
, ret
);
if ((ret
= (long)scif_register(mictc_endp_data
,
SCIF_PROT_READ
| SCIF_PROT_WRITE
,
pr_crit("%s:%s:%d scif_register failed failed with %ld\n", __FILE__
, __FUNCTION__
, __LINE__
, ret
);
pr_crit("%s:%s:%d scif_register scif_offset_xml = %lx\n", __FILE__
, __FUNCTION__
, __LINE__
, scif_offset_xml
);
// Register all of physical memory.
if ((ret
= (long)scif_register(mictc_endp_data
,
__va(0), // Physical page 0
SCIF_PROT_READ
| SCIF_PROT_WRITE
,
pr_crit("%s:%s:%d scif_register failed failed with %ld\n", __FILE__
, __FUNCTION__
, __LINE__
, ret
);
pr_crit("%s:%s:%d scif_register scif_offset_mem = %lx\n", __FILE__
, __FUNCTION__
, __LINE__
, scif_offset_mem
);
BARRIER(mictc_endp_data
, "before barrier");
if ((err
= scif_recv(mictc_endp_data
, &scif_offset_dst
, sizeof(scif_offset_dst
), SCIF_RECV_BLOCK
)) <= 0) {
pr_crit("%s:%s:%d scif_recv failed with err %ld\n", __FILE__
, __FUNCTION__
, __LINE__
, err
);
// g_traceBufferDataOffset = (u32 *)ret;
// pr_crit("%s:%s:%d scif_register ret %lx\n", __FILE__, __FUNCTION__, __LINE__, scif_offset);
if ((err
= scif_send(mictc_endp_data
, &scif_offset_xml
, sizeof(scif_offset_xml
), SCIF_SEND_BLOCK
)) <= 0) {
pr_crit("%s:%s:%d scif_send failed with err %ld\n", __FILE__
, __FUNCTION__
, __LINE__
, err
);
while (*g_traceBufferStatusOffset
!= TRACE_HOST_READY
)
for (i
= 0; i
< TRACE_TRIGGER_MAX
; i
++) {
g_traceTriggers
[i
] = *g_traceBufferTriggerOffset
;
printk("Found trace trigger %d\n", g_traceTriggers
[i
]);
g_traceBufferTriggerOffset
++;
if (g_traceTriggers
[i
] == TRACE_EOL
) break;
// Is the trigger data empty? If so, accept everything.
if (g_traceTriggers
[0] == TRACE_EOL
) {
printk("Trace trigger data is empty.\n");
} else if (g_traceTriggers
[0] == TRACE_IGNORE
) {
printk("Ignoring current trace.");
// See if g_traceCurrentTrigger is in the trigger data.
// If not, abort this trace.
for (i
= 0; i
< TRACE_TRIGGER_MAX
; i
++) {
if (g_traceTriggers
[i
] == TRACE_EOL
) break;
if (g_traceTriggers
[i
] == g_traceCurrentTrigger
) {
printk("Matched trace trigger %d\n", g_traceTriggers
[i
]);
printk("Trace trigger did not match -- aborting.\n");
*g_traceBufferStatusOffset
= TRACE_ABORTED
;
// Mmap memory at 0xfee03000 physical.
spu_addr
= ioremap(0xfee03000, 0x1000);
pr_crit("%s ioremap failed.\n", __FUNCTION__
);
printk("CPU ioremap %p\n", spu_addr
);
atomic_set(&cpus_stopped
, 0);
atomic_set(&cpus_released
, 0);
// Send IPI to capture all other cpus.
apic
->send_IPI_allbutself(NMI_VECTOR
);
mictc_trace_capture(task_pt_regs(current
));
atomic_inc(&cpus_stopped
);
pr_debug("start_capture: Entering wait loop until lock count %d >= %d on cpu %d\n", atomic_read(&cpus_stopped
), num_online_cpus() - 1, smp_processor_id());
// Wait for every other CPU to finish its trace capture tasks.
while (atomic_read(&cpus_stopped
) < num_online_cpus()) {
//STH touch_nmi_watchdog();
printk("%s:%d *** waiting loop cpus_stopped = %d\n", __FUNCTION__
, __LINE__
, atomic_read(&cpus_stopped
));
printk("%s out of wait loop.\n", __FUNCTION__
);
// Get a memory dump here before exiting.
err
= mictc_capture_memory();
printk("Completed Memory Dump.\n");
// printk("Completed Memory Dump. DMASetuptime = %ld , DMATime = %ld, HostAckTime = %ld\n", dmasetuptime, dmacomptime, hostacktime);
// Now release all cores.
atomic_set(&cpus_stopped
, num_online_cpus() + 1);
// Wait for every other CPU to be released
while (atomic_read(&cpus_released
) < num_online_cpus() - 1) {
// FIXME This cleanup probably needs to be checked.
// scif_unregister(mictc_endp_data, scif_offset, MICTC_XML_BUFFER_SIZE);
scif_close(mictc_endp_data
);
kfree(g_traceBufferAllocated
);
spin_unlock(&mictc_lock
);
printk("Ending tracecapture on cpu %d. Releasing lock.\n", smp_processor_id());
EXPORT_SYMBOL(mictc_start_capture
);
* mictc_handle_exception() - main entry point from a kernel exception
* interface locks, if any (begin_session)
mictc_handle_exception(int evector
, int signo
, int ecode
, struct pt_regs
*regs
)
// printk("Entering mictc_handle_exception on cpu %d pid: %d, name: %s\n", smp_processor_id(), current->pid, current->comm);
mictc_trace_capture(regs
);
atomic_inc(&cpus_stopped
);
pr_debug("handler: Entering wait loop until lock count %d >= %d on cpu %d\n", atomic_read(&cpus_stopped
), num_online_cpus() - 1, smp_processor_id());
// Wait for every other CPU to finish its Trace Capture Tasks.
// This test is for num_online_cpus+1 to hold all threads that are
// in interrupt context so that the main thread can dump memory.
while (atomic_read(&cpus_stopped
) < num_online_cpus() + 1) {
//STH touch_nmi_watchdog();
atomic_inc(&cpus_released
);
printk("Exiting mictc_handle_exception on cpu %d %s\n", smp_processor_id(), current
->comm
);
static int __mictc_notify(struct die_args
*args
, unsigned long cmd
)
struct pt_regs
*regs
= args
->regs
;
if (atomic_read(&kgdb_active
) != -1) {
kgdb_nmicallback(smp_processor_id(), regs
);
was_in_debug_nmi
[smp_processor_id()] = 1;
if (was_in_debug_nmi
[smp_processor_id()]) {
was_in_debug_nmi
[smp_processor_id()] = 0;
if (atomic_read(&kgdb_cpu_doing_single_step
) != -1) {
return single_step_cont(regs
, args
);
} else if (test_thread_flag(TIF_SINGLESTEP
))
/* This means a user thread is single stepping
* a system call which should be ignored
if (mictc_handle_exception(args
->trapnr
, args
->signr
, cmd
, regs
)) {
/* Must touch watchdog before return to normal operation */
mictc_notify(struct notifier_block
*self
, unsigned long cmd
, void *ptr
)
ret
= __mictc_notify(ptr
, cmd
);
local_irq_restore(flags
);
* This function is called whenever a process tries to do an ioctl on our
* device file. We get two extra parameters (additional to the inode and file
* structures, which all device functions get): the number of the ioctl called
* and the parameter given to the ioctl function.
* If the ioctl is write or read/write (meaning output is returned to the
* calling process), the ioctl call returns the output of this function.
struct file
*file
, /* ditto */
unsigned int ioctl_num
, /* number and param for ioctl */
unsigned long ioctl_param
)
// Switch according to the ioctl called
case MICTC_START_CAPTURE
:
// ioctl_param contains the trace trigger number.
// Save it to check against the g_traceTrigger array.
g_traceCurrentTrigger
= (u32
)ioctl_param
;
printk("IOCTL trace trigger %ld\n", ioctl_param
);
printk("Invalid ioctl.\n");
* This is called whenever a process attempts to open the device file
static int device_open(struct inode
*inode
, struct file
*file
)
printk(KERN_INFO
"device_open(%p)\n", file
);
* We don't want to talk to two processes at the same time
try_module_get(THIS_MODULE
);
static int device_release(struct inode
*inode
, struct file
*file
)
printk(KERN_INFO
"device_release(%p,%p)\n", inode
, file
);
* We're now ready for our next caller
* This structure will hold the functions to be called
* when a process does something to the device we
* created. Since a pointer to this structure is kept in
* the devices table, it can't be local to
* init_module. NULL is for unimplemented functions.
struct file_operations Fops
= {
// .write = device_write,
.unlocked_ioctl
= device_ioctl
,
.release
= device_release
, /* a.k.a. close */
static struct notifier_block mictc_notifier
= {
.notifier_call
= mictc_notify
,
.priority
= 0x7fffffff /* we need to be notified first */
* mictc_init - Register our notifier
* Register the character device (atleast try)
ret_val
= register_chrdev(MICTC_MAJOR_NUM
, MICTC_DEVICE_NAME
, &Fops
);
* Negative values signify an error
printk(KERN_ALERT
"%s failed with %d\n",
"Sorry, registering the character device ", ret_val
);
printk(KERN_INFO
"%s The major device number is %d.\n",
"Registeration is a success", MICTC_MAJOR_NUM
);
printk(KERN_INFO
"To use trace capture you'll have to create a device file:\n");
printk(KERN_INFO
"mknod %s c %d 0\n", MICTC_FILE_NAME
, MICTC_MAJOR_NUM
);
return register_die_notifier(&mictc_notifier
);
MODULE_AUTHOR("Intel Corp. 2011 (sth " __DATE__
") ver " TC_VER
);
MODULE_DESCRIPTION("Trace Capture module for K1OM");