| // SPDX-License-Identifier: GPL-2.0 |
| |
| /* |
| * Copyright (C) 2015 Intel Corporation |
| * Author: Tony Luck |
| */ |
| |
| #include "einj.h" |
| |
| struct error_type error_types[] = { |
| { 0x00000001, "Processor Correctable",}, |
| { 0x00000002, "Processor Uncorrectable non-fatal",}, |
| { 0x00000004, "Processor Uncorrectable fatal",}, |
| { 0x00000008, "Memory Correctable",}, |
| { 0x00000010, "Memory Uncorrectable non-fatal",}, |
| { 0x00000020, "Memory Uncorrectable fatal",}, |
| { 0x00000040, "PCI Express Correctable",}, |
| { 0x00000080, "PCI Express Uncorrectable non-fatal",}, |
| { 0x00000100, "PCI Express Uncorrectable fatal",}, |
| { 0x00000200, "Platform Correctabl",}, |
| { 0x00000400, "Platform Uncorrectable non-fatal",}, |
| { 0x00000800, "Platform Uncorrectable fatal",}, |
| { -1, NULL } |
| }; |
| |
| int check_errortype_available(char *file, unsigned long long val) |
| { |
| FILE *fp; |
| int ret = -1; |
| unsigned long long available_error_type; |
| |
| if (strcmp(file, EINJ_ETYPE) != 0) |
| return 0; |
| |
| fp = fopen(EINJ_ETYPE_AVAILABLE, "r"); |
| if (!fp) { |
| fprintf(stderr, "%s: cannot open '%s'\n", progname, file); |
| exit(1); |
| } |
| |
| while (fscanf(fp, "%llx%*[^\n]", &available_error_type) == 1) { |
| if (val == available_error_type) { |
| ret = 0; |
| break; |
| } |
| } |
| |
| fclose(fp); |
| return ret; |
| } |
| |
| void wfile(char *file, unsigned long long val) |
| { |
| FILE *fp; |
| |
| if (check_errortype_available(file, val) != 0) { |
| fprintf(stderr, "%s: no support for error type: 0x%llx\n", progname, val); |
| exit(1); |
| } |
| |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) |
| if (!strcmp(file, EINJ_FLAGS)) |
| return; |
| #endif |
| |
| fp = fopen(file, "w"); |
| if (fp == NULL) { |
| fprintf(stderr, "%s: cannot open '%s'\n", progname, file); |
| exit(1); |
| } |
| fprintf(fp, "0x%llx\n", val); |
| if (fclose(fp) == EOF) { |
| fprintf(stderr, "%s: write error on '%s'\n", progname, file); |
| exit(1); |
| } |
| } |
| |
| int is_einj_support(void) |
| { |
| if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1) { |
| fprintf(stderr, "%s: Error injection not supported, check your BIOS settings\n", progname); |
| return 0; |
| } |
| if (access(EINJ_NOTRIGGER, R_OK|W_OK) == -1) { |
| fprintf(stderr, "%s: Is the einj.ko module loaded?\n", progname); |
| return 0; |
| } |
| return 1; |
| } |
| |
| int is_privileged(void) |
| { |
| if (getuid() != 0) { |
| fprintf(stderr, "%s: must be root to run error injection tests\n", progname); |
| return 0; |
| } |
| return 1; |
| } |
| |
| void inject_mem_uc(unsigned long long addr, void *vaddr, int notrigger) |
| { |
| PRINT_INJECTING; |
| |
| if (Sflag) { |
| vaddr = (void *)((long)vaddr & ~(pagesize - 1)); |
| madvise(vaddr, pagesize, MADV_HWPOISON); |
| return; |
| } |
| |
| wfile(EINJ_ETYPE, 0x10); |
| wfile(EINJ_ADDR, addr); |
| wfile(EINJ_MASK, ~0x0ul); |
| wfile(EINJ_FLAGS, 2); |
| wfile(EINJ_NOTRIGGER, notrigger); |
| wfile(EINJ_DOIT, 1); |
| } |
| |
| char *lookup_type_name(unsigned long long type) |
| { |
| struct error_type *t; |
| |
| for (t = error_types; t->type_name; t++) |
| if (t->type == type) |
| return t->type_name; |
| fprintf(stderr, "%s: unknown type '%x'\n", progname, type); |
| exit(1); |
| } |