xref: /original-bsd/sys/i386/i386/locore.s (revision 0cad3712)
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
7 *
8 * %sccs.include.redist.c%
9 *
10 *	@(#)locore.s	7.10 (Berkeley) 10/11/92
11 */
12
13#include "assym.s"
14#include <machine/psl.h>
15#include <machine/pte.h>
16
17#include <sys/errno.h>
18
19#include <machine/trap.h>
20
21#include "npx.h"
22
23/*
24 * Note: This version greatly munged to avoid various assembler errors
25 * that may be fixed in newer versions of gas. Perhaps newer versions
26 * will have more pleasant appearance.
27 */
28
29	.set	IDXSHIFT,10
30	.set	SYSTEM,0xFE000000	# virtual address of system start
31	/*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */
32	.set	SYSPDROFF,0x3F8		# Page dir index of System Base
33
34/* IBM "compatible" nop - sensitive macro on "fast" 386 machines */
35#define	NOP	;
36
37/*
38 * PTmap is recursive pagemap at top of virtual address space.
39 * Within PTmap, the page directory can be found (third indirection).
40 */
41	.set	PDRPDROFF,0x3F7		# Page dir index of Page dir
42	.globl	_PTmap, _PTD, _PTDpde
43	.set	_PTmap,0xFDC00000
44	.set	_PTD,0xFDFF7000
45	.set	_PTDpde,0xFDFF7000+4*PDRPDROFF
46
47/*
48 * APTmap, APTD is the alternate recursive pagemap.
49 * It's used when modifying another process's page tables.
50 */
51	.set	APDRPDROFF,0x3FE		# Page dir index of Page dir
52	.globl	_APTmap, _APTD, _APTDpde
53	.set	_APTmap,0xFF800000
54	.set	_APTD,0xFFBFE000
55	.set	_APTDpde,0xFDFF7000+4*APDRPDROFF
56
57/*
58 * Access to each processes kernel stack is via a region of
59 * per-process address space (at the beginning), immediatly above
60 * the user process stack.
61 */
62	.set	_kstack, USRSTACK
63	.globl	_kstack
64	.set	PPDROFF,0x3F6
65	.set	PPTEOFF,0x400-UPAGES	# 0x3FE
66
67#define	ENTRY(name) \
68	.globl _/**/name; _/**/name:
69#define	ALTENTRY(name) \
70	.globl _/**/name; _/**/name:
71
72/*
73 * Initialization
74 */
75	.data
76	.globl	_cpu,_cold,_boothowto,_bootdev,_cyloffset,_atdevbase,_atdevphys
77_cpu:	.long	0		# are we 386, 386sx, or 486
78_cold:	.long	1		# cold till we are not
79_atdevbase:	.long	0	# location of start of iomem in virtual
80_atdevphys:	.long	0	# location of device mapping ptes (phys)
81
82	.globl	_IdlePTD, _KPTphys
83_IdlePTD:	.long	0
84_KPTphys:	.long	0
85
86pcb:
87	.space 8192
88tmpstk:
89pcb2:
90	.space 8192
91tmpstk2:
92	.text
93	.globl	start
94 #start:
95	.set start,0
96	movw	$0x1234,%ax
97	movw	%ax,0x472	# warm boot
98	jmp	1f
99	.space	0x500		# skip over warm boot shit
100
101	/* enable a20! yecchh!! - move this to bootstrap? */
1021:	inb	$0x64,%al
103	andb	$2,%al
104	jnz	1b
105	movb	$0xd1,%al
106	NOP
107	outb	%al,$0x64
108	NOP
1091:	inb	$0x64,%al
110	andb	$2,%al
111	jnz	1b
112	movb	$0xdf,%al
113	NOP
114	outb	%al,$0x60
115
116	/*
117	 * pass parameters on stack (howto, bootdev, unit, cyloffset)
118	 * note: 0(%esp) is return address of boot
119	 * ( if we want to hold onto /boot, it's physical %esp up to _end)
120	 */
121
122 1:	movl	4(%esp),%eax
123	movl	%eax,_boothowto-SYSTEM
124	movl	8(%esp),%eax
125	movl	%eax,_bootdev-SYSTEM
126	movl	12(%esp),%eax
127	movl	%eax, _cyloffset-SYSTEM
128
129	/* count up memory */
130
131	xorl	%edx,%edx		# start with base memory at 0x0
132	#movl	$ 0xA0000/NBPG,%ecx	# look every 4K up to 640K
133	movl	$ 0xA0,%ecx		# look every 4K up to 640K
1341:	movl	0(%edx),%ebx		# save location to check
135	movl	$0xa55a5aa5,0(%edx)	# write test pattern
136
137	inb	$0x84,%al		# flush write buffer
138	/* flush stupid cache here! (with bcopy (0,0,512*1024) ) */
139
140	cmpl	$0xa55a5aa5,0(%edx)	# does not check yet for rollover
141	jne	2f
142	movl	%ebx,0(%edx)		# restore memory
143	addl	$ NBPG,%edx
144	loop	1b
145
146	movl	$0x100000,%edx		# next, talley remaining memory
147	#movl	$((0xFFF000-0x100000)/NBPG),%ecx
148	movl	$(0xFFF-0x100),%ecx
1491:	movl	0(%edx),%ebx		# save location to check
150	movl	$0xa55a5aa5,0(%edx)	# write test pattern
151	cmpl	$0xa55a5aa5,0(%edx)	# does not check yet for rollover
152	jne	2f
153	movl	%ebx,0(%edx)		# restore memory
154	addl	$ NBPG,%edx
155	loop	1b
1562:	shrl	$12,%edx
157	movl	%edx,_Maxmem-SYSTEM
158
159/* find end of kernel image */
160	movl	$_end-SYSTEM,%ecx
161	addl	$ NBPG-1,%ecx
162	andl	$~(NBPG-1),%ecx
163	movl	%ecx,%esi
164
165/* clear bss and memory for bootstrap pagetables. */
166	movl	$_edata-SYSTEM,%edi
167	subl	%edi,%ecx
168	addl	$(UPAGES+5)*NBPG,%ecx
169/*
170 * Virtual address space of kernel:
171 *
172 *	text | data | bss | page dir | proc0 kernel stack | usr stk map | Sysmap
173 *			     0               1       2       3             4
174 */
175	xorl	%eax,%eax	# pattern
176	cld
177	rep
178	stosb
179
180	movl	%esi,_IdlePTD-SYSTEM /*physical address of Idle Address space */
181	movl	$ tmpstk-SYSTEM,%esp	# bootstrap stack end location
182
183#define	fillkpt		\
1841:	movl	%eax,0(%ebx)	; \
185	addl	$ NBPG,%eax	; /* increment physical address */ \
186	addl	$4,%ebx		; /* next pte */ \
187	loop	1b		;
188
189/*
190 * Map Kernel
191 * N.B. don't bother with making kernel text RO, as 386
192 * ignores R/W AND U/S bits on kernel access (only v works) !
193 *
194 * First step - build page tables
195 */
196	movl	%esi,%ecx		# this much memory,
197	shrl	$ PGSHIFT,%ecx		# for this many pte s
198	addl	$ UPAGES+4,%ecx		# including our early context
199	movl	$ PG_V,%eax		#  having these bits set,
200	lea	(4*NBPG)(%esi),%ebx	#   physical address of KPT in proc 0,
201	movl	%ebx,_KPTphys-SYSTEM	#    in the kernel page table,
202	fillkpt
203
204/* map I/O memory map */
205
206	movl	$0x100-0xa0,%ecx	# for this many pte s,
207	movl	$(0xa0000|PG_V),%eax	#  having these bits set, (perhaps URW?)
208	movl	%ebx,_atdevphys-SYSTEM	#   remember phys addr of ptes
209	fillkpt
210
211 /* map proc 0's kernel stack into user page table page */
212
213	movl	$ UPAGES,%ecx		# for this many pte s,
214	lea	(1*NBPG)(%esi),%eax	# physical address in proc 0
215	lea	(SYSTEM)(%eax),%edx
216	movl	%edx,_proc0paddr-SYSTEM  # remember VA for 0th process init
217	orl	$ PG_V|PG_URKW,%eax	#  having these bits set,
218	lea	(3*NBPG)(%esi),%ebx	# physical address of stack pt in proc 0
219	addl	$(PPTEOFF*4),%ebx
220	fillkpt
221
222/*
223 * Construct a page table directory
224 * (of page directory elements - pde's)
225 */
226	/* install a pde for temporary double map of bottom of VA */
227	lea	(4*NBPG)(%esi),%eax	# physical address of kernel page table
228	orl	$ PG_V,%eax		# pde entry is valid
229	movl	%eax,(%esi)		# which is where temp maps!
230
231	/* kernel pde's */
232	movl	$ 3,%ecx		# for this many pde s,
233	lea	(SYSPDROFF*4)(%esi), %ebx	# offset of pde for kernel
234	fillkpt
235
236	/* install a pde recursively mapping page directory as a page table! */
237	movl	%esi,%eax		# phys address of ptd in proc 0
238	orl	$ PG_V,%eax		# pde entry is valid
239	movl	%eax, PDRPDROFF*4(%esi)	# which is where PTmap maps!
240
241	/* install a pde to map kernel stack for proc 0 */
242	lea	(3*NBPG)(%esi),%eax	# physical address of pt in proc 0
243	orl	$ PG_V,%eax		# pde entry is valid
244	movl	%eax,PPDROFF*4(%esi)	# which is where kernel stack maps!
245
246	/* load base of page directory, and enable mapping */
247	movl	%esi,%eax		# phys address of ptd in proc 0
248 	orl	$ I386_CR3PAT,%eax
249	movl	%eax,%cr3		# load ptd addr into mmu
250	movl	%cr0,%eax		# get control word
251	orl	$0x80000001,%eax	# and let s page!
252	movl	%eax,%cr0		# NOW!
253
254	pushl	$begin				# jump to high mem!
255	ret
256
257begin: /* now running relocated at SYSTEM where the system is linked to run */
258
259	.globl _Crtat
260	movl	_Crtat,%eax
261	subl	$0xfe0a0000,%eax
262	movl	_atdevphys,%edx	# get pte PA
263	subl	_KPTphys,%edx	# remove base of ptes, now have phys offset
264	shll	$ PGSHIFT-2,%edx  # corresponding to virt offset
265	addl	$ SYSTEM,%edx	# add virtual base
266	movl	%edx, _atdevbase
267	addl	%eax,%edx
268	movl	%edx,_Crtat
269
270	/* set up bootstrap stack */
271	movl	$ _kstack+UPAGES*NBPG-4*12,%esp	# bootstrap stack end location
272	xorl	%eax,%eax		# mark end of frames
273	movl	%eax,%ebp
274	movl	_proc0paddr, %eax
275	movl	%esi, PCB_CR3(%eax)
276
277	lea	7*NBPG(%esi),%esi	# skip past stack.
278	pushl	%esi
279
280	call	_init386		# wire 386 chip for unix operation
281	popl	%esi
282
283	movl	$0,_PTD
284	call 	_main
285
286	.globl	__ucodesel,__udatasel
287	movzwl	__ucodesel,%eax
288	movzwl	__udatasel,%ecx
289	# build outer stack frame
290	pushl	%ecx		# user ss
291	pushl	$ USRSTACK	# user esp
292	pushl	%eax		# user cs
293	pushl	$0		# user ip
294	movw	%cx,%ds
295	movw	%cx,%es
296	# movw	%ax,%fs		# double map cs to fs
297	# movw	%cx,%gs		# and ds to gs
298	lret	# goto user!
299
300	pushl	$lretmsg1	/* "should never get here!" */
301	call	_panic
302lretmsg1:
303	.asciz	"lret: toinit\n"
304
305	.globl	__exit
306__exit:
307	call _reset_cpu
308	/* NOTREACHED */
309
310	.set	exec,59
311	.set	exit,1
312	.globl	_icode
313	.globl	_szicode
314
315#define	LCALL(x,y)	.byte 0x9a ; .long y; .word x
316/*
317 * Icode is copied out to process 1 to exec /etc/init.
318 * If the exec fails, process 1 exits.
319 */
320_icode:
321	pushl	$0 /* environment */
322
323	# pushl	$argv-_icode	# gas fucks up again
324	movl	$argv,%eax
325	subl	$_icode,%eax
326	pushl	%eax
327
328	# pushl	$init-_icode
329	movl	$init,%eax
330	subl	$_icode,%eax
331	pushl	%eax
332	pushl	%eax	# dummy out rta
333
334	movl	%esp,%ebp
335	movl	$exec,%eax
336	LCALL(0x7,0x0)
337	pushl	%eax
338	movl	$exit,%eax
339	pushl	%eax	# dummy out rta
340	LCALL(0x7,0x0)
341
342init:
343	.asciz	"/sbin/init"
344	.align	2
345argv:
346	.long	init+6-_icode		# argv[0] = "init" ("/sbin/init" + 6)
347	.long	eicode-_icode		# argv[1] follows icode after copyout
348	.long	0
349eicode:
350
351_szicode:
352	.long	_szicode-_icode
353
354	.globl	_sigcode,_szsigcode
355_sigcode:
356	movl	12(%esp),%eax	# unsure if call will dec stack 1st
357	call	%eax
358	xorl	%eax,%eax	# smaller movl $103,%eax
359	movb	$103,%al	# sigreturn()
360	LCALL(0x7,0)		# enter kernel with args on stack
361	hlt			# never gets here
362
363_szsigcode:
364	.long	_szsigcode-_sigcode
365
366	.globl ___udivsi3
367___udivsi3:
368	movl 4(%esp),%eax
369	xorl %edx,%edx
370	divl 8(%esp)
371	ret
372
373	.globl ___divsi3
374___divsi3:
375	movl 4(%esp),%eax
376	xorl %edx,%edx
377	cltd
378	idivl 8(%esp)
379	ret
380
381	.globl	_inb
382_inb:	movl	4(%esp),%edx
383	# inb	$0x84,%al	# Compaq SystemPro
384	subl	%eax,%eax	# clr eax
385	NOP
386	inb	%dx,%al
387	NOP
388	ret
389
390
391	.globl	_rtcin
392_rtcin:	movl	4(%esp),%eax
393	outb	%al,$0x70
394	subl	%eax,%eax	# clr eax
395	inb	$0x71,%al	# Compaq SystemPro
396	ret
397
398	.globl	_outb
399_outb:	movl	4(%esp),%edx
400	movl	8(%esp),%eax
401	NOP
402	outb	%al,%dx
403	# inb	$0x84,%al
404	NOP
405	ret
406
407	#
408	# bzero (base,cnt)
409	#
410
411	.globl _bzero
412	.globl _blkclr
413_bzero:
414_blkclr:
415	pushl	%edi
416	movl	8(%esp),%edi
417	movl	12(%esp),%ecx
418	xorl	%eax,%eax
419	shrl	$2,%ecx
420	cld
421	rep
422	stosl
423	movl	12(%esp),%ecx
424	andl	$3,%ecx
425	rep
426	stosb
427	popl	%edi
428	ret
429
430	#
431	# fillw (pat,base,cnt)
432	#
433
434	.globl _fillw
435_fillw:
436	pushl	%edi
437	movl	8(%esp),%eax
438	movl	12(%esp),%edi
439	movl	16(%esp),%ecx
440	cld
441	rep
442	stosw
443	popl	%edi
444	ret
445
446	#
447	# bcopy (src,dst,cnt)
448	# NOTE: does not (yet) handle overlapped copies
449	#
450
451	.globl	_bcopy
452_bcopy:
453	pushl	%esi
454	pushl	%edi
455	movl	12(%esp),%esi
456	movl	16(%esp),%edi
457	movl	20(%esp),%ecx
458	shrl	$2,%ecx
459	cld
460	rep
461	movsl
462	movl	20(%esp),%ecx
463	andl	$3,%ecx
464	rep
465	movsb
466	popl	%edi
467	popl	%esi
468	xorl	%eax,%eax
469	ret
470
471	#
472	# ovbcopy (src,dst,cnt)
473	# NOTE: does not (yet) work doing words at a time
474	#
475
476	.globl	_ovbcopy
477_ovbcopy:
478	pushl	%esi
479	pushl	%edi
480	movl	12(%esp),%esi
481	movl	16(%esp),%edi
482	movl	20(%esp),%ecx
483	addl	%ecx,%esi	/* copy from end to beginning */
484	addl	%ecx,%edi
485	decl	%esi
486	decl	%edi
487	std			/* decrementing as we go */
488	rep
489	movsb
490	popl	%edi
491	popl	%esi
492	xorl	%eax,%eax
493	cld
494	ret
495
496	.globl	_copyin
497_copyin:
498	movl	_curpcb,%eax
499	movl	$cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
500	pushl	%esi
501	pushl	%edi
502	movl	12(%esp),%esi
503	movl	16(%esp),%edi
504	movl	20(%esp),%ecx
505
506	/* if dest >= USRSTACK, return error */
507	cmpl	$ USRSTACK, %esi
508	jae	cpyflt
509
510	/* if USRSTACK-dest < len, return error */
511	movl	$ USRSTACK, %eax
512	subl	%esi, %eax
513	cmpl	%ecx, %eax
514	jb	cpyflt
515
516	shrl	$2,%ecx
517	cld
518	rep
519	movsl
520	movl	20(%esp),%ecx
521	andl	$3,%ecx
522	rep
523	movsb
524	popl	%edi
525	popl	%esi
526	xorl	%eax,%eax
527	movl	_curpcb,%edx
528	movl	%eax,PCB_ONFAULT(%edx)
529	ret
530
531cpyflt: popl	%edi
532	popl	%esi
533	movl	_curpcb,%edx
534	movl	$0,PCB_ONFAULT(%edx)
535	movl	$ EFAULT,%eax
536	ret
537
538	# insb(port,addr,cnt)
539	.globl	_insb
540_insb:
541	pushl	%edi
542	movw	8(%esp),%dx
543	movl	12(%esp),%edi
544	movl	16(%esp),%ecx
545	cld
546	NOP
547	rep
548	insb
549	NOP
550	movl	%edi,%eax
551	popl	%edi
552	ret
553
554	# insw(port,addr,cnt)
555	.globl	_insw
556_insw:
557	pushl	%edi
558	movw	8(%esp),%dx
559	movl	12(%esp),%edi
560	movl	16(%esp),%ecx
561	cld
562	NOP
563	.byte 0x66,0xf2,0x6d	# rep insw
564	NOP
565	movl	%edi,%eax
566	popl	%edi
567	ret
568
569	# outsw(port,addr,cnt)
570	.globl	_outsw
571_outsw:
572	pushl	%esi
573	movw	8(%esp),%dx
574	movl	12(%esp),%esi
575	movl	16(%esp),%ecx
576	cld
577	NOP
578	.byte 0x66,0xf2,0x6f	# rep outsw
579	NOP
580	movl	%esi,%eax
581	popl	%esi
582	ret
583
584	# lgdt(*gdt, ngdt)
585	.globl	_lgdt
586	# .globl	_gdt
587xxx:	.word 31
588	.long 0
589_lgdt:
590	movl	4(%esp),%eax
591	movl	%eax,xxx+2
592	movl	8(%esp),%eax
593	movw	%ax,xxx
594	lgdt	xxx
595	jmp	1f
596	NOP
5971:	movw	$0x10,%ax
598	movw	%ax,%ds
599	movw	%ax,%es
600	movw	%ax,%ss
601	movl	0(%esp),%eax
602	pushl	%eax
603	movl	$8,4(%esp)
604	lret
605
606	# lidt(*idt, nidt)
607	.globl	_lidt
608yyy:	.word	255
609	.long	0
610_lidt:
611	movl	4(%esp),%eax
612	movl	%eax,yyy+2
613	movl	8(%esp),%eax
614	movw	%ax,yyy
615	lidt	yyy
616	ret
617
618	# lldt(sel)
619	.globl	_lldt
620_lldt:
621	movl	4(%esp),%eax
622	lldt	%eax
623	ret
624
625	# ltr(sel)
626	.globl	_ltr
627_ltr:
628	movl	4(%esp),%eax
629	ltr	%eax
630	ret
631
632	# lcr3(cr3)
633	.globl	_lcr3
634	.globl	_load_cr3
635_load_cr3:
636_lcr3:
637	inb	$0x84,%al	# check wristwatch
638	movl	4(%esp),%eax
639 	orl	$ I386_CR3PAT,%eax
640
641	movl	$tmpstk2,%edx
642	movl	(%edx),%ecx	# touch stack, fault if not there
643	movl	%ecx,(%edx)
644	movl	%esp,%ecx
645	movl	%edx,%esp
646
647	movl	%eax,%cr3
648	inb	$0x84,%al	# check wristwatch
649
650	movl	(%ecx),%edx	# touch stack, fault if not there
651	movl	%edx,(%ecx)
652	movl	%ecx,%esp
653	ret
654
655	# tlbflush()
656	.globl	_tlbflush
657_tlbflush:
658	inb	$0x84,%al	# check wristwatch
659	movl	%cr3,%eax
660 	orl	$ I386_CR3PAT,%eax
661
662	movl	$tmpstk2,%edx
663	movl	(%edx),%ecx	# touch stack, fault if not there
664	movl	%ecx,(%edx)
665	movl	%esp,%ecx
666	movl	%edx,%esp
667
668	movl	%eax,%cr3
669	inb	$0x84,%al	# check wristwatch
670
671	movl	(%ecx),%edx	# touch stack, fault if not there
672	movl	%edx,(%ecx)
673	movl	%ecx,%esp
674	ret
675
676	# lcr0(cr0)
677	.globl	_lcr0,_load_cr0
678_lcr0:
679_load_cr0:
680	movl	4(%esp),%eax
681	movl	%eax,%cr0
682	ret
683
684	# rcr0()
685	.globl	_rcr0
686_rcr0:
687	movl	%cr0,%eax
688	ret
689
690	# rcr2()
691	.globl	_rcr2
692_rcr2:
693	movl	%cr2,%eax
694	ret
695
696	# rcr3()
697	.globl	_rcr3
698	.globl	__cr3
699__cr3:
700_rcr3:
701	movl	%cr3,%eax
702	ret
703
704	# ssdtosd(*ssdp,*sdp)
705	.globl	_ssdtosd
706_ssdtosd:
707	pushl	%ebx
708	movl	8(%esp),%ecx
709	movl	8(%ecx),%ebx
710	shll	$16,%ebx
711	movl	(%ecx),%edx
712	roll	$16,%edx
713	movb	%dh,%bl
714	movb	%dl,%bh
715	rorl	$8,%ebx
716	movl	4(%ecx),%eax
717	movw	%ax,%dx
718	andl	$0xf0000,%eax
719	orl	%eax,%ebx
720	movl	12(%esp),%ecx
721	movl	%edx,(%ecx)
722	movl	%ebx,4(%ecx)
723	popl	%ebx
724	ret
725
726/*
727 * {fu,su},{byte,word}
728 */
729ALTENTRY(fuiword)
730ENTRY(fuword)
731	movl	_curpcb,%ecx
732	movl	$fusufault,PCB_ONFAULT(%ecx)
733	movl	4(%esp),%edx
734
735	cmpl	$ USRSTACK - 3, %edx
736	jae	fusufault
737
738	# .byte	0x65		# use gs
739	movl	0(%edx),%eax
740	movl	$0,PCB_ONFAULT(%ecx)
741	ret
742
743ALTENTRY(fuibyte)
744ENTRY(fubyte)
745	movl	_curpcb,%ecx
746	movl	$fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
747	movl	4(%esp),%edx
748
749	cmpl	$ USRSTACK, %edx
750	jae	fusufault
751
752	# .byte	0x65		# use gs
753	movzbl	0(%edx),%eax
754	movl	$0,PCB_ONFAULT(%ecx)
755	ret
756
757fusufault:
758	movl	_curpcb,%ecx
759	xorl	%eax,%eax
760	movl	%eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
761	decl	%eax
762	ret
763
764
765/*
766 * There is a little bit of duplicated code so we can avoid flushing the
767 * prefetch queue in the common case.
768 */
769
770ALTENTRY(suiword)
771ENTRY(suword)
772	movl 4(%esp), %eax /* address */
773
774	cmpl $ USRSTACK, %eax
775	jae return_minus_one
776
777	/* check if the destination crosses a page boundary */
778	movl %eax, %ecx
779	andl $ NBPG - 1, %ecx
780	cmpl $ NBPG - 4, %ecx
781	ja suword_breakup
782
783	/* make sure the page table is present */
784	movl %eax, %ecx
785	shrl $ PDRSHIFT, %ecx
786	movl _PTD(,%ecx,4), %ecx
787	andl $ PG_V, %ecx
788	jnz suword_fault
789
790	/* now make sure the page is present with user write permission */
791	movl %eax, %ecx
792	shrl $ PGSHIFT, %ecx
793	movl _PTmap(,%ecx,4), %ecx
794	andl $ PG_V | PG_UW, %ecx
795	cmpl $ PG_V | PG_UW, %ecx
796	jnz suword_fault
797
798	movl 8(%esp), %ecx
799	movl %ecx, (%eax)
800	xorl %eax, %eax
801	ret
802
803suword_fault:
804	/*
805	 * this is a slow case anyway, so build a frame to make the debugger
806	 * more useful
807	 */
808	pushl %ebp
809	movl %esp, %ebp
810
811	pushl %eax
812	call _user_write_fault
813
814	leave
815
816	cmpl $0, %eax
817	jnz return_minus_one
818
819	movl 4(%esp), %eax
820	movl 8(%esp), %ecx
821	movl %ecx, (%eax)
822	xorl %eax, %eax
823	ret
824
825
826suword_breakup:
827	/* crosses page boundary ... do each byte separately */
828	pushl %ebp
829	movl %esp, %ebp
830	pushl %esi
831	pushl %edi
832	pushl %ebx
833
834	movl %eax, %edi
835	movl 12(%ebp), %ebx
836	movl $4, %esi
837
838suword_breakup_loop:
839	pushl %ebx
840	pushl %edi
841	call _subyte
842	addl $8, %esp
843
844	cmpl $-1, %eax
845	jz suword_breakup_error
846
847	incl %edi
848	shrl $8, %ebx
849	decl %esi
850	jnz suword_breakup_loop
851
852	xorl %eax, %eax
853	popl %ebx
854	popl %edi
855	popl %esi
856	leave
857	ret
858
859suword_breakup_error:
860	movl $-1, %eax
861	popl %ebx
862	popl %edi
863	popl %esi
864	leave
865	ret
866
867ALTENTRY(suibyte)
868ENTRY(subyte)
869	movl 4(%esp), %eax /* address */
870
871	cmpl $ USRSTACK, %eax
872	jae return_minus_one
873
874	/* make sure the page table is present */
875	movl %eax, %ecx
876	shrl $ PDRSHIFT, %ecx
877	movl _PTD(,%ecx,4), %ecx
878	andl $ PG_V, %ecx
879	jnz subyte_fault
880
881	/* now make sure the page is present with user write permission */
882	movl %eax, %ecx
883	shrl $ PGSHIFT, %ecx
884	movl _PTmap(,%ecx,4), %ecx
885	andl $ PG_V | PG_UW, %ecx
886	cmpl $ PG_V | PG_UW, %ecx
887	jnz subyte_fault
888
889	movl 8(%esp), %ecx
890	movb %cl, (%eax)
891	xorl %eax, %eax
892	ret
893
894subyte_fault:
895	pushl %ebp
896	movl %esp, %ebp
897
898	pushl %eax
899	call _user_write_fault
900
901	leave
902
903	cmpl $0, %eax
904	jnz return_minus_one
905
906	movl 4(%esp), %eax
907	movl 8(%esp), %ecx
908	movb %cl, (%eax)
909	xorl %eax, %eax
910	ret
911
912return_minus_one:
913	movl $-1, %eax
914	ret
915
916	ENTRY(setjmp)
917	movl	4(%esp),%eax
918	movl	%ebx, 0(%eax)		# save ebx
919	movl	%esp, 4(%eax)		# save esp
920	movl	%ebp, 8(%eax)		# save ebp
921	movl	%esi,12(%eax)		# save esi
922	movl	%edi,16(%eax)		# save edi
923	movl	(%esp),%edx		# get rta
924	movl	%edx,20(%eax)		# save eip
925	xorl	%eax,%eax		# return (0);
926	ret
927
928#ifdef notdef
929	ENTRY(longjmp)
930	movl	4(%esp),%eax
931	movl	 0(%eax),%ebx		# restore ebx
932	movl	 4(%eax),%esp		# restore esp
933	movl	 8(%eax),%ebp		# restore ebp
934	movl	12(%eax),%esi		# restore esi
935	movl	16(%eax),%edi		# restore edi
936	movl	20(%eax),%edx		# get rta
937	movl	%edx,(%esp)		# put in return frame
938	xorl	%eax,%eax		# return (1);
939	incl	%eax
940	ret
941#endif
942/*
943 * The following primitives manipulate the run queues.
944 * _whichqs tells which of the 32 queues _qs
945 * have processes in them.  Setrq puts processes into queues, Remrq
946 * removes them from queues.  The running process is on no queue,
947 * other processes are on a queue related to p->p_pri, divided by 4
948 * actually to shrink the 0-127 range of priorities into the 32 available
949 * queues.
950 */
951
952	.globl	_whichqs,_qs,_cnt,_panic
953	.comm	_noproc,4
954	.comm	_runrun,4
955
956/*
957 * Setrq(p)
958 *
959 * Call should be made at spl6(), and p->p_stat should be SRUN
960 */
961ENTRY(setrq)
962	movl	4(%esp),%eax
963	cmpl	$0,P_RLINK(%eax)	# should not be on q already
964	je	set1
965	pushl	$set2
966	call	_panic
967set1:
968	movzbl	P_PRI(%eax),%edx
969	shrl	$2,%edx
970	btsl	%edx,_whichqs		# set q full bit
971	shll	$3,%edx
972	addl	$_qs,%edx		# locate q hdr
973	movl	%edx,P_LINK(%eax)	# link process on tail of q
974	movl	P_RLINK(%edx),%ecx
975	movl	%ecx,P_RLINK(%eax)
976	movl	%eax,P_RLINK(%edx)
977	movl	%eax,P_LINK(%ecx)
978	ret
979
980set2:	.asciz	"setrq"
981
982/*
983 * Remrq(p)
984 *
985 * Call should be made at spl6().
986 */
987ENTRY(remrq)
988	movl	4(%esp),%eax
989	movzbl	P_PRI(%eax),%edx
990	shrl	$2,%edx
991	btrl	%edx,_whichqs		# clear full bit, panic if clear already
992	jb	rem1
993	pushl	$rem3
994	call	_panic
995rem1:
996	pushl	%edx
997	movl	P_LINK(%eax),%ecx	# unlink process
998	movl	P_RLINK(%eax),%edx
999	movl	%edx,P_RLINK(%ecx)
1000	movl	P_RLINK(%eax),%ecx
1001	movl	P_LINK(%eax),%edx
1002	movl	%edx,P_LINK(%ecx)
1003	popl	%edx
1004	movl	$_qs,%ecx
1005	shll	$3,%edx
1006	addl	%edx,%ecx
1007	cmpl	P_LINK(%ecx),%ecx	# q still has something?
1008	je	rem2
1009	shrl	$3,%edx			# yes, set bit as still full
1010	btsl	%edx,_whichqs
1011rem2:
1012	movl	$0,P_RLINK(%eax)	# zap reverse link to indicate off list
1013	ret
1014
1015rem3:	.asciz	"remrq"
1016sw0:	.asciz	"swtch"
1017
1018/*
1019 * When no processes are on the runq, Swtch branches to idle
1020 * to wait for something to come ready.
1021 */
1022	.globl	Idle
1023Idle:
1024idle:
1025	call	_spl0
1026	cmpl	$0,_whichqs
1027	jne	sw1
1028	hlt		# wait for interrupt
1029	jmp	idle
1030
1031badsw:
1032	pushl	$sw0
1033	call	_panic
1034	/*NOTREACHED*/
1035
1036/*
1037 * Swtch()
1038 */
1039ENTRY(swtch)
1040
1041	incl	_cnt+V_SWTCH
1042
1043	/* switch to new process. first, save context as needed */
1044
1045	movl	_curproc,%ecx
1046	movl	P_ADDR(%ecx),%ecx
1047
1048
1049	movl	(%esp),%eax		# Hardware registers
1050	movl	%eax, PCB_EIP(%ecx)
1051	movl	%ebx, PCB_EBX(%ecx)
1052	movl	%esp, PCB_ESP(%ecx)
1053	movl	%ebp, PCB_EBP(%ecx)
1054	movl	%esi, PCB_ESI(%ecx)
1055	movl	%edi, PCB_EDI(%ecx)
1056
1057#if 0 && NNPX > 0
1058	movb	PCB_FLAGS(%ecx),%al
1059	/* have we used fp, and need a save? */
1060	andb	$ FP_WASUSED|FP_NEEDSSAVE,%al
1061	cmpb	$ FP_WASUSED|FP_NEEDSSAVE,%al
1062	jne	1f
1063	movl	%cr0,%eax		/* insure fp is enabled */
1064	andb 	$0xfb,%al
1065	movl	%eax,%cr0
1066	fnsave	PCB_SAVEFPU(%ecx)
1067	orb 	$4,%al			/* disable it */
1068	movl	%eax,%cr0
1069	movb	PCB_FLAGS(%ecx),%al
1070	xorb	$ FP_NEEDSSAVE,%al	/* save processed */
1071	movb	%al,PCB_FLAGS(%ecx)
10721:
1073#endif
1074
1075	movl	_CMAP2,%eax		# save temporary map PTE
1076	movl	%eax,PCB_CMAP2(%ecx)	# in our context
1077
1078	movw	_cpl, %ax
1079	movw	%ax, PCB_IML(%ecx)	# save ipl
1080
1081	movl	$tmpstk2,%edx
1082	movl	(%edx),%eax	# touch stack, fault if not there
1083	movl	%eax,(%edx)
1084	movl	%edx,%esp
1085	movl	$pcb2,_curpcb
1086
1087	/* save is done, now choose a new process or idle */
1088sw1:
1089	cli				# XXX?
1090	movl	_whichqs,%edi
10912:
1092	bsfl	%edi,%eax		# find a full q
1093	jz	idle			# if none, idle
1094	# XX update whichqs?
1095swfnd:
1096	btrl	%eax,%edi		# clear q full status
1097	jnb	2b		# if it was clear, look for another
1098	movl	%eax,%ebx		# save which one we are using
1099
1100	shll	$3,%eax
1101	addl	$_qs,%eax		# select q
1102	movl	%eax,%esi
1103
1104#ifdef	DIAGNOSTIC
1105	cmpl	P_LINK(%eax),%eax # linked to self? (e.g. not on list)
1106	je	badsw			# not possible
1107#endif
1108
1109	movl	P_LINK(%eax),%ecx	# unlink from front of process q
1110	movl	P_LINK(%ecx),%edx
1111	movl	%edx,P_LINK(%eax)
1112	movl	P_RLINK(%ecx),%eax
1113	movl	%eax,P_RLINK(%edx)
1114
1115	cmpl	P_LINK(%ecx),%esi	# q empty
1116	je	3f
1117	btsl	%ebx,%edi		# nope, set to indicate full
11183:
1119	movl	%edi,_whichqs		# update q status
1120
1121	movl	$0,%eax
1122	movl	%ecx,_curproc
1123	movl	%eax,_want_resched
1124
1125#ifdef	DIAGNOSTIC
1126	cmpl	%eax,P_WCHAN(%ecx)
1127	jne	badsw
1128	cmpb	$ SRUN,P_STAT(%ecx)
1129	jne	badsw
1130#endif
1131
1132	movl	%eax,P_RLINK(%ecx) /* isolate process to run */
1133	movl	P_ADDR(%ecx),%edx
1134	movl	%edx,_curpcb
1135	inb	$0x84,%al	# flush write buffers
1136	movl	PCB_CR3(%edx),%ebx
1137
1138	/* switch address space */
1139	cli
1140 	orl	$ I386_CR3PAT,%ebx
1141	movl	%ebx,%cr3	# context switch address space
1142
1143	jmp	7f
1144	nop
1145 7:	inb	$0x84,%al	# flush write buffers
1146	movl	PCB_ESP(%edx), %ecx
1147	movl	(%ecx),%eax	# touch stack, fault if not there
1148	movl	%eax,(%ecx)
1149	movl	%ecx,%esp
1150
1151	/* restore context */
1152	movl	PCB_EBX(%edx), %ebx
1153	movl	PCB_ESP(%edx), %esp
1154	movl	PCB_EBP(%edx), %ebp
1155	movl	PCB_ESI(%edx), %esi
1156	movl	PCB_EDI(%edx), %edi
1157	movl	PCB_EIP(%edx), %eax
1158	movl	%eax, (%esp)
1159
1160#if NNPX > 0
1161#ifdef notdef
1162	movb	PCB_FLAGS(%edx),%al
1163	/* if fp could be used, a dna trap will do a restore */
1164	testb	$ FP_WASUSED,%al
1165	je	1f
1166	orb	$ FP_NEEDSRESTORE,PCB_FLAGS(%ecx)
11671:
1168#endif
1169	movl	%cr0,%eax
1170	orb 	$4,%al			/* disable it */
1171	movl	%eax,%cr0
1172#endif
1173
1174	movl	PCB_CMAP2(%edx),%eax	# get temporary map
1175	movl	%eax,_CMAP2		# reload temporary map PTE
1176
1177	pushl	PCB_IML(%edx)
1178	call	_splx
1179	popl	%eax
1180
1181	movl	%edx,%eax		# return (1);
1182	ret
1183
1184/*
1185 * struct proc *swtch_to_inactive(p) ; struct proc *p;
1186 *
1187 * At exit of a process, move off the address space of the
1188 * process and onto a "safe" one. Then, on a temporary stack
1189 * return and run code that disposes of the old state.
1190 * Since this code requires a parameter from the "old" stack,
1191 * pass it back as a return value.
1192 */
1193ENTRY(swtch_to_inactive)
1194
1195	movl	$tmpstk2-4,%ecx		# temporary stack, compensated for call
1196	movl	(%ecx),%eax		# touch stack, fault if not there
1197	movl	%eax,(%ecx)
1198
1199	popl	%edx			# old pc
1200	popl	%eax			# arg, our return value
1201	inb	$0x84,%al	# flush write buffers
1202
1203	movl	%ecx,%esp
1204
1205	movl	_IdlePTD,%ecx
1206
1207	movl	%ecx,%cr3		# good bye address space
1208	inb	$0x84,%al	# flush write buffers
1209
1210 #write buffer?
1211	movl	$pcb2,_curpcb
1212	jmp	%edx			# return, execute remainder of cleanup
1213
1214/*
1215 * savectx(pcb, altreturn)
1216 * Update pcb, saving current processor state and arranging
1217 * for alternate return ala longjmp in swtch if altreturn is true.
1218 */
1219ENTRY(savectx)
1220	movl	4(%esp), %ecx
1221	movw	_cpl, %ax
1222	movw	%ax,  PCB_IML(%ecx)
1223	movl	(%esp), %eax
1224	movl	%eax, PCB_EIP(%ecx)
1225	movl	%ebx, PCB_EBX(%ecx)
1226	movl	%esp, PCB_ESP(%ecx)
1227	movl	%ebp, PCB_EBP(%ecx)
1228	movl	%esi, PCB_ESI(%ecx)
1229	movl	%edi, PCB_EDI(%ecx)
1230#if 0 && NNPX > 0
1231	/* have we ever used fp, and need to save? */
1232	testb	$ FP_WASUSED, PCB_FLAGS(%ecx)
1233	je	1f
1234	movl	%cr0, %edx
1235	andb 	$0xfb, %dl
1236	movl	%edx, %cr0
1237	fnsave	PCB_SAVEFPU(%ecx)
1238	orb 	$4, %edx
1239	movl	%edx, %cr0
12401:
1241#endif
1242	movl	_CMAP2, %edx		# save temporary map PTE
1243	movl	%edx, PCB_CMAP2(%ecx)	# in our context
1244
1245	cmpl	$0, 8(%esp)
1246	je	1f
1247	movl	%esp, %edx		# relocate current sp relative to pcb
1248	subl	$_kstack, %edx		#   (sp is relative to kstack):
1249	addl	%edx, %ecx		#   pcb += sp - kstack;
1250	movl	%eax, (%ecx)		# write return pc at (relocated) sp@
1251	# this mess deals with replicating register state gcc hides
1252	movl	12(%esp),%eax
1253	movl	%eax,12(%ecx)
1254	movl	16(%esp),%eax
1255	movl	%eax,16(%ecx)
1256	movl	20(%esp),%eax
1257	movl	%eax,20(%ecx)
1258	movl	24(%esp),%eax
1259	movl	%eax,24(%ecx)
12601:
1261	xorl	%eax, %eax		# return 0
1262	ret
1263
1264	.globl	_mvesp
1265_mvesp:	movl	%esp,%eax
1266	ret
1267
1268/*
1269 * update profiling information for the user
1270 * addupc(pc, up, ticks) struct uprof *up;
1271 */
1272
1273ENTRY(addupc)
1274	movl	4(%esp),%eax		/* pc */
1275	movl	8(%esp),%ecx		/* up */
1276
1277	/* does sampled pc fall within bottom of profiling window? */
1278	subl	PR_OFF(%ecx),%eax 	/* pc -= up->pr_off; */
1279	jl	1f 			/* if (pc < 0) return; */
1280
1281	/* construct scaled index */
1282	shrl	$1,%eax			/* reduce pc to a short index */
1283	mull	PR_SCALE(%ecx)		/* pc*up->pr_scale */
1284	shrdl	$15,%edx,%eax 		/* praddr >> 15 */
1285	cmpl	$0,%edx			/* if overflow, ignore */
1286	jne	1f
1287	andb	$0xfe,%al		/* praddr &= ~1 */
1288
1289	/* within profiling buffer? if so, compute address */
1290	cmpl	%eax,PR_SIZE(%ecx)	/* if (praddr > up->pr_size) return; */
1291	jg	1f
1292	addl	PR_BASE(%ecx),%eax	/* praddr += up->pr_base; */
1293
1294	/* tally ticks to selected counter */
1295	movl	_curpcb,%ecx
1296	movl	$proffault,PCB_ONFAULT(%ecx) #in case we page/protection violate
1297	movl	12(%esp),%edx		/* ticks */
1298	addw	%dx,(%eax)
1299	movl	$0,PCB_ONFAULT(%ecx)
13001:	ret
1301
1302proffault:
1303	/* disable profiling if we get a fault */
1304	movl	$0,PR_SCALE(%ecx) /*	up->pr_scale = 0; */
1305	movl	_curpcb,%ecx
1306	movl	$0,PCB_ONFAULT(%ecx)
1307	ret
1308
1309.data
1310	.globl	_cyloffset, _curpcb
1311_cyloffset:	.long	0
1312	.globl	_proc0paddr
1313_proc0paddr:	.long	0
1314LF:	.asciz "swtch %x"
1315
1316.text
1317	.globl _astoff
1318_astoff:
1319	movl	$0,_astpending
1320	ret
1321
1322#define	IDTVEC(name)	.align 4; .globl _X/**/name; _X/**/name:
1323#define	PANIC(msg)	xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \
1324			call _panic; 1: .asciz msg
1325#define	PRINTF(n,msg)	pushal ; pushl 1f; call _printf; MSG(msg) ; \
1326			 popl %eax ; popal
1327#define	MSG(msg)	.data; 1: .asciz msg; .text
1328
1329	.text
1330
1331/*
1332 * Trap and fault vector routines
1333 */
1334#define	TRAP(a)		pushl $a ; jmp alltraps
1335#ifdef KGDB
1336#define	BPTTRAP(a)	pushl $a ; jmp bpttraps
1337#else
1338#define	BPTTRAP(a)	TRAP(a)
1339#endif
1340
1341IDTVEC(div)
1342	pushl $0; TRAP(T_DIVIDE)
1343IDTVEC(dbg)
1344	pushl $0; BPTTRAP(T_TRCTRAP)
1345IDTVEC(nmi)
1346	pushl $0; TRAP(T_NMI)
1347IDTVEC(bpt)
1348	pushl $0; BPTTRAP(T_BPTFLT)
1349IDTVEC(ofl)
1350	pushl $0; TRAP(T_OFLOW)
1351IDTVEC(bnd)
1352	pushl $0; TRAP(T_BOUND)
1353IDTVEC(ill)
1354	pushl $0; TRAP(T_PRIVINFLT)
1355IDTVEC(dna)
1356	pushl $0; TRAP(T_DNA)
1357IDTVEC(dble)
1358	TRAP(T_DOUBLEFLT)
1359	/*PANIC("Double Fault");*/
1360IDTVEC(fpusegm)
1361	pushl $0; TRAP(T_FPOPFLT)
1362IDTVEC(tss)
1363	TRAP(T_TSSFLT)
1364	/*PANIC("TSS not valid");*/
1365IDTVEC(missing)
1366	TRAP(T_SEGNPFLT)
1367IDTVEC(stk)
1368	TRAP(T_STKFLT)
1369IDTVEC(prot)
1370	TRAP(T_PROTFLT)
1371IDTVEC(page)
1372	TRAP(T_PAGEFLT)
1373IDTVEC(rsvd)
1374	pushl $0; TRAP(T_RESERVED)
1375IDTVEC(fpu)
1376	pushl $0; TRAP(T_ARITHTRAP)
1377	/* 17 - 31 reserved for future exp */
1378IDTVEC(rsvd0)
1379	pushl $0; TRAP(17)
1380IDTVEC(rsvd1)
1381	pushl $0; TRAP(18)
1382IDTVEC(rsvd2)
1383	pushl $0; TRAP(19)
1384IDTVEC(rsvd3)
1385	pushl $0; TRAP(20)
1386IDTVEC(rsvd4)
1387	pushl $0; TRAP(21)
1388IDTVEC(rsvd5)
1389	pushl $0; TRAP(22)
1390IDTVEC(rsvd6)
1391	pushl $0; TRAP(23)
1392IDTVEC(rsvd7)
1393	pushl $0; TRAP(24)
1394IDTVEC(rsvd8)
1395	pushl $0; TRAP(25)
1396IDTVEC(rsvd9)
1397	pushl $0; TRAP(26)
1398IDTVEC(rsvd10)
1399	pushl $0; TRAP(27)
1400IDTVEC(rsvd11)
1401	pushl $0; TRAP(28)
1402IDTVEC(rsvd12)
1403	pushl $0; TRAP(29)
1404IDTVEC(rsvd13)
1405	pushl $0; TRAP(30)
1406IDTVEC(rsvd14)
1407	pushl $0; TRAP(31)
1408
1409alltraps:
1410	pushal
1411	push %ds
1412	push %es
1413	movw	$0x10,%ax
1414	movw	%ax,%ds
1415	movw	%ax,%es
1416calltrap:
1417	incl	_cnt+V_TRAP
1418	call	_trap
1419
1420	cli
1421
1422	/* this value may also be used in return_to_user_mode */
1423	movl	0x34(%esp),%esi /* previous cs */
1424	andl	$3,%esi
1425	jz	trap_return
1426
1427	cmpl	$0,_astpending
1428	jnz	do_astflt
1429
1430	cmpw	$0,_cpl
1431	jnz	return_to_user_mode /* in icu.s */
1432
1433trap_return:
1434	pop %es
1435	pop %ds
1436	popal
1437	nop
1438	addl	$8,%esp			# pop type, code
1439	iret
1440
1441do_astflt:
1442	/* pop off the old trap frame, then create a new one that
1443	 * will give trap() another chance
1444	 */
1445	pop	%es
1446	pop	%ds
1447	popa
1448	addl	$8,%esp
1449
1450	pushl	$0
1451	TRAP (T_ASTFLT)
1452	/* NORETURN */
1453
1454
1455
1456#ifdef KGDB
1457/*
1458 * This code checks for a kgdb trap, then falls through
1459 * to the regular trap code.
1460 */
1461bpttraps:
1462	pushal
1463	push	%es
1464	push	%ds
1465	movw	$0x10,%ax
1466	movw	%ax,%ds
1467	movw	%ax,%es
1468	movzwl	52(%esp),%eax
1469	test	$3,%eax
1470	jne	calltrap
1471	call	_kgdb_trap_glue
1472	jmp	calltrap
1473#endif
1474
1475/*
1476 * Call gate entry for syscall
1477 */
1478
1479IDTVEC(syscall)
1480	pushfl	# only for stupid carry bit and more stupid wait3 cc kludge
1481	pushal	# only need eax,ecx,edx - trap resaves others
1482	movw	$0x10,%ax	# switch to kernel segments
1483	movw	%ax,%ds
1484	movw	%ax,%es
1485	call	_syscall
1486
1487	cli
1488
1489	cmpl	$0,_astpending
1490	jnz	syscall_ast
1491
1492	cmpw	$0,_cpl
1493	jnz	syscall_fix_cpl
1494
1495	movw	__udatasel,%ax	# switch back to user segments
1496	movw	%ax,%ds
1497	movw	%ax,%es
1498	popal
1499	nop
1500	popfl
1501	lret
1502
1503syscall_ast:
1504	movw	__udatasel,%ax
1505	movw	%ax,%ds
1506	movw	%ax,%es
1507	popal
1508
1509	/* convert to trap frame
1510	 * stack is now ss, sp, cs,    ip, flags
1511	 * we want      ss, sp, flags, cs, ip
1512 	 * offsets      16  12  8      4   0
1513	 */
1514	xchgl	%eax,8(%esp) /* now eax has cs */
1515	xchgl	%eax,4(%esp) /* now eax has ip */
1516	xchgl	%eax,0(%esp) /* now eax has flags */
1517	xchgl	%eax,8(%esp) /* now eax has its original value */
1518	pushl $0
1519	TRAP (T_ASTFLT)
1520	/* NORETURN */
1521
1522syscall_fix_cpl:
1523	movw	__udatasel,%ax
1524	movw	%ax,%ds
1525	movw	%ax,%es
1526	popal
1527
1528	/* convert to trap frame
1529	 * stack is now ss, sp, cs,    ip, flags
1530	 * we want      ss, sp, flags, cs, ip
1531 	 * offsets      16  12  8      4   0
1532	 */
1533	xchgl	%eax,8(%esp) /* now eax has cs */
1534	xchgl	%eax,4(%esp) /* now eax has ip */
1535	xchgl	%eax,0(%esp) /* now eax has flags */
1536	xchgl	%eax,8(%esp) /* now eax has its original value */
1537
1538	pushl $0
1539	pushl $ T_ASTFLT
1540
1541	pushal
1542	nop
1543	push %ds
1544	push %es
1545	movw	$0x10,%ax
1546	movw	%ax,%ds
1547	movw	%ax,%es
1548
1549	movl	$1, %esi /* non-zero to indicate return to user mode */
1550	jmp	return_to_user_mode /* in icu.s */
1551
1552
1553ENTRY(htonl)
1554ENTRY(ntohl)
1555	movl	4(%esp),%eax
1556	xchgb	%al,%ah
1557	roll	$16,%eax
1558	xchgb	%al,%ah
1559	ret
1560
1561ENTRY(htons)
1562ENTRY(ntohs)
1563	movzwl	4(%esp),%eax
1564	xchgb	%al,%ah
1565	ret
1566
1567/* DELAY(n)  delay about n microseconds */
1568ENTRY(DELAY)
1569	movl 4(%esp), %ecx
1570	incl %ecx /* make DELAY(0) go through the loop just once */
1571
1572	/*
1573	 * 0x80 is the manufacturing test port, which should be safe to
1574	 * write to on any motherboard.  The output instruction will
1575	 * be executed at bus speed, rather than processor speed, so
1576	 * it will be about 750ns on any ISA or EISA machine.
1577	 */
15781:
1579	outb %al, $0x80
1580	loop 1b
1581	ret
1582
1583#include "vector.s"
1584#include <i386/isa/icu.s>
1585