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