summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/arch/i386/core/virtaddr.S
blob: 5e5d7735247530743a6df3b8646670e604f1b096 (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
/*
 * Functions to support the virtual addressing method of relocation
 * that Etherboot uses.
 *
 */

FILE_LICENCE ( GPL2_OR_LATER )

#include "librm.h"
		
	.arch i386
	.text
	.code32
	
/****************************************************************************
 * _virt_to_phys (virtual addressing)
 *
 * Switch from virtual to flat physical addresses.  %esp is adjusted
 * to a physical value.  Segment registers are set to flat physical
 * selectors.  All other registers are preserved.  Flags are
 * preserved.
 *
 * Parameters: none
 * Returns: none
 ****************************************************************************
 */
	.globl _virt_to_phys
_virt_to_phys:
	/* Preserve registers and flags */
	pushfl
	pushl	%eax
	pushl	%ebp

	/* Change return address to a physical address */
	movl	virt_offset, %ebp
	addl	%ebp, 12(%esp)

	/* Switch to physical code segment */
	cli
	pushl	$PHYSICAL_CS
	leal	1f(%ebp), %eax
	pushl	%eax
	lret
1:
	/* Reload other segment registers and adjust %esp */
	movl	$PHYSICAL_DS, %eax
	movl	%eax, %ds
	movl	%eax, %es
	movl	%eax, %fs
	movl	%eax, %gs
	movl	%eax, %ss
	addl	%ebp, %esp

	/* Restore registers and flags, and return */
	popl	%ebp
	popl	%eax
	popfl
	ret

/****************************************************************************
 * _phys_to_virt (flat physical addressing)
 *
 * Switch from flat physical to virtual addresses.  %esp is adjusted
 * to a virtual value.  Segment registers are set to virtual
 * selectors.  All other registers are preserved.  Flags are
 * preserved.
 *
 * Parameters: none
 * Returns: none
 ****************************************************************************
 */
	.globl _phys_to_virt
_phys_to_virt:
	/* Preserve registers and flags */
	pushfl
	pushl	%eax
	pushl	%ebp

	/* Switch to virtual code segment */
	cli
	ljmp	$VIRTUAL_CS, $1f
1:
	/* Reload data segment registers */
	movl	$VIRTUAL_DS, %eax
	movl	%eax, %ds
	movl	%eax, %es
	movl	%eax, %fs
	movl	%eax, %gs

	/* Reload stack segment and adjust %esp */
	movl	virt_offset, %ebp
	movl	%eax, %ss
	subl	%ebp, %esp

	/* Change the return address to a virtual address */
	subl	%ebp, 12(%esp)

	/* Restore registers and flags, and return */
	popl	%ebp
	popl	%eax
	popfl
	ret

/****************************************************************************
 * _intr_to_virt (virtual code segment, virtual or physical stack segment)
 *
 * Switch from virtual code segment with either a virtual or physical
 * stack segment to using virtual addressing.  %esp is adjusted if
 * necessary to a virtual value.  Segment registers are set to virtual
 * selectors.  All other registers are preserved.  Flags are
 * preserved.
 *
 * Parameters: none
 * Returns: none
 ****************************************************************************
 */
	.globl _intr_to_virt
_intr_to_virt:
	/* Preserve registers and flags */
	pushfl
	pushl	%eax
	pushl	%ebp

	/* Check whether stack segment is physical or virtual */
	movl	%ss, %eax
	cmpw	$VIRTUAL_DS, %ax
	movl	$VIRTUAL_DS, %eax

	/* Reload data segment registers */
	movl	%eax, %ds
	movl	%eax, %es
	movl	%eax, %fs
	movl	%eax, %gs

	/* Reload stack segment and adjust %esp if necessary */
	je	1f
	movl	virt_offset, %ebp
	movl	%eax, %ss
	subl	%ebp, %esp
1:
	/* Restore registers and flags, and return */
	popl	%ebp
	popl	%eax
	popfl
	ret