summaryrefslogtreecommitdiff
path: root/usr/src/boot/efi/loader/arch/i386/multiboot_tramp.S
blob: 60be6a378d67ae79a5e75ce55530a00ecaaf54ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2016 Toomas Soome <tsoome@me.com>
 */

#include <x86/specialreg.h>

	.file	"multiboot_tramp.s"

/*
 * dboot expects a 32-bit multiboot environment and to execute in 32-bit mode.
 *
 * EAX: MB magic
 * EBX: 32-bit physical address of MBI
 * CS: 32-bit read/execute code segment with offset 0 and limit 0xFFFFFFFF
 * DS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * ES: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * FS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * GS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * SS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF
 * A20 enabled
 * CR0: PG cleared, PE set
 * EFLAGS: VM cleared, IF cleared
 * interrupts disabled
 */

		.set	SEL_SCODE,0x8
		.set	SEL_SDATA,0x10

		.text
		.p2align 4
		.globl	multiboot_tramp
		.type	multiboot_tramp, STT_FUNC

/*
 * Note as we are running in 32-bit mode, all pointers are 32-bit.
 * void multiboot_tramp(uint32_t magic, struct relocator *relocator,
 *    vm_offset_t entry)
 */
multiboot_tramp:
		cli
		pushl	%ebp		/* keep familiar stack frame */
		movl	%esp, %ebp	/* current SP */
		movl	0xc(%ebp),%eax	/* relocator */
		movl	(%eax), %eax	/* new SP */
		movl	%eax, %esp

		/* now copy arguments to new stack */
		movl	0x10(%ebp),%eax	/* entry */
		pushl	%eax
		movl	0xc(%ebp),%eax	/* relocator */
		pushl	%eax
		movl	0x8(%ebp),%eax	/* magic */
		pushl	%eax
		xorl	%eax,%eax
		pushl	%eax		/* fake IP, just to keep stack frame */
		pushl	%ebp
		movl	%esp, %ebp
		subl	$0x30, %esp	/* local mbi, gdt and gdt desc */

		movl	0xc(%ebp), %eax	/* relocator */
		pushl	%eax
		movl	0x4(%eax), %eax	/* relocator->copy */
		call	*%eax
		addl	$0x4, %esp
		movl	%eax, -0x4(%ebp)	/* save MBI */

		/* set up GDT descriptor */
		lea	-0x1c(%ebp), %eax	/* address of GDT */
		movw	$0x17, -0x22(%ebp)	/* limit */
		movl	%eax, -0x20(%ebp)	/* base */

/*
 * set up following GDT:
 *		.word	0x0, 0x0		NULL entry
 *		.byte	0x0, 0x0, 0x0, 0x0
 *		.word	0xffff, 0x0		code segment
 *		.byte	0x0, 0x9a, 0xcf, 0x0
 *		.word	0xffff, 0x0		data segment
 *		.byte	0x0, 0x92, 0xcf, 0x0
 *
 * This will create access for 4GB flat memory with
 * base = 0x00000000, segment limit = 0xffffffff
 * page granulariy 4k
 * 32-bit protected mode
 * ring 0
 * code segment is executable RW
 * data segment is not-executable RW
 */
		movw	$0x0, -0x1c(%ebp)
		movw	$0x0, -0x1a(%ebp)
		movb	$0x0, -0x18(%ebp)
		movb	$0x0, -0x17(%ebp)
		movb	$0x0, -0x16(%ebp)
		movb	$0x0, -0x15(%ebp)

		movw	$0xffff, -0x14(%ebp)
		movw	$0x0, -0x12(%ebp)
		movb	$0x0, -0x10(%ebp)
		movb	$0x9a, -0xf(%ebp)
		movb	$0xcf, -0xe(%ebp)
		movb	$0x0, -0xd(%ebp)

		movw	$0xffff, -0xc(%ebp)
		movw	$0x0, -0xa(%ebp)
		movb	$0x0, -0x8(%ebp)
		movb	$0x92, -0x7(%ebp)
		movb	$0xcf, -0x6(%ebp)
		movb	$0x0, -0x5(%ebp)

		lea	-0x22(%ebp), %eax	/* address of GDT */
		lgdt	(%eax)

		movl	0x8(%ebp), %edx		/* magic */
		movl	-0x4(%ebp), %ebx	/* MBI */
		movl	0x10(%ebp), %esi	/* entry */

		movl	$SEL_SDATA, %eax
		movw	%ax, %ss
		movw	%ax, %ds
		movw	%ax, %es
		movw	%ax, %fs
		movw	%ax, %gs

		/*
		 * We most likely don't need to push SEL_SDATA and esp
		 * because we do not expect to perform a privilege transition.
		 * However, it doesn't hurt us to push them as dboot will set
		 * up its own stack.
		 */
		movl	%esp, %eax
		pushl	$SEL_SDATA
		pushl	%eax
		pushf
		pushl	$SEL_SCODE
		pushl	%esi
		movl	%edx, %eax
		iretl

multiboot_tramp_end: