summaryrefslogtreecommitdiff
path: root/exec/loader-mipsel.s
blob: f1cdcfcf14916c02a455c6c53dd7b0541d1f8324 (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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# Copyright (C) 2023-2024 Free Software Foundation, Inc.
#
# This file is part of GNU Emacs.
#
# GNU Emacs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# GNU Emacs is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Emacs.	 If not, see <https://www.gnu.org/licenses/>.

include(`config-mips.m4')

# Make sure not to use t4 through t7, in order to maintain portability
# with N32 ABI systems.

	.set noreorder			# delay slots managed by hand
	.section .text
	.global __start
__start:
dnl	li	$v0, SYSCALL_nanosleep	# SYS_nanosleep
dnl	la	$a0, .timespec		# rqtp
dnl	li	$a1, 0			# rmtp
dnl	syscall				# syscall
	lw	$s6, ($sp)		# original stack pointer
	addi	$s0, $sp, 8		# start of load area
	addi	$sp, -8			# primary fd, secondary fd
	li	$t0, -1			# secondary fd
	sw	$t0, 4($sp)		# initialize secondary fd
.next_action:
	lw	$s2, ($s0)		# action number
	nop				# delay slot
	andi	$t0, $s2, 15		# t0 = s2 & 15
	beqz	$t0, .open_file		# open file?
	li	$t1, 3			# t1 = 3, delay slot
	beq	$t0, $t1, .rest_of_exec	# jump to code
	li	$t1, 4			# t1 = 4, delay slot
	beq	$t0, $t1, .do_mmap_anon	# anonymous mmap
.do_mmap:
	lw	$a0, 4($s0)		# vm_address, delay slot
	lw	$v1, 8($s0)		# file_offset
	lw	$a2, 12($s0)		# protection
	lw	$a1, 16($s0)		# length
	lw	$a3, 20($s0)		# flags
	lw	$v0, ($sp)		# primary fd
	andi	$t1, $s2, 16		# t1 = s2 & 16
	beqz	$t1, .do_mmap_1		# secondary fd?
	nop				# delay slot
	lw	$v0, 4($sp)		# secondary fd
	nop				# delay slot
.do_mmap_1:
SYSCALL(`$v0',`$v1',`$zero',`$zero')	# syscall args
	li	$v0, SYSCALL_mmap	# SYS_mmap
	syscall				# syscall
	bne	$a3, $zero, .perror	# perror
RESTORE()				# delay slot, restore sp
	lw	$s5, 24($s0)		# clear
	add	$t0, $a0, $a1		# t0 = length + vm_address, delay slot
	sub	$t1, $t0, $s5		# t1 = t0 - clear
.align:
	beq	$t0, $t1, .continue	# already finished?
	nop				# delay slot
	andi	$t2, $t1, 3		# t1 & 3?
	bnez	$t2, .fillw		# start filling longs
	nop				# delay slot
	sb	$zero, ($t1)		# clear byte
	addi	$t1, $t1, 1		# t1++
	j	.align			# continue
	nop				# delay slot
.fillw:
	sub	$t2, $t0, $t1		# t2 = t0 - t1
	sltiu	$t2, $t2, 32		# r2 < 32?
	bne	$t2, $zero, .fillb	# fill bytes
	nop				# delay slot
	sw	$zero, ($t1)		# zero word
	addi	$t1, $t1, 4		# next word
	sw	$zero, ($t1)		# zero word
	addi	$t1, $t1, 4		# next word
	sw	$zero, ($t1)		# zero word
	addi	$t1, $t1, 4		# next word
	sw	$zero, ($t1)		# zero word
	addi	$t1, $t1, 4		# next word
	sw	$zero, ($t1)		# zero word
	addi	$t1, $t1, 4		# next word
	sw	$zero, ($t1)		# zero word
	addi	$t1, $t1, 4		# next word
	sw	$zero, ($t1)		# zero word
	addi	$t1, $t1, 4		# next word
	sw	$zero, ($t1)		# zero word
	addi	$t1, $t1, 4		# next word
	j	.fillw			# fill either word or byte
	nop				# delay slot
.fillb:
	beq	$t0, $t1, .continue	# already finished?
	nop				# delay slot
	sb	$zero, ($t1)		# clear byte
	addi	$t1, $t1, 1		# t1++
.continue:
	addi	$s0, $s0, 28		# s0 = next action
	j	.next_action		# next action
	nop				# delay slot
.do_mmap_anon:
	lw	$v1, 8($s0)		# file_offset
	lw	$a2, 12($s0)		# protection
	lw	$a1, 16($s0)		# length
	lw	$a3, 20($s0)		# flags
	li	$t4, -1			# fd
	j	.do_mmap_1		# do mmap
	nop				# delay slot
.open_file:
	li	$v0, SYSCALL_open	# SYS_open
	addi	$a0, $s0, 4		# start of name
	move	$a1, $zero		# flags = O_RDONLY
	move	$a2, $zero		# mode = 0
	syscall				# syscall
	bne	$a3, $zero, .perror	# perror
	addi	$s0, $s0, 4		# start of string, delay slot
	move	$t3, $s0		# t3 = char past separator
.nextc:
	lb	$t0, ($s0)		# load byte
	addi	$s0, $s0, 1		# s0++
	li	$t1, 47			# directory separator `/'
	bne	$t0, $t1, .nextc1	# is separator char?
	nop				# delay slot
	move	$t3, $s0		# t3 = char past separator
.nextc1:
	bnez	$t0, .nextc		# next character?
	nop				# delay slot
	addi	$s0, $s0, 3		# adjust for round
	li	$t2, -4			# t2 = -4
	and	$s0, $s0, $t2		# mask for round
	andi	$t0, $s2, 16		# t1 = s2 & 16
	beqz	$t0, .primary		# primary fd?
	move	$t0, $sp		# address of primary fd, delay slot
	addi	$t0, $t0, 4		# address of secondary fd
	j	.next_action		# next action
.primary:
	sw	$v0, ($t0)		# store fd, delay slot
	li	$v0, SYSCALL_prctl	# SYS_prctl
	li	$a0, 15			# PR_SET_NAME
	move	$a1, $t3		# name
	move	$a2, $zero		# arg1
	move	$a3, $zero		# arg2
SYSCALL(`$a2',`$a2',`$a2',`$a2')	# syscall args
	syscall				# syscall
RESTORE()				# restore sp
	j	.next_action		# next action
	nop				# delay slot
.perror:
	move	$a0, $v0		# errno
	li	$v0, SYSCALL_exit	# SYS_exit
	syscall				# syscall
.rest_of_exec:
	move	$s1, $s6		# s1 = original SP
	lw	$t0, ($s1)		# argc
	nop				# delay slot
	sll	$t0, $t0, 2		# argc *= 4
	addi	$t0, $t0, 8		# argc += 8
	add	$s1, $s1, $t0		# s1 = start of envp
.skipenv:
	lw	$t0, ($s1)		# t0 = *s1
	addi	$s1, $s1, 4		# s1++
	bne	$t0, $zero, .skipenv	# skip again
	nop				# delay slot
	la	$s2, .auxvtab		# address of auxv table
.one_auxv:
	lw	$t0, ($s1)		# t0 = auxv type
	li	$t1, 10			# t1 = 10, delay slot
	beqz	$t0, .finish		# is AT_IGNORE?
	sltu	$t1, $t0, $t1		# t1 = t0 < num offsets, delay slot
	beq	$t1, $zero, .next	# next auxv
	sll	$t1, $t0, 2		# t1 = t0 * 4, delay slot
	add	$t1, $s2, $t1		# t1 = .auxvtab + t1
	lw	$t2, ($t1)		# t2 = *t1
	nop				# delay slot
	beqz	$t2, .next		# skip auxv
	add	$t2, $s0, $t2		# t2 = s0 + t2
	lw	$t2, ($t2)		# t2 = *t2
	nop				# delay slot
	sw	$t2, 4($s1)		# set auxv value
.next:
	addi	$s1, $s1, 8		# next auxv
	j	.one_auxv		# next auxv
	nop				# delay slot
.finish:
	lw	$t0, 4($sp)		# secondary fd
	lw	$s1, ($sp)		# primary fd, delay slot, preserved
	li	$t2, -1			# immediate -1
	beq	$t0, $t2, .finish1	# secondary fd set?
	li	$v0, SYSCALL_close	# SYS_close, delay slot
	move	$a0, $t0		# fd
	syscall				# syscall
	li	$v0, SYSCALL_close	# SYS_close
.finish1:
	move	$a0, $s1		# primary fd
	syscall				# syscall
	li	$v0, SYSCALL_prctl	# SYS_prctl
	li	$a0, 45			# PR_SET_FP_MODE
	lw	$a1, 28($s0)		# fpu_mode
	move	$a2, $zero		# arg3
	move	$a3, $zero		# arg4
SYSCALL(`$a2',`$a2',`$a2',`$a2')	# syscall args
	syscall				# syscall
RESTORE()				# restore sp
.jump:
	move	$v0, $zero		# rtld_fini
	lw	$t0, 4($s0)		# entry
	move	$sp, $s6		# restore stack pointer, delay slot
	jr	$t0			# enter
	nop				# delay slot

.auxvtab:
	.long	0			# 0
	.long	0			# 1
	.long	0			# 2
	.long	20			# 3 AT_PHDR
	.long	12			# 4 AT_PHENT
	.long	16			# 5 AT_PHNUM
	.long	0			# 6
	.long	24			# 7 AT_BASE
	.long	0			# 8
	.long	8			# 9 AT_ENTRY

.timespec:
	.long	10
	.long	10

# Local Variables:
# asm-comment-char: ?#
# End: