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