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