1 /*
2 * virarch.c: architecture handling
3 *
4 * Copyright (C) 2012 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include <config.h>
23
24 #ifdef WIN32
25 # define WIN32_LEAN_AND_MEAN
26 # include <windows.h>
27 #else
28 # include <sys/utsname.h>
29 #endif
30
31 #include "virlog.h"
32 #include "virarch.h"
33
34 VIR_LOG_INIT("util.arch");
35
36 /* The canonical names are used in XML documents. ie ABI sensitive */
37 static const struct virArchData {
38 const char *name;
39 unsigned int wordsize;
40 virArchEndian endian;
41 } virArchData[] = {
42 { "none", 0, VIR_ARCH_LITTLE_ENDIAN },
43 { "alpha", 64, VIR_ARCH_BIG_ENDIAN },
44 { "armv6l", 32, VIR_ARCH_LITTLE_ENDIAN },
45 { "armv7l", 32, VIR_ARCH_LITTLE_ENDIAN },
46 { "armv7b", 32, VIR_ARCH_BIG_ENDIAN },
47
48 { "aarch64", 64, VIR_ARCH_LITTLE_ENDIAN },
49 { "cris", 32, VIR_ARCH_LITTLE_ENDIAN },
50 { "i686", 32, VIR_ARCH_LITTLE_ENDIAN },
51 { "ia64", 64, VIR_ARCH_LITTLE_ENDIAN },
52 { "lm32", 32, VIR_ARCH_BIG_ENDIAN },
53
54 { "m68k", 32, VIR_ARCH_BIG_ENDIAN },
55 { "microblaze", 32, VIR_ARCH_BIG_ENDIAN },
56 { "microblazeel", 32, VIR_ARCH_LITTLE_ENDIAN},
57 { "mips", 32, VIR_ARCH_BIG_ENDIAN },
58 { "mipsel", 32, VIR_ARCH_LITTLE_ENDIAN },
59
60 { "mips64", 64, VIR_ARCH_BIG_ENDIAN },
61 { "mips64el", 64, VIR_ARCH_LITTLE_ENDIAN },
62 { "openrisc", 32, VIR_ARCH_BIG_ENDIAN },
63 { "parisc", 32, VIR_ARCH_BIG_ENDIAN },
64 { "parisc64", 64, VIR_ARCH_BIG_ENDIAN },
65
66 { "ppc", 32, VIR_ARCH_BIG_ENDIAN },
67 { "ppcle", 32, VIR_ARCH_LITTLE_ENDIAN },
68 { "ppc64", 64, VIR_ARCH_BIG_ENDIAN },
69 { "ppc64le", 64, VIR_ARCH_LITTLE_ENDIAN },
70 { "ppcemb", 32, VIR_ARCH_BIG_ENDIAN },
71
72 { "riscv32", 32, VIR_ARCH_LITTLE_ENDIAN },
73 { "riscv64", 64, VIR_ARCH_LITTLE_ENDIAN },
74 { "s390", 32, VIR_ARCH_BIG_ENDIAN },
75 { "s390x", 64, VIR_ARCH_BIG_ENDIAN },
76 { "sh4", 32, VIR_ARCH_LITTLE_ENDIAN },
77
78 { "sh4eb", 64, VIR_ARCH_BIG_ENDIAN },
79 { "sparc", 32, VIR_ARCH_BIG_ENDIAN },
80 { "sparc64", 64, VIR_ARCH_BIG_ENDIAN },
81 { "unicore32", 32, VIR_ARCH_LITTLE_ENDIAN },
82 { "x86_64", 64, VIR_ARCH_LITTLE_ENDIAN },
83
84 { "xtensa", 32, VIR_ARCH_LITTLE_ENDIAN },
85 { "xtensaeb", 32, VIR_ARCH_BIG_ENDIAN },
86 };
87
88 G_STATIC_ASSERT(G_N_ELEMENTS(virArchData) == VIR_ARCH_LAST);
89
90
91 /**
92 * virArchGetWordSize:
93 * @arch: the CPU architecture
94 *
95 * Return the wordsize of the CPU architecture (32 or 64)
96 */
virArchGetWordSize(virArch arch)97 unsigned int virArchGetWordSize(virArch arch)
98 {
99 if (arch >= VIR_ARCH_LAST)
100 arch = VIR_ARCH_NONE;
101
102 return virArchData[arch].wordsize;
103 }
104
105 /**
106 * virArchGetEndian:
107 * @arch: the CPU architecture
108 *
109 * Return the endian-ness of the CPU architecture
110 * (VIR_ARCH_LITTLE_ENDIAN or VIR_ARCH_BIG_ENDIAN)
111 */
virArchGetEndian(virArch arch)112 virArchEndian virArchGetEndian(virArch arch)
113 {
114 if (arch >= VIR_ARCH_LAST)
115 arch = VIR_ARCH_NONE;
116
117 return virArchData[arch].endian;
118 }
119
120 /**
121 * virArchToString:
122 * @arch: the CPU architecture
123 *
124 * Return the string name of the architecture
125 */
virArchToString(virArch arch)126 const char *virArchToString(virArch arch)
127 {
128 if (arch >= VIR_ARCH_LAST)
129 arch = VIR_ARCH_NONE;
130
131 return virArchData[arch].name;
132 }
133
134
135 /**
136 * virArchFromString:
137 * @archstr: the CPU architecture string
138 *
139 * Return the architecture matching @archstr,
140 * defaulting to VIR_ARCH_NONE if unidentified
141 */
virArchFromString(const char * archstr)142 virArch virArchFromString(const char *archstr)
143 {
144 size_t i;
145 for (i = 1; i < VIR_ARCH_LAST; i++) {
146 if (STREQ(virArchData[i].name, archstr))
147 return i;
148 }
149
150 VIR_DEBUG("Unknown arch %s", archstr);
151 return VIR_ARCH_NONE;
152 }
153
154
155 /**
156 * virArchFromHost:
157 *
158 * Return the host architecture. Prefer this to the
159 * uname 'machine' field, since this will canonicalize
160 * architecture names like 'amd64' into 'x86_64'.
161 */
162 #ifdef WIN32
163
164 /*
165 * Missing in ming64 headers 6.0.0, but defined as '12' in:
166 *
167 * https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
168 */
169 # ifndef PROCESSOR_ARCHITECTURE_ARM64
170 # define PROCESSOR_ARCHITECTURE_ARM64 12
171 # endif
172
virArchFromHost(void)173 virArch virArchFromHost(void)
174 {
175 SYSTEM_INFO info;
176
177 GetSystemInfo(&info);
178
179 switch (info.wProcessorArchitecture) {
180 case PROCESSOR_ARCHITECTURE_AMD64:
181 return VIR_ARCH_X86_64;
182 case PROCESSOR_ARCHITECTURE_IA64:
183 return VIR_ARCH_ITANIUM;
184 case PROCESSOR_ARCHITECTURE_INTEL:
185 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
186 return VIR_ARCH_I686;
187 case PROCESSOR_ARCHITECTURE_MIPS:
188 return VIR_ARCH_MIPS;
189 case PROCESSOR_ARCHITECTURE_ALPHA:
190 return VIR_ARCH_ALPHA;
191 case PROCESSOR_ARCHITECTURE_PPC:
192 return VIR_ARCH_PPC;
193 case PROCESSOR_ARCHITECTURE_SHX:
194 return VIR_ARCH_SH4;
195 case PROCESSOR_ARCHITECTURE_ARM:
196 return VIR_ARCH_ARMV7L;
197 case PROCESSOR_ARCHITECTURE_ARM64:
198 return VIR_ARCH_AARCH64;
199 default:
200 VIR_WARN("Unknown host arch '%d', report to libvir-list@redhat.com",
201 info.wProcessorArchitecture);
202 return VIR_ARCH_NONE;
203 }
204 }
205 #else /* !WIN32 */
virArchFromHost(void)206 virArch virArchFromHost(void)
207 {
208 struct utsname ut;
209 virArch arch;
210
211 uname(&ut);
212
213 /* Some special cases we need to handle first
214 * for non-canonical names */
215 if (strlen(ut.machine) == 4 &&
216 ut.machine[0] == 'i' &&
217 ut.machine[2] == '8' &&
218 ut.machine[3] == '6' &&
219 ut.machine[4] == '\0') {
220 arch = VIR_ARCH_I686;
221 } else if (STREQ(ut.machine, "amd64")) {
222 arch = VIR_ARCH_X86_64;
223 } else if (STREQ(ut.machine, "arm64")) {
224 arch = VIR_ARCH_AARCH64;
225 } else {
226 /* Otherwise assume the canonical name */
227 if ((arch = virArchFromString(ut.machine)) == VIR_ARCH_NONE) {
228 VIR_WARN("Unknown host arch %s, report to libvir-list@redhat.com",
229 ut.machine);
230 }
231 }
232
233 VIR_DEBUG("Mapped %s to %d (%s)",
234 ut.machine, arch, virArchToString(arch));
235
236 return arch;
237 }
238 #endif /* !WIN32 */
239