• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Error Record Serialization Table(ERST) is used to save and retrieve hardware
3  * error information to and from a persistent store, such as flash or NVRAM.
4  *
5  * This test case is used to test ERST operation including read/write/clean.
6  * To be sure of loading erst-dbg module before executing this test.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public
10  * License as published by the Free Software Foundation; version 2.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should find a copy of v2 of the GNU General Public License somewhere
18  * on your Linux system; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  * Copyright (C) 2011, Intel Corp.
22  * Author: Chen Gong <gong.chen@intel.com>
23  *
24  * Original written by Huang Ying <ying.huang@intel.com>
25  * Updated by Chen Gong <gong.chen@intel.com>
26  *
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <sys/ioctl.h>
36 
37 #include "cper.h"
38 
39 #define ERST_DEV "/dev/erst_dbg"
40 
41 #define APEI_ERST_CLEAR_RECORD         _IOW('E', 1, u64)
42 #define APEI_ERST_GET_RECORD_COUNT     _IOR('E', 2, u32)
43 
44 #define CPER_CREATOR_LINUX						\
45 	LGUID(0x94DB0E05, 0xEE60, 0x42D8, 0x91, 0xA5, 0xC6, 0xC0,	\
46 			0x02, 0x41, 0x6C, 0x6A)
47 
48 #define ERROR_EXIT_ON(check, fmt, x...)					\
49 	do {								\
50 		if (check)						\
51 			error_exit(fmt, ## x);				\
52 	} while (0)
53 
error_exit(char * fmt,...)54 void error_exit(char *fmt, ...)
55 {
56 	va_list ap;
57 
58 	fprintf(stderr, "Error: ");
59 	va_start(ap, fmt);
60 	vfprintf(stderr, fmt, ap);
61 	va_end(ap);
62 
63 	if (errno)
64 		fprintf(stderr, ", errno: %d (%s)\n", errno, strerror(errno));
65 	else
66 		fprintf(stderr, "\n");
67 	exit(-1);
68 }
69 
inject(int fd,u64 record_id)70 void inject(int fd, u64 record_id)
71 {
72 	int rc;
73 	unsigned int len;
74 	struct cper_record_header *rcd_hdr;
75 	struct cper_section_descriptor *sec_hdr;
76 	struct cper_sec_mem_err *mem_err;
77 
78 	len = sizeof(*rcd_hdr) + sizeof(*sec_hdr) + sizeof(*mem_err);
79 	printf("sizes: %lu, %lu, %lu\n", sizeof(*rcd_hdr), sizeof(*sec_hdr),
80 			sizeof(*mem_err));
81 	rcd_hdr = malloc(len);
82 	ERROR_EXIT_ON(!rcd_hdr, "Can not alloc mem");
83 
84 #define LE 0
85 
86 	sec_hdr = (void *)(rcd_hdr + 1);
87 	mem_err = (void *)(sec_hdr + 1);
88 
89 	memset(rcd_hdr, 0, sizeof(*rcd_hdr));
90 #if 0
91 	memcpy(rcd_hdr->signature, "REPC", 4);
92 #else
93 	memcpy(rcd_hdr->signature, "CPER", 4);
94 #endif
95 	rcd_hdr->revision = 0x0100;
96 	rcd_hdr->signature_end = 0xffffffff;
97 	rcd_hdr->error_severity = CPER_SER_FATAL;
98 	rcd_hdr->validation_bits = 0;
99 	rcd_hdr->creator_id = CPER_CREATOR_LINUX;
100 	rcd_hdr->notification_type = CPER_NOTIFY_NMI;
101 	rcd_hdr->section_count = 1;
102 	rcd_hdr->record_length = len;
103 	rcd_hdr->record_id = record_id;
104 #if LE
105 	memcpy(&rcd_hdr->persistence_information, "RE", 2);
106 #else
107 	memcpy(&rcd_hdr->persistence_information, "ER", 2);
108 #endif
109 
110 	memset(sec_hdr, 0, sizeof(*sec_hdr));
111 	sec_hdr->section_offset = (void *)mem_err - (void *)rcd_hdr;
112 	sec_hdr->section_length = sizeof(*mem_err);
113 	sec_hdr->revision = 0x0100;
114 	sec_hdr->validation_bits = 0;
115 	sec_hdr->flags = 0;
116 	sec_hdr->section_type = CPER_SEC_PLATFORM_MEM;
117 	sec_hdr->section_severity = CPER_SER_FATAL;
118 
119 	memset(mem_err, 0, sizeof(*mem_err));
120 	mem_err->validation_bits = 0x6;
121 	mem_err->physical_addr = 0x2000;
122 	mem_err->physical_addr_mask = ~0xfffULL;
123 
124 	rc = write(fd, rcd_hdr, len);
125 	ERROR_EXIT_ON(rc != len, "Error inject: %d", rc);
126 
127 	free(rcd_hdr);
128 }
129 
130 #define POLL_BUF_SIZ           (1024 * 1024)
131 
poll(int fd)132 int poll(int fd)
133 {
134 	int rc;
135 	struct cper_record_header *rcd_hdr;
136 	struct cper_section_descriptor *sec_hdr;
137 	struct cper_sec_mem_err *mem_err;
138 
139 	rcd_hdr = malloc(POLL_BUF_SIZ);
140 	ERROR_EXIT_ON(!rcd_hdr, "Can not alloc mem");
141 
142 	rc = read(fd, rcd_hdr, POLL_BUF_SIZ);
143 	ERROR_EXIT_ON(rc < 0, "Error poll: %d", rc);
144 
145 	sec_hdr = (void *)(rcd_hdr + 1);
146 	mem_err = (void *)(sec_hdr + 1);
147 
148 	printf("rc: %d\n", rc);
149 
150 	printf("rcd sig: %4s\n", rcd_hdr->signature);
151 	printf("rcd id: 0x%llx\n", rcd_hdr->record_id);
152 
153 	free(rcd_hdr);
154 
155 	return rc;
156 }
157 
clear(int fd,u64 record_id)158 void clear(int fd, u64 record_id)
159 {
160 	int rc;
161 
162 	printf("clear an error record: id = 0x%llx\n", record_id);
163 
164 	rc = ioctl(fd, APEI_ERST_CLEAR_RECORD, &record_id);
165 	ERROR_EXIT_ON(rc, "Error clear: %d", rc);
166 }
167 
get_record_count(int fd,u32 * record_count)168 void get_record_count(int fd, u32 *record_count)
169 {
170 	int rc;
171 	rc = ioctl(fd, APEI_ERST_GET_RECORD_COUNT, record_count);
172 	ERROR_EXIT_ON(rc, "Error get record count: %d", rc);
173 
174 	printf("total error record count: %u\n", *record_count);
175 }
176 
177 enum {
178 	ERST_INJECT,
179 	ERST_POLL,
180 	ERST_CLEAR,
181 	ERST_COUNT,
182 	ERST_MAX = 255
183 };
184 
usage()185 void usage()
186 {
187 	printf("Usage: ./erst-inject [option] <id>\n");
188 	printf("PAY ATTENTION, <id> is hexadecimal.\n");
189 	printf("\tp\treturn all error records in the ERST\n");
190 	printf("\ti\twrite an error record to be persisted into one item with <id>\n");
191 	printf("\tc\tclean specific error record with <id>\n");
192 	printf("\tn\treturn error records count in the ERST\n");
193 	printf("\nExample:\t ./erst-inject -p\n");
194 	printf("\t\t ./erst-inject -i 0x1234567\n");
195 	printf("\t\t ./erst-inject -c 5050\n");
196 	printf("\t\t ./erst-inject -n\n");
197 }
198 
main(int argc,char * argv[])199 int main(int argc, char *argv[])
200 {
201 	int fd;
202 	int todo = ERST_MAX;
203 	int opt;
204 	u64 record_id = 0x12345678;
205 	u32 record_count;
206 
207 	if (argc == 1) {
208 		usage();
209 		exit(0);
210 	}
211 
212 	while ((opt = getopt(argc, argv, "pi:c:n")) != -1) {
213 		switch (opt) {
214 		case 'p':
215 			todo = ERST_POLL;
216 			break;
217 		case 'i':
218 			todo = ERST_INJECT;
219 			record_id = strtoull(optarg, NULL, 16);
220 			break;
221 		case 'c':
222 			todo = ERST_CLEAR;
223 			record_id = strtoull(optarg, NULL, 16);
224 			break;
225 		case 'n':
226 			todo = ERST_COUNT;
227 			break;
228 		}
229 	}
230 
231 	fd = open(ERST_DEV, O_RDWR);
232 	ERROR_EXIT_ON(fd < 0, "Can not open dev file");
233 
234 	switch (todo) {
235 	case ERST_INJECT:
236 		inject(fd, record_id);
237 		break;
238 	case ERST_POLL:
239 		while (poll(fd));
240 		break;
241 	case ERST_CLEAR:
242 		clear(fd, record_id);
243 		break;
244 	case ERST_COUNT:
245 		get_record_count(fd, &record_count);
246 		break;
247 	case ERST_MAX:
248 		usage();
249 		break;
250 	}
251 
252 	close(fd);
253 
254 	return 0;
255 }
256