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