1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2011 NetApp, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/types.h>
30
31 #include <machine/vmm.h>
32 #include <machine/vmm_dev.h>
33 #include <machine/vmm_instruction_emul.h>
34 #include <amd64/vmm/intel/vmcs.h>
35 #include <x86/apicreg.h>
36
37 #include <assert.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <strings.h>
42 #include <unistd.h>
43
44 #include <vmmapi.h>
45
46 #include "bhyverun.h"
47 #include "config.h"
48 #include "debug.h"
49 #include "gdb.h"
50 #include "inout.h"
51 #include "mem.h"
52 #ifdef BHYVE_SNAPSHOT
53 #include "snapshot.h"
54 #endif
55 #include "spinup_ap.h"
56 #include "vmexit.h"
57 #include "xmsr.h"
58
59 void
vm_inject_fault(struct vcpu * vcpu,int vector,int errcode_valid,int errcode)60 vm_inject_fault(struct vcpu *vcpu, int vector, int errcode_valid,
61 int errcode)
62 {
63 int error, restart_instruction;
64
65 restart_instruction = 1;
66
67 error = vm_inject_exception(vcpu, vector, errcode_valid, errcode,
68 restart_instruction);
69 assert(error == 0);
70 }
71
72 static int
vmexit_inout(struct vmctx * ctx,struct vcpu * vcpu,struct vm_run * vmrun)73 vmexit_inout(struct vmctx *ctx, struct vcpu *vcpu, struct vm_run *vmrun)
74 {
75 struct vm_exit *vme;
76 int error;
77 int bytes, port, in;
78
79 vme = vmrun->vm_exit;
80 port = vme->u.inout.port;
81 bytes = vme->u.inout.bytes;
82 in = vme->u.inout.in;
83
84 error = emulate_inout(ctx, vcpu, vme);
85 if (error) {
86 EPRINTLN("Unhandled %s%c 0x%04x at 0x%lx",
87 in ? "in" : "out",
88 bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'),
89 port, vme->rip);
90 return (VMEXIT_ABORT);
91 } else {
92 return (VMEXIT_CONTINUE);
93 }
94 }
95
96 static int
vmexit_rdmsr(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_run * vmrun)97 vmexit_rdmsr(struct vmctx *ctx __unused, struct vcpu *vcpu,
98 struct vm_run *vmrun)
99 {
100 struct vm_exit *vme;
101 uint64_t val;
102 uint32_t eax, edx;
103 int error;
104
105 vme = vmrun->vm_exit;
106
107 val = 0;
108 error = emulate_rdmsr(vcpu, vme->u.msr.code, &val);
109 if (error != 0) {
110 if (get_config_bool("x86.strictmsr") ||
111 get_config_bool("x86.verbosemsr")) {
112 EPRINTLN("rdmsr to register %#x on vcpu %d",
113 vme->u.msr.code, vcpu_id(vcpu));
114 }
115 if (get_config_bool("x86.strictmsr")) {
116 vm_inject_gp(vcpu);
117 return (VMEXIT_CONTINUE);
118 }
119 }
120
121 eax = val;
122 error = vm_set_register(vcpu, VM_REG_GUEST_RAX, eax);
123 assert(error == 0);
124
125 edx = val >> 32;
126 error = vm_set_register(vcpu, VM_REG_GUEST_RDX, edx);
127 assert(error == 0);
128
129 return (VMEXIT_CONTINUE);
130 }
131
132 static int
vmexit_wrmsr(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_run * vmrun)133 vmexit_wrmsr(struct vmctx *ctx __unused, struct vcpu *vcpu,
134 struct vm_run *vmrun)
135 {
136 struct vm_exit *vme;
137 int error;
138
139 vme = vmrun->vm_exit;
140
141 error = emulate_wrmsr(vcpu, vme->u.msr.code, vme->u.msr.wval);
142 if (error != 0) {
143 if (get_config_bool("x86.strictmsr") ||
144 get_config_bool("x86.verbosemsr")) {
145 EPRINTLN("wrmsr to register %#x(%#lx) on vcpu %d",
146 vme->u.msr.code, vme->u.msr.wval, vcpu_id(vcpu));
147 }
148 if (get_config_bool("x86.strictmsr")) {
149 vm_inject_gp(vcpu);
150 return (VMEXIT_CONTINUE);
151 }
152 }
153 return (VMEXIT_CONTINUE);
154 }
155
156 static const char * const vmx_exit_reason_desc[] = {
157 [EXIT_REASON_EXCEPTION] = "Exception or non-maskable interrupt (NMI)",
158 [EXIT_REASON_EXT_INTR] = "External interrupt",
159 [EXIT_REASON_TRIPLE_FAULT] = "Triple fault",
160 [EXIT_REASON_INIT] = "INIT signal",
161 [EXIT_REASON_SIPI] = "Start-up IPI (SIPI)",
162 [EXIT_REASON_IO_SMI] = "I/O system-management interrupt (SMI)",
163 [EXIT_REASON_SMI] = "Other SMI",
164 [EXIT_REASON_INTR_WINDOW] = "Interrupt window",
165 [EXIT_REASON_NMI_WINDOW] = "NMI window",
166 [EXIT_REASON_TASK_SWITCH] = "Task switch",
167 [EXIT_REASON_CPUID] = "CPUID",
168 [EXIT_REASON_GETSEC] = "GETSEC",
169 [EXIT_REASON_HLT] = "HLT",
170 [EXIT_REASON_INVD] = "INVD",
171 [EXIT_REASON_INVLPG] = "INVLPG",
172 [EXIT_REASON_RDPMC] = "RDPMC",
173 [EXIT_REASON_RDTSC] = "RDTSC",
174 [EXIT_REASON_RSM] = "RSM",
175 [EXIT_REASON_VMCALL] = "VMCALL",
176 [EXIT_REASON_VMCLEAR] = "VMCLEAR",
177 [EXIT_REASON_VMLAUNCH] = "VMLAUNCH",
178 [EXIT_REASON_VMPTRLD] = "VMPTRLD",
179 [EXIT_REASON_VMPTRST] = "VMPTRST",
180 [EXIT_REASON_VMREAD] = "VMREAD",
181 [EXIT_REASON_VMRESUME] = "VMRESUME",
182 [EXIT_REASON_VMWRITE] = "VMWRITE",
183 [EXIT_REASON_VMXOFF] = "VMXOFF",
184 [EXIT_REASON_VMXON] = "VMXON",
185 [EXIT_REASON_CR_ACCESS] = "Control-register accesses",
186 [EXIT_REASON_DR_ACCESS] = "MOV DR",
187 [EXIT_REASON_INOUT] = "I/O instruction",
188 [EXIT_REASON_RDMSR] = "RDMSR",
189 [EXIT_REASON_WRMSR] = "WRMSR",
190 [EXIT_REASON_INVAL_VMCS] =
191 "VM-entry failure due to invalid guest state",
192 [EXIT_REASON_INVAL_MSR] = "VM-entry failure due to MSR loading",
193 [EXIT_REASON_MWAIT] = "MWAIT",
194 [EXIT_REASON_MTF] = "Monitor trap flag",
195 [EXIT_REASON_MONITOR] = "MONITOR",
196 [EXIT_REASON_PAUSE] = "PAUSE",
197 [EXIT_REASON_MCE_DURING_ENTRY] =
198 "VM-entry failure due to machine-check event",
199 [EXIT_REASON_TPR] = "TPR below threshold",
200 [EXIT_REASON_APIC_ACCESS] = "APIC access",
201 [EXIT_REASON_VIRTUALIZED_EOI] = "Virtualized EOI",
202 [EXIT_REASON_GDTR_IDTR] = "Access to GDTR or IDTR",
203 [EXIT_REASON_LDTR_TR] = "Access to LDTR or TR",
204 [EXIT_REASON_EPT_FAULT] = "EPT violation",
205 [EXIT_REASON_EPT_MISCONFIG] = "EPT misconfiguration",
206 [EXIT_REASON_INVEPT] = "INVEPT",
207 [EXIT_REASON_RDTSCP] = "RDTSCP",
208 [EXIT_REASON_VMX_PREEMPT] = "VMX-preemption timer expired",
209 [EXIT_REASON_INVVPID] = "INVVPID",
210 [EXIT_REASON_WBINVD] = "WBINVD",
211 [EXIT_REASON_XSETBV] = "XSETBV",
212 [EXIT_REASON_APIC_WRITE] = "APIC write",
213 [EXIT_REASON_RDRAND] = "RDRAND",
214 [EXIT_REASON_INVPCID] = "INVPCID",
215 [EXIT_REASON_VMFUNC] = "VMFUNC",
216 [EXIT_REASON_ENCLS] = "ENCLS",
217 [EXIT_REASON_RDSEED] = "RDSEED",
218 [EXIT_REASON_PM_LOG_FULL] = "Page-modification log full",
219 [EXIT_REASON_XSAVES] = "XSAVES",
220 [EXIT_REASON_XRSTORS] = "XRSTORS"
221 };
222
223 static const char *
vmexit_vmx_desc(uint32_t exit_reason)224 vmexit_vmx_desc(uint32_t exit_reason)
225 {
226
227 if (exit_reason >= nitems(vmx_exit_reason_desc) ||
228 vmx_exit_reason_desc[exit_reason] == NULL)
229 return ("Unknown");
230 return (vmx_exit_reason_desc[exit_reason]);
231 }
232
233 #define DEBUG_EPT_MISCONFIG
234 #ifdef DEBUG_EPT_MISCONFIG
235 #define VMCS_GUEST_PHYSICAL_ADDRESS 0x00002400
236
237 static uint64_t ept_misconfig_gpa, ept_misconfig_pte[4];
238 static int ept_misconfig_ptenum;
239 #endif
240
241 static int
vmexit_vmx(struct vmctx * ctx,struct vcpu * vcpu,struct vm_run * vmrun)242 vmexit_vmx(struct vmctx *ctx, struct vcpu *vcpu, struct vm_run *vmrun)
243 {
244 struct vm_exit *vme;
245
246 vme = vmrun->vm_exit;
247
248 EPRINTLN("vm exit[%d]", vcpu_id(vcpu));
249 EPRINTLN("\treason\t\tVMX");
250 EPRINTLN("\trip\t\t0x%016lx", vme->rip);
251 EPRINTLN("\tinst_length\t%d", vme->inst_length);
252 EPRINTLN("\tstatus\t\t%d", vme->u.vmx.status);
253 EPRINTLN("\texit_reason\t%u (%s)", vme->u.vmx.exit_reason,
254 vmexit_vmx_desc(vme->u.vmx.exit_reason));
255 EPRINTLN("\tqualification\t0x%016lx",
256 vme->u.vmx.exit_qualification);
257 EPRINTLN("\tinst_type\t\t%d", vme->u.vmx.inst_type);
258 EPRINTLN("\tinst_error\t\t%d", vme->u.vmx.inst_error);
259 #ifdef DEBUG_EPT_MISCONFIG
260 if (vme->u.vmx.exit_reason == EXIT_REASON_EPT_MISCONFIG) {
261 vm_get_register(vcpu,
262 VMCS_IDENT(VMCS_GUEST_PHYSICAL_ADDRESS),
263 &ept_misconfig_gpa);
264 vm_get_gpa_pmap(ctx, ept_misconfig_gpa, ept_misconfig_pte,
265 &ept_misconfig_ptenum);
266 EPRINTLN("\tEPT misconfiguration:");
267 EPRINTLN("\t\tGPA: %#lx", ept_misconfig_gpa);
268 EPRINTLN("\t\tPTE(%d): %#lx %#lx %#lx %#lx",
269 ept_misconfig_ptenum, ept_misconfig_pte[0],
270 ept_misconfig_pte[1], ept_misconfig_pte[2],
271 ept_misconfig_pte[3]);
272 }
273 #endif /* DEBUG_EPT_MISCONFIG */
274 return (VMEXIT_ABORT);
275 }
276
277 static int
vmexit_svm(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_run * vmrun)278 vmexit_svm(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_run *vmrun)
279 {
280 struct vm_exit *vme;
281
282 vme = vmrun->vm_exit;
283
284 EPRINTLN("vm exit[%d]", vcpu_id(vcpu));
285 EPRINTLN("\treason\t\tSVM");
286 EPRINTLN("\trip\t\t0x%016lx", vme->rip);
287 EPRINTLN("\tinst_length\t%d", vme->inst_length);
288 EPRINTLN("\texitcode\t%#lx", vme->u.svm.exitcode);
289 EPRINTLN("\texitinfo1\t%#lx", vme->u.svm.exitinfo1);
290 EPRINTLN("\texitinfo2\t%#lx", vme->u.svm.exitinfo2);
291 return (VMEXIT_ABORT);
292 }
293
294 static int
vmexit_bogus(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_run * vmrun)295 vmexit_bogus(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
296 struct vm_run *vmrun)
297 {
298 assert(vmrun->vm_exit->inst_length == 0);
299
300 return (VMEXIT_CONTINUE);
301 }
302
303 static int
vmexit_reqidle(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_run * vmrun)304 vmexit_reqidle(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
305 struct vm_run *vmrun)
306 {
307 assert(vmrun->vm_exit->inst_length == 0);
308
309 return (VMEXIT_CONTINUE);
310 }
311
312 static int
vmexit_hlt(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_run * vmrun __unused)313 vmexit_hlt(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
314 struct vm_run *vmrun __unused)
315 {
316 /*
317 * Just continue execution with the next instruction. We use
318 * the HLT VM exit as a way to be friendly with the host
319 * scheduler.
320 */
321 return (VMEXIT_CONTINUE);
322 }
323
324 static int
vmexit_pause(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_run * vmrun __unused)325 vmexit_pause(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
326 struct vm_run *vmrun __unused)
327 {
328 return (VMEXIT_CONTINUE);
329 }
330
331 static int
vmexit_mtrap(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_run * vmrun)332 vmexit_mtrap(struct vmctx *ctx __unused, struct vcpu *vcpu,
333 struct vm_run *vmrun)
334 {
335 assert(vmrun->vm_exit->inst_length == 0);
336
337 #ifdef BHYVE_SNAPSHOT
338 checkpoint_cpu_suspend(vcpu_id(vcpu));
339 #endif
340 gdb_cpu_mtrap(vcpu);
341 #ifdef BHYVE_SNAPSHOT
342 checkpoint_cpu_resume(vcpu_id(vcpu));
343 #endif
344
345 return (VMEXIT_CONTINUE);
346 }
347
348 static int
vmexit_inst_emul(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_run * vmrun)349 vmexit_inst_emul(struct vmctx *ctx __unused, struct vcpu *vcpu,
350 struct vm_run *vmrun)
351 {
352 struct vm_exit *vme;
353 struct vie *vie;
354 int err, i, cs_d;
355 enum vm_cpu_mode mode;
356
357 vme = vmrun->vm_exit;
358
359 vie = &vme->u.inst_emul.vie;
360 if (!vie->decoded) {
361 /*
362 * Attempt to decode in userspace as a fallback. This allows
363 * updating instruction decode in bhyve without rebooting the
364 * kernel (rapid prototyping), albeit with much slower
365 * emulation.
366 */
367 vie_restart(vie);
368 mode = vme->u.inst_emul.paging.cpu_mode;
369 cs_d = vme->u.inst_emul.cs_d;
370 if (vmm_decode_instruction(mode, cs_d, vie) != 0)
371 goto fail;
372 if (vm_set_register(vcpu, VM_REG_GUEST_RIP,
373 vme->rip + vie->num_processed) != 0)
374 goto fail;
375 }
376
377 err = emulate_mem(vcpu, vme->u.inst_emul.gpa, vie,
378 &vme->u.inst_emul.paging);
379 if (err) {
380 if (err == ESRCH) {
381 EPRINTLN("Unhandled memory access to 0x%lx\n",
382 vme->u.inst_emul.gpa);
383 }
384 goto fail;
385 }
386
387 return (VMEXIT_CONTINUE);
388
389 fail:
390 fprintf(stderr, "Failed to emulate instruction sequence [ ");
391 for (i = 0; i < vie->num_valid; i++)
392 fprintf(stderr, "%02x", vie->inst[i]);
393 FPRINTLN(stderr, " ] at 0x%lx", vme->rip);
394 return (VMEXIT_ABORT);
395 }
396
397 static int
vmexit_suspend(struct vmctx * ctx,struct vcpu * vcpu,struct vm_run * vmrun)398 vmexit_suspend(struct vmctx *ctx, struct vcpu *vcpu, struct vm_run *vmrun)
399 {
400 struct vm_exit *vme;
401 enum vm_suspend_how how;
402 int vcpuid = vcpu_id(vcpu);
403
404 vme = vmrun->vm_exit;
405
406 how = vme->u.suspended.how;
407
408 fbsdrun_deletecpu(vcpuid);
409
410 switch (how) {
411 case VM_SUSPEND_RESET:
412 exit(0);
413 case VM_SUSPEND_POWEROFF:
414 if (get_config_bool_default("destroy_on_poweroff", false))
415 vm_destroy(ctx);
416 exit(1);
417 case VM_SUSPEND_HALT:
418 exit(2);
419 case VM_SUSPEND_TRIPLEFAULT:
420 exit(3);
421 default:
422 EPRINTLN("vmexit_suspend: invalid reason %d", how);
423 exit(100);
424 }
425 return (0); /* NOTREACHED */
426 }
427
428 static int
vmexit_debug(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_run * vmrun __unused)429 vmexit_debug(struct vmctx *ctx __unused, struct vcpu *vcpu,
430 struct vm_run *vmrun __unused)
431 {
432
433 #ifdef BHYVE_SNAPSHOT
434 checkpoint_cpu_suspend(vcpu_id(vcpu));
435 #endif
436 gdb_cpu_suspend(vcpu);
437 #ifdef BHYVE_SNAPSHOT
438 checkpoint_cpu_resume(vcpu_id(vcpu));
439 #endif
440 /*
441 * XXX-MJ sleep for a short period to avoid chewing up the CPU in the
442 * window between activation of the vCPU thread and the STARTUP IPI.
443 */
444 usleep(1000);
445 return (VMEXIT_CONTINUE);
446 }
447
448 static int
vmexit_db(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_run * vmrun)449 vmexit_db(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_run *vmrun)
450 {
451
452 #ifdef BHYVE_SNAPSHOT
453 checkpoint_cpu_suspend(vcpu_id(vcpu));
454 #endif
455 gdb_cpu_debug(vcpu, vmrun->vm_exit);
456 #ifdef BHYVE_SNAPSHOT
457 checkpoint_cpu_resume(vcpu_id(vcpu));
458 #endif
459 return (VMEXIT_CONTINUE);
460 }
461
462 static int
vmexit_breakpoint(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_run * vmrun)463 vmexit_breakpoint(struct vmctx *ctx __unused, struct vcpu *vcpu,
464 struct vm_run *vmrun)
465 {
466 gdb_cpu_breakpoint(vcpu, vmrun->vm_exit);
467 return (VMEXIT_CONTINUE);
468 }
469
470 static int
vmexit_ipi(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_run * vmrun)471 vmexit_ipi(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
472 struct vm_run *vmrun)
473 {
474 struct vm_exit *vme;
475 cpuset_t *dmask;
476 int error = -1;
477 int i;
478
479 dmask = vmrun->cpuset;
480 vme = vmrun->vm_exit;
481
482 switch (vme->u.ipi.mode) {
483 case APIC_DELMODE_INIT:
484 CPU_FOREACH_ISSET(i, dmask) {
485 error = fbsdrun_suspendcpu(i);
486 if (error) {
487 warnx("failed to suspend cpu %d", i);
488 break;
489 }
490 }
491 break;
492 case APIC_DELMODE_STARTUP:
493 CPU_FOREACH_ISSET(i, dmask) {
494 spinup_ap(fbsdrun_vcpu(i),
495 vme->u.ipi.vector << PAGE_SHIFT);
496 }
497 error = 0;
498 break;
499 default:
500 break;
501 }
502
503 return (error);
504 }
505
506 int vmexit_task_switch(struct vmctx *, struct vcpu *, struct vm_run *);
507
508 const vmexit_handler_t vmexit_handlers[VM_EXITCODE_MAX] = {
509 [VM_EXITCODE_INOUT] = vmexit_inout,
510 [VM_EXITCODE_INOUT_STR] = vmexit_inout,
511 [VM_EXITCODE_VMX] = vmexit_vmx,
512 [VM_EXITCODE_SVM] = vmexit_svm,
513 [VM_EXITCODE_BOGUS] = vmexit_bogus,
514 [VM_EXITCODE_REQIDLE] = vmexit_reqidle,
515 [VM_EXITCODE_RDMSR] = vmexit_rdmsr,
516 [VM_EXITCODE_WRMSR] = vmexit_wrmsr,
517 [VM_EXITCODE_MTRAP] = vmexit_mtrap,
518 [VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,
519 [VM_EXITCODE_SUSPENDED] = vmexit_suspend,
520 [VM_EXITCODE_TASK_SWITCH] = vmexit_task_switch,
521 [VM_EXITCODE_DEBUG] = vmexit_debug,
522 [VM_EXITCODE_BPT] = vmexit_breakpoint,
523 [VM_EXITCODE_IPI] = vmexit_ipi,
524 [VM_EXITCODE_HLT] = vmexit_hlt,
525 [VM_EXITCODE_PAUSE] = vmexit_pause,
526 [VM_EXITCODE_DB] = vmexit_db,
527 };
528