1ae115bc7Smrj/*
2ae115bc7Smrj * CDDL HEADER START
3ae115bc7Smrj *
4ae115bc7Smrj * The contents of this file are subject to the terms of the
5ae115bc7Smrj * Common Development and Distribution License (the "License").
6ae115bc7Smrj * You may not use this file except in compliance with the License.
7ae115bc7Smrj *
8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing.
10ae115bc7Smrj * See the License for the specific language governing permissions
11ae115bc7Smrj * and limitations under the License.
12ae115bc7Smrj *
13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each
14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the
16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying
17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner]
18ae115bc7Smrj *
19ae115bc7Smrj * CDDL HEADER END
20ae115bc7Smrj */
21ae115bc7Smrj
22ae115bc7Smrj/*
23ae115bc7Smrj * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24ae115bc7Smrj * Use is subject to license terms.
25ae115bc7Smrj */
26ae115bc7Smrj
279b0bb795SJohn Levon/*
289b0bb795SJohn Levon * Copyright 2019 Joyent, Inc.
299b0bb795SJohn Levon */
30ae115bc7Smrj
31ae115bc7Smrj#include <sys/segments.h>
32ae115bc7Smrj#include <sys/controlregs.h>
33ae115bc7Smrj
34ae115bc7Smrj/*
35ae115bc7Smrj * Do a call into BIOS.  This goes down to 16 bit real mode and back again.
36ae115bc7Smrj */
37ae115bc7Smrj
38ae115bc7Smrj/*
39ae115bc7Smrj * instruction prefix to change operand size in instruction
40ae115bc7Smrj */
41ae115bc7Smrj#define DATASZ	.byte 0x66;
42ae115bc7Smrj
43ae115bc7Smrj	.globl	_start
44ae115bc7Smrj_start:
45ae115bc7Smrj
46ae115bc7Smrj	/*
47ae115bc7Smrj	 * Save caller registers
48ae115bc7Smrj	 */
49ae115bc7Smrj	movq	%rbp, save_rbp
50ae115bc7Smrj	movq	%rsp, save_rsp
51ae115bc7Smrj	movq	%rbx, save_rbx
52ae115bc7Smrj	movq	%rsi, save_rsi
53ae115bc7Smrj	movq	%r12, save_r12
54ae115bc7Smrj	movq	%r13, save_r13
55ae115bc7Smrj	movq	%r14, save_r14
56ae115bc7Smrj	movq	%r15, save_r15
57ae115bc7Smrj
58ae115bc7Smrj	/* Switch to a low memory stack */
59ae115bc7Smrj	movq	$_start, %rsp
60ae115bc7Smrj
61ae115bc7Smrj	/* put interrupt number in %bl */
62ae115bc7Smrj	movq	%rdi, %rbx
63ae115bc7Smrj
64ae115bc7Smrj	/* allocate space for args on stack */
65ae115bc7Smrj	subq	$18, %rsp
66ae115bc7Smrj	movq	%rsp, %rdi
67ae115bc7Smrj
68ae115bc7Smrj	/* copy args from high memory to stack in low memory */
69ae115bc7Smrj	cld
70ae115bc7Smrj	movl	$18, %ecx
71ae115bc7Smrj	rep
72ae115bc7Smrj	movsb
73ae115bc7Smrj
74ae115bc7Smrj	/*
75ae115bc7Smrj	 * Save system registers
76ae115bc7Smrj	 */
77ae115bc7Smrj	sidt	save_idt
78ae115bc7Smrj	sgdt	save_gdt
79ae115bc7Smrj	str	save_tr
80ae115bc7Smrj	movw	%cs, save_cs
81ae115bc7Smrj	movw	%ds, save_ds
82ae115bc7Smrj	movw	%ss, save_ss
83ae115bc7Smrj	movw	%es, save_es
84ae115bc7Smrj	movw	%fs, save_fs
85ae115bc7Smrj	movw	%gs, save_gs
869b0bb795SJohn Levon	movq	%cr4, %rax
879b0bb795SJohn Levon	movq	%rax, save_cr4
889b0bb795SJohn Levon	movq	%cr3, %rax
899b0bb795SJohn Levon	movq	%rax, save_cr3
909b0bb795SJohn Levon	movq	%cr0, %rax
919b0bb795SJohn Levon	movq	%rax, save_cr0
92ae115bc7Smrj
93ae115bc7Smrj	/*
94ae115bc7Smrj	 * save/clear the extension parts of the fs/gs base registers and cr8
95ae115bc7Smrj	 */
96ae115bc7Smrj	movl	$MSR_AMD_FSBASE, %ecx
97ae115bc7Smrj	rdmsr
98ae115bc7Smrj	movl	%eax, save_fsbase
99ae115bc7Smrj	movl	%edx, save_fsbase + 4
100ae115bc7Smrj	xorl	%eax, %eax
101ae115bc7Smrj	xorl	%edx, %edx
102ae115bc7Smrj	wrmsr
103ae115bc7Smrj
104ae115bc7Smrj	movl	$MSR_AMD_GSBASE, %ecx
105ae115bc7Smrj	rdmsr
106ae115bc7Smrj	movl	%eax, save_gsbase
107ae115bc7Smrj	movl	%edx, save_gsbase + 4
108ae115bc7Smrj	xorl	%eax, %eax
109ae115bc7Smrj	xorl	%edx, %edx
110ae115bc7Smrj	wrmsr
111ae115bc7Smrj
112ae115bc7Smrj	movl	$MSR_AMD_KGSBASE, %ecx
113ae115bc7Smrj	rdmsr
114ae115bc7Smrj	movl	%eax, save_kgsbase
115ae115bc7Smrj	movl	%edx, save_kgsbase + 4
116ae115bc7Smrj	xorl	%eax, %eax
117ae115bc7Smrj	xorl	%edx, %edx
118ae115bc7Smrj	wrmsr
119ae115bc7Smrj
120ae115bc7Smrj	movq	%cr8, %rax
121ae115bc7Smrj	movq	%rax, save_cr8
122ae115bc7Smrj
123ae115bc7Smrj	/*
124ae115bc7Smrj	 * set offsets in 16 bit ljmp instructions below
125ae115bc7Smrj	 */
1269b0bb795SJohn Levon	leaq	enter_real, %rax
127ae115bc7Smrj	movw	%ax, enter_real_ljmp
128ae115bc7Smrj
1299b0bb795SJohn Levon	leaq	enter_protected, %rax
130ae115bc7Smrj	movw	%ax, enter_protected_ljmp
131ae115bc7Smrj
1329b0bb795SJohn Levon	leaq	gdt_info, %rax
133ae115bc7Smrj	movw	%ax, gdt_info_load
134ae115bc7Smrj
135ae115bc7Smrj	/*
136ae115bc7Smrj	 * insert BIOS interrupt number into later instruction
137ae115bc7Smrj	 */
138ae115bc7Smrj	movb    %bl, int_instr+1
139ae115bc7Smrj	jmp     1f
140ae115bc7Smrj1:
141ae115bc7Smrj
142ae115bc7Smrj	/*
143ae115bc7Smrj	 * zero out all the registers to make sure they're 16 bit clean
144ae115bc7Smrj	 */
145ae115bc7Smrj	xorq	%r8, %r8
146ae115bc7Smrj	xorq	%r9, %r9
147ae115bc7Smrj	xorq	%r10, %r10
148ae115bc7Smrj	xorq	%r11, %r11
149ae115bc7Smrj	xorq	%r12, %r12
150ae115bc7Smrj	xorq	%r13, %r13
151ae115bc7Smrj	xorq	%r14, %r14
152ae115bc7Smrj	xorq	%r15, %r15
153ae115bc7Smrj	xorl	%eax, %eax
154ae115bc7Smrj	xorl	%ebx, %ebx
155ae115bc7Smrj	xorl	%ecx, %ecx
156ae115bc7Smrj	xorl	%edx, %edx
157ae115bc7Smrj	xorl	%ebp, %ebp
158ae115bc7Smrj	xorl	%esi, %esi
159ae115bc7Smrj	xorl	%edi, %edi
160ae115bc7Smrj
161ae115bc7Smrj	/*
162ae115bc7Smrj	 * Load our own GDT/IDT
163ae115bc7Smrj	 */
164ae115bc7Smrj	lgdt	gdt_info
165ae115bc7Smrj	lidt	idt_info
166ae115bc7Smrj
167ae115bc7Smrj	/*
1689b0bb795SJohn Levon	 * Shut down 64 bit mode. First get into compatibility mode.
169ae115bc7Smrj	 */
170ae115bc7Smrj	movq	%rsp, %rax
171ae115bc7Smrj	pushq	$B32DATA_SEL
172ae115bc7Smrj	pushq	%rax
173ae115bc7Smrj	pushf
174ae115bc7Smrj	pushq	$B32CODE_SEL
175ae115bc7Smrj	pushq	$1f
176ae115bc7Smrj	iretq
177ae115bc7Smrj1:
178ae115bc7Smrj	.code32
179ae115bc7Smrj
180ae115bc7Smrj	/*
181ae115bc7Smrj	 * disable long mode by:
182ae115bc7Smrj	 * - shutting down paging (bit 31 of cr0)
183ae115bc7Smrj	 * - flushing the TLB
184ae115bc7Smrj	 * - disabling LME (long made enable) in EFER (extended feature reg)
185ae115bc7Smrj	 */
186ae115bc7Smrj	movl	%cr0, %eax
187ae115bc7Smrj	btcl	$31, %eax		/* disable paging */
188ae115bc7Smrj	movl	%eax, %cr0
189ae115bc7Smrj	ljmp	$B32CODE_SEL, $1f
190ae115bc7Smrj1:
191ae115bc7Smrj
192ae115bc7Smrj	xorl	%eax, %eax
193ae115bc7Smrj	movl	%eax, %cr3		/* flushes TLB */
194ae115bc7Smrj
195ae115bc7Smrj	movl	$MSR_AMD_EFER, %ecx	/* Extended Feature Enable */
196ae115bc7Smrj	rdmsr
197ae115bc7Smrj	btcl	$8, %eax		/* bit 8 Long Mode Enable bit */
198ae115bc7Smrj	wrmsr
199ae115bc7Smrj
200ae115bc7Smrj	/*
201ae115bc7Smrj	 * ok.. now enter 16 bit mode, so we can shut down protected mode
202ae115bc7Smrj	 *
203ae115bc7Smrj	 * We'll have to act like we're still in a 32 bit section.
204ae115bc7Smrj	 * So the code from this point has DATASZ in front of it to get 32 bit
205ae115bc7Smrj	 * operands. If DATASZ is missing the operands will be 16 bit.
206ae115bc7Smrj	 *
207ae115bc7Smrj	 * Now shut down paging and protected (ie. segmentation) modes.
208ae115bc7Smrj	 */
209ae115bc7Smrj	ljmp	$B16CODE_SEL, $enter_16_bit
210ae115bc7Smrjenter_16_bit:
211ae115bc7Smrj
212ae115bc7Smrj	/*
213ae115bc7Smrj	 * Make sure hidden parts of segment registers are 16 bit clean
214ae115bc7Smrj	 */
215ae115bc7Smrj	DATASZ	movl	$B16DATA_SEL, %eax
216ae115bc7Smrj		movw    %ax, %ss
217ae115bc7Smrj		movw    %ax, %ds
218ae115bc7Smrj		movw    %ax, %es
219ae115bc7Smrj		movw    %ax, %fs
220ae115bc7Smrj		movw    %ax, %gs
221ae115bc7Smrj
222ae115bc7Smrj
223ae115bc7Smrj	DATASZ	movl	$0x0, %eax	/* put us in real mode */
224ae115bc7Smrj	DATASZ	movl	%eax, %cr0
225ae115bc7Smrj	.byte	0xea			/* ljmp */
226ae115bc7Smrjenter_real_ljmp:
227ae115bc7Smrj	.value	0			/* addr (16 bit) */
228ae115bc7Smrj	.value	0x0			/* value for %cs */
229ae115bc7Smrjenter_real:
230ae115bc7Smrj
231ae115bc7Smrj	/*
232ae115bc7Smrj	 * zero out the remaining segment registers
233ae115bc7Smrj	 */
234ae115bc7Smrj	DATASZ	xorl	%eax, %eax
235ae115bc7Smrj		movw    %ax, %ss
236ae115bc7Smrj		movw    %ax, %ds
237ae115bc7Smrj		movw    %ax, %es
238ae115bc7Smrj		movw    %ax, %fs
239ae115bc7Smrj		movw    %ax, %gs
240ae115bc7Smrj
241ae115bc7Smrj	/*
242ae115bc7Smrj	 * load the arguments to the BIOS call from the stack
243ae115bc7Smrj	 */
244ae115bc7Smrj	popl	%eax	/* really executes a 16 bit pop */
245ae115bc7Smrj	popl	%ebx
246ae115bc7Smrj	popl	%ecx
247ae115bc7Smrj	popl	%edx
248ae115bc7Smrj	popl	%esi
249ae115bc7Smrj	popl	%edi
250ae115bc7Smrj	popl	%ebp
251ae115bc7Smrj	pop	%es
252ae115bc7Smrj	pop	%ds
253ae115bc7Smrj
254ae115bc7Smrj	/*
255ae115bc7Smrj	 * do the actual BIOS call
256ae115bc7Smrj	 */
257ae115bc7Smrj	sti
258ae115bc7Smrjint_instr:
259ae115bc7Smrj	int	$0x10		/* this int number is overwritten */
260ae115bc7Smrj	cli			/* ensure interrupts remain disabled */
261ae115bc7Smrj
262ae115bc7Smrj	/*
263ae115bc7Smrj	 * save results of the BIOS call
264ae115bc7Smrj	 */
265ae115bc7Smrj	pushf
266ae115bc7Smrj	push	%ds
267ae115bc7Smrj	push	%es
268ae115bc7Smrj	pushl	%ebp		/* still executes as 16 bit */
269ae115bc7Smrj	pushl	%edi
270ae115bc7Smrj	pushl	%esi
271ae115bc7Smrj	pushl	%edx
272ae115bc7Smrj	pushl	%ecx
273ae115bc7Smrj	pushl	%ebx
274ae115bc7Smrj	pushl	%eax
275ae115bc7Smrj
276ae115bc7Smrj	/*
277ae115bc7Smrj	 * Restore protected mode and 32 bit execution
278ae115bc7Smrj	 */
279ae115bc7Smrj	push	$0			/* make sure %ds is zero before lgdt */
280ae115bc7Smrj	pop	%ds
281ae115bc7Smrj	.byte	0x0f, 0x01, 0x16	/* lgdt */
282ae115bc7Smrjgdt_info_load:
283ae115bc7Smrj	.value	0	/* temp GDT in currently addressible mem */
284ae115bc7Smrj
285ae115bc7Smrj	DATASZ	movl	$0x1, %eax
286ae115bc7Smrj	DATASZ	movl	%eax, %cr0
287ae115bc7Smrj
288ae115bc7Smrj	.byte	0xea			/* ljmp */
289ae115bc7Smrjenter_protected_ljmp:
290ae115bc7Smrj	.value	0			/* addr (still in 16 bit) */
291ae115bc7Smrj	.value	B32CODE_SEL		/* %cs value */
292ae115bc7Smrjenter_protected:
293ae115bc7Smrj
294ae115bc7Smrj	/*
295ae115bc7Smrj	 * We are now back in a 32 bit code section, fix data/stack segments
296ae115bc7Smrj	 */
297ae115bc7Smrj	.code32
298ae115bc7Smrj	movw	$B32DATA_SEL, %ax
299ae115bc7Smrj	movw	%ax, %ds
300ae115bc7Smrj	movw	%ax, %ss
301ae115bc7Smrj
302ae115bc7Smrj	/*
303ae115bc7Smrj	 * Re-enable paging. Note we only use 32 bit mov's to restore these
304ae115bc7Smrj	 * control registers. That's OK as the upper 32 bits are always zero.
305ae115bc7Smrj	 */
306ae115bc7Smrj	movl	save_cr4, %eax
307ae115bc7Smrj	movl	%eax, %cr4
308ae115bc7Smrj	movl	save_cr3, %eax
309ae115bc7Smrj	movl	%eax, %cr3
310ae115bc7Smrj
311ae115bc7Smrj	/*
312ae115bc7Smrj	 * re-enable long mode
313ae115bc7Smrj	 */
314ae115bc7Smrj	movl	$MSR_AMD_EFER, %ecx
315ae115bc7Smrj	rdmsr
316ae115bc7Smrj	btsl	$8, %eax
317ae115bc7Smrj	wrmsr
318ae115bc7Smrj
319ae115bc7Smrj	movl	save_cr0, %eax
320ae115bc7Smrj	movl	%eax, %cr0
321ae115bc7Smrj	jmp	enter_paging
322ae115bc7Smrjenter_paging:
323ae115bc7Smrj
324ae115bc7Smrj
325ae115bc7Smrj	/*
326ae115bc7Smrj	 * transition back to 64 bit mode
327ae115bc7Smrj	 */
328ae115bc7Smrj	pushl	$B64CODE_SEL
329ae115bc7Smrj	pushl	$longmode
330ae115bc7Smrj	lret
331ae115bc7Smrjlongmode:
332ae115bc7Smrj	.code64
333ae115bc7Smrj	/*
334ae115bc7Smrj	 * restore caller frame pointer and segment registers
335ae115bc7Smrj	 */
336ae115bc7Smrj	lgdt	save_gdt
337ae115bc7Smrj	lidt	save_idt
338ae115bc7Smrj
339ae115bc7Smrj	/*
340ae115bc7Smrj	 * Before loading the task register we need to reset the busy bit
341ae115bc7Smrj	 * in its corresponding GDT selector. The busy bit is the 2nd bit in
342ae115bc7Smrj	 * the 5th byte of the selector.
343ae115bc7Smrj	 */
344ae115bc7Smrj	movzwq	save_tr, %rax
345ae115bc7Smrj	addq	save_gdt+2, %rax
346ae115bc7Smrj	btcl	$1, 5(%rax)
347ae115bc7Smrj	ltr	save_tr
348ae115bc7Smrj	movw	save_ds, %ds
349ae115bc7Smrj	movw	save_ss, %ss
350ae115bc7Smrj	movw	save_es, %es
351ae115bc7Smrj	movw	save_fs, %fs
352ae115bc7Smrj	movw	save_gs, %gs
353ae115bc7Smrj
354ae115bc7Smrj	pushq	save_cs
355ae115bc7Smrj	pushq	$.newcs
356ae115bc7Smrj	lretq
357ae115bc7Smrj.newcs:
358ae115bc7Smrj
359ae115bc7Smrj	/*
360ae115bc7Smrj	 * restore the hidden kernel segment base register values
361ae115bc7Smrj	 */
362ae115bc7Smrj	movl	save_fsbase, %eax
363ae115bc7Smrj	movl	save_fsbase + 4, %edx
364ae115bc7Smrj	movl	$MSR_AMD_FSBASE, %ecx
365ae115bc7Smrj	wrmsr
366ae115bc7Smrj
367ae115bc7Smrj	movl	save_gsbase, %eax
368ae115bc7Smrj	movl	save_gsbase + 4, %edx
369ae115bc7Smrj	movl	$MSR_AMD_GSBASE, %ecx
370ae115bc7Smrj	wrmsr
371ae115bc7Smrj
372ae115bc7Smrj	movl	save_kgsbase, %eax
373ae115bc7Smrj	movl	save_kgsbase + 4, %edx
374ae115bc7Smrj	movl	$MSR_AMD_KGSBASE, %ecx
375ae115bc7Smrj	wrmsr
376ae115bc7Smrj
377ae115bc7Smrj	movq	save_cr8, %rax
378ae115bc7Smrj	cmpq	$0, %rax
379ae115bc7Smrj	je	1f
380ae115bc7Smrj	movq	%rax, %cr8
381ae115bc7Smrj1:
382ae115bc7Smrj
383ae115bc7Smrj	/*
384ae115bc7Smrj	 * copy results to caller's location, then restore remaining registers
385ae115bc7Smrj	 */
386ae115bc7Smrj	movq    save_rsi, %rdi
387ae115bc7Smrj	movq	%rsp, %rsi
388ae115bc7Smrj	movq	$18, %rcx
389ae115bc7Smrj	rep
390ae115bc7Smrj	movsb
391ae115bc7Smrj	movw	18(%rsp), %ax
392ae115bc7Smrj	andq	$0xffff, %rax
393ae115bc7Smrj	movq    save_r12, %r12
394ae115bc7Smrj	movq    save_r13, %r13
395ae115bc7Smrj	movq    save_r14, %r14
396ae115bc7Smrj	movq    save_r15, %r15
397ae115bc7Smrj	movq    save_rbx, %rbx
398ae115bc7Smrj	movq    save_rbp, %rbp
399ae115bc7Smrj	movq    save_rsp, %rsp
400ae115bc7Smrj	ret
401ae115bc7Smrj
402ae115bc7Smrj
403ae115bc7Smrj/*
404ae115bc7Smrj * Caller's registers to restore
405ae115bc7Smrj */
406ae115bc7Smrj	.align 4
407ae115bc7Smrjsave_esi:
408ae115bc7Smrj	.long	0
409ae115bc7Smrjsave_edi:
410ae115bc7Smrj	.long	0
411ae115bc7Smrjsave_ebx:
412ae115bc7Smrj	.long	0
413ae115bc7Smrjsave_ebp:
414ae115bc7Smrj	.long	0
415ae115bc7Smrjsave_esp:
416ae115bc7Smrj	.long	0
417ae115bc7Smrj
418ae115bc7Smrj	.align 8
419ae115bc7Smrjsave_rsi:
420ae115bc7Smrj	.quad	0
421ae115bc7Smrjsave_rbx:
422ae115bc7Smrj	.quad	0
423ae115bc7Smrjsave_rbp:
424ae115bc7Smrj	.quad	0
425ae115bc7Smrjsave_rsp:
426ae115bc7Smrj	.quad	0
427ae115bc7Smrjsave_r12:
428ae115bc7Smrj	.quad	0
429ae115bc7Smrjsave_r13:
430ae115bc7Smrj	.quad	0
431ae115bc7Smrjsave_r14:
432ae115bc7Smrj	.quad	0
433ae115bc7Smrjsave_r15:
434ae115bc7Smrj	.quad	0
435ae115bc7Smrjsave_kgsbase:
436ae115bc7Smrj	.quad	0
437ae115bc7Smrjsave_gsbase:
438ae115bc7Smrj	.quad	0
439ae115bc7Smrjsave_fsbase:
440ae115bc7Smrj	.quad	0
441ae115bc7Smrjsave_cr8:
442ae115bc7Smrj	.quad	0
443ae115bc7Smrj
444ae115bc7Smrjsave_idt:
445ae115bc7Smrj	.quad	0
446ae115bc7Smrj	.quad	0
447ae115bc7Smrj
448ae115bc7Smrjsave_gdt:
449ae115bc7Smrj	.quad	0
450ae115bc7Smrj	.quad	0
451ae115bc7Smrj
452ae115bc7Smrjsave_cr0:
453ae115bc7Smrj	.quad	0
454ae115bc7Smrjsave_cr3:
455ae115bc7Smrj	.quad	0
456ae115bc7Smrjsave_cr4:
457ae115bc7Smrj	.quad	0
458ae115bc7Smrjsave_cs:
459ae115bc7Smrj	.quad	0
460ae115bc7Smrjsave_ss:
461ae115bc7Smrj	.value	0
462ae115bc7Smrjsave_ds:
463ae115bc7Smrj	.value	0
464ae115bc7Smrjsave_es:
465ae115bc7Smrj	.value	0
466ae115bc7Smrjsave_fs:
467ae115bc7Smrj	.value	0
468ae115bc7Smrjsave_gs:
469ae115bc7Smrj	.value	0
470ae115bc7Smrjsave_tr:
471ae115bc7Smrj	.value	0
472ae115bc7Smrj
473ae115bc7Smrjidt_info:
474ae115bc7Smrj	.value 0x3ff
475ae115bc7Smrj	.quad 0
476ae115bc7Smrj
477ae115bc7Smrj
478ae115bc7Smrj/*
479ae115bc7Smrj * We need to trampoline thru a gdt we have in low memory.
480ae115bc7Smrj */
481ae115bc7Smrj#include "../boot/boot_gdt.s"
482