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