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