xref: /openbmc/linux/arch/x86/boot/cpu.c (revision f0be6c6a)
196ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
296ae6ea0SThomas Gleixner  *
396ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
4f0be6c6aSH. Peter Anvin  *   Copyright 2007-2008 rPath, Inc. - All Rights Reserved
596ae6ea0SThomas Gleixner  *
696ae6ea0SThomas Gleixner  *   This file is part of the Linux kernel, and is made available under
796ae6ea0SThomas Gleixner  *   the terms of the GNU General Public License version 2.
896ae6ea0SThomas Gleixner  *
996ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
1096ae6ea0SThomas Gleixner 
1196ae6ea0SThomas Gleixner /*
12f0be6c6aSH. Peter Anvin  * arch/x86/boot/cpu.c
1396ae6ea0SThomas Gleixner  *
1496ae6ea0SThomas Gleixner  * Check for obligatory CPU features and abort if the features are not
1596ae6ea0SThomas Gleixner  * present.
1696ae6ea0SThomas Gleixner  */
1796ae6ea0SThomas Gleixner 
1896ae6ea0SThomas Gleixner #include "boot.h"
1996ae6ea0SThomas Gleixner #include "bitops.h"
2096ae6ea0SThomas Gleixner #include <asm/cpufeature.h>
2196ae6ea0SThomas Gleixner 
22f0be6c6aSH. Peter Anvin #include "cpustr.h"
23f0be6c6aSH. Peter Anvin 
2496ae6ea0SThomas Gleixner static char *cpu_name(int level)
2596ae6ea0SThomas Gleixner {
2696ae6ea0SThomas Gleixner 	static char buf[6];
2796ae6ea0SThomas Gleixner 
2896ae6ea0SThomas Gleixner 	if (level == 64) {
2996ae6ea0SThomas Gleixner 		return "x86-64";
3096ae6ea0SThomas Gleixner 	} else {
3196ae6ea0SThomas Gleixner 		sprintf(buf, "i%d86", level);
3296ae6ea0SThomas Gleixner 		return buf;
3396ae6ea0SThomas Gleixner 	}
3496ae6ea0SThomas Gleixner }
3596ae6ea0SThomas Gleixner 
3696ae6ea0SThomas Gleixner int validate_cpu(void)
3796ae6ea0SThomas Gleixner {
3896ae6ea0SThomas Gleixner 	u32 *err_flags;
3996ae6ea0SThomas Gleixner 	int cpu_level, req_level;
40f0be6c6aSH. Peter Anvin 	const unsigned char *msg_strs;
4196ae6ea0SThomas Gleixner 
4296ae6ea0SThomas Gleixner 	check_cpu(&cpu_level, &req_level, &err_flags);
4396ae6ea0SThomas Gleixner 
4496ae6ea0SThomas Gleixner 	if (cpu_level < req_level) {
4596ae6ea0SThomas Gleixner 		printf("This kernel requires an %s CPU, ",
4696ae6ea0SThomas Gleixner 		       cpu_name(req_level));
4796ae6ea0SThomas Gleixner 		printf("but only detected an %s CPU.\n",
4896ae6ea0SThomas Gleixner 		       cpu_name(cpu_level));
4996ae6ea0SThomas Gleixner 		return -1;
5096ae6ea0SThomas Gleixner 	}
5196ae6ea0SThomas Gleixner 
5296ae6ea0SThomas Gleixner 	if (err_flags) {
5396ae6ea0SThomas Gleixner 		int i, j;
5496ae6ea0SThomas Gleixner 		puts("This kernel requires the following features "
5596ae6ea0SThomas Gleixner 		     "not present on the CPU:\n");
5696ae6ea0SThomas Gleixner 
57f0be6c6aSH. Peter Anvin 		msg_strs = (const unsigned char *)x86_cap_strs;
58f0be6c6aSH. Peter Anvin 
5996ae6ea0SThomas Gleixner 		for (i = 0; i < NCAPINTS; i++) {
6096ae6ea0SThomas Gleixner 			u32 e = err_flags[i];
6196ae6ea0SThomas Gleixner 
6296ae6ea0SThomas Gleixner 			for (j = 0; j < 32; j++) {
63f0be6c6aSH. Peter Anvin 				int n = (i << 5)+j;
64f0be6c6aSH. Peter Anvin 				if (*msg_strs < n) {
65f0be6c6aSH. Peter Anvin 					/* Skip to the next string */
66f0be6c6aSH. Peter Anvin 					do {
67f0be6c6aSH. Peter Anvin 						msg_strs++;
68f0be6c6aSH. Peter Anvin 					} while (*msg_strs);
69f0be6c6aSH. Peter Anvin 					msg_strs++;
70f0be6c6aSH. Peter Anvin 				}
71f0be6c6aSH. Peter Anvin 				if (e & 1) {
72f0be6c6aSH. Peter Anvin 					if (*msg_strs == n && msg_strs[1])
73f0be6c6aSH. Peter Anvin 						printf("%s ", msg_strs+1);
74f0be6c6aSH. Peter Anvin 					else
7596ae6ea0SThomas Gleixner 						printf("%d:%d ", i, j);
76f0be6c6aSH. Peter Anvin 				}
7796ae6ea0SThomas Gleixner 				e >>= 1;
7896ae6ea0SThomas Gleixner 			}
7996ae6ea0SThomas Gleixner 		}
8096ae6ea0SThomas Gleixner 		putchar('\n');
8196ae6ea0SThomas Gleixner 		return -1;
8296ae6ea0SThomas Gleixner 	} else {
8396ae6ea0SThomas Gleixner 		return 0;
8496ae6ea0SThomas Gleixner 	}
8596ae6ea0SThomas Gleixner }
86