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