xref: /original-bsd/sys/i386/i386/locore.s (revision 95a66346)
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.386.c%
9 *
10 *	@(#)locore.s	5.9 (Berkeley) 01/19/91
11 */
12
13/*
14 * locore.s:	4BSD machine support for the Intel 386
15 *		Preliminary version
16 *		Written by William F. Jolitz, 386BSD Project
17 */
18
19#include "machine/psl.h"
20#include "machine/pte.h"
21
22#include "errno.h"
23#include "cmap.h"
24
25#include "machine/trap.h"
26
27/*
28 * Note: This version greatly munged to avoid various assembler errors
29 * that may be fixed in newer versions of gas. Perhaps newer versions
30 * will have more pleasant appearance.
31 */
32
33	.set	IDXSHIFT,10
34	.set	SYSTEM,0xFE000000	# virtual address of system start
35	/*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */
36	.set	SYSPDROFF,0x3F8		# Page dir
37
38	.set	IOPHYSmem,0xa0000
39
40/* IBM "compatible" nop - sensitive macro on "fast" 386 machines */
41#define	NOP	jmp 7f ; nop ; 7: jmp 7f ; nop ; 7:
42
43/*
44 * User structure is UPAGES at top of user space.
45 */
46	.set	_u,0xFDFFE000
47	.globl	_u
48	.set	UPDROFF,0x3F7
49	.set	UPTEOFF,0x3FE
50
51#define	ENTRY(name) \
52	.globl _/**/name; _/**/name:
53#define	ALTENTRY(name) \
54	.globl _/**/name; _/**/name:
55
56/*
57 * System page table
58 * Mbmap and Usrptmap are enlarged by CLSIZE entries
59 * as they are managed by resource maps starting with index 1 or CLSIZE.
60 */
61#define	SYSMAP(mname, vname, npte)		\
62_/**/mname:	.globl	_/**/mname;		\
63	.space	(npte)*4;			\
64	.set	_/**/vname,ptes*NBPG+SYSTEM;	\
65	.globl	_/**/vname;			\
66	.set	ptes,ptes + npte
67#define	ZSYSMAP(mname, vname, npte)		\
68_/**/mname:	.globl	_/**/mname;		\
69	.set	_/**/vname,ptes*NBPG+SYSTEM;	\
70	.globl	_/**/vname;
71
72	.data
73	# assumed to start at data mod 4096
74	.set	ptes,0
75	SYSMAP(Sysmap,Sysbase,SYSPTSIZE)
76	SYSMAP(Forkmap,forkutl,UPAGES)
77	SYSMAP(Xswapmap,xswaputl,UPAGES)
78	SYSMAP(Xswap2map,xswap2utl,UPAGES)
79	SYSMAP(Swapmap,swaputl,UPAGES)
80	SYSMAP(Pushmap,pushutl,UPAGES)
81	SYSMAP(Vfmap,vfutl,UPAGES)
82	SYSMAP(CMAP1,CADDR1,1)
83	SYSMAP(CMAP2,CADDR2,1)
84	SYSMAP(mmap,vmmap,1)
85	SYSMAP(alignmap,alignutl,1)	/* XXX */
86	SYSMAP(msgbufmap,msgbuf,MSGBUFPTECNT)
87	/* SYSMAP(EMCmap,EMCbase,1) */
88	SYSMAP(Npxmap,npxutl,UPAGES)
89	SYSMAP(Swtchmap,Swtchbase,UPAGES)
90	.set mbxxx,(NMBCLUSTERS*MCLBYTES)
91	.set mbyyy,(mbxxx>>PGSHIFT)
92	.set mbpgs,(mbyyy+CLSIZE)
93	SYSMAP(Mbmap,mbutl,mbpgs)
94	/*
95	 * XXX: NEED way to compute kmem size from maxusers,
96	 * device complement
97	 */
98	SYSMAP(kmempt,kmembase,300*CLSIZE)
99#ifdef	GPROF
100	SYSMAP(profmap,profbase,600*CLSIZE)
101#endif
102	.set	atmemsz,0x100000-0xa0000
103	.set	atpgs,(atmemsz>>PGSHIFT)
104	SYSMAP(ATDevmem,atdevbase,atpgs)
105	SYSMAP(Usriomap,usrio,USRIOSIZE+CLSIZE) /* for PHYSIO */
106	ZSYSMAP(ekmempt,kmemlimit,0)
107	SYSMAP(Usrptmap,usrpt,USRPTSIZE+CLSIZE)
108
109eSysmap:
110	# .set	_Syssize,(eSysmap-_Sysmap)/4
111	.set	_Syssize,ptes
112	.globl	_Syssize
113
114	/* align on next page boundary */
115	# . = . + NBPG - 1 & -NBPG	/* align to page boundry-does not work*/
116	# .space (PGSIZE - ((eSysmap-_Sysmap) % PGSIZE)) % PGSIZE
117	.set sz,(4*ptes)%NBPG
118	# .set rptes,(ptes)%1024
119	# .set rptes,1024-rptes
120	# .set ptes,ptes+rptes
121	.set Npdes,8
122	# .space (NBPG - sz)
123
124/*
125 * Initialization
126 */
127	.data
128	.globl	_cpu, _cold, _boothowto, _bootdev, _cyloffset, _Maxmem
129_cpu:	.long	0		# are we 386, 386sx, or 486
130_cold:	.long	1		# cold till we are not
131	.text
132	.globl	start
133start:				# This is assumed to be location zero!
134	movw	$0x1234,%ax
135	movw	%ax,0x472	# warm boot
136	jmp	1f
137	.space	0x500		# skip over warm boot shit
138
139	/* enable a20! yecchh!! */
1401:	inb	$0x64,%al
141	andb	$2,%al
142	jnz	1b
143	movb	$0xd1,%al
144	NOP
145	outb	%al,$0x64
146	NOP
1471:	inb	$0x64,%al
148	andb	$2,%al
149	jnz	1b
150	movb	$0xdf,%al
151	NOP
152	outb	%al,$0x60
153
154	/* pass parameters on stack (howto, bootdev, unit, cyloffset) */
155
156	movl	4(%esp),%eax
157	movl	%eax,_boothowto-SYSTEM
158	movl	8(%esp),%eax
159	movl	%eax,_bootdev-SYSTEM
160	movl	12(%esp),%eax
161	movl	%eax, _cyloffset-SYSTEM
162
163	/* count up memory */
164
165	xorl	%eax,%eax		# start with base memory at 0x0
166	#movl	$ 0xA0000/NBPG,%ecx	# look every 4K up to 640K
167	movl	$ 0xA0,%ecx		# look every 4K up to 640K
1681:	movl	0(%eax),%ebx		# save location to check
169	movl	$0xa55a5aa5,0(%eax)	# write test pattern
170	cmpl	$0xa55a5aa5,0(%eax)	# does not check yet for rollover
171	jne	2f
172	movl	%ebx,0(%eax)		# restore memory
173	addl	$ NBPG,%eax
174	loop	1b
1752:	shrl	$12,%eax
176	movl	%eax,_Maxmem-SYSTEM
177
178	movl	$0x100000,%eax		# next, talley remaining memory
179	#movl	$((0xFFF000-0x100000)/NBPG),%ecx
180	movl	$(0xFFF-0x100),%ecx
1811:	movl	0(%eax),%ebx		# save location to check
182	movl	$0xa55a5aa5,0(%eax)	# write test pattern
183	cmpl	$0xa55a5aa5,0(%eax)	# does not check yet for rollover
184	jne	2f
185	movl	%ebx,0(%eax)		# restore memory
186	addl	$ NBPG,%eax
187	loop	1b
1882:	shrl	$12,%eax
189	movl	%eax,_Maxmem-SYSTEM
190
191/* clear memory. */
192	movl	$_edata-SYSTEM,%edi
193	movl	$_end-SYSTEM,%ecx
194	addl	$ NBPG-1,%ecx
195	andl	$~(NBPG-1),%ecx
196	movl	%ecx,%esi
197	subl	%edi,%ecx
198	addl	$(UPAGES*NBPG)+NBPG+NBPG+NBPG,%ecx
199	#	txt+data+proc zero pt+u.
200	xorl	%eax,%eax	# pattern
201	cld
202	rep
203	stosb
204
205/* should do all of memory, but some systems don't probe correctly (yet)*/
206	movl	$0x100000,%edi
207	movl	$0x200000,%ecx
208	xorl	%eax,%eax	# pattern
209	cld
210	rep
211	stosb
212/*
213 * Map Kernel
214 * N.B. don't bother with making kernel text RO, as 386
215 * ignores R/W AND U/S bits on kernel access (only v works) !
216 *
217 * First step - build page tables
218 */
219	movl	%esi,%ecx		# this much memory,
220	shrl	$ PGSHIFT,%ecx		# for this many pte s
221	movl	$ PG_V,%eax		#  having these bits set,
222	movl	$_Sysmap-SYSTEM,%ebx	#   in the kernel page table,
223					#    fill in kernel page table.
2241:	movl	%eax,0(%ebx)
225	addl	$ NBPG,%eax			# increment physical address
226	addl	$4,%ebx				# next pte
227	loop	1b
228
229/* temporary double map  virt == real */
230
231	movl	$1024,%ecx		# for this many pte s,
232	movl	$ PG_V,%eax		#  having these bits set,
233	movl	$_Sysmap+4096-SYSTEM,%ebx	#   in the temporary page table,
234					#    fill in kernel page table.
2351:	movl	%eax,0(%ebx)
236	addl	$ NBPG,%eax			# increment physical address
237	addl	$4,%ebx				# next pte
238	loop	1b
239
240/* map I/O memory map */
241
242	movl	$atpgs,%ecx		# for this many pte s,
243	movl	$(IOPHYSmem|PG_V),%eax	#  having these bits set, (perhaps URW?)
244	movl	$_ATDevmem-SYSTEM,%ebx	#   in the temporary page table,
245					#    fill in kernel page table.
2461:	movl	%eax,0(%ebx)
247	addl	$ NBPG,%eax			# increment physical address
248	addl	$4,%ebx				# next pte
249	loop	1b
250
251/* map proc 0's page table (P1 region) */
252
253	movl	$_Usrptmap-SYSTEM,%ebx	# get pt map address
254	lea	(0*NBPG)(%esi),%eax	# physical address of pt in proc 0
255	orl	$ PG_V,%eax		#  having these bits set,
256	movl	%eax,0(%ebx)
257
258 /* map proc 0's _u */
259
260	movl	$ UPAGES,%ecx		# for this many pte s,
261	lea	(2*NBPG)(%esi),%eax	# physical address of _u in proc 0
262	orl	$ PG_V|PG_URKW,%eax	#  having these bits set,
263	lea	(0*NBPG)(%esi),%ebx	# physical address of stack pt in proc 0
264	addl	$(UPTEOFF*4),%ebx
265					#    fill in proc 0 stack page table.
2661:	movl	%eax,0(%ebx)
267	addl	$ NBPG,%eax			# increment physical address
268	addl	$4,%ebx				# next pte
269	loop	1b
270
271 /* locate proc 0's page directory*/
272	lea	(1*NBPG)(%esi),%eax	# physical address of ptd in proc 0
273	movl	%eax,%edi		# remember ptd physical address
274
275/*
276 * Construct a page table directory
277 * (of page directory elements - pde's)
278 */
279					/* kernel pde's */
280	movl	$_Sysmap-SYSTEM,%eax	# physical address of kernel page table
281	orl	$ PG_V,%eax		# pde entry is valid
282	movl	$ Npdes,%ecx		# for this many pde s,
283	movl	%edi,%ebx		# phys address of ptd in proc 0
284	addl	$(SYSPDROFF*4), %ebx	# offset of pde for kernel
2851:	movl	%eax,0(%ebx)
286	addl	$ NBPG,%eax			# increment physical address
287	addl	$4,%ebx				# next pde
288	loop	1b
289					# install a pde for temporary double map
290	movl	$_Sysmap+4096-SYSTEM,%eax	# physical address of temp page table
291	orl	$ PG_V,%eax		# pde entry is valid
292	movl	%edi,%ebx		# phys address of ptd in proc 0
293	movl	%eax,0(%ebx)			# which is where temp maps!
294					# install a pde to map _u for proc 0
295	lea	(0*NBPG)(%esi),%eax	# physical address of pt in proc 0
296	orl	$ PG_V,%eax		# pde entry is valid
297	movl	%edi,%ebx		# phys address of ptd in proc 0
298	addl	$(UPDROFF*4), %ebx	# offset of pde for kernel
299	movl	%eax,0(%ebx)		# which is where _u maps!
300
301	movl	%edi,%eax		# phys address of ptd in proc 0
302 	orl	$ I386_CR3PAT,%eax
303	movl	%eax,%cr3		# load ptd addr into mmu
304	movl	%cr0,%eax		# get control word
305	orl	$0x80000001,%eax	# and let s page!
306	movl	%eax,%cr0		# NOW!
307
308	pushl	$begin				# jump to high mem!
309	ret		# jmp $begin does not work
310begin:
311	movl	$_Sysbase,%eax		# kernel stack just below system
312	movl	%eax,%esp
313	xorl	%eax,%eax		# mark end of frames
314	movl	%eax,%ebp
315
316	movl	_Crtat,%eax		# initialize Crt video ram address
317	subl	$ IOPHYSmem,%eax
318	addl	$_atdevbase,%eax
319	movl	%eax,_Crtat
320
321	call	_init386		# wire 386 chip for unix operation
322
323/* initialize (slightly) the pcb */
324	movl	$_u,%eax		# proc0 u-area
325	movl	$_usrpt,%ecx
326	movl	%ecx,PCB_P0BR(%eax)	# p0br: SVA of text/data user PT
327	xorl	%ecx,%ecx
328	movl	%ecx,PCB_P0LR(%eax)	# p0lr: 0 (doesn t really exist)
329	movl	%ecx,PCB_FLAGS(%eax)	# no fp yet.
330	movl	$_usrpt+NBPG,%ecx	# addr of end of PT
331	subl	$ P1PAGES*4,%ecx		# backwards size of P1 region
332	movl	%ecx,PCB_P1BR(%eax)	# p1br: P1PAGES from end of PT
333	movl	$ P1PAGES-UPAGES,PCB_P1LR(%eax)	# p1lr: vax style
334	movl	$ CLSIZE,PCB_SZPT(%eax)	# page table size
335	movl	%edi,PCB_CR3(%eax)
336	pushl	%edi	# cr3
337	movl	%esi,%eax
338	addl	$(UPAGES*NBPG)+NBPG+NBPG+NBPG,%eax
339	shrl	$ PGSHIFT,%eax
340	pushl	%eax	# firstaddr
341
342	pushl	$20		# install signal trampoline code
343	pushl	$_u+PCB_SIGC
344	pushl	$sigcode
345	call	_bcopy
346	addl	$12,%esp
347
348	call 	_main
349
350	.globl	__ucodesel,__udatasel
351	movzwl	__ucodesel,%eax
352	movzwl	__udatasel,%ecx
353	# build outer stack frame
354	pushl	%ecx		# user ss
355	pushl	$_u	# user esp
356	pushl	%eax	# user cs
357	pushl	$0	# user ip
358	movw	%cx,%ds
359	movw	%cx,%es
360	movw	%ax,%fs		# double map cs to fs
361	movw	%cx,%gs		# and ds to gs
362	lret	# goto user!
363
364	.globl	__exit
365__exit:
366	call _reset_cpu
367	/* NOTREACHED */
368
369	.set	exec,11
370	.set	exit,1
371	.globl	_icode
372	.globl	_initflags
373	.globl	_szicode
374/* gas fucks up offset -- */
375#define	LCALL(x,y)	.byte 0x9a ; .long y; .word x
376/*
377 * Icode is copied out to process 1 to exec /etc/init.
378 * If the exec fails, process 1 exits.
379 */
380_icode:
381	# pushl	$argv-_icode	# gas fucks up again
382	movl	$argv,%eax
383	subl	$_icode,%eax
384	pushl	%eax
385
386	# pushl	$init-_icode
387	movl	$init,%eax
388	subl	$_icode,%eax
389	pushl	%eax
390	pushl	%eax	# dummy out rta
391
392	movl	%esp,%ebp
393	movl	$exec,%eax
394	LCALL(0x7,0x0)
395	pushl	%eax
396	movl	$exit,%eax
397	pushl	%eax	# dummy out rta
398	LCALL(0x7,0x0)
399
400init:	.asciz	"/sbin/init"
401	.align	2
402_initflags:
403	.long	0
404argv:	.long	init-_icode
405	.long	_initflags-_icode
406	.long	0
407_szicode:
408	.long	_szicode-_icode
409sigcode:
410	movl	12(%esp),%eax	# unsure if call will dec stack 1st
411	call	%eax
412	xorl	%eax,%eax	# smaller movl $103,%eax
413	movb	$103,%al	# sigreturn()
414	LCALL(0x7,0)		# enter kernel with args on stack
415	hlt			# never gets here
416
417
418	.globl ___udivsi3
419___udivsi3:
420	movl 4(%esp),%eax
421	xorl %edx,%edx
422	divl 8(%esp)
423	ret
424
425	.globl ___divsi3
426___divsi3:
427	movl 4(%esp),%eax
428	xorl %edx,%edx
429	cltd
430	idivl 8(%esp)
431	ret
432
433	.globl	_inb
434_inb:	movl	4(%esp),%edx
435	inb	$0x84,%al	# Compaq SystemPro
436	subl	%eax,%eax	# clr eax
437	NOP
438	inb	%dx,%al
439	NOP
440	ret
441
442	.globl	_outb
443_outb:	movl	4(%esp),%edx
444	movl	8(%esp),%eax
445	NOP
446	outb	%al,%dx
447	inb	$0x84,%al
448	NOP
449	ret
450
451	#
452	# bzero (base,cnt)
453	#
454
455	.globl _bzero
456	.globl _blkclr
457_bzero:
458_blkclr:
459	pushl	%edi
460	movl	8(%esp),%edi
461	movl	12(%esp),%ecx
462	xorl	%eax,%eax
463	shrl	$2,%ecx
464	cld
465	rep
466	stosl
467	movl	12(%esp),%ecx
468	andl	$3,%ecx
469	rep
470	stosb
471	popl	%edi
472	ret
473
474	#
475	# fillw (pat,base,cnt)
476	#
477
478	.globl _fillw
479_fillw:
480	pushl	%edi
481	movl	8(%esp),%eax
482	movl	12(%esp),%edi
483	movl	16(%esp),%ecx
484	# xorl	%eax,%eax
485	cld
486	rep
487	stosw
488	popl	%edi
489	ret
490
491	#
492	# bcopy (src,dst,cnt)
493	# NOTE: does not (yet) handle overlapped copies
494	#
495
496	.globl	_bcopy
497_bcopy:
498	pushl	%esi
499	pushl	%edi
500	movl	12(%esp),%esi
501	movl	16(%esp),%edi
502	movl	20(%esp),%ecx
503	shrl	$2,%ecx
504	cld
505	rep
506	movsl
507	movl	20(%esp),%ecx
508	andl	$3,%ecx
509	rep
510	movsb
511	popl	%edi
512	popl	%esi
513	xorl	%eax,%eax
514	ret
515
516	.globl	_copyout
517_copyout:
518	movl	$cpyflt,_nofault	# in case we page/protection violate
519	pushl	%esi
520	pushl	%edi
521	movl	12(%esp),%esi
522	movl	16(%esp),%edi
523	movl	20(%esp),%ecx
524	shrl	$2,%ecx
525	cld
526	rep
527	movsl
528	movl	20(%esp),%ecx
529	andl	$3,%ecx
530	rep
531	movsb
532	popl	%edi
533	popl	%esi
534	xorl	%eax,%eax
535	movl	%eax,_nofault
536	ret
537
538	.globl	_copyin
539_copyin:
540	movl	$cpyflt,_nofault	# in case we page/protection violate
541	pushl	%esi
542	pushl	%edi
543	movl	12(%esp),%esi
544	movl	16(%esp),%edi
545	movl	20(%esp),%ecx
546	shrl	$2,%ecx
547	cld
548	rep
549	movsl
550	movl	20(%esp),%ecx
551	andl	$3,%ecx
552	rep
553	movsb
554	popl	%edi
555	popl	%esi
556	xorl	%eax,%eax
557	movl	%eax,_nofault
558	ret
559
560cpyflt: popl	%edi
561	popl	%esi
562	xorl	%eax,%eax
563	movl	%eax,_nofault
564	movl	$ EFAULT,%eax
565	ret
566
567	# insb(port,addr,cnt)
568	.globl	_insb
569_insb:
570	pushl	%edi
571	movw	8(%esp),%dx
572	movl	12(%esp),%edi
573	movl	16(%esp),%ecx
574	cld
575	NOP
576	rep
577	insb
578	NOP
579	movl	%edi,%eax
580	popl	%edi
581	ret
582
583	# insw(port,addr,cnt)
584	.globl	_insw
585_insw:
586	pushl	%edi
587	movw	8(%esp),%dx
588	movl	12(%esp),%edi
589	movl	16(%esp),%ecx
590	cld
591	NOP
592	.byte 0x66,0xf2,0x6d	# rep insw
593	NOP
594	movl	%edi,%eax
595	popl	%edi
596	ret
597
598	# outsw(port,addr,cnt)
599	.globl	_outsw
600_outsw:
601	pushl	%esi
602	movw	8(%esp),%dx
603	movl	12(%esp),%esi
604	movl	16(%esp),%ecx
605	cld
606	NOP
607	.byte 0x66,0xf2,0x6f	# rep outsw
608	NOP
609	movl	%esi,%eax
610	popl	%esi
611	ret
612
613	# lgdt(*gdt, ngdt)
614	.globl	_lgdt
615	# .globl	_gdt
616xxx:	.word 31
617	.long 0
618_lgdt:
619	movl	4(%esp),%eax
620	movl	%eax,xxx+2
621	movl	8(%esp),%eax
622	movw	%ax,xxx
623	lgdt	xxx
624	jmp	1f
625	NOP
6261:	movw	$0x10,%ax
627	movw	%ax,%ds
628	movw	%ax,%es
629	movw	%ax,%ss
630	movl	0(%esp),%eax
631	pushl	%eax
632	movl	$8,4(%esp)
633	lret
634
635	# lidt(*idt, nidt)
636	.globl	_lidt
637yyy:	.word	255
638	.long	0
639_lidt:
640	movl	4(%esp),%eax
641	movl	%eax,yyy+2
642	movl	8(%esp),%eax
643	movw	%ax,yyy
644	lidt	yyy
645	ret
646
647	# lldt(sel)
648	.globl	_lldt
649_lldt:
650	movl	4(%esp),%eax
651	lldt	%eax
652	ret
653
654	# ltr(sel)
655	.globl	_ltr
656_ltr:
657	movl	4(%esp),%eax
658	ltr	%eax
659	ret
660
661	# lcr3(cr3)
662	.globl	_lcr3
663	.globl	_load_cr3
664_load_cr3:
665_lcr3:
666	movl	4(%esp),%eax
667 	orl	$ I386_CR3PAT,%eax
668	movl	%eax,%cr3
669	movl	%cr3,%eax
670	ret
671
672	# lcr0(cr0)
673	.globl	_lcr0,_load_cr0
674_lcr0:
675_load_cr0:
676	movl	4(%esp),%eax
677	movl	%eax,%cr0
678	ret
679
680	# rcr0()
681	.globl	_rcr0
682_rcr0:
683	movl	%cr0,%eax
684	ret
685
686	# rcr2()
687	.globl	_rcr2
688_rcr2:
689	movl	%cr2,%eax
690	ret
691
692	# rcr3()
693	.globl	_rcr3
694	.globl	__cr3
695__cr3:
696_rcr3:
697	movl	%cr3,%eax
698	ret
699
700	# ssdtosd(*ssdp,*sdp)
701	.globl	_ssdtosd
702_ssdtosd:
703	pushl	%ebx
704	movl	8(%esp),%ecx
705	movl	8(%ecx),%ebx
706	shll	$16,%ebx
707	movl	(%ecx),%edx
708	roll	$16,%edx
709	movb	%dh,%bl
710	movb	%dl,%bh
711	rorl	$8,%ebx
712	movl	4(%ecx),%eax
713	movw	%ax,%dx
714	andl	$0xf0000,%eax
715	orl	%eax,%ebx
716	movl	12(%esp),%ecx
717	movl	%edx,(%ecx)
718	movl	%ebx,4(%ecx)
719	popl	%ebx
720	ret
721
722/*
723 * {fu,su},{byte,word}
724 */
725ALTENTRY(fuiword)
726ENTRY(fuword)
727	movl	$fusufault,_nofault	# in case we page/protection violate
728	movl	4(%esp),%edx
729	.byte	0x65		# use gs
730	movl	0(%edx),%eax
731	xorl	%edx,%edx
732	movl	%edx,_nofault
733	ret
734
735ENTRY(fusword)
736	movl	$fusufault,_nofault	# in case we page/protection violate
737	movl	4(%esp),%edx
738	.byte	0x65		# use gs
739	movzwl	0(%edx),%eax
740	xorl	%edx,%edx
741	movl	%edx,_nofault
742	ret
743
744ALTENTRY(fuibyte)
745ENTRY(fubyte)
746	movl	$fusufault,_nofault	# in case we page/protection violate
747	movl	4(%esp),%edx
748	.byte	0x65		# use gs
749	movzbl	0(%edx),%eax
750	xorl	%edx,%edx
751	movl	%edx,_nofault
752	ret
753
754fusufault:
755	xorl	%eax,%eax
756	movl	%eax,_nofault
757	decl	%eax
758	ret
759
760ALTENTRY(suiword)
761ENTRY(suword)
762	movl	$fusufault,_nofault	# in case we page/protection violate
763	movl	4(%esp),%edx
764	movl	8(%esp),%eax
765	.byte	0x65		# use gs
766	movl	%eax,0(%edx)
767	xorl	%eax,%eax
768	movl	%eax,_nofault
769	ret
770
771ENTRY(susword)
772	movl	$fusufault,_nofault	# in case we page/protection violate
773	movl	4(%esp),%edx
774	movl	8(%esp),%eax
775	.byte	0x65		# use gs
776	movw	%ax,0(%edx)
777	xorl	%eax,%eax
778	movl	%eax,_nofault
779	ret
780
781ALTENTRY(suibyte)
782ENTRY(subyte)
783	movl	$fusufault,_nofault	# in case we page/protection violate
784	movl	4(%esp),%edx
785	movl	8(%esp),%eax
786	.byte	0x65		# use gs
787	movb	%eax,0(%edx)
788	xorl	%eax,%eax
789	movl	%eax,_nofault
790	ret
791
792	ALTENTRY(savectx)
793	ENTRY(setjmp)
794	movl	4(%esp),%eax
795	movl	%ebx, 0(%eax)		# save ebx
796	movl	%esp, 4(%eax)		# save esp
797	movl	%ebp, 8(%eax)		# save ebp
798	movl	%esi,12(%eax)		# save esi
799	movl	%edi,16(%eax)		# save edi
800	movl	(%esp),%edx		# get rta
801	movl	%edx,20(%eax)		# save eip
802	xorl	%eax,%eax		# return (0);
803	ret
804
805	ENTRY(longjmp)
806	movl	4(%esp),%eax
807	movl	 0(%eax),%ebx		# restore ebx
808	movl	 4(%eax),%esp		# restore esp
809	movl	 8(%eax),%ebp		# restore ebp
810	movl	12(%eax),%esi		# restore esi
811	movl	16(%eax),%edi		# restore edi
812	movl	20(%eax),%edx		# get rta
813	movl	%edx,(%esp)		# put in return frame
814	xorl	%eax,%eax		# return (1);
815	incl	%eax
816	ret
817/*
818 * The following primitives manipulate the run queues.
819 * _whichqs tells which of the 32 queues _qs
820 * have processes in them.  Setrq puts processes into queues, Remrq
821 * removes them from queues.  The running process is on no queue,
822 * other processes are on a queue related to p->p_pri, divided by 4
823 * actually to shrink the 0-127 range of priorities into the 32 available
824 * queues.
825 */
826
827	.globl	_whichqs,_qs,_cnt,_panic
828	.comm	_noproc,4
829	.comm	_runrun,4
830
831/*
832 * Setrq(p)
833 *
834 * Call should be made at spl6(), and p->p_stat should be SRUN
835 */
836ENTRY(setrq)
837	movl	4(%esp),%eax
838	cmpl	$0,P_RLINK(%eax)	# should not be on q already
839	je	set1
840	pushl	$set2
841	call	_panic
842set1:
843	movzbl	P_PRI(%eax),%edx
844	shrl	$2,%edx
845	btsl	%edx,_whichqs		# set q full bit
846	shll	$3,%edx
847	addl	$_qs,%edx		# locate q hdr
848	movl	%edx,P_LINK(%eax)	# link process on tail of q
849	movl	P_RLINK(%edx),%ecx
850	movl	%ecx,P_RLINK(%eax)
851	movl	%eax,P_RLINK(%edx)
852	movl	%eax,P_LINK(%ecx)
853	ret
854
855set2:	.asciz	"setrq"
856
857/*
858 * Remrq(p)
859 *
860 * Call should be made at spl6().
861 */
862ENTRY(remrq)
863	movl	4(%esp),%eax
864	movzbl	P_PRI(%eax),%edx
865	shrl	$2,%edx
866	btrl	%edx,_whichqs		# clear full bit, panic if clear already
867	jb	rem1
868	pushl	$rem3
869	call	_panic
870rem1:
871	pushl	%edx
872	movl	P_LINK(%eax),%ecx	# unlink process
873	movl	P_RLINK(%eax),%edx
874	movl	%edx,P_RLINK(%ecx)
875	movl	P_RLINK(%eax),%ecx
876	movl	P_LINK(%eax),%edx
877	movl	%edx,P_LINK(%ecx)
878	popl	%edx
879	movl	$_qs,%ecx
880	shll	$3,%edx
881	addl	%edx,%ecx
882	cmpl	P_LINK(%ecx),%ecx	# q still has something?
883	je	rem2
884	shrl	$3,%edx			# yes, set bit as still full
885	btsl	%edx,_whichqs
886rem2:
887	movl	$0,P_RLINK(%eax)	# zap reverse link to indicate off list
888	ret
889
890rem3:	.asciz	"remrq"
891sw0:	.asciz	"swtch"
892
893/*
894 * When no processes are on the runq, Swtch branches to idle
895 * to wait for something to come ready.
896 */
897	.globl	Idle
898Idle:
899idle:
900	call	_spl0
901	cmpl	$0,_whichqs
902	jne	sw1
903	hlt		# wait for interrupt
904	jmp	idle
905
906badsw:
907	pushl	$sw0
908	call	_panic
909	/*NOTREACHED*/
910
911/*
912 * Swtch()
913 */
914ENTRY(swtch)
915	movw	_cpl, %ax
916	movw	%ax, _u+PCB_IML
917	movl	$1,%eax
918	movl	%eax,_noproc
919	incl	_cnt+V_SWTCH
920sw1:
921	cli
922	bsfl	_whichqs,%eax	# find a full q
923	jz	idle		# if none, idle
924swfnd:
925	btrl	%eax,_whichqs	# clear q full status
926	jnb	sw1		# if it was clear, look for another
927	pushl	%eax		# save which one we are using
928	shll	$3,%eax
929	addl	$_qs,%eax	# select q
930	pushl	%eax
931
932	cmpl	P_LINK(%eax),%eax	# linked to self? (e.g. not on list)
933	je	badsw		# not possible
934	movl	P_LINK(%eax),%ecx	# unlink from front of process q
935	movl	P_LINK(%ecx),%edx
936	movl	%edx,P_LINK(%eax)
937	movl	P_RLINK(%ecx),%eax
938	movl	%eax,P_RLINK(%edx)
939
940	popl	%eax
941	popl	%edx
942	cmpl	P_LINK(%ecx),%eax	# q empty
943	je	sw2
944	btsl	%edx,_whichqs		# nope, indicate full
945sw2:
946	movl	$0,%eax
947	movl	%eax,_noproc
948	movl	%eax,_runrun
949	cmpl	$0,P_WCHAN(%ecx)
950	jne	badsw
951	cmpb	$ SRUN,P_STAT(%ecx)
952	jne	badsw
953	movl	%eax,P_RLINK(%ecx)
954
955	movl	P_ADDR(%ecx),%edx
956	movl	(%edx),%eax
957	movl	%eax,_Swtchmap
958	movl	_Swtchbase+PCB_CR3,%edx
959
960/* switch to new process. first, save context as needed */
961
962	movl	$_u,%ecx
963
964	movl	(%esp),%eax		# Hardware registers
965	movl	%eax, PCB_EIP(%ecx)
966	movl	%ebx, PCB_EBX(%ecx)
967	movl	%esp, PCB_ESP(%ecx)
968	movl	%ebp, PCB_EBP(%ecx)
969	movl	%esi, PCB_ESI(%ecx)
970	movl	%edi, PCB_EDI(%ecx)
971
972#ifdef NPX
973	movb	PCB_FLAGS(%ecx),%al
974	/* have we used fp, and need a save? */
975	andb	$ FP_WASUSED|FP_NEEDSSAVE,%al
976	cmpb	$ FP_WASUSED|FP_NEEDSSAVE,%al
977	jne	1f
978	movl	%cr0,%eax		/* insure fp is enabled */
979	andb 	$0xfb,%al
980	movl	%eax,%cr0
981	fnsave	PCB_SAVEFPU(%ecx)
982	orb 	$4,%al			/* disable it */
983	movl	%eax,%cr0
984	movb	PCB_FLAGS(%ecx),%al
985	xorb	$ FP_NEEDSSAVE,%al	/* save processed */
986	movb	%al,PCB_FLAGS(%ecx)
9871:
988#endif
989
990	movl	_CMAP2,%eax		# save temporary map PTE
991	movl	%eax,PCB_CMAP2(%ecx)	# in our context
992
993 	orl	$ I386_CR3PAT,%edx
994	movl	%edx,%cr3	# context switch address space
995
996	movl	$_u,%ecx
997
998/* restore context */
999	movl	PCB_EBX(%ecx), %ebx
1000	movl	PCB_ESP(%ecx), %esp
1001	movl	PCB_EBP(%ecx), %ebp
1002	movl	PCB_ESI(%ecx), %esi
1003	movl	PCB_EDI(%ecx), %edi
1004	movl	PCB_EIP(%ecx), %eax
1005	movl	%eax, (%esp)
1006
1007#ifdef NPX
1008	movb	PCB_FLAGS(%ecx),%al
1009	/* if fp could be used, a dna trap will do a restore */
1010	testb	$ FP_WASUSED,%al
1011	je	1f
1012	orb	$ FP_NEEDSRESTORE,%al
1013	movb	%al, PCB_FLAGS(%ecx)
10141:
1015#endif
1016
1017	movl	PCB_CMAP2(%ecx),%eax	# get temporary map
1018	movl	%eax,_CMAP2		# reload temporary map PTE
1019	cmpl	$0,PCB_SSWAP(%ecx)	# do an alternate return?
1020	jne	res3			# yes, go reload regs
1021
1022	call _spl0
1023	movl	$0,%eax
1024	ret
1025
1026res3:
1027	xorl	%eax,%eax		# inline restore context
1028	xchgl	PCB_SSWAP(%ecx),%eax	# addr of saved context, clear it
1029
1030	movl	 0(%eax),%ebx		# restore ebx
1031	movl	 4(%eax),%esp		# restore esp
1032	movl	 8(%eax),%ebp		# restore ebp
1033	movl	12(%eax),%esi		# restore esi
1034	movl	16(%eax),%edi		# restore edi
1035	movl	20(%eax),%edx		# get rta
1036	movl	%edx,(%esp)		# put in return frame
1037
1038	pushl	_u+PCB_IML
1039	call	_splx
1040	popl	%eax
1041
1042	xorl	%eax,%eax		# return (1);
1043	incl	%eax
1044	ret
1045
1046/*
1047 * Resume(p_addr)
1048 * current just used to fillout u. tss so fork can fake a return to swtch
1049 */
1050ENTRY(resume)
1051	# movl	4(%esp),%ecx
1052	movl	$_u,%ecx
1053	movw	_cpl, %ax
1054	movw	%ax,  PCB_IML(%ecx)
1055	movl	(%esp),%eax
1056	movl	%eax, PCB_EIP(%ecx)
1057	movl	%ebx, PCB_EBX(%ecx)
1058	movl	%esp, PCB_ESP(%ecx)
1059	movl	%ebp, PCB_EBP(%ecx)
1060	movl	%esi, PCB_ESI(%ecx)
1061	movl	%edi, PCB_EDI(%ecx)
1062#ifdef NPX
1063	/* have we ever used fp, and need to save? */
1064	testb	$ FP_WASUSED,PCB_FLAGS(%ecx)
1065	je	1f
1066	movl	%cr0,%eax
1067	andb 	$0xfb,%al
1068	movl	%eax,%cr0
1069	fnsave	PCB_SAVEFPU(%ecx)
1070	orb 	$4,%eax
1071	movl	%eax,%cr0
10721:
1073#endif
1074	movl	$0,%eax
1075	ret
1076
1077.data
1078	.globl	_cyloffset
1079_cyloffset:	.long	0
1080	.globl	_nofault
1081_nofault:	.long	0
1082.text
1083 # To be done:
1084	.globl _addupc
1085	.globl _astoff
1086	.globl _doadump
1087_addupc:		# sorry, no profiling
1088	.byte 0xcc
1089_astoff:
1090	ret
1091_doadump:
1092	call _reset_cpu
1093
1094#define	IDTVEC(name)	.align 4; .globl _X/**/name; _X/**/name:
1095/*#define	PANIC(msg)	xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \
1096			call _panic; 1: .asciz msg*/
1097#define	PRINTF(n,msg)	pushal ; pushl 1f; call _printf; MSG(msg) ; popl %eax ; popal
1098#define	MSG(msg)	.data; 1: .asciz msg; .text
1099
1100	.text
1101
1102/*
1103 * Trap and fault vector routines
1104 */
1105#define	TRAP(a)	pushl $ a; jmp alltraps
1106
1107IDTVEC(div)
1108	pushl $0; TRAP(T_DIVIDE)
1109IDTVEC(dbg)
1110	pushl $0; TRAP(T_TRCTRAP)
1111IDTVEC(nmi)
1112	pushl $0; TRAP(T_NMI)
1113IDTVEC(bpt)
1114	pushl $0; TRAP(T_BPTFLT)
1115IDTVEC(ofl)
1116	pushl $0; TRAP(T_OFLOW)
1117IDTVEC(bnd)
1118	pushl $0; TRAP(T_BOUND)
1119IDTVEC(ill)
1120	pushl $0; TRAP(T_PRIVINFLT)
1121IDTVEC(dna)
1122	pushl $0; TRAP(T_DNA)
1123IDTVEC(dble)
1124	TRAP(T_DOUBLEFLT)
1125	/*PANIC("Double Fault");*/
1126IDTVEC(fpusegm)
1127	pushl $0; TRAP(T_FPOPFLT)
1128IDTVEC(tss)
1129	TRAP(T_TSSFLT)
1130	/*PANIC("TSS not valid");*/
1131IDTVEC(missing)
1132	TRAP(T_SEGNPFLT)
1133IDTVEC(stk)
1134	TRAP(T_STKFLT)
1135IDTVEC(prot)
1136	TRAP(T_PROTFLT)
1137IDTVEC(page)
1138	TRAP(T_PAGEFLT)
1139IDTVEC(rsvd)
1140	pushl $0; TRAP(T_RESERVED)
1141IDTVEC(fpu)
1142	pushl $0; TRAP(T_ARITHTRAP)
1143	/* 17 - 31 reserved for future exp */
1144IDTVEC(rsvd0)
1145	pushl $0; TRAP(17)
1146IDTVEC(rsvd1)
1147	pushl $0; TRAP(18)
1148IDTVEC(rsvd2)
1149	pushl $0; TRAP(19)
1150IDTVEC(rsvd3)
1151	pushl $0; TRAP(20)
1152IDTVEC(rsvd4)
1153	pushl $0; TRAP(21)
1154IDTVEC(rsvd5)
1155	pushl $0; TRAP(22)
1156IDTVEC(rsvd6)
1157	pushl $0; TRAP(23)
1158IDTVEC(rsvd7)
1159	pushl $0; TRAP(24)
1160IDTVEC(rsvd8)
1161	pushl $0; TRAP(25)
1162IDTVEC(rsvd9)
1163	pushl $0; TRAP(26)
1164IDTVEC(rsvd10)
1165	pushl $0; TRAP(27)
1166IDTVEC(rsvd11)
1167	pushl $0; TRAP(28)
1168IDTVEC(rsvd12)
1169	pushl $0; TRAP(29)
1170IDTVEC(rsvd13)
1171	pushl $0; TRAP(30)
1172IDTVEC(rsvd14)
1173	pushl $0; TRAP(31)
1174
1175alltraps:
1176	pushal
1177	push %ds
1178	push %es
1179	movw	$0x10,%ax
1180	movw	%ax,%ds
1181	movw	%ax,%es
1182	incl	_cnt+V_TRAP
1183	call	_trap
1184	pop %es
1185	pop %ds
1186	popal
1187	nop
1188	addl	$8,%esp			# pop type, code
1189	iret
1190
1191/*
1192 * Call gate entry for syscall
1193 */
1194
1195IDTVEC(syscall)
1196	pushfl	# only for stupid carry bit and more stupid wait3 cc kludge
1197	pushal	# only need eax,ecx,edx - trap resaves others
1198	movw	$0x10,%ax	# switch to kernel segments
1199	movw	%ax,%ds
1200	movw	%ax,%es
1201	call	_syscall
1202	movw	__udatasel,%ax	# switch back to user segments
1203	movw	%ax,%ds
1204	movw	%ax,%es
1205	popal
1206	nop
1207	popfl
1208	lret
1209
1210ENTRY(htonl)
1211ENTRY(ntohl)
1212	movl	4(%esp),%eax
1213	xchgb	%al,%ah
1214	roll	$16,%eax
1215	xchgb	%al,%ah
1216	ret
1217
1218ENTRY(htons)
1219ENTRY(ntohs)
1220	movzwl	4(%esp),%eax
1221	xchgb	%al,%ah
1222	ret
1223