fix autoconf, move code to isa.c, remove debugging, drop redundant tlbflushes, macros...
[unix-history] / usr / src / sys / i386 / i386 / locore.s
CommitLineData
4bd1c0bf
WN
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.
876e2d36 7 *
4bd1c0bf
WN
8 * %sccs.include.386.c%
9 *
9c09b4f2 10 * @(#)locore.s 5.5 (Berkeley) %G%
4bd1c0bf
WN
11 */
12
13/*
14 * locore.s: 4BSD machine support for the Intel 386
15 * Preliminary version
16 * Written by William F. Jolitz, 386BSD Project
876e2d36
BJ
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"
876e2d36 26
4bd1c0bf
WN
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 */
876e2d36
BJ
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
4bd1c0bf 40/* IBM "compatible" nop - sensitive macro on "fast" 386 machines */
8cbc2ebb 41#define NOP jmp 7f ; nop ; 7: jmp 7f ; nop ; 7:
6595ba46 42
876e2d36
BJ
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
ec13cb01 51#define ENTRY(name) \
4bd1c0bf 52 .globl _/**/name; _/**/name:
ec13cb01 53#define ALTENTRY(name) \
4bd1c0bf 54 .globl _/**/name; _/**/name:
876e2d36
BJ
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) \
4bd1c0bf 62_/**/mname: .globl _/**/mname; \
876e2d36 63 .space (npte)*4; \
8cbc2ebb 64 .set _/**/vname,ptes*NBPG+SYSTEM; \
4bd1c0bf 65 .globl _/**/vname; \
876e2d36
BJ
66 .set ptes,ptes + npte
67#define ZSYSMAP(mname, vname, npte) \
4bd1c0bf 68_/**/mname: .globl _/**/mname; \
8cbc2ebb 69 .set _/**/vname,ptes*NBPG+SYSTEM; \
4bd1c0bf 70 .globl _/**/vname;
876e2d36
BJ
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)
8cbc2ebb
BJ
87 /* SYSMAP(EMCmap,EMCbase,1) */
88 SYSMAP(Npxmap,npxutl,UPAGES)
89 SYSMAP(Swtchmap,Swtchbase,UPAGES)
876e2d36
BJ
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)
8cbc2ebb 105/*#define USRIOSIZE 30*/
ec13cb01 106 SYSMAP(Usriomap,usrio,USRIOSIZE+CLSIZE) /* for PHYSIO */
876e2d36 107 ZSYSMAP(ekmempt,kmemlimit,0)
876e2d36
BJ
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
8cbc2ebb
BJ
122 .set Npdes,10
123 # .space (NBPG - sz)
876e2d36 124
876e2d36
BJ
125/*
126 * Initialization
127 */
128 .data
8cbc2ebb
BJ
129 .globl _cpu, _boothowto, _bootdev, _cyloffset, _Maxmem
130_cpu: .long 0 # are we 386, 386sx, or 486
876e2d36
BJ
131 .text
132 .globl start
4bd1c0bf 133start: # This is assumed to be location zero!
ec13cb01
BJ
134 movw $0x1234,%ax
135 movw %ax,0x472 # warm boot
136 jmp 1f
8cbc2ebb
BJ
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
876e2d36 165 xorl %eax,%eax # start with base memory at 0x0
8cbc2ebb
BJ
166 #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K
167 movl $ 0xA0,%ecx # look every 4K up to 640K
876e2d36
BJ
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
4bd1c0bf 173 addl $ NBPG,%eax
876e2d36 174 loop 1b
8cbc2ebb
BJ
1752: shrl $12,%eax
176 movl %eax,_Maxmem-SYSTEM
876e2d36
BJ
177
178 movl $0x100000,%eax # next, talley remaining memory
8cbc2ebb
BJ
179 #movl $((0xFFF000-0x100000)/NBPG),%ecx
180 movl $(0xFFF-0x100),%ecx
876e2d36
BJ
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
4bd1c0bf 186 addl $ NBPG,%eax
876e2d36 187 loop 1b
8cbc2ebb
BJ
1882: shrl $12,%eax
189 movl %eax,_Maxmem-SYSTEM
ec13cb01 190
4bd1c0bf 191/* clear memory. */
876e2d36
BJ
192 movl $_edata-SYSTEM,%edi
193 movl $_end-SYSTEM,%ecx
4bd1c0bf 194 addl $ NBPG-1,%ecx
876e2d36
BJ
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?
8cbc2ebb
BJ
201 # addl $ NBPG-1,%ecx
202 # andl $~(NBPG-1),%ecx
876e2d36
BJ
203 # shrl $2,%ecx # convert to long word count
204 xorl %eax,%eax # pattern
205 cld
206 rep
207 stosb
208
8cbc2ebb
BJ
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
876e2d36
BJ
234/*
235 * Map Kernel
236 * N.B. don't bother with making kernel text RO, as 386
4bd1c0bf 237 * ignores R/W AND U/S bits on kernel access (only v works) !
8cbc2ebb
BJ
238 *
239 * First step - build page tables
876e2d36 240 */
876e2d36 241 movl %esi,%ecx # this much memory,
4bd1c0bf
WN
242 shrl $ PGSHIFT,%ecx # for this many pte s
243 movl $ PG_V,%eax # having these bits set,
876e2d36
BJ
244 movl $_Sysmap-SYSTEM,%ebx # in the kernel page table,
245 # fill in kernel page table.
2461: movl %eax,0(%ebx)
4bd1c0bf 247 addl $ NBPG,%eax # increment physical address
876e2d36
BJ
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,
4bd1c0bf 254 movl $ PG_V,%eax # having these bits set,
8cbc2ebb 255 movl $_Sysmap+4096-SYSTEM,%ebx # in the temporary page table,
876e2d36
BJ
256 # fill in kernel page table.
2571: movl %eax,0(%ebx)
4bd1c0bf 258 addl $ NBPG,%eax # increment physical address
876e2d36
BJ
259 addl $4,%ebx # next pte
260 loop 1b
261
876e2d36
BJ
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)
4bd1c0bf 269 addl $ NBPG,%eax # increment physical address
876e2d36
BJ
270 addl $4,%ebx # next pte
271 loop 1b
272
8cbc2ebb
BJ
273/* map proc 0's page table (P1 region) */
274
876e2d36
BJ
275 movl $_Usrptmap-SYSTEM,%ebx # get pt map address
276 lea (0*NBPG)(%esi),%eax # physical address of pt in proc 0
4bd1c0bf 277 orl $ PG_V,%eax # having these bits set,
876e2d36
BJ
278 movl %eax,0(%ebx)
279
8cbc2ebb
BJ
280 /* map proc 0's _u */
281
4bd1c0bf 282 movl $ UPAGES,%ecx # for this many pte s,
ec13cb01 283 lea (2*NBPG)(%esi),%eax # physical address of _u in proc 0
4bd1c0bf 284 orl $ PG_V|PG_URKW,%eax # having these bits set,
876e2d36
BJ
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)
4bd1c0bf 289 addl $ NBPG,%eax # increment physical address
876e2d36
BJ
290 addl $4,%ebx # next pte
291 loop 1b
292
ec13cb01
BJ
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
8cbc2ebb 296#ifdef dubious
4bd1c0bf 297 orl $ PG_V|PG_URKW,%eax # having these bits set,
ec13cb01
BJ
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)
8cbc2ebb 302#endif
ec13cb01 303
876e2d36
BJ
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
4bd1c0bf
WN
310 orl $ PG_V,%eax # pde entry is valid
311 movl $ Npdes,%ecx # for this many pde s,
ec13cb01 312 movl %edi,%ebx # phys address of ptd in proc 0
876e2d36
BJ
313 addl $(SYSPDROFF*4), %ebx # offset of pde for kernel
3141: movl %eax,0(%ebx)
4bd1c0bf 315 addl $ NBPG,%eax # increment physical address
876e2d36
BJ
316 addl $4,%ebx # next pde
317 loop 1b
318 # install a pde for temporary double map
8cbc2ebb
BJ
319 movl $_Sysmap+4096-SYSTEM,%eax # physical address of temp page table
320 # movl $_Sysmap-SYSTEM,%eax # physical address of temp page table
4bd1c0bf 321 orl $ PG_V,%eax # pde entry is valid
ec13cb01 322 movl %edi,%ebx # phys address of ptd in proc 0
876e2d36 323 movl %eax,0(%ebx) # which is where temp maps!
876e2d36
BJ
324 # install a pde to map _u for proc 0
325 lea (0*NBPG)(%esi),%eax # physical address of pt in proc 0
4bd1c0bf 326 orl $ PG_V,%eax # pde entry is valid
ec13cb01 327 movl %edi,%ebx # phys address of ptd in proc 0
876e2d36
BJ
328 addl $(UPDROFF*4), %ebx # offset of pde for kernel
329 movl %eax,0(%ebx) # which is where _u maps!
330
ec13cb01 331 movl %edi,%eax # phys address of ptd in proc 0
b82cb0f0 332 orl $ I386_CR3PAT,%eax
e28d0f21
DA
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!
876e2d36
BJ
337
338 pushl $begin # jump to high mem!
4bd1c0bf 339 ret # jmp $begin does not work
876e2d36 340begin:
4bd1c0bf 341 movl $_Sysbase,%eax # kernel stack just below system
876e2d36 342 movl %eax,%esp
4bd1c0bf 343 xorl %eax,%eax # mark end of frames
876e2d36 344 movl %eax,%ebp
4bd1c0bf
WN
345
346 movl _Crtat,%eax # initialize Crt video ram address
347 subl $ IOPHYSmem,%eax
876e2d36
BJ
348 addl $_atdevbase,%eax
349 movl %eax,_Crtat
4bd1c0bf
WN
350
351 call _init386 # wire 386 chip for unix operation
352
ec13cb01
BJ
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
4bd1c0bf 360 subl $ P1PAGES*4,%ecx # backwards size of P1 region
ec13cb01 361 movl %ecx,PCB_P1BR(%eax) # p1br: P1PAGES from end of PT
4bd1c0bf
WN
362 movl $ P1PAGES-UPAGES,PCB_P1LR(%eax) # p1lr: vax style
363 movl $ CLSIZE,PCB_SZPT(%eax) # page table size
9c09b4f2
BJ
364 # fninit
365 # pushl $0x262
366 # fldcw 0(%esp)
367 # popl %ecx
368 # fnsave PCB_SAVEFPU(%eax)
8cbc2ebb 369 movl %edi,PCB_CR3(%eax)
ec13cb01
BJ
370 pushl %edi # cr3
371 movl %esi,%eax
ec13cb01 372 addl $(UPAGES*NBPG)+NBPG+NBPG+NBPG,%eax
4bd1c0bf 373 shrl $ PGSHIFT,%eax
ec13cb01
BJ
374 pushl %eax # firstaddr
375
4bd1c0bf 376 pushl $20 # install signal trampoline code
ec13cb01
BJ
377 pushl $_u+PCB_SIGC
378 pushl $sigcode
379 call _bcopy
380 addl $12,%esp
381
876e2d36 382 call _main
ec13cb01
BJ
383
384 .globl __ucodesel,__udatasel
385 movzwl __ucodesel,%eax
386 movzwl __udatasel,%ecx
387 # build outer stack frame
4bd1c0bf
WN
388 pushl %ecx # user ss
389 pushl $_u # user esp
ec13cb01
BJ
390 pushl %eax # user cs
391 pushl $0 # user ip
392 movw %cx,%ds
393 movw %cx,%es
4bd1c0bf
WN
394 movw %ax,%fs # double map cs to fs
395 movw %cx,%gs # and ds to gs
ec13cb01 396 lret # goto user!
ec13cb01
BJ
397
398 .globl __exit
399__exit:
8cbc2ebb 400 call _reset_cpu
4bd1c0bf
WN
401 lidt xaxa # invalidate interrupt descriptor
402 movl $0,%esp # hardware "freeze" fault
876e2d36
BJ
403 ret
404xaxa: .long 0,0
4bd1c0bf 405
ec13cb01
BJ
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
ec13cb01
BJ
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
876e2d36 453
876e2d36 454
ec13cb01
BJ
455 .globl ___udivsi3
456___udivsi3:
457 movl 4(%esp),%eax
458 xorl %edx,%edx
459 divl 8(%esp)
460 ret
876e2d36 461
ec13cb01
BJ
462 .globl ___divsi3
463___divsi3:
464 movl 4(%esp),%eax
465 xorl %edx,%edx
466 cltd
467 idivl 8(%esp)
468 ret
876e2d36 469
ec13cb01
BJ
470 .globl _inb
471_inb: movl 4(%esp),%edx
472 subl %eax,%eax # clr eax
6595ba46 473 NOP
ec13cb01 474 inb %dx,%al
6595ba46 475 NOP
ec13cb01 476 ret
876e2d36 477
ec13cb01
BJ
478 .globl _outb
479_outb: movl 4(%esp),%edx
480 movl 8(%esp),%eax
6595ba46 481 NOP
ec13cb01 482 outb %al,%dx
6595ba46 483 NOP
876e2d36
BJ
484 ret
485
ec13cb01
BJ
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
4bd1c0bf
WN
497 xorl %eax,%eax
498 shrl $2,%ecx
ec13cb01
BJ
499 cld
500 rep
4bd1c0bf
WN
501 stosl
502 movl 12(%esp),%ecx
503 andl $3,%ecx
504 rep
ec13cb01
BJ
505 stosb
506 popl %edi
876e2d36 507 ret
ec13cb01 508
8cbc2ebb
BJ
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
ec13cb01
BJ
526 #
527 # bcopy (src,dst,cnt)
528 # NOTE: does not (yet) handle overlapped copies
529 #
530
531 .globl _bcopy
ec13cb01 532_bcopy:
6595ba46
BJ
533 pushl %esi
534 pushl %edi
535 movl 12(%esp),%esi
536 movl 16(%esp),%edi
537 movl 20(%esp),%ecx
4bd1c0bf
WN
538 shrl $2,%ecx
539 cld
540 rep
541 movsl
542 movl 20(%esp),%ecx
543 andl $3,%ecx
6595ba46
BJ
544 rep
545 movsb
546 popl %edi
547 popl %esi
548 xorl %eax,%eax
549 ret
550
551 .globl _copyout
ec13cb01 552_copyout:
6595ba46
BJ
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
4bd1c0bf 559 shrl $2,%ecx
6595ba46 560 cld
4bd1c0bf
WN
561 rep
562 movsl
563 movl 20(%esp),%ecx
564 andl $3,%ecx
6595ba46
BJ
565 rep
566 movsb
567 popl %edi
568 popl %esi
569 xorl %eax,%eax
570 movl %eax,_nofault
571 ret
572
573 .globl _copyin
ec13cb01 574_copyin:
6595ba46 575 movl $cpyflt,_nofault # in case we page/protection violate
ec13cb01
BJ
576 pushl %esi
577 pushl %edi
578 movl 12(%esp),%esi
579 movl 16(%esp),%edi
580 movl 20(%esp),%ecx
4bd1c0bf 581 shrl $2,%ecx
ec13cb01 582 cld
4bd1c0bf
WN
583 rep
584 movsl
585 movl 20(%esp),%ecx
586 andl $3,%ecx
ec13cb01
BJ
587 rep
588 movsb
589 popl %edi
590 popl %esi
6595ba46
BJ
591 xorl %eax,%eax
592 movl %eax,_nofault
876e2d36
BJ
593 ret
594
6595ba46
BJ
595cpyflt: popl %edi
596 popl %esi
597 xorl %eax,%eax
598 movl %eax,_nofault
4bd1c0bf 599 movl $ EFAULT,%eax
6595ba46
BJ
600 ret
601
8cbc2ebb
BJ
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
6595ba46 617
ec13cb01
BJ
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
6595ba46 626 NOP
ec13cb01 627 .byte 0x66,0xf2,0x6d # rep insw
6595ba46 628 NOP
ec13cb01
BJ
629 movl %edi,%eax
630 popl %edi
876e2d36 631 ret
ec13cb01
BJ
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
6595ba46 641 NOP
ec13cb01 642 .byte 0x66,0xf2,0x6f # rep outsw
6595ba46 643 NOP
ec13cb01
BJ
644 movl %esi,%eax
645 popl %esi
876e2d36
BJ
646 ret
647
ec13cb01
BJ
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
6595ba46 660 NOP
ec13cb01
BJ
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
ec13cb01 672yyy: .word 255
4bd1c0bf 673 .long 0
ec13cb01
BJ
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
876e2d36 681
ec13cb01
BJ
682 # lldt(sel)
683 .globl _lldt
684_lldt:
685 movl 4(%esp),%eax
686 lldt %eax
687 ret
876e2d36 688
ec13cb01
BJ
689 # ltr(sel)
690 .globl _ltr
691_ltr:
692 movl 4(%esp),%eax
693 ltr %eax
694 ret
876e2d36 695
ec13cb01
BJ
696 # lcr3(cr3)
697 .globl _lcr3
698 .globl _load_cr3
699_load_cr3:
700_lcr3:
701 movl 4(%esp),%eax
b82cb0f0 702 orl $ I386_CR3PAT,%eax
ec13cb01
BJ
703 movl %eax,%cr3
704 movl %cr3,%eax
705 ret
876e2d36 706
ec13cb01
BJ
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
876e2d36
BJ
754 ret
755
876e2d36 756/*
4bd1c0bf 757 * {fu,su},{byte,word}
876e2d36 758 */
ec13cb01
BJ
759ALTENTRY(fuiword)
760ENTRY(fuword)
761 movl $fusufault,_nofault # in case we page/protection violate
762 movl 4(%esp),%edx
4bd1c0bf 763 .byte 0x65 # use gs
ec13cb01
BJ
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
4bd1c0bf 772 .byte 0x65 # use gs
ec13cb01
BJ
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
4bd1c0bf 782 .byte 0x65 # use gs
ec13cb01
BJ
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
876e2d36
BJ
792 ret
793
ec13cb01
BJ
794ALTENTRY(suiword)
795ENTRY(suword)
796 movl $fusufault,_nofault # in case we page/protection violate
797 movl 4(%esp),%edx
798 movl 8(%esp),%eax
4bd1c0bf 799 .byte 0x65 # use gs
ec13cb01
BJ
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
4bd1c0bf
WN
809 .byte 0x65 # use gs
810 movw %ax,0(%edx)
ec13cb01
BJ
811 xorl %eax,%eax
812 movl %eax,_nofault
813 ret
876e2d36 814
ec13cb01
BJ
815ALTENTRY(suibyte)
816ENTRY(subyte)
817 movl $fusufault,_nofault # in case we page/protection violate
818 movl 4(%esp),%edx
819 movl 8(%esp),%eax
4bd1c0bf
WN
820 .byte 0x65 # use gs
821 movb %eax,0(%edx)
ec13cb01
BJ
822 xorl %eax,%eax
823 movl %eax,_nofault
824 ret
876e2d36 825
ec13cb01
BJ
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
e28d0f21 836 xorl %eax,%eax # return (0);
ec13cb01 837 ret
876e2d36 838
ec13cb01
BJ
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
876e2d36 851/*
ec13cb01
BJ
852 * The following primitives manipulate the run queues.
853 * _whichqs tells which of the 32 queues _qs
876e2d36
BJ
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
4bd1c0bf 861 .globl _whichqs,_qs,_cnt,_panic
ec13cb01
BJ
862 .comm _noproc,4
863 .comm _runrun,4
ec13cb01 864
876e2d36 865/*
ec13cb01 866 * Setrq(p)
876e2d36 867 *
ec13cb01 868 * Call should be made at spl6(), and p->p_stat should be SRUN
876e2d36 869 */
ec13cb01
BJ
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
876e2d36 876set1:
ec13cb01
BJ
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
876e2d36 888
ec13cb01 889set2: .asciz "setrq"
876e2d36
BJ
890
891/*
ec13cb01 892 * Remrq(p)
876e2d36 893 *
ec13cb01 894 * Call should be made at spl6().
876e2d36 895 */
ec13cb01
BJ
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
876e2d36 904rem1:
ec13cb01
BJ
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
876e2d36 920rem2:
ec13cb01
BJ
921 movl $0,P_RLINK(%eax) # zap reverse link to indicate off list
922 ret
876e2d36
BJ
923
924rem3: .asciz "remrq"
876e2d36 925sw0: .asciz "swtch"
ec13cb01
BJ
926sw01: .asciz "swtch1"
927sw02: .asciz "swtch2"
876e2d36
BJ
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
ec13cb01
BJ
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
876e2d36
BJ
945 /*NOTREACHED*/
946
947/*
ec13cb01 948 * Swtch()
876e2d36 949 */
ec13cb01 950ENTRY(swtch)
8cbc2ebb
BJ
951 movl _cpl,%eax
952 movl %eax,_u+PCB_IML
ec13cb01
BJ
953 movl $1,%eax
954 movl %eax,_noproc
876e2d36 955 incl _cnt+V_SWTCH
ec13cb01 956sw1:
8cbc2ebb 957 cli
ec13cb01
BJ
958 bsfl _whichqs,%eax # find a full q
959 jz idle # if none, idle
960swfnd:
ec13cb01
BJ
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
876e2d36 981sw2:
ec13cb01
BJ
982 movl $0,%eax
983 movl %eax,_noproc
984 movl %eax,_runrun
985 cmpl $0,P_WCHAN(%ecx)
986 jne badsw
4bd1c0bf 987 cmpb $ SRUN,P_STAT(%ecx)
ec13cb01
BJ
988 jne badsw
989 movl %eax,P_RLINK(%ecx)
8cbc2ebb
BJ
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
9c09b4f2
BJ
996 # movl %cr3,%eax
997 # orl $ I386_CR3PAT,%eax
998 # movl %eax,%cr3
8cbc2ebb
BJ
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
ec13cb01
BJ
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
8cbc2ebb 1014 fsave PCB_SAVEFPU(%ecx)
876e2d36 1015
ec13cb01
BJ
1016 movl _CMAP2,%eax # save temporary map PTE
1017 movl %eax,PCB_CMAP2(%ecx) # in our context
876e2d36 1018
b82cb0f0 1019 orl $ I386_CR3PAT,%edx
ec13cb01 1020 movl %edx,%cr3 # context switch
876e2d36 1021
4bd1c0bf 1022 movl $_u,%ecx
8cbc2ebb
BJ
1023 # .globl __gsel_tss
1024 # movw __gsel_tss,%ax
4bd1c0bf 1025 # ltr %ax
876e2d36 1026
ec13cb01
BJ
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
8cbc2ebb 1036 frstor PCB_SAVEFPU(%ecx)
ec13cb01 1037
4bd1c0bf 1038 movl PCB_CMAP2(%ecx),%eax # get temporary map
ec13cb01
BJ
1039 movl %eax,_CMAP2 # reload temporary map PTE
1040#ifdef FPUNOTYET
1041#endif
4bd1c0bf 1042 cmpl $0,PCB_SSWAP(%ecx) # do an alternate return?
ec13cb01 1043 jne res3 # yes, go reload regs
8cbc2ebb
BJ
1044
1045 pushl PCB_IML(%ecx)
1046 call _splx
1047 popl %eax
1048 movl $0,%eax
ec13cb01 1049 ret
8cbc2ebb 1050
ec13cb01
BJ
1051res3:
1052 xorl %eax,%eax # inline restore context
4bd1c0bf
WN
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
ec13cb01
BJ
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
8cbc2ebb 1064 call _spl0
ec13cb01
BJ
1065 xorl %eax,%eax # return (1);
1066 incl %eax
876e2d36
BJ
1067 ret
1068
1069/*
ec13cb01
BJ
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 ]
876e2d36 1073 */
ec13cb01 1074ENTRY(resume)
e28d0f21
DA
1075 # movl 4(%esp),%ecx
1076 movl $_u,%ecx
ec13cb01
BJ
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
8cbc2ebb
BJ
1086 fsave PCB_SAVEFPU(%ecx)
1087 movl _cpl,%eax
1088 movl %eax,PCB_IML(%ecx)
ec13cb01 1089 movl $0,%eax
876e2d36
BJ
1090 ret
1091
ec13cb01
BJ
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
ec13cb01
BJ
1103 .globl _physaddr
1104_addupc:
1105 .byte 0xcc
1106_astoff:
876e2d36 1107 ret
ec13cb01
BJ
1108_doadump:
1109 .byte 0xcc
ec13cb01
BJ
1110_physaddr:
1111 .byte 0xcc
4bd1c0bf 1112
9c09b4f2
BJ
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
876e2d36 1118
9c09b4f2
BJ
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!
ec13cb01 1257