1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2022 Oxide Computer Company
14  */
15 
16 #include "payload_common.h"
17 #include "payload_utils.h"
18 
19 int
leaf_cmp(const uint32_t * a,const uint32_t * b)20 leaf_cmp(const uint32_t *a, const uint32_t *b)
21 {
22 	return (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]);
23 }
24 
25 const uint32_t expected_base[] = { 5, 0x74737552, 0x65646978, 0x4f206465 };
26 
27 struct test_case {
28 	uint32_t func;
29 	uint32_t idx;
30 	uint32_t val_eax;
31 	int fallback;
32 };
33 
34 const struct test_case cases[] = {
35 	/* basic leaf match */
36 	{
37 		.func = 1,
38 		.val_eax = 0x100,
39 	},
40 	/* index matching */
41 	{
42 		.func = 3,
43 		.idx = 0,
44 		.val_eax = 0x300,
45 	},
46 	{
47 		.func = 3,
48 		.idx = 1,
49 		.val_eax = 0x301,
50 	},
51 	/* leaf match with hole */
52 	{
53 		.func = 4,
54 		.idx = 0,
55 		.val_eax = 0x400,
56 	},
57 	{
58 		.func = 4,
59 		.idx = 2,
60 		.val_eax = 0x402,
61 	},
62 	/* last std leaf */
63 	{
64 		.func = 5,
65 		.val_eax = 0x5,
66 	},
67 
68 	/* invalid leaf */
69 	{
70 		.func = 2,
71 		.val_eax = 0,
72 	},
73 	/* invalid index */
74 	{
75 		.func = 3,
76 		.idx = 2,
77 		.val_eax = 0,
78 	},
79 	{
80 		.func = 4,
81 		.idx = 1,
82 		.val_eax = 0x0,
83 	},
84 	{
85 		.func = 4,
86 		.idx = 0xffff,
87 		.val_eax = 0x0,
88 	},
89 
90 	/* basic extd leaf match */
91 	{
92 		.func = 0x80000000,
93 		.val_eax = 0x80000001,
94 	},
95 	/* basic extd index match */
96 	{
97 		.func = 0x80000001,
98 		.idx = 0,
99 		.val_eax = 0x8000,
100 	},
101 	{
102 		.func = 0x80000001,
103 		.idx = 1,
104 		.val_eax = 0x8001,
105 	},
106 	/* zeroed for invalid index */
107 	{
108 		.func = 0x80000001,
109 		.idx = 5,
110 		.val_eax = 0,
111 	},
112 
113 	/* fallback beyond std leaf */
114 	{
115 		.func = 6,
116 		.fallback = 1,
117 	},
118 	/* fallback beyond extd leaf */
119 	{
120 		.func = 0x80000002,
121 		.fallback = 1,
122 	},
123 };
124 #define	NCASES	(sizeof (cases) / sizeof (cases[0]))
125 
126 void
do_test(int intel_fallback)127 do_test(int intel_fallback)
128 {
129 	uint32_t regs[4];
130 	uint32_t expected_fallback[4] = { 0 };
131 
132 	cpuid(0, 0, regs);
133 	if (!leaf_cmp(regs, expected_base)) {
134 		outb(IOP_TEST_RESULT, TEST_RESULT_FAIL);
135 	}
136 
137 	if (intel_fallback) {
138 		cpuid(regs[0], 0, expected_fallback);
139 	}
140 
141 	for (uint_t i = 0; i < NCASES; i++) {
142 		cpuid(cases[i].func, cases[i].idx, regs);
143 		if (cases[i].fallback != 0) {
144 			if (!leaf_cmp(regs, expected_fallback)) {
145 				outb(IOP_TEST_RESULT, TEST_RESULT_FAIL);
146 			}
147 		} else {
148 			if (regs[0] != cases[i].val_eax) {
149 				outb(IOP_TEST_RESULT, TEST_RESULT_FAIL);
150 			}
151 		}
152 	}
153 }
154 
155 void
start(void)156 start(void)
157 {
158 	/* Check results expecting Intel-style fallback */
159 	do_test(1);
160 
161 	/* Notify userspace component to change fallback style */
162 	outl(IOP_TEST_VALUE, 0);
163 
164 	/* Check results expecting AMD-style fallback */
165 	do_test(0);
166 
167 	/* If all is well by this point, indicate success */
168 	outb(IOP_TEST_RESULT, TEST_RESULT_PASS);
169 }
170