]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/l.s
pc: dont handle pending floating point exception in fpsave thru FPOFF
[plan9front.git] / sys / src / 9 / pc / l.s
1 #include "mem.h"
2 #undef DELAY
3
4 #define PADDR(a)        ((a) & ~KZERO)
5 #define KADDR(a)        (KZERO|(a))
6
7 /*
8  * Some machine instructions not handled by 8[al].
9  */
10 #define OP16            BYTE $0x66
11 #define DELAY           BYTE $0xEB; BYTE $0x00  /* JMP .+2 */
12 #define CPUID           BYTE $0x0F; BYTE $0xA2  /* CPUID, argument in AX */
13 #define WRMSR           BYTE $0x0F; BYTE $0x30  /* WRMSR, argument in AX/DX (lo/hi) */
14 #define RDTSC           BYTE $0x0F; BYTE $0x31  /* RDTSC, result in AX/DX (lo/hi) */
15 #define RDMSR           BYTE $0x0F; BYTE $0x32  /* RDMSR, result in AX/DX (lo/hi) */
16 #define HLT             BYTE $0xF4
17 #define INVLPG  BYTE $0x0F; BYTE $0x01; BYTE $0x39      /* INVLPG (%ecx) */
18 #define WBINVD  BYTE $0x0F; BYTE $0x09
19
20 #define VectorSYSCALL   0x40
21
22 /*
23  * Macros for calculating offsets within the page directory base
24  * and page tables. Note that these are assembler-specific hence
25  * the '<<2'.
26  */
27 #define PDO(a)          (((((a))>>22) & 0x03FF)<<2)
28 #define PTO(a)          (((((a))>>12) & 0x03FF)<<2)
29
30 /*
31  * For backwards compatiblity with 9load - should go away when 9load is changed
32  * 9load currently sets up the mmu, however the first 16MB of memory is identity
33  * mapped, so behave as if the mmu was not setup
34  */
35 TEXT _startKADDR(SB), $0
36         MOVL    $_startPADDR(SB), AX
37         ANDL    $~KZERO, AX
38         JMP*    AX
39
40 /*
41  * Must be 4-byte aligned.
42  */
43 TEXT _multibootheader(SB), $0
44         LONG    $0x1BADB002                     /* magic */
45         LONG    $0x00010003                     /* flags */
46         LONG    $-(0x1BADB002 + 0x00010003)     /* checksum */
47         LONG    $_multibootheader-KZERO(SB)     /* header_addr */
48         LONG    $_startKADDR-KZERO(SB)          /* load_addr */
49         LONG    $edata-KZERO(SB)                /* load_end_addr */
50         LONG    $end-KZERO(SB)                  /* bss_end_addr */
51         LONG    $_multibootentry-KZERO(SB)              /* entry_addr */
52         LONG    $0                              /* mode_type */
53         LONG    $0                              /* width */
54         LONG    $0                              /* height */
55         LONG    $0                              /* depth */
56
57 /* 
58  * the kernel expects the data segment to be page-aligned
59  * multiboot bootloaders put the data segment right behind text
60  */
61 TEXT _multibootentry(SB), $0
62         MOVL    $etext-KZERO(SB), SI
63         MOVL    SI, DI
64         ADDL    $0xfff, DI
65         ANDL    $~0xfff, DI
66         MOVL    $edata-KZERO(SB), CX
67         SUBL    DI, CX
68         ADDL    CX, SI
69         ADDL    CX, DI
70         INCL    CX      /* one more for post decrement */
71         STD
72         REP; MOVSB
73         ADDL    $KZERO, BX
74         MOVL    BX, multiboot-KZERO(SB)
75         MOVL    $_startPADDR(SB), AX
76         ANDL    $~KZERO, AX
77         JMP*    AX
78
79 /* multiboot structure pointer */
80 TEXT multiboot(SB), $0
81         LONG    $0
82
83 /*
84  * In protected mode with paging turned off and segment registers setup
85  * to linear map all memory. Entered via a jump to PADDR(entry),
86  * the physical address of the virtual kernel entry point of KADDR(entry).
87  * Make the basic page tables for processor 0. Six pages are needed for
88  * the basic set:
89  *      a page directory;
90  *      page tables for mapping the first 8MB of physical memory to KZERO;
91  *      a page for the GDT;
92  *      virtual and physical pages for mapping the Mach structure.
93  * The remaining PTEs will be allocated later when memory is sized.
94  * An identity mmu map is also needed for the switch to virtual mode.
95  * This identity mapping is removed once the MMU is going and the JMP has
96  * been made to virtual memory.
97  */
98 TEXT _startPADDR(SB), $0
99         CLI                                     /* make sure interrupts are off */
100
101         /* set up the gdt so we have sane plan 9 style gdts. */
102         MOVL    $tgdtptr(SB), AX
103         ANDL    $~KZERO, AX
104         MOVL    (AX), GDTR
105         MOVW    $1, AX
106         MOVW    AX, MSW
107
108         /* clear prefetch queue (weird code to avoid optimizations) */
109         DELAY
110
111         /* set segs to something sane (avoid traps later) */
112         MOVW    $(1<<3), AX
113         MOVW    AX, DS
114         MOVW    AX, SS
115         MOVW    AX, ES
116         MOVW    AX, FS
117         MOVW    AX, GS
118
119 /*      JMP     $(2<<3):$mode32bit(SB) /**/
120          BYTE   $0xEA
121          LONG   $mode32bit-KZERO(SB)
122          WORD   $(2<<3)
123
124 /*
125  *  gdt to get us to 32-bit/segmented/unpaged mode
126  */
127 TEXT tgdt(SB), $0
128
129         /* null descriptor */
130         LONG    $0
131         LONG    $0
132
133         /* data segment descriptor for 4 gigabytes (PL 0) */
134         LONG    $(0xFFFF)
135         LONG    $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
136
137         /* exec segment descriptor for 4 gigabytes (PL 0) */
138         LONG    $(0xFFFF)
139         LONG    $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
140
141 /*
142  *  pointer to initial gdt
143  *  Note the -KZERO which puts the physical address in the gdtptr. 
144  *  that's needed as we start executing in physical addresses. 
145  */
146 TEXT tgdtptr(SB), $0
147         WORD    $(3*8)
148         LONG    $tgdt-KZERO(SB)
149
150 TEXT m0rgdtptr(SB), $0
151         WORD    $(NGDT*8-1)
152         LONG    $(CPU0GDT-KZERO)
153
154 TEXT m0gdtptr(SB), $0
155         WORD    $(NGDT*8-1)
156         LONG    $CPU0GDT
157
158 TEXT m0idtptr(SB), $0
159         WORD $(256*8-1)
160         LONG $IDTADDR
161
162 TEXT mode32bit(SB), $0
163         /* At this point, the GDT setup is done. */
164
165         MOVL    $((CPU0END-CPU0PDB)>>2), CX
166         MOVL    $PADDR(CPU0PDB), DI
167         XORL    AX, AX
168
169         CLD
170         REP;    STOSL
171
172         MOVL    $PADDR(CPU0PTE), DX
173         MOVL    $(PTEWRITE|PTEVALID), BX        /* page permissions */
174         ORL     BX, DX
175
176         MOVL    $PADDR(CPU0PDB), AX
177         ADDL    $PDO(KZERO), AX                 /* page directory offset for KZERO */
178
179         MOVL    DX, 0(AX)                       /* PTE's for KZERO */
180         ADDL    $BY2PG, DX
181         MOVL    DX, 4(AX)                       /* PTE's for KZERO+4MB */
182         ADDL    $BY2PG, DX
183         MOVL    DX, 8(AX)                       /* PTE's for KZERO+8MB */
184         ADDL    $BY2PG, DX
185         MOVL    DX, 12(AX)                      /* PTE's for KZERO+12MB */
186
187         MOVL    $PADDR(CPU0PTE), AX             /* first page of page table */
188         MOVL    $end-KZERO(SB), CX
189         ADDL    $(BY2XPG-1), CX
190         ANDL    $~(BY2XPG-1), CX                /* round to 4MB */
191         MOVL    CX, MemMin-KZERO(SB)            /* see memory.c */
192         SHRL    $PGSHIFT, CX
193         MOVL    BX, DX
194 _setpte:
195         MOVL    DX, (AX)
196         ADDL    $BY2PG, DX
197         ADDL    $4, AX
198         LOOP    _setpte
199
200         MOVL    $PADDR(CPU0PTE), AX
201         ADDL    $PTO(MACHADDR), AX              /* page table entry offset for MACHADDR */
202         ORL     $PADDR(CPU0MACH), BX
203         MOVL    BX, (AX)                        /* PTE for Mach */
204
205 /*
206  * Now ready to use the new map. Make sure the processor options are what is wanted.
207  * It is necessary on some processors to immediately follow mode switching with a JMP instruction
208  * to clear the prefetch queues.
209  */
210         MOVL    $PADDR(CPU0PDB), CX             /* load address of page directory */
211         MOVL    (PDO(KZERO))(CX), DX            /* double-map KZERO at 0 */
212         MOVL    DX, (PDO(0))(CX)
213         MOVL    CX, CR3
214         DELAY                                   /* JMP .+2 */
215
216         MOVL    CR0, DX
217         ORL     $0x80010000, DX                 /* PG|WP */
218         ANDL    $~0x6000000A, DX                /* ~(CD|NW|TS|MP) */
219
220         MOVL    $_startpg(SB), AX               /* this is a virtual address */
221         MOVL    DX, CR0                         /* turn on paging */
222         JMP*    AX                              /* jump to the virtual nirvana */
223
224 /*
225  * Basic machine environment set, can clear BSS and create a stack.
226  * The stack starts at the top of the page containing the Mach structure.
227  * The x86 architecture forces the use of the same virtual address for
228  * each processor's Mach structure, so the global Mach pointer 'm' can
229  * be initialised here.
230  */
231 TEXT _startpg(SB), $0
232         MOVL    $0, (PDO(0))(CX)                /* undo double-map of KZERO at 0 */
233         MOVL    CX, CR3                         /* load and flush the mmu */
234
235 _clearbss:
236         MOVL    $edata(SB), DI
237         XORL    AX, AX
238         MOVL    $end(SB), CX
239         SUBL    DI, CX                          /* end-edata bytes */
240         SHRL    $2, CX                          /* end-edata doublewords */
241
242         CLD
243         REP;    STOSL                           /* clear BSS */
244
245         MOVL    $MACHADDR, SP
246         MOVL    SP, m(SB)                       /* initialise global Mach pointer */
247         MOVL    $0, 0(SP)                       /* initialise m->machno */
248
249
250         ADDL    $(MACHSIZE-4), SP               /* initialise stack */
251
252 /*
253  * Need to do one final thing to ensure a clean machine environment,
254  * clear the EFLAGS register, which can only be done once there is a stack.
255  */
256         MOVL    $0, AX
257         PUSHL   AX
258         POPFL
259
260         CALL    main(SB)
261
262 /*
263  * Park a processor. Should never fall through a return from main to here,
264  * should only be called by application processors when shutting down.
265  */
266 TEXT idle(SB), $0
267 _idle:
268         STI
269         HLT
270         JMP     _idle
271
272
273 TEXT load_fs(SB), $0
274         MOVW fs+0(FP), AX
275         MOVW AX, FS
276         RET
277
278 TEXT load_gs(SB), $0
279         MOVW gs+0(FP), AX
280         MOVW AX, GS
281         RET
282
283 /*
284  * BIOS32.
285  */
286 TEXT bios32call(SB), $0
287         MOVL    ci+0(FP), BP
288         MOVL    0(BP), AX
289         MOVL    4(BP), BX
290         MOVL    8(BP), CX
291         MOVL    12(BP), DX
292         MOVL    16(BP), SI
293         MOVL    20(BP), DI
294         PUSHL   BP
295
296         MOVL    12(SP), BP                      /* ptr */
297         BYTE $0xFF; BYTE $0x5D; BYTE $0x00      /* CALL FAR 0(BP) */
298
299         POPL    BP
300         MOVL    DI, 20(BP)
301         MOVL    SI, 16(BP)
302         MOVL    DX, 12(BP)
303         MOVL    CX, 8(BP)
304         MOVL    BX, 4(BP)
305         MOVL    AX, 0(BP)
306
307         XORL    AX, AX
308         JCC     _bios32xxret
309         INCL    AX
310
311 _bios32xxret:
312         RET
313
314 /*
315  * Port I/O.
316  *      in[bsl]         input a byte|short|long
317  *      ins[bsl]        input a string of bytes|shorts|longs
318  *      out[bsl]        output a byte|short|long
319  *      outs[bsl]       output a string of bytes|shorts|longs
320  */
321 TEXT inb(SB), $0
322         MOVL    port+0(FP), DX
323         XORL    AX, AX
324         INB
325         RET
326
327 TEXT insb(SB), $0
328         MOVL    port+0(FP), DX
329         MOVL    address+4(FP), DI
330         MOVL    count+8(FP), CX
331         CLD
332         REP;    INSB
333         RET
334
335 TEXT ins(SB), $0
336         MOVL    port+0(FP), DX
337         XORL    AX, AX
338         OP16;   INL
339         RET
340
341 TEXT inss(SB), $0
342         MOVL    port+0(FP), DX
343         MOVL    address+4(FP), DI
344         MOVL    count+8(FP), CX
345         CLD
346         REP;    OP16; INSL
347         RET
348
349 TEXT inl(SB), $0
350         MOVL    port+0(FP), DX
351         INL
352         RET
353
354 TEXT insl(SB), $0
355         MOVL    port+0(FP), DX
356         MOVL    address+4(FP), DI
357         MOVL    count+8(FP), CX
358         CLD
359         REP;    INSL
360         RET
361
362 TEXT outb(SB), $0
363         MOVL    port+0(FP), DX
364         MOVL    byte+4(FP), AX
365         OUTB
366         RET
367
368 TEXT outsb(SB), $0
369         MOVL    port+0(FP), DX
370         MOVL    address+4(FP), SI
371         MOVL    count+8(FP), CX
372         CLD
373         REP;    OUTSB
374         RET
375
376 TEXT outs(SB), $0
377         MOVL    port+0(FP), DX
378         MOVL    short+4(FP), AX
379         OP16;   OUTL
380         RET
381
382 TEXT outss(SB), $0
383         MOVL    port+0(FP), DX
384         MOVL    address+4(FP), SI
385         MOVL    count+8(FP), CX
386         CLD
387         REP;    OP16; OUTSL
388         RET
389
390 TEXT outl(SB), $0
391         MOVL    port+0(FP), DX
392         MOVL    long+4(FP), AX
393         OUTL
394         RET
395
396 TEXT outsl(SB), $0
397         MOVL    port+0(FP), DX
398         MOVL    address+4(FP), SI
399         MOVL    count+8(FP), CX
400         CLD
401         REP;    OUTSL
402         RET
403
404 /*
405  * Read/write various system registers.
406  * CR4 and the 'model specific registers' should only be read/written
407  * after it has been determined the processor supports them
408  */
409 TEXT lgdt(SB), $0                               /* GDTR - global descriptor table */
410         MOVL    gdtptr+0(FP), AX
411         MOVL    (AX), GDTR
412         RET
413
414 TEXT lldt(SB), $0                               /* LDTR - local descriptor table */
415         MOVL    sel+0(FP), AX
416         BYTE $0x0F; BYTE $0x00; BYTE $0xD0      /* LLDT AX */
417         RET
418
419 TEXT lidt(SB), $0                               /* IDTR - interrupt descriptor table */
420         MOVL    idtptr+0(FP), AX
421         MOVL    (AX), IDTR
422         RET
423
424 TEXT ltr(SB), $0                                /* TR - task register */
425         MOVL    tptr+0(FP), AX
426         MOVW    AX, TASK
427         RET
428
429 TEXT getcr0(SB), $0                             /* CR0 - processor control */
430         MOVL    CR0, AX
431         RET
432
433 TEXT getcr2(SB), $0                             /* CR2 - page fault linear address */
434         MOVL    CR2, AX
435         RET
436
437 TEXT getcr3(SB), $0                             /* CR3 - page directory base */
438         MOVL    CR3, AX
439         RET
440
441 TEXT putcr0(SB), $0
442         MOVL    cr0+0(FP), AX
443         MOVL    AX, CR0
444         RET
445
446 TEXT putcr3(SB), $0
447         MOVL    cr3+0(FP), AX
448         MOVL    AX, CR3
449         RET
450
451 TEXT getcr4(SB), $0                             /* CR4 - extensions */
452         MOVL    CR4, AX
453         RET
454
455 TEXT putcr4(SB), $0
456         MOVL    cr4+0(FP), AX
457         MOVL    AX, CR4
458         RET
459
460 TEXT invlpg(SB), $0
461         /* 486+ only */
462         MOVL    va+0(FP), CX
463         INVLPG
464         RET
465
466 TEXT wbinvd(SB), $0
467         WBINVD
468         RET
469
470 TEXT _cycles(SB), $0                            /* time stamp counter */
471         RDTSC
472         MOVL    vlong+0(FP), CX                 /* &vlong */
473         MOVL    AX, 0(CX)                       /* lo */
474         MOVL    DX, 4(CX)                       /* hi */
475         RET
476
477 /*
478  * stub for:
479  * time stamp counter; low-order 32 bits of 64-bit cycle counter
480  * Runs at fasthz/4 cycles per second (m->clkin>>3)
481  */
482 TEXT lcycles(SB),1,$0
483         RDTSC
484         RET
485
486 TEXT rdmsr(SB), $0                              /* model-specific register */
487         MOVL    $0, BP
488         MOVL    index+0(FP), CX
489 TEXT _rdmsrinst(SB), $0
490         RDMSR
491         MOVL    vlong+4(FP), CX                 /* &vlong */
492         MOVL    AX, 0(CX)                       /* lo */
493         MOVL    DX, 4(CX)                       /* hi */
494         MOVL    BP, AX                          /* BP set to -1 if traped */
495         RET
496         
497 TEXT wrmsr(SB), $0
498         MOVL    $0, BP
499         MOVL    index+0(FP), CX
500         MOVL    lo+4(FP), AX
501         MOVL    hi+8(FP), DX
502 TEXT _wrmsrinst(SB), $0
503         WRMSR
504         MOVL    BP, AX                          /* BP set to -1 if traped */
505         RET
506
507 /*
508  * Try to determine the CPU type which requires fiddling with EFLAGS.
509  * If the Id bit can be toggled then the CPUID instruction can be used
510  * to determine CPU identity and features. First have to check if it's
511  * a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be
512  * toggled then it's an older 486 of some kind.
513  *
514  *      cpuid(fun, regs[4]);
515  */
516 TEXT cpuid(SB), $0
517         MOVL    $0x240000, AX
518         PUSHL   AX
519         POPFL                                   /* set Id|Ac */
520         PUSHFL
521         POPL    BX                              /* retrieve value */
522         MOVL    $0, AX
523         PUSHL   AX
524         POPFL                                   /* clear Id|Ac, EFLAGS initialised */
525         PUSHFL
526         POPL    AX                              /* retrieve value */
527         XORL    BX, AX
528         TESTL   $0x040000, AX                   /* Ac */
529         JZ      _cpu386                         /* can't set this bit on 386 */
530         TESTL   $0x200000, AX                   /* Id */
531         JZ      _cpu486                         /* can't toggle this bit on some 486 */
532         MOVL    fn+0(FP), AX
533         CPUID
534         JMP     _cpuid
535 _cpu486:
536         MOVL    $0x400, AX
537         JMP     _maybezapax
538 _cpu386:
539         MOVL    $0x300, AX
540 _maybezapax:
541         CMPL    fn+0(FP), $1
542         JE      _zaprest
543         XORL    AX, AX
544 _zaprest:
545         XORL    BX, BX
546         XORL    CX, CX
547         XORL    DX, DX
548 _cpuid:
549         MOVL    regs+4(FP), BP
550         MOVL    AX, 0(BP)
551         MOVL    BX, 4(BP)
552         MOVL    CX, 8(BP)
553         MOVL    DX, 12(BP)
554         RET
555
556 /*
557  * Basic timing loop to determine CPU frequency.
558  */
559 TEXT aamloop(SB), $0
560         MOVL    count+0(FP), CX
561 _aamloop:
562         AAM
563         LOOP    _aamloop
564         RET
565
566 /*
567  * Floating point.
568  * Note: the encodings for the FCLEX, FINIT, FSAVE, FSTCW, FSENV and FSTSW
569  * instructions do NOT have the WAIT prefix byte (i.e. they act like their
570  * FNxxx variations) so WAIT instructions must be explicitly placed in the
571  * code as necessary.
572  */
573 #define FPOFF                                                    ;\
574         MOVL    CR0, AX                                          ;\
575         ORL     $0x28, AX                       /* NE=1, TS=1 */ ;\
576         MOVL    AX, CR0
577
578 #define FPON                                                     ;\
579         MOVL    CR0, AX                                          ;\
580         ANDL    $~0xC, AX                       /* EM=0, TS=0 */ ;\
581         MOVL    AX, CR0
582
583 TEXT fpoff(SB), $0                              /* disable */
584         FPOFF
585         RET
586
587 TEXT fpinit(SB), $0                             /* enable and init */
588         FPON
589         FINIT
590         WAIT
591         /* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */
592         /* note that low 6 bits are masks, not enables, on this chip */
593         PUSHW   $0x0232
594         FLDCW   0(SP)
595         POPW    AX
596         WAIT
597         RET
598
599 TEXT fpx87save0(SB), $0                         /* save state and disable */
600         MOVL    p+0(FP), AX
601         FSAVE   0(AX)                           /* no WAIT */
602         FPOFF
603         RET
604
605 TEXT fpx87restore0(SB), $0                      /* enable and restore state */
606         FPON
607         MOVL    p+0(FP), AX
608         FRSTOR  0(AX)
609         WAIT
610         RET
611
612 TEXT fpstatus(SB), $0                           /* get floating point status */
613         FSTSW   AX
614         RET
615
616 TEXT fpenv(SB), $0                              /* save state without waiting */
617         MOVL    p+0(FP), AX
618         FSTENV  0(AX)
619         RET
620
621 TEXT fpclear(SB), $0                            /* clear pending exceptions */
622         FPON
623         FCLEX                                   /* no WAIT */
624         FPOFF
625         RET
626
627 TEXT fpssesave0(SB), $0                         /* save state and disable */
628         MOVL    p+0(FP), AX
629         FXSAVE  0(AX)                           /* no WAIT */
630         FPOFF
631         RET
632
633 TEXT fpsserestore0(SB), $0                      /* enable and restore state */
634         FPON
635         MOVL    p+0(FP), AX
636         FXRSTOR 0(AX)
637         WAIT
638         RET
639
640 TEXT ldmxcsr(SB), $0                            /* Load MXCSR */
641         LDMXCSR mxcsr+0(FP)
642         RET
643
644 /*
645  */
646 TEXT splhi(SB), $0
647 shi:
648         PUSHFL
649         POPL    AX
650         TESTL   $0x200, AX
651         JZ      alreadyhi
652         MOVL    $(MACHADDR+0x04), CX            /* save PC in m->splpc */
653         MOVL    (SP), BX
654         MOVL    BX, (CX)
655 alreadyhi:
656         CLI
657         RET
658
659 TEXT spllo(SB), $0
660 slo:
661         PUSHFL
662         POPL    AX
663         TESTL   $0x200, AX
664         JNZ     alreadylo
665         MOVL    $(MACHADDR+0x04), CX            /* clear m->splpc */
666         MOVL    $0, (CX)
667 alreadylo:
668         STI
669         RET
670
671 TEXT splx(SB), $0
672         MOVL    s+0(FP), AX
673         TESTL   $0x200, AX
674         JNZ     slo
675         JMP     shi
676
677 TEXT spldone(SB), $0
678         RET
679
680 TEXT islo(SB), $0
681         PUSHFL
682         POPL    AX
683         ANDL    $0x200, AX                      /* interrupt enable flag */
684         RET
685
686 /*
687  * Test-And-Set
688  */
689 TEXT tas(SB), $0
690         MOVL    $0xDEADDEAD, AX
691         MOVL    lock+0(FP), BX
692         XCHGL   AX, (BX)                        /* lock->key */
693         RET
694
695 TEXT mb386(SB), $0
696         POPL    AX                              /* return PC */
697         PUSHFL
698         PUSHL   CS
699         PUSHL   AX
700         IRETL
701
702 TEXT mb586(SB), $0
703         XORL    AX, AX
704         CPUID
705         RET
706
707 TEXT sfence(SB), $0
708         BYTE $0x0f
709         BYTE $0xae
710         BYTE $0xf8
711         RET
712
713 TEXT lfence(SB), $0
714         BYTE $0x0f
715         BYTE $0xae
716         BYTE $0xe8
717         RET
718
719 TEXT mfence(SB), $0
720         BYTE $0x0f
721         BYTE $0xae
722         BYTE $0xf0
723         RET
724
725 TEXT xchgw(SB), $0
726         MOVL    v+4(FP), AX
727         MOVL    p+0(FP), BX
728         XCHGW   AX, (BX)
729         RET
730
731 TEXT cmpswap486(SB), $0
732         MOVL    addr+0(FP), BX
733         MOVL    old+4(FP), AX
734         MOVL    new+8(FP), CX
735         LOCK
736         BYTE $0x0F; BYTE $0xB1; BYTE $0x0B      /* CMPXCHGL CX, (BX) */
737         JNZ didnt
738         MOVL    $1, AX
739         RET
740 didnt:
741         XORL    AX,AX
742         RET
743
744 TEXT mul64fract(SB), $0
745 /*
746  * Multiply two 64-bit number s and keep the middle 64 bits from the 128-bit result
747  * See ../port/tod.c for motivation.
748  */
749         MOVL    r+0(FP), CX
750         XORL    BX, BX                          /* BX = 0 */
751
752         MOVL    a+8(FP), AX
753         MULL    b+16(FP)                        /* a1*b1 */
754         MOVL    AX, 4(CX)                       /* r2 = lo(a1*b1) */
755
756         MOVL    a+8(FP), AX
757         MULL    b+12(FP)                        /* a1*b0 */
758         MOVL    AX, 0(CX)                       /* r1 = lo(a1*b0) */
759         ADDL    DX, 4(CX)                       /* r2 += hi(a1*b0) */
760
761         MOVL    a+4(FP), AX
762         MULL    b+16(FP)                        /* a0*b1 */
763         ADDL    AX, 0(CX)                       /* r1 += lo(a0*b1) */
764         ADCL    DX, 4(CX)                       /* r2 += hi(a0*b1) + carry */
765
766         MOVL    a+4(FP), AX
767         MULL    b+12(FP)                        /* a0*b0 */
768         ADDL    DX, 0(CX)                       /* r1 += hi(a0*b0) */
769         ADCL    BX, 4(CX)                       /* r2 += carry */
770         RET
771
772 /*
773  *  label consists of a stack pointer and a PC
774  */
775 TEXT gotolabel(SB), $0
776         MOVL    label+0(FP), AX
777         MOVL    0(AX), SP                       /* restore sp */
778         MOVL    4(AX), AX                       /* put return pc on the stack */
779         MOVL    AX, 0(SP)
780         MOVL    $1, AX                          /* return 1 */
781         RET
782
783 TEXT setlabel(SB), $0
784         MOVL    label+0(FP), AX
785         MOVL    SP, 0(AX)                       /* store sp */
786         MOVL    0(SP), BX                       /* store return pc */
787         MOVL    BX, 4(AX)
788         MOVL    $0, AX                          /* return 0 */
789         RET
790
791 /*
792  * Attempt at power saving. -rsc
793  */
794 TEXT halt(SB), $0
795         CLI
796         CMPL    nrdy(SB), $0
797         JEQ     _nothingready
798         STI
799         RET
800
801 _nothingready:
802         STI
803         HLT
804         RET
805
806 TEXT mwait(SB), $0
807         MOVL    addr+0(FP), AX
808         MOVL    (AX), CX
809         ORL     CX, CX
810         JNZ     _mwaitdone
811         XORL    DX, DX
812         BYTE $0x0f; BYTE $0x01; BYTE $0xc8      /* MONITOR */
813         MOVL    (AX), CX
814         ORL     CX, CX
815         JNZ     _mwaitdone
816         XORL    AX, AX
817         BYTE $0x0f; BYTE $0x01; BYTE $0xc9      /* MWAIT */
818 _mwaitdone:
819         RET
820
821 #define RDRANDAX        BYTE $0x0f; BYTE $0xc7; BYTE $0xf0
822
823 TEXT rdrand32(SB), $-4
824 _rloop32:
825         RDRANDAX
826         JCC     _rloop32
827         RET
828
829 TEXT rdrandbuf(SB), $0
830         MOVL    buf+0(FP), DI
831         MOVL    cnt+4(FP), CX
832         CLD
833         MOVL    CX, DX
834         SHRL    $2, CX
835         CMPL    CX, $0
836         JE      _rndleft
837 _rnddwords:
838         CALL    rdrand32(SB)
839         STOSL
840         LOOP _rnddwords
841 _rndleft:
842         MOVL    DX, CX
843         ANDL    $3, CX
844         CMPL    CX, $0
845         JE      _rnddone
846 _rndbytes:
847         CALL rdrand32(SB)
848         STOSB
849         LOOP _rndbytes
850 _rnddone:
851         RET
852
853 /*
854  *  Used to get to the first process:
855  *      set up an interrupt return frame and IRET to user level.
856  */
857 TEXT touser(SB), $0
858         PUSHL   $(UDSEL)                        /* old ss */
859         MOVL    sp+0(FP), AX                    /* old sp */
860         PUSHL   AX
861         MOVL    $0x200, AX                      /* interrupt enable flag */
862         PUSHL   AX                              /* old flags */
863         PUSHL   $(UESEL)                        /* old cs */
864         PUSHL   $(UTZERO+32)                    /* old pc */
865         MOVL    $(UDSEL), AX
866         MOVW    AX, DS
867         MOVW    AX, ES
868         MOVW    AX, GS
869         MOVW    AX, FS
870         IRETL
871
872 /*
873  * Interrupt/exception handling.
874  * Each entry in the vector table calls either _strayintr or _strayintrx depending
875  * on whether an error code has been automatically pushed onto the stack
876  * (_strayintrx) or not, in which case a dummy entry must be pushed before retrieving
877  * the trap type from the vector table entry and placing it on the stack as part
878  * of the Ureg structure.
879  * The size of each entry in the vector table (6 bytes) is known in trapinit().
880  */
881 TEXT _strayintr(SB), $0
882         PUSHL   AX                      /* save AX */
883         MOVL    4(SP), AX               /* return PC from vectortable(SB) */
884         JMP     intrcommon
885
886 TEXT _strayintrx(SB), $0
887         XCHGL   AX, (SP)                /* swap AX with vectortable CALL PC */
888 intrcommon:
889         PUSHL   DS                      /* save DS */
890         PUSHL   $(KDSEL)
891         POPL    DS                      /* fix up DS */
892         MOVBLZX (AX), AX                /* trap type -> AX */
893         XCHGL   AX, 4(SP)               /* exchange trap type with saved AX */
894
895         PUSHL   ES                      /* save ES */
896         PUSHL   $(KDSEL)
897         POPL    ES                      /* fix up ES */
898
899         PUSHL   FS                      /* save the rest of the Ureg struct */
900         PUSHL   GS
901         PUSHAL
902
903         PUSHL   SP                      /* Ureg* argument to trap */
904         CALL    trap(SB)
905
906 TEXT forkret(SB), $0
907         POPL    AX
908         POPAL
909 TEXT _forkretpopgs(SB), $0
910         POPL    GS
911 TEXT _forkretpopfs(SB), $0
912         POPL    FS
913 TEXT _forkretpopes(SB), $0
914         POPL    ES
915 TEXT _forkretpopds(SB), $0
916         POPL    DS
917         ADDL    $8, SP                  /* pop error code and trap type */
918 TEXT _forkretiret(SB), $0
919         IRETL
920
921 /*
922  * This is merely _strayintr optimised to vector
923  * to syscall() without going through trap().
924  */
925 TEXT _syscallintr(SB), $0
926         PUSHL   $VectorSYSCALL          /* trap type */
927
928         PUSHL   DS
929         PUSHL   ES
930         PUSHL   FS
931         PUSHL   GS
932         PUSHAL
933         MOVL    $(KDSEL), AX
934         MOVW    AX, DS
935         MOVW    AX, ES
936
937         MOVL    $syscall(SB), AX
938
939         PUSHL   SP                      /* Ureg* argument to syscall */
940         PUSHL   $forkret(SB)            /* return pc */
941         JMP     *AX
942
943 TEXT vectortable(SB), $0
944         CALL _strayintr(SB); BYTE $0x00         /* divide error */
945         CALL _strayintr(SB); BYTE $0x01         /* debug exception */
946         CALL _strayintr(SB); BYTE $0x02         /* NMI interrupt */
947         CALL _strayintr(SB); BYTE $0x03         /* breakpoint */
948         CALL _strayintr(SB); BYTE $0x04         /* overflow */
949         CALL _strayintr(SB); BYTE $0x05         /* bound */
950         CALL _strayintr(SB); BYTE $0x06         /* invalid opcode */
951         CALL _strayintr(SB); BYTE $0x07         /* no coprocessor available */
952         CALL _strayintrx(SB); BYTE $0x08        /* double fault */
953         CALL _strayintr(SB); BYTE $0x09         /* coprocessor segment overflow */
954         CALL _strayintrx(SB); BYTE $0x0A        /* invalid TSS */
955         CALL _strayintrx(SB); BYTE $0x0B        /* segment not available */
956         CALL _strayintrx(SB); BYTE $0x0C        /* stack exception */
957         CALL _strayintrx(SB); BYTE $0x0D        /* general protection error */
958         CALL _strayintrx(SB); BYTE $0x0E        /* page fault */
959         CALL _strayintr(SB); BYTE $0x0F         /*  */
960         CALL _strayintr(SB); BYTE $0x10         /* coprocessor error */
961         CALL _strayintrx(SB); BYTE $0x11        /* alignment check */
962         CALL _strayintr(SB); BYTE $0x12         /* machine check */
963         CALL _strayintr(SB); BYTE $0x13         /* simd error */
964         CALL _strayintr(SB); BYTE $0x14
965         CALL _strayintr(SB); BYTE $0x15
966         CALL _strayintr(SB); BYTE $0x16
967         CALL _strayintr(SB); BYTE $0x17
968         CALL _strayintr(SB); BYTE $0x18
969         CALL _strayintr(SB); BYTE $0x19
970         CALL _strayintr(SB); BYTE $0x1A
971         CALL _strayintr(SB); BYTE $0x1B
972         CALL _strayintr(SB); BYTE $0x1C
973         CALL _strayintr(SB); BYTE $0x1D
974         CALL _strayintr(SB); BYTE $0x1E
975         CALL _strayintr(SB); BYTE $0x1F
976         CALL _strayintr(SB); BYTE $0x20         /* VectorLAPIC */
977         CALL _strayintr(SB); BYTE $0x21
978         CALL _strayintr(SB); BYTE $0x22
979         CALL _strayintr(SB); BYTE $0x23
980         CALL _strayintr(SB); BYTE $0x24
981         CALL _strayintr(SB); BYTE $0x25
982         CALL _strayintr(SB); BYTE $0x26
983         CALL _strayintr(SB); BYTE $0x27
984         CALL _strayintr(SB); BYTE $0x28
985         CALL _strayintr(SB); BYTE $0x29
986         CALL _strayintr(SB); BYTE $0x2A
987         CALL _strayintr(SB); BYTE $0x2B
988         CALL _strayintr(SB); BYTE $0x2C
989         CALL _strayintr(SB); BYTE $0x2D
990         CALL _strayintr(SB); BYTE $0x2E
991         CALL _strayintr(SB); BYTE $0x2F
992         CALL _strayintr(SB); BYTE $0x30
993         CALL _strayintr(SB); BYTE $0x31
994         CALL _strayintr(SB); BYTE $0x32
995         CALL _strayintr(SB); BYTE $0x33
996         CALL _strayintr(SB); BYTE $0x34
997         CALL _strayintr(SB); BYTE $0x35
998         CALL _strayintr(SB); BYTE $0x36
999         CALL _strayintr(SB); BYTE $0x37
1000         CALL _strayintr(SB); BYTE $0x38
1001         CALL _strayintr(SB); BYTE $0x39
1002         CALL _strayintr(SB); BYTE $0x3A
1003         CALL _strayintr(SB); BYTE $0x3B
1004         CALL _strayintr(SB); BYTE $0x3C
1005         CALL _strayintr(SB); BYTE $0x3D
1006         CALL _strayintr(SB); BYTE $0x3E
1007         CALL _strayintr(SB); BYTE $0x3F
1008         CALL _syscallintr(SB); BYTE $0x40       /* VectorSYSCALL */
1009         CALL _strayintr(SB); BYTE $0x41
1010         CALL _strayintr(SB); BYTE $0x42
1011         CALL _strayintr(SB); BYTE $0x43
1012         CALL _strayintr(SB); BYTE $0x44
1013         CALL _strayintr(SB); BYTE $0x45
1014         CALL _strayintr(SB); BYTE $0x46
1015         CALL _strayintr(SB); BYTE $0x47
1016         CALL _strayintr(SB); BYTE $0x48
1017         CALL _strayintr(SB); BYTE $0x49
1018         CALL _strayintr(SB); BYTE $0x4A
1019         CALL _strayintr(SB); BYTE $0x4B
1020         CALL _strayintr(SB); BYTE $0x4C
1021         CALL _strayintr(SB); BYTE $0x4D
1022         CALL _strayintr(SB); BYTE $0x4E
1023         CALL _strayintr(SB); BYTE $0x4F
1024         CALL _strayintr(SB); BYTE $0x50
1025         CALL _strayintr(SB); BYTE $0x51
1026         CALL _strayintr(SB); BYTE $0x52
1027         CALL _strayintr(SB); BYTE $0x53
1028         CALL _strayintr(SB); BYTE $0x54
1029         CALL _strayintr(SB); BYTE $0x55
1030         CALL _strayintr(SB); BYTE $0x56
1031         CALL _strayintr(SB); BYTE $0x57
1032         CALL _strayintr(SB); BYTE $0x58
1033         CALL _strayintr(SB); BYTE $0x59
1034         CALL _strayintr(SB); BYTE $0x5A
1035         CALL _strayintr(SB); BYTE $0x5B
1036         CALL _strayintr(SB); BYTE $0x5C
1037         CALL _strayintr(SB); BYTE $0x5D
1038         CALL _strayintr(SB); BYTE $0x5E
1039         CALL _strayintr(SB); BYTE $0x5F
1040         CALL _strayintr(SB); BYTE $0x60
1041         CALL _strayintr(SB); BYTE $0x61
1042         CALL _strayintr(SB); BYTE $0x62
1043         CALL _strayintr(SB); BYTE $0x63
1044         CALL _strayintr(SB); BYTE $0x64
1045         CALL _strayintr(SB); BYTE $0x65
1046         CALL _strayintr(SB); BYTE $0x66
1047         CALL _strayintr(SB); BYTE $0x67
1048         CALL _strayintr(SB); BYTE $0x68
1049         CALL _strayintr(SB); BYTE $0x69
1050         CALL _strayintr(SB); BYTE $0x6A
1051         CALL _strayintr(SB); BYTE $0x6B
1052         CALL _strayintr(SB); BYTE $0x6C
1053         CALL _strayintr(SB); BYTE $0x6D
1054         CALL _strayintr(SB); BYTE $0x6E
1055         CALL _strayintr(SB); BYTE $0x6F
1056         CALL _strayintr(SB); BYTE $0x70
1057         CALL _strayintr(SB); BYTE $0x71
1058         CALL _strayintr(SB); BYTE $0x72
1059         CALL _strayintr(SB); BYTE $0x73
1060         CALL _strayintr(SB); BYTE $0x74
1061         CALL _strayintr(SB); BYTE $0x75
1062         CALL _strayintr(SB); BYTE $0x76
1063         CALL _strayintr(SB); BYTE $0x77
1064         CALL _strayintr(SB); BYTE $0x78
1065         CALL _strayintr(SB); BYTE $0x79
1066         CALL _strayintr(SB); BYTE $0x7A
1067         CALL _strayintr(SB); BYTE $0x7B
1068         CALL _strayintr(SB); BYTE $0x7C
1069         CALL _strayintr(SB); BYTE $0x7D
1070         CALL _strayintr(SB); BYTE $0x7E
1071         CALL _strayintr(SB); BYTE $0x7F
1072         CALL _strayintr(SB); BYTE $0x80         /* Vector[A]PIC */
1073         CALL _strayintr(SB); BYTE $0x81
1074         CALL _strayintr(SB); BYTE $0x82
1075         CALL _strayintr(SB); BYTE $0x83
1076         CALL _strayintr(SB); BYTE $0x84
1077         CALL _strayintr(SB); BYTE $0x85
1078         CALL _strayintr(SB); BYTE $0x86
1079         CALL _strayintr(SB); BYTE $0x87
1080         CALL _strayintr(SB); BYTE $0x88
1081         CALL _strayintr(SB); BYTE $0x89
1082         CALL _strayintr(SB); BYTE $0x8A
1083         CALL _strayintr(SB); BYTE $0x8B
1084         CALL _strayintr(SB); BYTE $0x8C
1085         CALL _strayintr(SB); BYTE $0x8D
1086         CALL _strayintr(SB); BYTE $0x8E
1087         CALL _strayintr(SB); BYTE $0x8F
1088         CALL _strayintr(SB); BYTE $0x90
1089         CALL _strayintr(SB); BYTE $0x91
1090         CALL _strayintr(SB); BYTE $0x92
1091         CALL _strayintr(SB); BYTE $0x93
1092         CALL _strayintr(SB); BYTE $0x94
1093         CALL _strayintr(SB); BYTE $0x95
1094         CALL _strayintr(SB); BYTE $0x96
1095         CALL _strayintr(SB); BYTE $0x97
1096         CALL _strayintr(SB); BYTE $0x98
1097         CALL _strayintr(SB); BYTE $0x99
1098         CALL _strayintr(SB); BYTE $0x9A
1099         CALL _strayintr(SB); BYTE $0x9B
1100         CALL _strayintr(SB); BYTE $0x9C
1101         CALL _strayintr(SB); BYTE $0x9D
1102         CALL _strayintr(SB); BYTE $0x9E
1103         CALL _strayintr(SB); BYTE $0x9F
1104         CALL _strayintr(SB); BYTE $0xA0
1105         CALL _strayintr(SB); BYTE $0xA1
1106         CALL _strayintr(SB); BYTE $0xA2
1107         CALL _strayintr(SB); BYTE $0xA3
1108         CALL _strayintr(SB); BYTE $0xA4
1109         CALL _strayintr(SB); BYTE $0xA5
1110         CALL _strayintr(SB); BYTE $0xA6
1111         CALL _strayintr(SB); BYTE $0xA7
1112         CALL _strayintr(SB); BYTE $0xA8
1113         CALL _strayintr(SB); BYTE $0xA9
1114         CALL _strayintr(SB); BYTE $0xAA
1115         CALL _strayintr(SB); BYTE $0xAB
1116         CALL _strayintr(SB); BYTE $0xAC
1117         CALL _strayintr(SB); BYTE $0xAD
1118         CALL _strayintr(SB); BYTE $0xAE
1119         CALL _strayintr(SB); BYTE $0xAF
1120         CALL _strayintr(SB); BYTE $0xB0
1121         CALL _strayintr(SB); BYTE $0xB1
1122         CALL _strayintr(SB); BYTE $0xB2
1123         CALL _strayintr(SB); BYTE $0xB3
1124         CALL _strayintr(SB); BYTE $0xB4
1125         CALL _strayintr(SB); BYTE $0xB5
1126         CALL _strayintr(SB); BYTE $0xB6
1127         CALL _strayintr(SB); BYTE $0xB7
1128         CALL _strayintr(SB); BYTE $0xB8
1129         CALL _strayintr(SB); BYTE $0xB9
1130         CALL _strayintr(SB); BYTE $0xBA
1131         CALL _strayintr(SB); BYTE $0xBB
1132         CALL _strayintr(SB); BYTE $0xBC
1133         CALL _strayintr(SB); BYTE $0xBD
1134         CALL _strayintr(SB); BYTE $0xBE
1135         CALL _strayintr(SB); BYTE $0xBF
1136         CALL _strayintr(SB); BYTE $0xC0
1137         CALL _strayintr(SB); BYTE $0xC1
1138         CALL _strayintr(SB); BYTE $0xC2
1139         CALL _strayintr(SB); BYTE $0xC3
1140         CALL _strayintr(SB); BYTE $0xC4
1141         CALL _strayintr(SB); BYTE $0xC5
1142         CALL _strayintr(SB); BYTE $0xC6
1143         CALL _strayintr(SB); BYTE $0xC7
1144         CALL _strayintr(SB); BYTE $0xC8
1145         CALL _strayintr(SB); BYTE $0xC9
1146         CALL _strayintr(SB); BYTE $0xCA
1147         CALL _strayintr(SB); BYTE $0xCB
1148         CALL _strayintr(SB); BYTE $0xCC
1149         CALL _strayintr(SB); BYTE $0xCD
1150         CALL _strayintr(SB); BYTE $0xCE
1151         CALL _strayintr(SB); BYTE $0xCF
1152         CALL _strayintr(SB); BYTE $0xD0
1153         CALL _strayintr(SB); BYTE $0xD1
1154         CALL _strayintr(SB); BYTE $0xD2
1155         CALL _strayintr(SB); BYTE $0xD3
1156         CALL _strayintr(SB); BYTE $0xD4
1157         CALL _strayintr(SB); BYTE $0xD5
1158         CALL _strayintr(SB); BYTE $0xD6
1159         CALL _strayintr(SB); BYTE $0xD7
1160         CALL _strayintr(SB); BYTE $0xD8
1161         CALL _strayintr(SB); BYTE $0xD9
1162         CALL _strayintr(SB); BYTE $0xDA
1163         CALL _strayintr(SB); BYTE $0xDB
1164         CALL _strayintr(SB); BYTE $0xDC
1165         CALL _strayintr(SB); BYTE $0xDD
1166         CALL _strayintr(SB); BYTE $0xDE
1167         CALL _strayintr(SB); BYTE $0xDF
1168         CALL _strayintr(SB); BYTE $0xE0
1169         CALL _strayintr(SB); BYTE $0xE1
1170         CALL _strayintr(SB); BYTE $0xE2
1171         CALL _strayintr(SB); BYTE $0xE3
1172         CALL _strayintr(SB); BYTE $0xE4
1173         CALL _strayintr(SB); BYTE $0xE5
1174         CALL _strayintr(SB); BYTE $0xE6
1175         CALL _strayintr(SB); BYTE $0xE7
1176         CALL _strayintr(SB); BYTE $0xE8
1177         CALL _strayintr(SB); BYTE $0xE9
1178         CALL _strayintr(SB); BYTE $0xEA
1179         CALL _strayintr(SB); BYTE $0xEB
1180         CALL _strayintr(SB); BYTE $0xEC
1181         CALL _strayintr(SB); BYTE $0xED
1182         CALL _strayintr(SB); BYTE $0xEE
1183         CALL _strayintr(SB); BYTE $0xEF
1184         CALL _strayintr(SB); BYTE $0xF0
1185         CALL _strayintr(SB); BYTE $0xF1
1186         CALL _strayintr(SB); BYTE $0xF2
1187         CALL _strayintr(SB); BYTE $0xF3
1188         CALL _strayintr(SB); BYTE $0xF4
1189         CALL _strayintr(SB); BYTE $0xF5
1190         CALL _strayintr(SB); BYTE $0xF6
1191         CALL _strayintr(SB); BYTE $0xF7
1192         CALL _strayintr(SB); BYTE $0xF8
1193         CALL _strayintr(SB); BYTE $0xF9
1194         CALL _strayintr(SB); BYTE $0xFA
1195         CALL _strayintr(SB); BYTE $0xFB
1196         CALL _strayintr(SB); BYTE $0xFC
1197         CALL _strayintr(SB); BYTE $0xFD
1198         CALL _strayintr(SB); BYTE $0xFE
1199         CALL _strayintr(SB); BYTE $0xFF