diff --git a/eBPF_Supermarket/kvm_watcher/docs/kvm_mmu.md b/eBPF_Supermarket/kvm_watcher/docs/kvm_mmu.md new file mode 100644 index 000000000..9c23ca138 --- /dev/null +++ b/eBPF_Supermarket/kvm_watcher/docs/kvm_mmu.md @@ -0,0 +1,116 @@ + + +vm exit(EPT_VIOLATION)处理流程: + +``` +static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { +... + [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation, +... +}; + +``` + +```c +vmx_handle_exit() { + # 处理 VMX(虚拟机扩展)退出的主要函数 + __vmx_handle_exit() { + handle_ept_violation() { + # 处理 EPT(扩展页表)违规的函数 + kvm_mmu_page_fault() { + # 处理 KVM MMU(内存管理单元)页错误 + kvm_tdp_page_fault() { + # 处理 TDP(两级页表)页错误 + kvm_arch_has_noncoherent_dma(); + direct_page_fault() { + # 处理直接页错误 + kvm_vcpu_gfn_to_memslot(); + page_fault_handle_page_track(); + fast_page_fault(); + mmu_topup_memory_caches() { + # 增加内存缓存 + kvm_mmu_topup_memory_cache() { + __kvm_mmu_topup_memory_cache(); + } + kvm_mmu_topup_memory_cache() { + __kvm_mmu_topup_memory_cache(); + } + kvm_mmu_topup_memory_cache() { + __kvm_mmu_topup_memory_cache(); + } + } + kvm_faultin_pfn() { + # 处理 KVM PFN(物理帧号)故障 + __gfn_to_pfn_memslot() { + # 将 GFN(全局帧号)转换为 PFN(物理帧号)并获取内存插槽 + hva_to_pfn() { + # 将 HVA(主机虚拟地址)转换为 PFN(物理帧号) + get_user_pages_fast_only() { + # 快速获取用户页 + internal_get_user_pages_fast() { + # 内部快速获取用户页 + lockless_pages_from_mm() { + # 从内存管理结构中获取无锁页 + gup_pgd_range() { + # 获取页表项(PGD)范围 + pud_huge(); + gup_pmd_range.constprop.0() { + # 获取中间页表项(PMD)范围 + gup_huge_pmd() { + # 获取巨大页面的中间页表项 + try_grab_folio(); + } + } + } + } + } + } + } + } + } + handle_abnormal_pfn(); + _raw_read_lock(); + is_page_fault_stale(); + kvm_tdp_mmu_map() { + # TDP MMU 映射 + kvm_mmu_hugepage_adjust() { + # 调整 KVM MMU 巨大页面 + kvm_mmu_max_mapping_level() { + # 获取 KVM MMU 最大映射级别 + host_pfn_mapping_level(); + } + } + __rcu_read_lock(); + tdp_iter_start() { + # TDP 迭代器开始 + tdp_iter_restart() { + # TDP 迭代器重新启动 + tdp_iter_refresh_sptep(); + } + } + disallowed_hugepage_adjust(); + tdp_iter_next() { + # TDP 迭代器下一个 + tdp_iter_refresh_sptep(); + } + disallowed_hugepage_adjust(); + tdp_iter_next() { + # TDP 迭代器下一个 + tdp_iter_refresh_sptep(); + } + } + tdp_iter_next() { + # TDP 迭代器下一个 + tdp_iter_refresh_sptep(); + } + } + disallowed_hugepage_adjust(); + } + } + } + } +} + +``` + +![kvm-init-mmu](https://gitee.com/nan-shuaibo/image/raw/master/202403081421893.png) \ No newline at end of file diff --git a/eBPF_Supermarket/kvm_watcher/include/kvm_exits.h b/eBPF_Supermarket/kvm_watcher/include/kvm_exits.h index 9fb034a07..29fb8043a 100644 --- a/eBPF_Supermarket/kvm_watcher/include/kvm_exits.h +++ b/eBPF_Supermarket/kvm_watcher/include/kvm_exits.h @@ -58,7 +58,7 @@ static int trace_kvm_exit(struct exit *ctx, pid_t vm_pid) { CHECK_PID(vm_pid); u32 reason; reason = (u32)ctx->exit_reason; - //如果是节能停止退出,就不采集数据 + // 如果是节能停止退出,就不采集数据 if (reason == EXIT_REASON_HLT) { return 0; } diff --git a/eBPF_Supermarket/kvm_watcher/include/kvm_ioctl.h b/eBPF_Supermarket/kvm_watcher/include/kvm_ioctl.h new file mode 100644 index 000000000..97d13ba03 --- /dev/null +++ b/eBPF_Supermarket/kvm_watcher/include/kvm_ioctl.h @@ -0,0 +1,32 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: nanshuaibo811@163.com +// +// Kernel space BPF program used for KVM ioctl + +#ifndef __KVM_IOCTL_H +#define __KVM_IOCTL_H + +#include "kvm_watcher.h" +#include "vmlinux.h" +#include +#include +#include + +static int trace_kvm_ioctl(struct trace_event_raw_sys_enter *args) { + return 0; +} + +#endif /* __KVM_IOCTL_H */ \ No newline at end of file diff --git a/eBPF_Supermarket/kvm_watcher/include/kvm_mmu.h b/eBPF_Supermarket/kvm_watcher/include/kvm_mmu.h index 580508f45..52d5b4fa0 100644 --- a/eBPF_Supermarket/kvm_watcher/include/kvm_mmu.h +++ b/eBPF_Supermarket/kvm_watcher/include/kvm_mmu.h @@ -25,6 +25,8 @@ #include #include +#define PAGE_SHIFT 12 + struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 8192); @@ -56,9 +58,9 @@ static int trace_page_fault(struct page_fault *ctx, pid_t vm_pid) { return 0; } -static int trace_direct_page_fault(struct kvm_vcpu *vcpu, - struct kvm_page_fault *fault, void *rb, - struct common_event *e) { +static int trace_tdp_page_fault(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault, void *rb, + struct common_event *e) { u64 addr; bpf_probe_read_kernel(&addr, sizeof(u64), &fault->addr); u64 *ts; @@ -81,7 +83,6 @@ static int trace_direct_page_fault(struct kvm_vcpu *vcpu, if (count) { (*count)++; e->page_fault_data.count = *count; - bpf_map_update_elem(&pf_count, &addr, count, BPF_ANY); } else { e->page_fault_data.count = 1; bpf_map_update_elem(&pf_count, &addr, &new_count, BPF_ANY); @@ -104,36 +105,43 @@ static int trace_kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, CHECK_PID(vm_pid); if (error_code & PFERR_RSVD_MASK) { u64 ts = bpf_ktime_get_ns(); - u64 addr = cr2_or_gpa; - bpf_map_update_elem(&pf_delay, &addr, &ts, BPF_ANY); + u64 gfn = cr2_or_gpa >> PAGE_SHIFT; + bpf_map_update_elem(&pf_delay, &gfn, &ts, BPF_ANY); } return 0; } -static int trace_handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, - bool direct, void *rb, +struct mmio_page_fault { + u64 pad; + u64 addr; + gfn_t gfn; + unsigned access; +}; + +static int trace_handle_mmio_page_fault(struct mmio_page_fault *ctx, void *rb, struct common_event *e) { u64 *ts; - ts = bpf_map_lookup_elem(&pf_delay, &addr); + u64 gfn; + bpf_probe_read_kernel(&gfn, sizeof(u64), &ctx->gfn); + ts = bpf_map_lookup_elem(&pf_delay, &gfn); if (!ts) { return 0; } u32 *count; u32 new_count = 1; u64 delay = bpf_ktime_get_ns() - *ts; - bpf_map_delete_elem(&pf_delay, &addr); + bpf_map_delete_elem(&pf_delay, &gfn); RESERVE_RINGBUF_ENTRY(rb, e); - count = bpf_map_lookup_elem(&pf_count, &addr); + count = bpf_map_lookup_elem(&pf_count, &gfn); if (count) { (*count)++; e->page_fault_data.count = *count; - bpf_map_update_elem(&pf_count, &addr, count, BPF_ANY); } else { e->page_fault_data.count = 1; - bpf_map_update_elem(&pf_count, &addr, &new_count, BPF_ANY); + bpf_map_update_elem(&pf_count, &gfn, &new_count, BPF_ANY); } e->page_fault_data.delay = delay; - e->page_fault_data.addr = addr; + e->page_fault_data.addr = gfn; e->page_fault_data.error_code = PFERR_RSVD_MASK; e->process.pid = bpf_get_current_pid_tgid() >> 32; bpf_get_current_comm(&e->process.comm, sizeof(e->process.comm)); diff --git a/eBPF_Supermarket/kvm_watcher/include/kvm_watcher.h b/eBPF_Supermarket/kvm_watcher/include/kvm_watcher.h index a1a81e037..97c77244b 100644 --- a/eBPF_Supermarket/kvm_watcher/include/kvm_watcher.h +++ b/eBPF_Supermarket/kvm_watcher/include/kvm_watcher.h @@ -28,10 +28,7 @@ #define NS_TO_US_WITH_DECIMAL(ns) ((double)(ns) / NS_TO_US_FACTOR) #define NS_TO_MS_WITH_DECIMAL(ns) ((double)(ns) / NS_TO_MS_FACTOR) -#define MICROSECONDS_IN_SECOND 1000000 -#define OUTPUT_INTERVAL_SECONDS 2 - -#define OUTPUT_INTERVAL(us) usleep((__u32)(us * MICROSECONDS_IN_SECOND)) +#define OUTPUT_INTERVAL(SECONDS) sleep(SECONDS) #define OPTIONS_LIST "-w, -p, -d, -f, -c, -i, ,-h or -e" @@ -147,6 +144,7 @@ enum EventType { IRQCHIP, IRQ_INJECT, HYPERCALL, + IOCTL, } event_type; struct common_event { diff --git a/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.bpf.c b/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.bpf.c index 9c32befae..406e5d273 100644 --- a/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.bpf.c +++ b/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.bpf.c @@ -20,12 +20,13 @@ #include #include #include +#include "../include/kvm_watcher.h" #include "../include/kvm_exits.h" #include "../include/kvm_vcpu.h" #include "../include/kvm_mmu.h" #include "../include/kvm_irq.h" #include "../include/kvm_hypercall.h" -#include "../include/kvm_watcher.h" +#include "../include/kvm_ioctl.h" char LICENSE[] SEC("license") = "Dual BSD/GPL"; @@ -75,10 +76,10 @@ int tp_page_fault(struct page_fault *ctx) { return trace_page_fault(ctx, vm_pid); } -SEC("fexit/direct_page_fault") -int BPF_PROG(fexit_direct_page_fault, struct kvm_vcpu *vcpu, +SEC("fexit/kvm_tdp_page_fault") +int BPF_PROG(fexit_tdp_page_fault, struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { - return trace_direct_page_fault(vcpu, fault, &rb, e); + return trace_tdp_page_fault(vcpu, fault, &rb, e); } SEC("fentry/kvm_mmu_page_fault") @@ -87,10 +88,9 @@ int BPF_PROG(fentry_kvm_mmu_page_fault, struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, return trace_kvm_mmu_page_fault(vcpu, cr2_or_gpa, error_code, vm_pid); } -SEC("fexit/handle_mmio_page_fault") -int BPF_PROG(fexit_handle_mmio_page_fault, struct kvm_vcpu *vcpu, u64 addr, - bool direct) { - return trace_handle_mmio_page_fault(vcpu, addr, direct, &rb, e); +SEC("tp/kvmmmu/handle_mmio_page_fault") +int tp_handle_mmio_page_fault(struct mmio_page_fault *ctx) { + return trace_handle_mmio_page_fault(ctx, &rb, e); } SEC("fentry/kvm_pic_set_irq") @@ -145,3 +145,8 @@ SEC("fentry/kvm_emulate_hypercall") int BPF_PROG(fentry_emulate_hypercall, struct kvm_vcpu *vcpu) { return entry_emulate_hypercall(vcpu, &rb, e, vm_pid); } + +SEC("tracepoint/syscalls/sys_enter_ioctl") +int tp_ioctl(struct trace_event_raw_sys_enter *args) { + return trace_kvm_ioctl(args); +} \ No newline at end of file diff --git a/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.c b/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.c index 96889285a..2746149fe 100644 --- a/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.c +++ b/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.c @@ -54,101 +54,102 @@ FILE *create_temp_file(const char *filename) { return output; } -const char *getHypercallName(int number) { - struct Hypercall { +const char *getName(int number, enum EventType type) { + struct NameMapping { int number; const char *name; }; - + // 定义具体的退出原因 arch/x86/include/uapi/asm/vmx.h + struct NameMapping exitReasons[] = {{0, "EXCEPTION_NMI"}, + {1, "EXTERNAL_INTERRUPT"}, + {2, "TRIPLE_FAULT"}, + {3, "INIT_SIGNAL"}, + {4, "SIPI_SIGNAL"}, + {7, "INTERRUPT_WINDOW"}, + {8, "NMI_WINDOW"}, + {9, "TASK_SWITCH"}, + {10, "CPUID"}, + {12, "HLT"}, + {13, "INVD"}, + {14, "INVLPG"}, + {15, "RDPMC"}, + {16, "RDTSC"}, + {18, "VMCALL"}, + {19, "VMCLEAR"}, + {20, "VMLAUNCH"}, + {21, "VMPTRLD"}, + {22, "VMPTRST"}, + {23, "VMREAD"}, + {24, "VMRESUME"}, + {25, "VMWRITE"}, + {26, "VMOFF"}, + {27, "VMON"}, + {28, "CR_ACCESS"}, + {29, "DR_ACCESS"}, + {30, "IO_INSTRUCTION"}, + {31, "MSR_READ"}, + {32, "MSR_WRITE"}, + {33, "INVALID_STATE"}, + {34, "MSR_LOAD_FAIL"}, + {36, "MWAIT_INSTRUCTION"}, + {37, "MONITOR_TRAP_FLAG"}, + {39, "MONITOR_INSTRUCTION"}, + {40, "PAUSE_INSTRUCTION"}, + {41, "MCE_DURING_VMENTRY"}, + {43, "TPR_BELOW_THRESHOLD"}, + {44, "APIC_ACCESS"}, + {45, "EOI_INDUCED"}, + {46, "GDTR_IDTR"}, + {47, "LDTR_TR"}, + {48, "EPT_VIOLATION"}, + {49, "EPT_MISCONFIG"}, + {50, "INVEPT"}, + {51, "RDTSCP"}, + {52, "PREEMPTION_TIMER"}, + {53, "INVVPID"}, + {54, "WBINVD"}, + {55, "XSETBV"}, + {56, "APIC_WRITE"}, + {57, "RDRAND"}, + {58, "INVPCID"}, + {59, "VMFUNC"}, + {60, "ENCLS"}, + {61, "RDSEED"}, + {62, "PML_FULL"}, + {63, "XSAVES"}, + {64, "XRSTORS"}, + {67, "UMWAIT"}, + {68, "TPAUSE"}, + {74, "BUS_LOCK"}, + {75, "NOTIFY"}}; // 定义超级调用 include\uapi\linux\kvm_para.h - struct Hypercall hypercalls[] = { + struct NameMapping hypercalls[] = { {1, "VAPIC_POLL_IRQ"}, {5, "KICK_CPU"}, {9, "CLOCK_PAIRING"}, {10, "SEND_IPI"}, {11, "SCHED_YIELD"}, {12, "MAP_GPA_RANGE"}}; - - for (int i = 0; i < sizeof(hypercalls) / sizeof(hypercalls[0]); i++) { - if (hypercalls[i].number == number) { - return hypercalls[i].name; - } + // 根据枚举类型选择使用哪个结构体数组进行转换 + struct NameMapping *mappings; + int count; + switch (type) { + case EXIT: + mappings = exitReasons; + count = sizeof(exitReasons) / sizeof(exitReasons[0]); + break; + case HYPERCALL: + mappings = hypercalls; + count = sizeof(hypercalls) / sizeof(hypercalls[0]); + break; + default: + return "Unknown"; } - return "Unknown"; // 如果找不到对应的超级调用号,返回一个默认值 -} - -const char *getExitReasonName(int number) { - struct ExitReason { - int number; - const char *name; - }; - // 定义具体的退出原因 arch/x86/include/uapi/asm/vmx.h - struct ExitReason exitReasons[] = {{0, "EXCEPTION_NMI"}, - {1, "EXTERNAL_INTERRUPT"}, - {2, "TRIPLE_FAULT"}, - {3, "INIT_SIGNAL"}, - {4, "SIPI_SIGNAL"}, - {7, "INTERRUPT_WINDOW"}, - {8, "NMI_WINDOW"}, - {9, "TASK_SWITCH"}, - {10, "CPUID"}, - {12, "HLT"}, - {13, "INVD"}, - {14, "INVLPG"}, - {15, "RDPMC"}, - {16, "RDTSC"}, - {18, "VMCALL"}, - {19, "VMCLEAR"}, - {20, "VMLAUNCH"}, - {21, "VMPTRLD"}, - {22, "VMPTRST"}, - {23, "VMREAD"}, - {24, "VMRESUME"}, - {25, "VMWRITE"}, - {26, "VMOFF"}, - {27, "VMON"}, - {28, "CR_ACCESS"}, - {29, "DR_ACCESS"}, - {30, "IO_INSTRUCTION"}, - {31, "MSR_READ"}, - {32, "MSR_WRITE"}, - {33, "INVALID_STATE"}, - {34, "MSR_LOAD_FAIL"}, - {36, "MWAIT_INSTRUCTION"}, - {37, "MONITOR_TRAP_FLAG"}, - {39, "MONITOR_INSTRUCTION"}, - {40, "PAUSE_INSTRUCTION"}, - {41, "MCE_DURING_VMENTRY"}, - {43, "TPR_BELOW_THRESHOLD"}, - {44, "APIC_ACCESS"}, - {45, "EOI_INDUCED"}, - {46, "GDTR_IDTR"}, - {47, "LDTR_TR"}, - {48, "EPT_VIOLATION"}, - {49, "EPT_MISCONFIG"}, - {50, "INVEPT"}, - {51, "RDTSCP"}, - {52, "PREEMPTION_TIMER"}, - {53, "INVVPID"}, - {54, "WBINVD"}, - {55, "XSETBV"}, - {56, "APIC_WRITE"}, - {57, "RDRAND"}, - {58, "INVPCID"}, - {59, "VMFUNC"}, - {60, "ENCLS"}, - {61, "RDSEED"}, - {62, "PML_FULL"}, - {63, "XSAVES"}, - {64, "XRSTORS"}, - {67, "UMWAIT"}, - {68, "TPAUSE"}, - {74, "BUS_LOCK"}, - {75, "NOTIFY"}}; - - for (int i = 0; i < sizeof(exitReasons) / sizeof(exitReasons[0]); i++) { - if (exitReasons[i].number == number) { - return exitReasons[i].name; + // 根据给定的编号在选择的结构体数组中搜索对应的名称 + for (int i = 0; i < count; i++) { + if (mappings[i].number == number) { + return mappings[i].name; } } - return "Unknown"; // 如果找不到对应的退出原因,返回一个默认值 + + return "Unknown"; // 如果找不到对应的条目,返回一个默认值 } // 检查具有给定 PID 的进程是否存在 @@ -256,7 +257,6 @@ int save_count_dirtypagemap_to_file(struct bpf_map *map) { static struct env { bool execute_vcpu_wakeup; bool execute_exit; - bool ShowStats; bool execute_halt_poll_ns; bool execute_mark_page_dirty; bool execute_page_fault; @@ -264,13 +264,13 @@ static struct env { bool execute_irqchip; bool execute_irq_inject; bool execute_hypercall; + bool execute_ioctl; int monitoring_time; pid_t vm_pid; enum EventType event_type; } env = { .execute_vcpu_wakeup = false, .execute_exit = false, - .ShowStats = false, .execute_halt_poll_ns = false, .execute_mark_page_dirty = false, .execute_page_fault = false, @@ -278,6 +278,7 @@ static struct env { .execute_irq_inject = false, .mmio_page_fault = false, .execute_hypercall = false, + .execute_ioctl = false, .monitoring_time = 0, .vm_pid = -1, .event_type = NONE_TYPE, @@ -297,9 +298,9 @@ static const struct argp_option opts[] = { "Monitor virtual machine dirty page information."}, {"kvmmmu_page_fault", 'f', NULL, 0, "Monitoring the data of kvmmmu page fault."}, - {"kvm_irqchip(software)", 'c', NULL, 0, + {"kvm_irqchip", 'c', NULL, 0, "Monitor the irqchip setting information in KVM VM."}, - {"irq_inject(hardware)", 'i', NULL, 0, + {"irq_inject", 'i', NULL, 0, "Monitor the virq injection information in KVM VM "}, {"hypercall", 'h', NULL, 0, "Monitor the hypercall information in KVM VM "}, {"mmio", 'm', NULL, 0, @@ -307,6 +308,7 @@ static const struct argp_option opts[] = { "specified.)"}, {"vm_pid", 'p', "PID", 0, "Specify the virtual machine pid to monitor."}, {"monitoring_time", 't', "SEC", 0, "Time for monitoring."}, + {"kvm_ioctl", 'l', NULL, 0, "Monitoring the KVM IOCTL."}, {NULL, 'H', NULL, OPTION_HIDDEN, "Show the full help"}, {}, }; @@ -343,13 +345,8 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { case 'h': SET_OPTION_AND_CHECK_USAGE(option_selected, env.execute_hypercall); break; - case 's': - if (env.execute_exit) { - env.ShowStats = true; - } else { - fprintf(stderr, "The -e option must be specified.\n"); - argp_state_help(state, stdout, ARGP_HELP_STD_HELP); - } + case 'l': + SET_OPTION_AND_CHECK_USAGE(option_selected, env.execute_ioctl); break; case 'm': if (env.execute_page_fault) { @@ -425,6 +422,8 @@ static int determineEventType(struct env *env) { env->event_type = IRQ_INJECT; } else if (env->execute_hypercall) { env->event_type = HYPERCALL; + } else if (env->execute_ioctl) { + env->event_type = IOCTL; } else { env->event_type = NONE_TYPE; // 或者根据需要设置一个默认的事件类型 } @@ -472,7 +471,7 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { } case PAGE_FAULT: { // 使用 e->page_fault_data 访问 PAGE_FAULT 特有成员 - printf("%-18.6f %-15s %-10u %-12llx %-6u %-10.4f ", timestamp_ms, + printf("%-18.6f %-15s %-10u %-14llx %-6u %-10.4f ", timestamp_ms, e->process.comm, e->process.pid, e->page_fault_data.addr, e->page_fault_data.count, NS_TO_US_WITH_DECIMAL(e->page_fault_data.delay)); @@ -593,7 +592,7 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { fprintf(output, "%-18.6f %-15s %-10d %-10d %-10s %-11llu", timestamp_ms, e->process.comm, e->process.pid, e->hypercall_data.vcpu_id, - getHypercallName(e->hypercall_data.hc_nr), + getName(e->hypercall_data.hc_nr, HYPERCALL), e->hypercall_data.hypercalls); if (e->hypercall_data.hc_nr == 5) { fprintf(output, "apic_id:%llu\n", e->hypercall_data.a1); @@ -621,6 +620,9 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { fclose(output); break; } + case IOCTL: { + break; + } default: // 处理未知事件类型 break; @@ -653,8 +655,8 @@ static int print_event_head(struct env *env) { break; case PAGE_FAULT: printf("%-18s %-15s %-10s %-12s %-6s %-10s %-20s %-17s %-10s %s\n", - "TIME(ms)", "COMM", "PID", "ADDRESS", "COUNT", "DELAY(us)", - "HVA", "PFN", "MEM_SLOTID", "ERROR_TYPE"); + "TIME(ms)", "COMM", "PID", "(f(GPA)m(GFN))", "COUNT", + "DELAY(us)", "HVA", "PFN", "MEM_SLOTID", "ERROR_TYPE"); break; case IRQCHIP: printf("%-18s %-15s %-10s %-10s %-14s %-10s %-10s\n", "TIME(ms)", @@ -678,6 +680,10 @@ static int print_event_head(struct env *env) { fclose(output); break; } + case IOCTL: { + printf("wait....\n"); + break; + } default: // Handle default case or display an error message break; @@ -701,11 +707,11 @@ static void set_disable_load(struct kvm_watcher_bpf *skel) { env.execute_mark_page_dirty ? true : false); bpf_program__set_autoload(skel->progs.tp_page_fault, env.execute_page_fault ? true : false); - bpf_program__set_autoload(skel->progs.fexit_direct_page_fault, + bpf_program__set_autoload(skel->progs.fexit_tdp_page_fault, env.execute_page_fault ? true : false); bpf_program__set_autoload(skel->progs.fentry_kvm_mmu_page_fault, env.mmio_page_fault ? true : false); - bpf_program__set_autoload(skel->progs.fexit_handle_mmio_page_fault, + bpf_program__set_autoload(skel->progs.tp_handle_mmio_page_fault, env.mmio_page_fault ? true : false); bpf_program__set_autoload(skel->progs.fentry_kvm_pic_set_irq, env.execute_irqchip ? true : false); @@ -725,6 +731,23 @@ static void set_disable_load(struct kvm_watcher_bpf *skel) { env.execute_irq_inject ? true : false); bpf_program__set_autoload(skel->progs.fentry_emulate_hypercall, env.execute_hypercall ? true : false); + bpf_program__set_autoload(skel->progs.tp_ioctl, + env.execute_ioctl ? true : false); +} + +// 函数不接受参数,返回一个静态分配的字符串 +const char *getCurrentTimeFormatted() { + static char ts[32]; // 静态分配,每次调用都会覆盖 + time_t t; + struct tm *tm; + + time(&t); + tm = localtime(&t); + + // 格式化时间到静态分配的字符串中 + strftime(ts, sizeof(ts), "%H:%M:%S", tm); + + return ts; // 返回指向静态字符串的指针 } int print_hc_map(struct kvm_watcher_bpf *skel) { @@ -734,12 +757,6 @@ int print_hc_map(struct kvm_watcher_bpf *skel) { struct hc_key lookup_key = {}; struct hc_key next_key = {}; struct hc_value hc_value = {}; - struct tm *tm; - char ts[32]; - time_t t; - time(&t); - tm = localtime(&t); - strftime(ts, sizeof(ts), "%H:%M:%S", tm); int first_run = 1; // Iterate over the map while (!bpf_map_get_next_key(fd, &lookup_key, &next_key)) { @@ -749,7 +766,7 @@ int print_hc_map(struct kvm_watcher_bpf *skel) { "--------------------------------------------------------------" "----------" "\n"); - printf("TIME:%s\n", ts); + printf("TIME:%s\n", getCurrentTimeFormatted()); printf("%-12s %-12s %-12s %-12s %-12s\n", "PID", "VCPU_ID", "NAME", "COUNTS", "HYPERCALLS"); } @@ -760,8 +777,8 @@ int print_hc_map(struct kvm_watcher_bpf *skel) { return -1; } printf("%-12d %-12d %-12s %-12d %-12lld\n", next_key.pid, - next_key.vcpu_id, getHypercallName(next_key.nr), hc_value.counts, - hc_value.hypercalls); + next_key.vcpu_id, getName(next_key.nr, HYPERCALL), + hc_value.counts, hc_value.hypercalls); // // Move to the next key lookup_key = next_key; } @@ -835,12 +852,6 @@ int print_exit_map(struct kvm_watcher_bpf *skel) { int err; struct exit_key lookup_key = {}; struct exit_key next_key = {}; - struct tm *tm; - char ts[32]; - time_t t; - time(&t); - tm = localtime(&t); - strftime(ts, sizeof(ts), "%H:%M:%S", tm); int first_run = 1; struct exit_key keys[8192]; struct exit_value values[8192]; @@ -851,7 +862,7 @@ int print_exit_map(struct kvm_watcher_bpf *skel) { for (int i = 0; i < count; i++) { if (first_run) { first_run = 0; - printf("\nTIME:%s\n", ts); + printf("\nTIME:%s\n", getCurrentTimeFormatted()); printf("%-12s %-12s %-12s %-12s %-12s %-12s %-12s\n", "pid", "tid", "total_time", "max_time", "min_time", "counts", "reason"); printf( @@ -873,13 +884,13 @@ int print_exit_map(struct kvm_watcher_bpf *skel) { NS_TO_MS_WITH_DECIMAL(values[i].total_time), NS_TO_MS_WITH_DECIMAL(values[i].max_time), NS_TO_MS_WITH_DECIMAL(values[i].min_time), values[i].count, - getExitReasonName(keys[i].reason)); + getName(keys[i].reason, EXIT)); } else if (tid == keys[i].tid) { printf("%25s %-12.4f %-12.4f %-12.4f %-12u %-12s\n", "", NS_TO_MS_WITH_DECIMAL(values[i].total_time), NS_TO_MS_WITH_DECIMAL(values[i].max_time), NS_TO_MS_WITH_DECIMAL(values[i].min_time), values[i].count, - getExitReasonName(keys[i].reason)); + getName(keys[i].reason, EXIT)); } } // clear the maps @@ -898,7 +909,7 @@ int print_exit_map(struct kvm_watcher_bpf *skel) { void print_map_and_check_error(int (*print_func)(struct kvm_watcher_bpf *), struct kvm_watcher_bpf *skel, const char *map_name, int err) { - OUTPUT_INTERVAL(OUTPUT_INTERVAL_SECONDS); + OUTPUT_INTERVAL(2); print_func(skel); if (err < 0) { printf("Error printing %s map: %d\n", map_name, err);