xref: /original-bsd/sys/i386/i386/locore.s (revision e718337e)
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.6 (Berkeley) 11/25/90
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 "psl.h"
20#include "pte.h"
21
22#include "errno.h"
23#include "cmap.h"
24
25#include "../i386/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/*#define USRIOSIZE 30*/
106	SYSMAP(Usriomap,usrio,USRIOSIZE+CLSIZE) /* for PHYSIO */
107	ZSYSMAP(ekmempt,kmemlimit,0)
108	SYSMAP(Usrptmap,usrpt,USRPTSIZE+CLSIZE)
109
110eSysmap:
111	# .set	_Syssize,(eSysmap-_Sysmap)/4
112	.set	_Syssize,ptes
113	.globl	_Syssize
114
115	/* align on next page boundary */
116	# . = . + NBPG - 1 & -NBPG	/* align to page boundry-does not work*/
117	# .space (PGSIZE - ((eSysmap-_Sysmap) % PGSIZE)) % PGSIZE
118	.set sz,(4*ptes)%NBPG
119	# .set rptes,(ptes)%1024
120	# .set rptes,1024-rptes
121	# .set ptes,ptes+rptes
122	.set Npdes,10
123	# .space (NBPG - sz)
124
125/*
126 * Initialization
127 */
128	.data
129	.globl	_cpu, _boothowto, _bootdev, _cyloffset, _Maxmem
130_cpu:	.long	0		# are we 386, 386sx, or 486
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	# any other junk?
201	# addl	$ NBPG-1,%ecx
202	# andl	$~(NBPG-1),%ecx
203	# shrl	$2,%ecx	# convert to long word count
204	xorl	%eax,%eax	# pattern
205	cld
206	rep
207	stosb
208
209	/* pass parameters on stack (howto, bootdev, unit, cyloffset) */
210
211	movl	4(%esp),%eax
212	movl	%eax,_boothowto-SYSTEM
213	movl	8(%esp),%eax
214	movl	%eax,_bootdev-SYSTEM
215	movl	12(%esp),%eax
216	movl	%eax, _cyloffset-SYSTEM
217
218#ifdef notdef
219
220	movl	$0x36000,%edi
221	movl	$0x68000,%ecx
222	xorl	%eax,%eax	# pattern
223	cld
224	rep
225	stosb
226
227#endif
228	movl	$0x100000,%edi
229	movl	$0x200000,%ecx
230	xorl	%eax,%eax	# pattern
231	cld
232	rep
233	stosb
234/*
235 * Map Kernel
236 * N.B. don't bother with making kernel text RO, as 386
237 * ignores R/W AND U/S bits on kernel access (only v works) !
238 *
239 * First step - build page tables
240 */
241	movl	%esi,%ecx		# this much memory,
242	shrl	$ PGSHIFT,%ecx		# for this many pte s
243	movl	$ PG_V,%eax		#  having these bits set,
244	movl	$_Sysmap-SYSTEM,%ebx	#   in the kernel 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/* temporary double map  virt == real */
252
253	movl	$1024,%ecx		# for this many pte s,
254	movl	$ PG_V,%eax		#  having these bits set,
255	movl	$_Sysmap+4096-SYSTEM,%ebx	#   in the temporary page table,
256					#    fill in kernel page table.
2571:	movl	%eax,0(%ebx)
258	addl	$ NBPG,%eax			# increment physical address
259	addl	$4,%ebx				# next pte
260	loop	1b
261
262/* map I/O memory map */
263
264	movl	$atpgs,%ecx		# for this many pte s,
265	movl	$(IOPHYSmem|PG_V),%eax	#  having these bits set, (perhaps URW?)
266	movl	$_ATDevmem-SYSTEM,%ebx	#   in the temporary page table,
267					#    fill in kernel page table.
2681:	movl	%eax,0(%ebx)
269	addl	$ NBPG,%eax			# increment physical address
270	addl	$4,%ebx				# next pte
271	loop	1b
272
273/* map proc 0's page table (P1 region) */
274
275	movl	$_Usrptmap-SYSTEM,%ebx	# get pt map address
276	lea	(0*NBPG)(%esi),%eax	# physical address of pt in proc 0
277	orl	$ PG_V,%eax		#  having these bits set,
278	movl	%eax,0(%ebx)
279
280 /* map proc 0's _u */
281
282	movl	$ UPAGES,%ecx		# for this many pte s,
283	lea	(2*NBPG)(%esi),%eax	# physical address of _u in proc 0
284	orl	$ PG_V|PG_URKW,%eax	#  having these bits set,
285	lea	(0*NBPG)(%esi),%ebx	# physical address of stack pt in proc 0
286	addl	$(UPTEOFF*4),%ebx
287					#    fill in proc 0 stack page table.
2881:	movl	%eax,0(%ebx)
289	addl	$ NBPG,%eax			# increment physical address
290	addl	$4,%ebx				# next pte
291	loop	1b
292
293 /*# map proc 0's page directory*/
294	lea	(1*NBPG)(%esi),%eax	# physical address of ptd in proc 0
295	movl	%eax,%edi		# remember ptd physical address
296#ifdef dubious
297	orl	$ PG_V|PG_URKW,%eax	#  having these bits set,
298	lea	(0*NBPG)(%esi),%ebx	# physical address of stack pt in proc 0
299	addl	$(UPTEOFF*4),%ebx
300	addl	$(UPAGES*4),%ebx
301	movl	%eax,0(%ebx)
302#endif
303
304/*
305 * Construct a page table directory
306 * (of page directory elements - pde's)
307 */
308					/* kernel pde's */
309	movl	$_Sysmap-SYSTEM,%eax	# physical address of kernel page table
310	orl	$ PG_V,%eax		# pde entry is valid
311	movl	$ Npdes,%ecx		# for this many pde s,
312	movl	%edi,%ebx		# phys address of ptd in proc 0
313	addl	$(SYSPDROFF*4), %ebx	# offset of pde for kernel
3141:	movl	%eax,0(%ebx)
315	addl	$ NBPG,%eax			# increment physical address
316	addl	$4,%ebx				# next pde
317	loop	1b
318					# install a pde for temporary double map
319	movl	$_Sysmap+4096-SYSTEM,%eax	# physical address of temp page table
320	# movl	$_Sysmap-SYSTEM,%eax	# physical address of temp page table
321	orl	$ PG_V,%eax		# pde entry is valid
322	movl	%edi,%ebx		# phys address of ptd in proc 0
323	movl	%eax,0(%ebx)			# which is where temp maps!
324					# install a pde to map _u for proc 0
325	lea	(0*NBPG)(%esi),%eax	# physical address of pt in proc 0
326	orl	$ PG_V,%eax		# pde entry is valid
327	movl	%edi,%ebx		# phys address of ptd in proc 0
328	addl	$(UPDROFF*4), %ebx	# offset of pde for kernel
329	movl	%eax,0(%ebx)		# which is where _u maps!
330
331	movl	%edi,%eax		# phys address of ptd in proc 0
332 	orl	$ I386_CR3PAT,%eax
333	movl	%eax,%cr3		# load ptd addr into mmu
334	movl	%cr0,%eax		# get control word
335	orl	$0x80000001,%eax	# and let s page!
336	movl	%eax,%cr0		# NOW!
337
338	pushl	$begin				# jump to high mem!
339	ret		# jmp $begin does not work
340begin:
341	movl	$_Sysbase,%eax		# kernel stack just below system
342	movl	%eax,%esp
343	xorl	%eax,%eax		# mark end of frames
344	movl	%eax,%ebp
345
346	movl	_Crtat,%eax		# initialize Crt video ram address
347	subl	$ IOPHYSmem,%eax
348	addl	$_atdevbase,%eax
349	movl	%eax,_Crtat
350
351	call	_init386		# wire 386 chip for unix operation
352
353/* initialize (slightly) the pcb */
354	movl	$_u,%eax		# proc0 u-area
355	movl	$_usrpt,%ecx
356	movl	%ecx,PCB_P0BR(%eax)	# p0br: SVA of text/data user PT
357	xorl	%ecx,%ecx
358	movl	%ecx,PCB_P0LR(%eax)	# p0lr: 0 (doesn t really exist)
359	movl	$_usrpt+NBPG,%ecx	# addr of end of PT
360	subl	$ P1PAGES*4,%ecx		# backwards size of P1 region
361	movl	%ecx,PCB_P1BR(%eax)	# p1br: P1PAGES from end of PT
362	movl	$ P1PAGES-UPAGES,PCB_P1LR(%eax)	# p1lr: vax style
363	movl	$ CLSIZE,PCB_SZPT(%eax)	# page table size
364	# fninit
365	# pushl	$0x262
366	# fldcw	0(%esp)
367	# popl	%ecx
368	# fnsave	PCB_SAVEFPU(%eax)
369	movl	%edi,PCB_CR3(%eax)
370	pushl	%edi	# cr3
371	movl	%esi,%eax
372	addl	$(UPAGES*NBPG)+NBPG+NBPG+NBPG,%eax
373	shrl	$ PGSHIFT,%eax
374	pushl	%eax	# firstaddr
375
376	pushl	$20		# install signal trampoline code
377	pushl	$_u+PCB_SIGC
378	pushl	$sigcode
379	call	_bcopy
380	addl	$12,%esp
381
382	call 	_main
383
384	.globl	__ucodesel,__udatasel
385	movzwl	__ucodesel,%eax
386	movzwl	__udatasel,%ecx
387	# build outer stack frame
388	pushl	%ecx		# user ss
389	pushl	$_u	# user esp
390	pushl	%eax	# user cs
391	pushl	$0	# user ip
392	movw	%cx,%ds
393	movw	%cx,%es
394	movw	%ax,%fs		# double map cs to fs
395	movw	%cx,%gs		# and ds to gs
396	lret	# goto user!
397
398	.globl	__exit
399__exit:
400	call _reset_cpu
401	lidt	xaxa		# invalidate interrupt descriptor
402	movl	$0,%esp		# hardware "freeze" fault
403	ret
404xaxa:	.long	0,0
405
406	.set	exec,11
407	.set	exit,1
408	.globl	_icode
409	.globl	_initflags
410	.globl	_szicode
411/* gas fucks up offset -- */
412#define	LCALL(x,y)	.byte 0x9a ; .long y; .word x
413/*
414 * Icode is copied out to process 1 to exec /etc/init.
415 * If the exec fails, process 1 exits.
416 */
417_icode:
418	# pushl	$argv-_icode
419	movl	$argv,%eax
420	subl	$_icode,%eax
421	pushl	%eax
422
423	# pushl	$init-_icode
424	movl	$init,%eax
425	subl	$_icode,%eax
426	pushl	%eax
427	pushl	%eax	# dummy out rta
428
429	movl	%esp,%ebp
430	movl	$exec,%eax
431	LCALL(0x7,0x0)
432	pushl	%eax
433	movl	$exit,%eax
434	pushl	%eax	# dummy out rta
435	LCALL(0x7,0x0)
436
437init:	.asciz	"/etc/init"
438	.align	2
439_initflags:
440	.long	0
441argv:	.long	init-_icode
442	.long	_initflags-_icode
443	.long	0
444_szicode:
445	.long	_szicode-_icode
446sigcode:
447	movl	12(%esp),%eax	# unsure if call will dec stack 1st
448	call	%eax
449	xorl	%eax,%eax	# smaller movl $103,%eax
450	movb	$103,%al	# sigreturn()
451	LCALL(0x7,0)		# enter kernel with args on stack
452	hlt			# never gets here
453
454
455	.globl ___udivsi3
456___udivsi3:
457	movl 4(%esp),%eax
458	xorl %edx,%edx
459	divl 8(%esp)
460	ret
461
462	.globl ___divsi3
463___divsi3:
464	movl 4(%esp),%eax
465	xorl %edx,%edx
466	cltd
467	idivl 8(%esp)
468	ret
469
470	.globl	_inb
471_inb:	movl	4(%esp),%edx
472	subl	%eax,%eax	# clr eax
473	NOP
474	inb	%dx,%al
475	NOP
476	ret
477
478	.globl	_outb
479_outb:	movl	4(%esp),%edx
480	movl	8(%esp),%eax
481	NOP
482	outb	%al,%dx
483	NOP
484	ret
485
486	#
487	# bzero (base,cnt)
488	#
489
490	.globl _bzero
491	.globl _blkclr
492_bzero:
493_blkclr:
494	pushl	%edi
495	movl	8(%esp),%edi
496	movl	12(%esp),%ecx
497	xorl	%eax,%eax
498	shrl	$2,%ecx
499	cld
500	rep
501	stosl
502	movl	12(%esp),%ecx
503	andl	$3,%ecx
504	rep
505	stosb
506	popl	%edi
507	ret
508
509	#
510	# fillw (pat,base,cnt)
511	#
512
513	.globl _fillw
514_fillw:
515	pushl	%edi
516	movl	8(%esp),%eax
517	movl	12(%esp),%edi
518	movl	16(%esp),%ecx
519	# xorl	%eax,%eax
520	cld
521	rep
522	stosw
523	popl	%edi
524	ret
525
526	#
527	# bcopy (src,dst,cnt)
528	# NOTE: does not (yet) handle overlapped copies
529	#
530
531	.globl	_bcopy
532_bcopy:
533	pushl	%esi
534	pushl	%edi
535	movl	12(%esp),%esi
536	movl	16(%esp),%edi
537	movl	20(%esp),%ecx
538	shrl	$2,%ecx
539	cld
540	rep
541	movsl
542	movl	20(%esp),%ecx
543	andl	$3,%ecx
544	rep
545	movsb
546	popl	%edi
547	popl	%esi
548	xorl	%eax,%eax
549	ret
550
551	.globl	_copyout
552_copyout:
553	movl	$cpyflt,_nofault	# in case we page/protection violate
554	pushl	%esi
555	pushl	%edi
556	movl	12(%esp),%esi
557	movl	16(%esp),%edi
558	movl	20(%esp),%ecx
559	shrl	$2,%ecx
560	cld
561	rep
562	movsl
563	movl	20(%esp),%ecx
564	andl	$3,%ecx
565	rep
566	movsb
567	popl	%edi
568	popl	%esi
569	xorl	%eax,%eax
570	movl	%eax,_nofault
571	ret
572
573	.globl	_copyin
574_copyin:
575	movl	$cpyflt,_nofault	# in case we page/protection violate
576	pushl	%esi
577	pushl	%edi
578	movl	12(%esp),%esi
579	movl	16(%esp),%edi
580	movl	20(%esp),%ecx
581	shrl	$2,%ecx
582	cld
583	rep
584	movsl
585	movl	20(%esp),%ecx
586	andl	$3,%ecx
587	rep
588	movsb
589	popl	%edi
590	popl	%esi
591	xorl	%eax,%eax
592	movl	%eax,_nofault
593	ret
594
595cpyflt: popl	%edi
596	popl	%esi
597	xorl	%eax,%eax
598	movl	%eax,_nofault
599	movl	$ EFAULT,%eax
600	ret
601
602	# insb(port,addr,cnt)
603	.globl	_insb
604_insb:
605	pushl	%edi
606	movw	8(%esp),%dx
607	movl	12(%esp),%edi
608	movl	16(%esp),%ecx
609	cld
610	NOP
611	rep
612	insb
613	NOP
614	movl	%edi,%eax
615	popl	%edi
616	ret
617
618	# insw(port,addr,cnt)
619	.globl	_insw
620_insw:
621	pushl	%edi
622	movw	8(%esp),%dx
623	movl	12(%esp),%edi
624	movl	16(%esp),%ecx
625	cld
626	NOP
627	.byte 0x66,0xf2,0x6d	# rep insw
628	NOP
629	movl	%edi,%eax
630	popl	%edi
631	ret
632
633	# outsw(port,addr,cnt)
634	.globl	_outsw
635_outsw:
636	pushl	%esi
637	movw	8(%esp),%dx
638	movl	12(%esp),%esi
639	movl	16(%esp),%ecx
640	cld
641	NOP
642	.byte 0x66,0xf2,0x6f	# rep outsw
643	NOP
644	movl	%esi,%eax
645	popl	%esi
646	ret
647
648	# lgdt(*gdt, ngdt)
649	.globl	_lgdt
650	# .globl	_gdt
651xxx:	.word 31
652	.long 0
653_lgdt:
654	movl	4(%esp),%eax
655	movl	%eax,xxx+2
656	movl	8(%esp),%eax
657	movw	%ax,xxx
658	lgdt	xxx
659	jmp	1f
660	NOP
6611:	movw	$0x10,%ax
662	movw	%ax,%ds
663	movw	%ax,%es
664	movw	%ax,%ss
665	movl	0(%esp),%eax
666	pushl	%eax
667	movl	$8,4(%esp)
668	lret
669
670	# lidt(*idt, nidt)
671	.globl	_lidt
672yyy:	.word	255
673	.long	0
674_lidt:
675	movl	4(%esp),%eax
676	movl	%eax,yyy+2
677	movl	8(%esp),%eax
678	movw	%ax,yyy
679	lidt	yyy
680	ret
681
682	# lldt(sel)
683	.globl	_lldt
684_lldt:
685	movl	4(%esp),%eax
686	lldt	%eax
687	ret
688
689	# ltr(sel)
690	.globl	_ltr
691_ltr:
692	movl	4(%esp),%eax
693	ltr	%eax
694	ret
695
696	# lcr3(cr3)
697	.globl	_lcr3
698	.globl	_load_cr3
699_load_cr3:
700_lcr3:
701	movl	4(%esp),%eax
702 	orl	$ I386_CR3PAT,%eax
703	movl	%eax,%cr3
704	movl	%cr3,%eax
705	ret
706
707	# lcr0(cr0)
708	.globl	_lcr0
709_lcr0:
710	movl	4(%esp),%eax
711	movl	%eax,%cr0
712	ret
713
714	# rcr0()
715	.globl	_rcr0
716_rcr0:
717	movl	%cr0,%eax
718	ret
719
720	# rcr2()
721	.globl	_rcr2
722_rcr2:
723	movl	%cr2,%eax
724	ret
725
726	# rcr3()
727	.globl	_rcr3
728	.globl	__cr3
729__cr3:
730_rcr3:
731	movl	%cr3,%eax
732	ret
733
734	# ssdtosd(*ssdp,*sdp)
735	.globl	_ssdtosd
736_ssdtosd:
737	pushl	%ebx
738	movl	8(%esp),%ecx
739	movl	8(%ecx),%ebx
740	shll	$16,%ebx
741	movl	(%ecx),%edx
742	roll	$16,%edx
743	movb	%dh,%bl
744	movb	%dl,%bh
745	rorl	$8,%ebx
746	movl	4(%ecx),%eax
747	movw	%ax,%dx
748	andl	$0xf0000,%eax
749	orl	%eax,%ebx
750	movl	12(%esp),%ecx
751	movl	%edx,(%ecx)
752	movl	%ebx,4(%ecx)
753	popl	%ebx
754	ret
755
756/*
757 * {fu,su},{byte,word}
758 */
759ALTENTRY(fuiword)
760ENTRY(fuword)
761	movl	$fusufault,_nofault	# in case we page/protection violate
762	movl	4(%esp),%edx
763	.byte	0x65		# use gs
764	movl	0(%edx),%eax
765	xorl	%edx,%edx
766	movl	%edx,_nofault
767	ret
768
769ENTRY(fusword)
770	movl	$fusufault,_nofault	# in case we page/protection violate
771	movl	4(%esp),%edx
772	.byte	0x65		# use gs
773	movzwl	0(%edx),%eax
774	xorl	%edx,%edx
775	movl	%edx,_nofault
776	ret
777
778ALTENTRY(fuibyte)
779ENTRY(fubyte)
780	movl	$fusufault,_nofault	# in case we page/protection violate
781	movl	4(%esp),%edx
782	.byte	0x65		# use gs
783	movzbl	0(%edx),%eax
784	xorl	%edx,%edx
785	movl	%edx,_nofault
786	ret
787
788fusufault:
789	xorl	%eax,%eax
790	movl	%eax,_nofault
791	decl	%eax
792	ret
793
794ALTENTRY(suiword)
795ENTRY(suword)
796	movl	$fusufault,_nofault	# in case we page/protection violate
797	movl	4(%esp),%edx
798	movl	8(%esp),%eax
799	.byte	0x65		# use gs
800	movl	%eax,0(%edx)
801	xorl	%eax,%eax
802	movl	%eax,_nofault
803	ret
804
805ENTRY(susword)
806	movl	$fusufault,_nofault	# in case we page/protection violate
807	movl	4(%esp),%edx
808	movl	8(%esp),%eax
809	.byte	0x65		# use gs
810	movw	%ax,0(%edx)
811	xorl	%eax,%eax
812	movl	%eax,_nofault
813	ret
814
815ALTENTRY(suibyte)
816ENTRY(subyte)
817	movl	$fusufault,_nofault	# in case we page/protection violate
818	movl	4(%esp),%edx
819	movl	8(%esp),%eax
820	.byte	0x65		# use gs
821	movb	%eax,0(%edx)
822	xorl	%eax,%eax
823	movl	%eax,_nofault
824	ret
825
826	ALTENTRY(savectx)
827	ENTRY(setjmp)
828	movl	4(%esp),%eax
829	movl	%ebx, 0(%eax)		# save ebx
830	movl	%esp, 4(%eax)		# save esp
831	movl	%ebp, 8(%eax)		# save ebp
832	movl	%esi,12(%eax)		# save esi
833	movl	%edi,16(%eax)		# save edi
834	movl	(%esp),%edx		# get rta
835	movl	%edx,20(%eax)		# save eip
836	xorl	%eax,%eax		# return (0);
837	ret
838
839	ENTRY(longjmp)
840	movl	4(%esp),%eax
841	movl	 0(%eax),%ebx		# restore ebx
842	movl	 4(%eax),%esp		# restore esp
843	movl	 8(%eax),%ebp		# restore ebp
844	movl	12(%eax),%esi		# restore esi
845	movl	16(%eax),%edi		# restore edi
846	movl	20(%eax),%edx		# get rta
847	movl	%edx,(%esp)		# put in return frame
848	xorl	%eax,%eax		# return (1);
849	incl	%eax
850	ret
851/*
852 * The following primitives manipulate the run queues.
853 * _whichqs tells which of the 32 queues _qs
854 * have processes in them.  Setrq puts processes into queues, Remrq
855 * removes them from queues.  The running process is on no queue,
856 * other processes are on a queue related to p->p_pri, divided by 4
857 * actually to shrink the 0-127 range of priorities into the 32 available
858 * queues.
859 */
860
861	.globl	_whichqs,_qs,_cnt,_panic
862	.comm	_noproc,4
863	.comm	_runrun,4
864
865/*
866 * Setrq(p)
867 *
868 * Call should be made at spl6(), and p->p_stat should be SRUN
869 */
870ENTRY(setrq)
871	movl	4(%esp),%eax
872	cmpl	$0,P_RLINK(%eax)	# should not be on q already
873	je	set1
874	pushl	$set2
875	call	_panic
876set1:
877	movzbl	P_PRI(%eax),%edx
878	shrl	$2,%edx
879	btsl	%edx,_whichqs		# set q full bit
880	shll	$3,%edx
881	addl	$_qs,%edx		# locate q hdr
882	movl	%edx,P_LINK(%eax)	# link process on tail of q
883	movl	P_RLINK(%edx),%ecx
884	movl	%ecx,P_RLINK(%eax)
885	movl	%eax,P_RLINK(%edx)
886	movl	%eax,P_LINK(%ecx)
887	ret
888
889set2:	.asciz	"setrq"
890
891/*
892 * Remrq(p)
893 *
894 * Call should be made at spl6().
895 */
896ENTRY(remrq)
897	movl	4(%esp),%eax
898	movzbl	P_PRI(%eax),%edx
899	shrl	$2,%edx
900	btrl	%edx,_whichqs		# clear full bit, panic if clear already
901	jb	rem1
902	pushl	$rem3
903	call	_panic
904rem1:
905	pushl	%edx
906	movl	P_LINK(%eax),%ecx	# unlink process
907	movl	P_RLINK(%eax),%edx
908	movl	%edx,P_RLINK(%ecx)
909	movl	P_RLINK(%eax),%ecx
910	movl	P_LINK(%eax),%edx
911	movl	%edx,P_LINK(%ecx)
912	popl	%edx
913	movl	$_qs,%ecx
914	shll	$3,%edx
915	addl	%edx,%ecx
916	cmpl	P_LINK(%ecx),%ecx	# q still has something?
917	je	rem2
918	shrl	$3,%edx			# yes, set bit as still full
919	btsl	%edx,_whichqs
920rem2:
921	movl	$0,P_RLINK(%eax)	# zap reverse link to indicate off list
922	ret
923
924rem3:	.asciz	"remrq"
925sw0:	.asciz	"swtch"
926sw01:	.asciz	"swtch1"
927sw02:	.asciz	"swtch2"
928
929/*
930 * When no processes are on the runq, Swtch branches to idle
931 * to wait for something to come ready.
932 */
933	.globl	Idle
934Idle:
935idle:
936	call	_spl0
937	cmpl	$0,_whichqs
938	jne	sw1
939	hlt		# wait for interrupt
940	jmp	idle
941
942badsw:
943	pushl	$sw0
944	call	_panic
945	/*NOTREACHED*/
946
947/*
948 * Swtch()
949 */
950ENTRY(swtch)
951	movl	_cpl,%eax
952	movl	%eax,_u+PCB_IML
953	movl	$1,%eax
954	movl	%eax,_noproc
955	incl	_cnt+V_SWTCH
956sw1:
957	cli
958	bsfl	_whichqs,%eax	# find a full q
959	jz	idle		# if none, idle
960swfnd:
961	btrl	%eax,_whichqs	# clear q full status
962	jnb	sw1		# if it was clear, look for another
963	pushl	%eax		# save which one we are using
964	shll	$3,%eax
965	addl	$_qs,%eax	# select q
966	pushl	%eax
967
968	cmpl	P_LINK(%eax),%eax	# linked to self? (e.g. not on list)
969	je	badsw		# not possible
970	movl	P_LINK(%eax),%ecx	# unlink from front of process q
971	movl	P_LINK(%ecx),%edx
972	movl	%edx,P_LINK(%eax)
973	movl	P_RLINK(%ecx),%eax
974	movl	%eax,P_RLINK(%edx)
975
976	popl	%eax
977	popl	%edx
978	cmpl	P_LINK(%ecx),%eax	# q empty
979	je	sw2
980	btsl	%edx,_whichqs		# nope, indicate full
981sw2:
982	movl	$0,%eax
983	movl	%eax,_noproc
984	movl	%eax,_runrun
985	cmpl	$0,P_WCHAN(%ecx)
986	jne	badsw
987	cmpb	$ SRUN,P_STAT(%ecx)
988	jne	badsw
989	movl	%eax,P_RLINK(%ecx)
990
991	movl	P_ADDR(%ecx),%edx
992	movl	(%edx),%eax
993	movl	%eax,_Swtchmap
994	movl	4(%edx),%eax
995	movl	%eax,_Swtchmap+4
996	# movl	%cr3,%eax
997 	# orl	$ I386_CR3PAT,%eax
998	# movl	%eax,%cr3
999	movl	_Swtchbase+PCB_CR3,%edx
1000
1001 # pushal; pushl %edx ; pushl P_CR3(%ecx); pushl $l2; call _pg; popl %eax ; popl %eax; popl %eax ; popal ; .data ; l2: .asciz "s %x %x " ; .text
1002
1003/* switch to new process. first, save context as needed */
1004	movl	$_u,%ecx
1005
1006	movl	(%esp),%eax		# Hardware registers
1007	movl	%eax, PCB_EIP(%ecx)
1008	movl	%ebx, PCB_EBX(%ecx)
1009	movl	%esp, PCB_ESP(%ecx)
1010	movl	%ebp, PCB_EBP(%ecx)
1011	movl	%esi, PCB_ESI(%ecx)
1012	movl	%edi, PCB_EDI(%ecx)
1013
1014	fsave	PCB_SAVEFPU(%ecx)
1015
1016	movl	_CMAP2,%eax		# save temporary map PTE
1017	movl	%eax,PCB_CMAP2(%ecx)	# in our context
1018
1019 	orl	$ I386_CR3PAT,%edx
1020	movl	%edx,%cr3	# context switch
1021
1022	movl	$_u,%ecx
1023	# .globl	__gsel_tss
1024	# movw	__gsel_tss,%ax
1025	# ltr	%ax
1026
1027/* restore context */
1028	movl	PCB_EBX(%ecx), %ebx
1029	movl	PCB_ESP(%ecx), %esp
1030	movl	PCB_EBP(%ecx), %ebp
1031	movl	PCB_ESI(%ecx), %esi
1032	movl	PCB_EDI(%ecx), %edi
1033	movl	PCB_EIP(%ecx), %eax
1034	movl	%eax, (%esp)
1035
1036	frstor	PCB_SAVEFPU(%ecx)
1037
1038	movl	PCB_CMAP2(%ecx),%eax	# get temporary map
1039	movl	%eax,_CMAP2		# reload temporary map PTE
1040#ifdef FPUNOTYET
1041#endif
1042	cmpl	$0,PCB_SSWAP(%ecx)	# do an alternate return?
1043	jne	res3			# yes, go reload regs
1044
1045	pushl	PCB_IML(%ecx)
1046	call	_splx
1047	popl	%eax
1048	movl	$0,%eax
1049	ret
1050
1051res3:
1052	xorl	%eax,%eax		# inline restore context
1053	xchgl	PCB_SSWAP(%ecx),%eax	# addr of saved context, clear it
1054
1055 #pushal; pushl 20(%eax); pushl $l2; call _printf; popl %eax ; popl %eax; popal ; .data ; l2: .asciz "s %x\n" ; .text
1056
1057	movl	 0(%eax),%ebx		# restore ebx
1058	movl	 4(%eax),%esp		# restore esp
1059	movl	 8(%eax),%ebp		# restore ebp
1060	movl	12(%eax),%esi		# restore esi
1061	movl	16(%eax),%edi		# restore edi
1062	movl	20(%eax),%edx		# get rta
1063	movl	%edx,(%esp)		# put in return frame
1064	call	_spl0
1065	xorl	%eax,%eax		# return (1);
1066	incl	%eax
1067	ret
1068
1069/*
1070 * Resume(p_addr)
1071 * current just used to fillout u. tss so fork can fake a return to swtch
1072 * [ all thats really needed is esp and eip ]
1073 */
1074ENTRY(resume)
1075	# movl	4(%esp),%ecx
1076	movl	$_u,%ecx
1077	movl	(%esp),%eax
1078	movl	%eax, PCB_EIP(%ecx)
1079	movl	%ebx, PCB_EBX(%ecx)
1080	movl	%esp, PCB_ESP(%ecx)
1081	movl	%ebp, PCB_EBP(%ecx)
1082	movl	%esi, PCB_ESI(%ecx)
1083	movl	%edi, PCB_EDI(%ecx)
1084#ifdef FPUNOTYET
1085#endif
1086	fsave	PCB_SAVEFPU(%ecx)
1087	movl	_cpl,%eax
1088	movl	%eax,PCB_IML(%ecx)
1089	movl	$0,%eax
1090	ret
1091
1092.data
1093	.globl	_cyloffset
1094_cyloffset:	.long	0
1095	.globl	_nofault
1096_nofault:	.long	0
1097.text
1098 # To be done:
1099	.globl _addupc
1100	.globl _astoff
1101	.globl _doadump
1102	.globl _inittodr
1103	.globl _physaddr
1104_addupc:
1105	.byte 0xcc
1106_astoff:
1107	ret
1108_doadump:
1109	.byte 0xcc
1110_physaddr:
1111	.byte 0xcc
1112
1113#define	IDTVEC(name)	.align 4; .globl _X/**/name; _X/**/name:
1114/*#define	PANIC(msg)	xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \
1115			call _panic; 1: .asciz msg*/
1116#define	PRINTF(n,msg)	pushal ; pushl 1f; call _printf; MSG(msg) ; popl %eax ; popal
1117#define	MSG(msg)	.data; 1: .asciz msg; .text
1118
1119	.text
1120
1121/*
1122 * Trap and fault vector routines
1123 */
1124#define	TRAP(a)	pushl $ a; jmp alltraps
1125
1126IDTVEC(div)
1127	pushl $0; TRAP(T_DIVIDE)
1128IDTVEC(dbg)
1129	pushl $0; TRAP(T_TRCTRAP)
1130IDTVEC(nmi)
1131	pushl $0; TRAP(T_NMI)
1132IDTVEC(bpt)
1133	pushl $0; TRAP(T_BPTFLT)
1134IDTVEC(ofl)
1135	pushl $0; TRAP(T_OFLOW)
1136IDTVEC(bnd)
1137	pushl $0; TRAP(T_BOUND)
1138IDTVEC(ill)
1139	pushl $0; TRAP(T_PRIVINFLT)
1140IDTVEC(dna)
1141	pushl $0; TRAP(T_DNA)
1142IDTVEC(dble)
1143	TRAP(T_DOUBLEFLT)
1144	/*PANIC("Double Fault");*/
1145IDTVEC(fpusegm)
1146	pushl $0; TRAP(T_FPOPFLT)
1147IDTVEC(tss)
1148	TRAP(T_TSSFLT)
1149	/*PANIC("TSS not valid");*/
1150IDTVEC(missing)
1151	TRAP(T_SEGNPFLT)
1152IDTVEC(stk)
1153	TRAP(T_STKFLT)
1154IDTVEC(prot)
1155	TRAP(T_PROTFLT)
1156IDTVEC(page)
1157	TRAP(T_PAGEFLT)
1158IDTVEC(rsvd)
1159	pushl $0; TRAP(T_RESERVED)
1160IDTVEC(fpu)
1161	pushl $0; TRAP(T_ARITHTRAP)
1162	/* 17 - 31 reserved for future exp */
1163IDTVEC(rsvd0)
1164	pushl $0; TRAP(17)
1165IDTVEC(rsvd1)
1166	pushl $0; TRAP(18)
1167IDTVEC(rsvd2)
1168	pushl $0; TRAP(19)
1169IDTVEC(rsvd3)
1170	pushl $0; TRAP(20)
1171IDTVEC(rsvd4)
1172	pushl $0; TRAP(21)
1173IDTVEC(rsvd5)
1174	pushl $0; TRAP(22)
1175IDTVEC(rsvd6)
1176	pushl $0; TRAP(23)
1177IDTVEC(rsvd7)
1178	pushl $0; TRAP(24)
1179IDTVEC(rsvd8)
1180	pushl $0; TRAP(25)
1181IDTVEC(rsvd9)
1182	pushl $0; TRAP(26)
1183IDTVEC(rsvd10)
1184	pushl $0; TRAP(27)
1185IDTVEC(rsvd11)
1186	pushl $0; TRAP(28)
1187IDTVEC(rsvd12)
1188	pushl $0; TRAP(29)
1189IDTVEC(rsvd13)
1190	pushl $0; TRAP(30)
1191IDTVEC(rsvd14)
1192	pushl $0; TRAP(31)
1193
1194alltraps:
1195	pushal
1196	push %ds
1197	push %es
1198	movw	$0x10,%ax
1199	movw	%ax,%ds
1200	movw	%ax,%es
1201	incl	_cnt+V_TRAP
1202	call	_trap
1203
1204#ifdef junk
1205	cmpl	$0xfc000000,12*4(%esp)	# is it a user pc
1206	ja	1f
1207	cmpw	$0x1f,13*4(%esp)	# is it a user cs
1208	je	1f
1209	.data	; lx: .asciz "t user cs %x?" ; .text
12102:
1211	movl	13*4(%esp),%eax
1212	pushl	%eax
1213	pushl	$lx
1214	call	_pg
1215	popl %eax ; popl %eax
1216	jmp	2b
12171:
1218#endif junk
1219
1220	pop %es
1221	pop %ds
1222	popal
1223	addl	$8,%esp			# pop type, code
1224	iret
1225
1226/*
1227 * Call gate entry for syscall
1228 */
1229
1230IDTVEC(syscall)
1231	pushfl	# only for stupid carry bit and more stupid wait3 cc kludge
1232	pushal	# only need eax,ecx,edx - trap resaves others
1233	movw	$0x10,%ax	# switch to kernel segments
1234	movw	%ax,%ds
1235	movw	%ax,%es
1236	call	_syscall
1237
1238#ifdef notdef
1239	cmpw	$0x1f,10*4(%esp)	# is user cs what it should be?
1240	jz	1f
1241	.data	; lz: .asciz "s user cs %x?" ; .text
12422:
1243	movl	10*4(%esp),%eax
1244	pushl	%eax
1245	pushl	$lz
1246	call	_pg
1247	jmp	2b
12481:
1249#endif
1250
1251	movw	__udatasel,%ax	# switch back to user segments
1252	movw	%ax,%ds
1253	movw	%ax,%es
1254	popal
1255	popfl
1256	lret			# back we go, we hope!
1257
1258ENTRY(htonl)
1259ENTRY(ntohl)
1260	movl	4(%esp),%eax
1261	xchgb	%al,%ah
1262	roll	$16,%eax
1263	xchgb	%al,%ah
1264	ret
1265
1266ENTRY(htons)
1267ENTRY(ntohs)
1268	movzwl	4(%esp),%eax
1269	xchgb	%al,%ah
1270	ret
1271