xref: /dragonfly/sys/dev/virtual/nvmm/x86/nvmm_x86.c (revision 23b2397d)
1 /*	$NetBSD: nvmm_x86.c,v 1.21 2020/09/08 16:58:38 maxv Exp $	*/
2 
3 /*
4  * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
5  * All rights reserved.
6  *
7  * This code is part of the NVMM hypervisor.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <dev/virtual/nvmm/nvmm_compat.h>
32 #include <dev/virtual/nvmm/nvmm.h>
33 #include <dev/virtual/nvmm/nvmm_internal.h>
34 #include <dev/virtual/nvmm/x86/nvmm_x86.h>
35 
36 /*
37  * Code shared between x86-SVM and x86-VMX.
38  */
39 
40 const struct nvmm_x64_state nvmm_x86_reset_state = {
41 	.segs = {
42 		[NVMM_X64_SEG_ES] = {
43 			.selector = 0x0000,
44 			.base = 0x00000000,
45 			.limit = 0xFFFF,
46 			.attrib = {
47 				.type = 3,
48 				.s = 1,
49 				.p = 1,
50 			}
51 		},
52 		[NVMM_X64_SEG_CS] = {
53 			.selector = 0xF000,
54 			.base = 0xFFFF0000,
55 			.limit = 0xFFFF,
56 			.attrib = {
57 				.type = 3,
58 				.s = 1,
59 				.p = 1,
60 			}
61 		},
62 		[NVMM_X64_SEG_SS] = {
63 			.selector = 0x0000,
64 			.base = 0x00000000,
65 			.limit = 0xFFFF,
66 			.attrib = {
67 				.type = 3,
68 				.s = 1,
69 				.p = 1,
70 			}
71 		},
72 		[NVMM_X64_SEG_DS] = {
73 			.selector = 0x0000,
74 			.base = 0x00000000,
75 			.limit = 0xFFFF,
76 			.attrib = {
77 				.type = 3,
78 				.s = 1,
79 				.p = 1,
80 			}
81 		},
82 		[NVMM_X64_SEG_FS] = {
83 			.selector = 0x0000,
84 			.base = 0x00000000,
85 			.limit = 0xFFFF,
86 			.attrib = {
87 				.type = 3,
88 				.s = 1,
89 				.p = 1,
90 			}
91 		},
92 		[NVMM_X64_SEG_GS] = {
93 			.selector = 0x0000,
94 			.base = 0x00000000,
95 			.limit = 0xFFFF,
96 			.attrib = {
97 				.type = 3,
98 				.s = 1,
99 				.p = 1,
100 			}
101 		},
102 		[NVMM_X64_SEG_GDT] = {
103 			.selector = 0x0000,
104 			.base = 0x00000000,
105 			.limit = 0xFFFF,
106 			.attrib = {
107 				.type = 2,
108 				.s = 1,
109 				.p = 1,
110 			}
111 		},
112 		[NVMM_X64_SEG_IDT] = {
113 			.selector = 0x0000,
114 			.base = 0x00000000,
115 			.limit = 0xFFFF,
116 			.attrib = {
117 				.type = 2,
118 				.s = 1,
119 				.p = 1,
120 			}
121 		},
122 		[NVMM_X64_SEG_LDT] = {
123 			.selector = 0x0000,
124 			.base = 0x00000000,
125 			.limit = 0xFFFF,
126 			.attrib = {
127 				.type = 2,
128 				.s = 0,
129 				.p = 1,
130 			}
131 		},
132 		[NVMM_X64_SEG_TR] = {
133 			.selector = 0x0000,
134 			.base = 0x00000000,
135 			.limit = 0xFFFF,
136 			.attrib = {
137 				.type = 3,
138 				.s = 0,
139 				.p = 1,
140 			}
141 		},
142 	},
143 
144 	.gprs = {
145 		[NVMM_X64_GPR_RAX] = 0x00000000,
146 		[NVMM_X64_GPR_RCX] = 0x00000000,
147 		[NVMM_X64_GPR_RDX] = 0x00000600,
148 		[NVMM_X64_GPR_RBX] = 0x00000000,
149 		[NVMM_X64_GPR_RSP] = 0x00000000,
150 		[NVMM_X64_GPR_RBP] = 0x00000000,
151 		[NVMM_X64_GPR_RSI] = 0x00000000,
152 		[NVMM_X64_GPR_RDI] = 0x00000000,
153 		[NVMM_X64_GPR_R8] = 0x00000000,
154 		[NVMM_X64_GPR_R9] = 0x00000000,
155 		[NVMM_X64_GPR_R10] = 0x00000000,
156 		[NVMM_X64_GPR_R11] = 0x00000000,
157 		[NVMM_X64_GPR_R12] = 0x00000000,
158 		[NVMM_X64_GPR_R13] = 0x00000000,
159 		[NVMM_X64_GPR_R14] = 0x00000000,
160 		[NVMM_X64_GPR_R15] = 0x00000000,
161 		[NVMM_X64_GPR_RIP] = 0x0000FFF0,
162 		[NVMM_X64_GPR_RFLAGS] = 0x00000002,
163 	},
164 
165 	.crs = {
166 		[NVMM_X64_CR_CR0] = 0x60000010,
167 		[NVMM_X64_CR_CR2] = 0x00000000,
168 		[NVMM_X64_CR_CR3] = 0x00000000,
169 		[NVMM_X64_CR_CR4] = 0x00000000,
170 		[NVMM_X64_CR_CR8] = 0x00000000,
171 		[NVMM_X64_CR_XCR0] = 0x00000001,
172 	},
173 
174 	.drs = {
175 		[NVMM_X64_DR_DR0] = 0x00000000,
176 		[NVMM_X64_DR_DR1] = 0x00000000,
177 		[NVMM_X64_DR_DR2] = 0x00000000,
178 		[NVMM_X64_DR_DR3] = 0x00000000,
179 		[NVMM_X64_DR_DR6] = 0xFFFF0FF0,
180 		[NVMM_X64_DR_DR7] = 0x00000400,
181 	},
182 
183 	.msrs = {
184 		[NVMM_X64_MSR_EFER] = 0x00000000,
185 		[NVMM_X64_MSR_STAR] = 0x00000000,
186 		[NVMM_X64_MSR_LSTAR] = 0x00000000,
187 		[NVMM_X64_MSR_CSTAR] = 0x00000000,
188 		[NVMM_X64_MSR_SFMASK] = 0x00000000,
189 		[NVMM_X64_MSR_KERNELGSBASE] = 0x00000000,
190 		[NVMM_X64_MSR_SYSENTER_CS] = 0x00000000,
191 		[NVMM_X64_MSR_SYSENTER_ESP] = 0x00000000,
192 		[NVMM_X64_MSR_SYSENTER_EIP] = 0x00000000,
193 		[NVMM_X64_MSR_PAT] = 0x0007040600070406,
194 		[NVMM_X64_MSR_TSC] = 0,
195 	},
196 
197 	.intr = {
198 		.int_shadow = 0,
199 		.int_window_exiting = 0,
200 		.nmi_window_exiting = 0,
201 		.evt_pending = 0,
202 	},
203 
204 	.fpu = {
205 		.fx_cw = 0x0040,
206 		.fx_sw = 0x0000,
207 		.fx_tw = 0x55,
208 		.fx_zero = 0x55,
209 		.fx_mxcsr = 0x1F80,
210 	}
211 };
212 
213 const struct nvmm_x86_cpuid_mask nvmm_cpuid_00000001 = {
214 	.eax = ~0,
215 	.ebx = ~0,
216 	.ecx =
217 	    CPUID_0_01_ECX_SSE3 |
218 	    CPUID_0_01_ECX_PCLMULQDQ |
219 	    /* CPUID_0_01_ECX_DTES64 excluded */
220 	    /* CPUID_0_01_ECX_MONITOR excluded */
221 	    /* CPUID_0_01_ECX_DS_CPL excluded */
222 	    /* CPUID_0_01_ECX_VMX excluded */
223 	    /* CPUID_0_01_ECX_SMX excluded */
224 	    /* CPUID_0_01_ECX_EIST excluded */
225 	    /* CPUID_0_01_ECX_TM2 excluded */
226 	    CPUID_0_01_ECX_SSSE3 |
227 	    /* CPUID_0_01_ECX_CNXTID excluded */
228 	    /* CPUID_0_01_ECX_SDBG excluded */
229 	    CPUID_0_01_ECX_FMA |
230 	    CPUID_0_01_ECX_CX16 |
231 	    /* CPUID_0_01_ECX_XTPR excluded */
232 	    /* CPUID_0_01_ECX_PDCM excluded */
233 	    /* CPUID_0_01_ECX_PCID excluded, but re-included in VMX */
234 	    /* CPUID_0_01_ECX_DCA excluded */
235 	    CPUID_0_01_ECX_SSE41 |
236 	    CPUID_0_01_ECX_SSE42 |
237 	    /* CPUID_0_01_ECX_X2APIC excluded */
238 	    CPUID_0_01_ECX_MOVBE |
239 	    CPUID_0_01_ECX_POPCNT |
240 	    /* CPUID_0_01_ECX_TSC_DEADLINE excluded */
241 	    CPUID_0_01_ECX_AESNI |
242 	    CPUID_0_01_ECX_XSAVE |
243 	    CPUID_0_01_ECX_OSXSAVE |
244 	    /* CPUID_0_01_ECX_AVX excluded */
245 	    CPUID_0_01_ECX_F16C |
246 	    CPUID_0_01_ECX_RDRAND,
247 	    /* CPUID_0_01_ECX_RAZ excluded */
248 	.edx =
249 	    CPUID_0_01_EDX_FPU |
250 	    CPUID_0_01_EDX_VME |
251 	    CPUID_0_01_EDX_DE |
252 	    CPUID_0_01_EDX_PSE |
253 	    CPUID_0_01_EDX_TSC |
254 	    CPUID_0_01_EDX_MSR |
255 	    CPUID_0_01_EDX_PAE |
256 	    /* CPUID_0_01_EDX_MCE excluded */
257 	    CPUID_0_01_EDX_CX8 |
258 	    CPUID_0_01_EDX_APIC |
259 	    CPUID_0_01_EDX_SEP |
260 	    /* CPUID_0_01_EDX_MTRR excluded */
261 	    CPUID_0_01_EDX_PGE |
262 	    /* CPUID_0_01_EDX_MCA excluded */
263 	    CPUID_0_01_EDX_CMOV |
264 	    CPUID_0_01_EDX_PAT |
265 	    CPUID_0_01_EDX_PSE36 |
266 	    /* CPUID_0_01_EDX_PSN excluded */
267 	    CPUID_0_01_EDX_CLFSH |
268 	    /* CPUID_0_01_EDX_DS excluded */
269 	    /* CPUID_0_01_EDX_ACPI excluded */
270 	    CPUID_0_01_EDX_MMX |
271 	    CPUID_0_01_EDX_FXSR |
272 	    CPUID_0_01_EDX_SSE |
273 	    CPUID_0_01_EDX_SSE2 |
274 	    CPUID_0_01_EDX_SS |
275 	    CPUID_0_01_EDX_HTT |
276 	    /* CPUID_0_01_EDX_TM excluded */
277 	    CPUID_0_01_EDX_PBE
278 };
279 
280 const struct nvmm_x86_cpuid_mask nvmm_cpuid_00000007 = {
281 	.eax = ~0,
282 	.ebx =
283 	    CPUID_0_07_EBX_FSGSBASE |
284 	    /* CPUID_0_07_EBX_TSC_ADJUST excluded */
285 	    /* CPUID_0_07_EBX_SGX excluded */
286 	    CPUID_0_07_EBX_BMI1 |
287 	    /* CPUID_0_07_EBX_HLE excluded */
288 	    /* CPUID_0_07_EBX_AVX2 excluded */
289 	    CPUID_0_07_EBX_FDPEXONLY |
290 	    CPUID_0_07_EBX_SMEP |
291 	    CPUID_0_07_EBX_BMI2 |
292 	    CPUID_0_07_EBX_ERMS |
293 	    /* CPUID_0_07_EBX_INVPCID excluded, but re-included in VMX */
294 	    /* CPUID_0_07_EBX_RTM excluded */
295 	    /* CPUID_0_07_EBX_QM excluded */
296 	    CPUID_0_07_EBX_FPUCSDS |
297 	    /* CPUID_0_07_EBX_MPX excluded */
298 	    /* CPUID_0_07_EBX_PQE excluded */
299 	    /* CPUID_0_07_EBX_AVX512F excluded */
300 	    /* CPUID_0_07_EBX_AVX512DQ excluded */
301 	    CPUID_0_07_EBX_RDSEED |
302 	    CPUID_0_07_EBX_ADX |
303 	    CPUID_0_07_EBX_SMAP |
304 	    /* CPUID_0_07_EBX_AVX512_IFMA excluded */
305 	    CPUID_0_07_EBX_CLFLUSHOPT |
306 	    CPUID_0_07_EBX_CLWB,
307 	    /* CPUID_0_07_EBX_PT excluded */
308 	    /* CPUID_0_07_EBX_AVX512PF excluded */
309 	    /* CPUID_0_07_EBX_AVX512ER excluded */
310 	    /* CPUID_0_07_EBX_AVX512CD excluded */
311 	    /* CPUID_0_07_EBX_SHA excluded */
312 	    /* CPUID_0_07_EBX_AVX512BW excluded */
313 	    /* CPUID_0_07_EBX_AVX512VL excluded */
314 	.ecx =
315 	    CPUID_0_07_ECX_PREFETCHWT1 |
316 	    /* CPUID_0_07_ECX_AVX512_VBMI excluded */
317 	    CPUID_0_07_ECX_UMIP |
318 	    /* CPUID_0_07_ECX_PKU excluded */
319 	    /* CPUID_0_07_ECX_OSPKE excluded */
320 	    /* CPUID_0_07_ECX_WAITPKG excluded */
321 	    /* CPUID_0_07_ECX_AVX512_VBMI2 excluded */
322 	    /* CPUID_0_07_ECX_CET_SS excluded */
323 	    CPUID_0_07_ECX_GFNI |
324 	    CPUID_0_07_ECX_VAES |
325 	    CPUID_0_07_ECX_VPCLMULQDQ |
326 	    /* CPUID_0_07_ECX_AVX512_VNNI excluded */
327 	    /* CPUID_0_07_ECX_AVX512_BITALG excluded */
328 	    /* CPUID_0_07_ECX_AVX512_VPOPCNTDQ excluded */
329 	    /* CPUID_0_07_ECX_LA57 excluded */
330 	    /* CPUID_0_07_ECX_MAWAU excluded */
331 	    /* CPUID_0_07_ECX_RDPID excluded */
332 	    CPUID_0_07_ECX_CLDEMOTE |
333 	    CPUID_0_07_ECX_MOVDIRI |
334 	    CPUID_0_07_ECX_MOVDIR64B,
335 	    /* CPUID_0_07_ECX_SGXLC excluded */
336 	    /* CPUID_0_07_ECX_PKS excluded */
337 	.edx =
338 	    /* CPUID_0_07_EDX_AVX512_4VNNIW excluded */
339 	    /* CPUID_0_07_EDX_AVX512_4FMAPS excluded */
340 	    CPUID_0_07_EDX_FSREP_MOV |
341 	    /* CPUID_0_07_EDX_AVX512_VP2INTERSECT excluded */
342 	    /* CPUID_0_07_EDX_SRBDS_CTRL excluded */
343 	    CPUID_0_07_EDX_MD_CLEAR |
344 	    /* CPUID_0_07_EDX_TSX_FORCE_ABORT excluded */
345 	    CPUID_0_07_EDX_SERIALIZE |
346 	    /* CPUID_0_07_EDX_HYBRID excluded */
347 	    /* CPUID_0_07_EDX_TSXLDTRK excluded */
348 	    /* CPUID_0_07_EDX_CET_IBT excluded */
349 	    /* CPUID_0_07_EDX_IBRS excluded */
350 	    /* CPUID_0_07_EDX_STIBP excluded */
351 	    /* CPUID_0_07_EDX_L1D_FLUSH excluded */
352 	    CPUID_0_07_EDX_ARCH_CAP
353 	    /* CPUID_0_07_EDX_CORE_CAP excluded */
354 	    /* CPUID_0_07_EDX_SSBD excluded */
355 };
356 
357 const struct nvmm_x86_cpuid_mask nvmm_cpuid_80000001 = {
358 	.eax = ~0,
359 	.ebx = ~0,
360 	.ecx =
361 	    CPUID_8_01_ECX_LAHF |
362 	    CPUID_8_01_ECX_CMPLEGACY |
363 	    /* CPUID_8_01_ECX_SVM excluded */
364 	    /* CPUID_8_01_ECX_EAPIC excluded */
365 	    CPUID_8_01_ECX_ALTMOVCR8 |
366 	    CPUID_8_01_ECX_ABM |
367 	    CPUID_8_01_ECX_SSE4A |
368 	    CPUID_8_01_ECX_MISALIGNSSE |
369 	    CPUID_8_01_ECX_3DNOWPF |
370 	    /* CPUID_8_01_ECX_OSVW excluded */
371 	    /* CPUID_8_01_ECX_IBS excluded */
372 	    CPUID_8_01_ECX_XOP |
373 	    /* CPUID_8_01_ECX_SKINIT excluded */
374 	    /* CPUID_8_01_ECX_WDT excluded */
375 	    /* CPUID_8_01_ECX_LWP excluded */
376 	    CPUID_8_01_ECX_FMA4 |
377 	    CPUID_8_01_ECX_TCE |
378 	    /* CPUID_8_01_ECX_NODEID excluded */
379 	    CPUID_8_01_ECX_TBM |
380 	    CPUID_8_01_ECX_TOPOEXT,
381 	    /* CPUID_8_01_ECX_PCEC excluded */
382 	    /* CPUID_8_01_ECX_PCENB excluded */
383 	    /* CPUID_8_01_ECX_DBE excluded */
384 	    /* CPUID_8_01_ECX_PERFTSC excluded */
385 	    /* CPUID_8_01_ECX_PERFEXTLLC excluded */
386 	    /* CPUID_8_01_ECX_MWAITX excluded */
387 	.edx =
388 	    CPUID_8_01_EDX_FPU |
389 	    CPUID_8_01_EDX_VME |
390 	    CPUID_8_01_EDX_DE |
391 	    CPUID_8_01_EDX_PSE |
392 	    CPUID_8_01_EDX_TSC |
393 	    CPUID_8_01_EDX_MSR |
394 	    CPUID_8_01_EDX_PAE |
395 	    /* CPUID_8_01_EDX_MCE excluded */
396 	    CPUID_8_01_EDX_CX8 |
397 	    CPUID_8_01_EDX_APIC |
398 	    CPUID_8_01_EDX_SYSCALL |
399 	    /* CPUID_8_01_EDX_MTRR excluded */
400 	    CPUID_8_01_EDX_PGE |
401 	    /* CPUID_8_01_EDX_MCA excluded */
402 	    CPUID_8_01_EDX_CMOV |
403 	    CPUID_8_01_EDX_PAT |
404 	    CPUID_8_01_EDX_PSE36 |
405 	    CPUID_8_01_EDX_XD |
406 	    CPUID_8_01_EDX_MMXEXT |
407 	    CPUID_8_01_EDX_MMX |
408 	    CPUID_8_01_EDX_FXSR |
409 	    CPUID_8_01_EDX_FFXSR |
410 	    CPUID_8_01_EDX_PAGE1GB |
411 	    /* CPUID_8_01_EDX_RDTSCP excluded */
412 	    CPUID_8_01_EDX_LM |
413 	    CPUID_8_01_EDX_3DNOWEXT |
414 	    CPUID_8_01_EDX_3DNOW
415 };
416 
417 const struct nvmm_x86_cpuid_mask nvmm_cpuid_80000007 = {
418 	.eax = 0,
419 	.ebx = 0,
420 	.ecx = 0,
421 	.edx =
422 	    /* CPUID_8_07_EDX_TS excluded */
423 	    /* CPUID_8_07_EDX_FID excluded */
424 	    /* CPUID_8_07_EDX_VID excluded */
425 	    /* CPUID_8_07_EDX_TTP excluded */
426 	    /* CPUID_8_07_EDX_TM excluded */
427 	    /* CPUID_8_07_EDX_100MHzSteps excluded */
428 	    /* CPUID_8_07_EDX_HwPstate excluded */
429 	    CPUID_8_07_EDX_TscInvariant,
430 	    /* CPUID_8_07_EDX_CPB excluded */
431 	    /* CPUID_8_07_EDX_EffFreqRO excluded */
432 	    /* CPUID_8_07_EDX_ProcFeedbackIntf excluded */
433 	    /* CPUID_8_07_EDX_ProcPowerReport excluded */
434 };
435 
436 const struct nvmm_x86_cpuid_mask nvmm_cpuid_80000008 = {
437 	.eax = ~0,
438 	.ebx =
439 	    CPUID_8_08_EBX_CLZERO |
440 	    /* CPUID_8_08_EBX_InstRetCntMsr excluded */
441 	    CPUID_8_08_EBX_RstrFpErrPtrs |
442 	    /* CPUID_8_08_EBX_INVLPGB excluded */
443 	    /* CPUID_8_08_EBX_RDPRU excluded */
444 	    /* CPUID_8_08_EBX_MCOMMIT excluded */
445 	    CPUID_8_08_EBX_WBNOINVD,
446 	    /* CPUID_8_08_EBX_IBPB excluded */
447 	    /* CPUID_8_08_EBX_INT_WBINVD excluded */
448 	    /* CPUID_8_08_EBX_IBRS excluded */
449 	    /* CPUID_8_08_EBX_EferLmsleUnsupp excluded */
450 	    /* CPUID_8_08_EBX_INVLPGBnestedPg excluded */
451 	    /* CPUID_8_08_EBX_STIBP excluded */
452 	    /* CPUID_8_08_EBX_IBRS_ALWAYSON excluded */
453 	    /* CPUID_8_08_EBX_STIBP_ALWAYSON excluded */
454 	    /* CPUID_8_08_EBX_PREFER_IBRS excluded */
455 	    /* CPUID_8_08_EBX_SSBD excluded */
456 	    /* CPUID_8_08_EBX_VIRT_SSBD excluded */
457 	    /* CPUID_8_08_EBX_SSB_NO excluded */
458 	.ecx = 0,
459 	.edx = 0
460 };
461 
462 bool
463 nvmm_x86_pat_validate(uint64_t val)
464 {
465 	uint8_t *pat = (uint8_t *)&val;
466 	size_t i;
467 
468 	for (i = 0; i < 8; i++) {
469 		if (__predict_false(pat[i] & ~__BITS(2,0)))
470 			return false;
471 		if (__predict_false(pat[i] == 2 || pat[i] == 3))
472 			return false;
473 	}
474 
475 	return true;
476 }
477 
478 uint32_t
479 nvmm_x86_xsave_size(uint64_t xcr0)
480 {
481 	uint32_t size;
482 
483 	if (xcr0 & XCR0_SSE) {
484 		size = 512; /* x87 + SSE */
485 	} else {
486 		size = 108; /* x87 */
487 	}
488 	size += 64; /* XSAVE header */
489 
490 	return size;
491 }
492