]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/l.s
Add RDRAND Support for /dev/random
[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 fpsave(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 fprestore(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 /*
689  */
690 TEXT splhi(SB), $0
691 shi:
692         PUSHFL
693         POPL    AX
694         TESTL   $0x200, AX
695         JZ      alreadyhi
696         MOVL    $(MACHADDR+0x04), CX            /* save PC in m->splpc */
697         MOVL    (SP), BX
698         MOVL    BX, (CX)
699 alreadyhi:
700         CLI
701         RET
702
703 TEXT spllo(SB), $0
704 slo:
705         PUSHFL
706         POPL    AX
707         TESTL   $0x200, AX
708         JNZ     alreadylo
709         MOVL    $(MACHADDR+0x04), CX            /* clear m->splpc */
710         MOVL    $0, (CX)
711 alreadylo:
712         STI
713         RET
714
715 TEXT splx(SB), $0
716         MOVL    s+0(FP), AX
717         TESTL   $0x200, AX
718         JNZ     slo
719         JMP     shi
720
721 TEXT spldone(SB), $0
722         RET
723
724 TEXT islo(SB), $0
725         PUSHFL
726         POPL    AX
727         ANDL    $0x200, AX                      /* interrupt enable flag */
728         RET
729
730 /*
731  * Test-And-Set
732  */
733 TEXT tas(SB), $0
734         MOVL    $0xDEADDEAD, AX
735         MOVL    lock+0(FP), BX
736         XCHGL   AX, (BX)                        /* lock->key */
737         RET
738
739 TEXT _xinc(SB), $0                              /* void _xinc(long*); */
740         MOVL    l+0(FP), AX
741         LOCK;   INCL 0(AX)
742         RET
743
744 TEXT _xdec(SB), $0                              /* long _xdec(long*); */
745         MOVL    l+0(FP), BX
746         XORL    AX, AX
747         LOCK;   DECL 0(BX)
748         JLT     _xdeclt
749         JGT     _xdecgt
750         RET
751 _xdecgt:
752         INCL    AX
753         RET
754 _xdeclt:
755         DECL    AX
756         RET
757
758 TEXT mb386(SB), $0
759         POPL    AX                              /* return PC */
760         PUSHFL
761         PUSHL   CS
762         PUSHL   AX
763         IRETL
764
765 TEXT mb586(SB), $0
766         XORL    AX, AX
767         CPUID
768         RET
769
770 TEXT sfence(SB), $0
771         BYTE $0x0f
772         BYTE $0xae
773         BYTE $0xf8
774         RET
775
776 TEXT lfence(SB), $0
777         BYTE $0x0f
778         BYTE $0xae
779         BYTE $0xe8
780         RET
781
782 TEXT mfence(SB), $0
783         BYTE $0x0f
784         BYTE $0xae
785         BYTE $0xf0
786         RET
787
788 TEXT xchgw(SB), $0
789         MOVL    v+4(FP), AX
790         MOVL    p+0(FP), BX
791         XCHGW   AX, (BX)
792         RET
793
794 TEXT cmpswap486(SB), $0
795         MOVL    addr+0(FP), BX
796         MOVL    old+4(FP), AX
797         MOVL    new+8(FP), CX
798         LOCK
799         BYTE $0x0F; BYTE $0xB1; BYTE $0x0B      /* CMPXCHGL CX, (BX) */
800         JNZ didnt
801         MOVL    $1, AX
802         RET
803 didnt:
804         XORL    AX,AX
805         RET
806
807 TEXT mul64fract(SB), $0
808 /*
809  * Multiply two 64-bit number s and keep the middle 64 bits from the 128-bit result
810  * See ../port/tod.c for motivation.
811  */
812         MOVL    r+0(FP), CX
813         XORL    BX, BX                          /* BX = 0 */
814
815         MOVL    a+8(FP), AX
816         MULL    b+16(FP)                        /* a1*b1 */
817         MOVL    AX, 4(CX)                       /* r2 = lo(a1*b1) */
818
819         MOVL    a+8(FP), AX
820         MULL    b+12(FP)                        /* a1*b0 */
821         MOVL    AX, 0(CX)                       /* r1 = lo(a1*b0) */
822         ADDL    DX, 4(CX)                       /* r2 += hi(a1*b0) */
823
824         MOVL    a+4(FP), AX
825         MULL    b+16(FP)                        /* a0*b1 */
826         ADDL    AX, 0(CX)                       /* r1 += lo(a0*b1) */
827         ADCL    DX, 4(CX)                       /* r2 += hi(a0*b1) + carry */
828
829         MOVL    a+4(FP), AX
830         MULL    b+12(FP)                        /* a0*b0 */
831         ADDL    DX, 0(CX)                       /* r1 += hi(a0*b0) */
832         ADCL    BX, 4(CX)                       /* r2 += carry */
833         RET
834
835 /*
836  *  label consists of a stack pointer and a PC
837  */
838 TEXT gotolabel(SB), $0
839         MOVL    label+0(FP), AX
840         MOVL    0(AX), SP                       /* restore sp */
841         MOVL    4(AX), AX                       /* put return pc on the stack */
842         MOVL    AX, 0(SP)
843         MOVL    $1, AX                          /* return 1 */
844         RET
845
846 TEXT setlabel(SB), $0
847         MOVL    label+0(FP), AX
848         MOVL    SP, 0(AX)                       /* store sp */
849         MOVL    0(SP), BX                       /* store return pc */
850         MOVL    BX, 4(AX)
851         MOVL    $0, AX                          /* return 0 */
852         RET
853
854 /*
855  * Attempt at power saving. -rsc
856  */
857 TEXT halt(SB), $0
858         CLI
859         CMPL    nrdy(SB), $0
860         JEQ     _nothingready
861         STI
862         RET
863
864 _nothingready:
865         STI
866         HLT
867         RET
868
869 TEXT mwait(SB), $0
870         MOVL    addr+0(FP), AX
871         MOVL    (AX), CX
872         ORL     CX, CX
873         JNZ     _mwaitdone
874         XORL    DX, DX
875         BYTE $0x0f; BYTE $0x01; BYTE $0xc8      /* MONITOR */
876         MOVL    (AX), CX
877         ORL     CX, CX
878         JNZ     _mwaitdone
879         XORL    AX, AX
880         BYTE $0x0f; BYTE $0x01; BYTE $0xc9      /* MWAIT */
881 _mwaitdone:
882         RET
883
884 #define RDRANDAX        BYTE $0x0f; BYTE $0xc7; BYTE $0xf0
885
886 TEXT rdrand32(SB), $-4
887 _rloop32:
888         RDRANDAX
889         JCC     _rloop32
890         RET
891
892 TEXT rdrandbuf(SB), $0
893         MOVL    buf+0(FP), DI
894         MOVL    cnt+4(FP), CX
895         CLD
896         MOVL    CX, DX
897         SHRL    $2, CX
898         CMPL    CX, $0
899         JE      _rndleft
900 _rnddwords:
901         CALL    rdrand32(SB)
902         STOSL
903         LOOP _rnddwords
904 _rndleft:
905         MOVL    DX, CX
906         ANDL    $3, CX
907         CMPL    CX, $0
908         JE      _rnddone
909 _rndbytes:
910         CALL rdrand32(SB)
911         STOSB
912         LOOP _rndbytes
913 _rnddone:
914         RET
915         
916 /*
917  * Interrupt/exception handling.
918  * Each entry in the vector table calls either _strayintr or _strayintrx depending
919  * on whether an error code has been automatically pushed onto the stack
920  * (_strayintrx) or not, in which case a dummy entry must be pushed before retrieving
921  * the trap type from the vector table entry and placing it on the stack as part
922  * of the Ureg structure.
923  * The size of each entry in the vector table (6 bytes) is known in trapinit().
924  */
925 TEXT _strayintr(SB), $0
926         PUSHL   AX                      /* save AX */
927         MOVL    4(SP), AX               /* return PC from vectortable(SB) */
928         JMP     intrcommon
929
930 TEXT _strayintrx(SB), $0
931         XCHGL   AX, (SP)                /* swap AX with vectortable CALL PC */
932 intrcommon:
933         PUSHL   DS                      /* save DS */
934         PUSHL   $(KDSEL)
935         POPL    DS                      /* fix up DS */
936         MOVBLZX (AX), AX                /* trap type -> AX */
937         XCHGL   AX, 4(SP)               /* exchange trap type with saved AX */
938
939         PUSHL   ES                      /* save ES */
940         PUSHL   $(KDSEL)
941         POPL    ES                      /* fix up ES */
942
943         PUSHL   FS                      /* save the rest of the Ureg struct */
944         PUSHL   GS
945         PUSHAL
946
947         PUSHL   SP                      /* Ureg* argument to trap */
948         CALL    trap(SB)
949
950 TEXT forkret(SB), $0
951         POPL    AX
952         POPAL
953 TEXT _forkretpopgs(SB), $0
954         POPL    GS
955 TEXT _forkretpopfs(SB), $0
956         POPL    FS
957 TEXT _forkretpopes(SB), $0
958         POPL    ES
959 TEXT _forkretpopds(SB), $0
960         POPL    DS
961         ADDL    $8, SP                  /* pop error code and trap type */
962 TEXT _forkretiret(SB), $0
963         IRETL
964
965 TEXT vectortable(SB), $0
966         CALL _strayintr(SB); BYTE $0x00         /* divide error */
967         CALL _strayintr(SB); BYTE $0x01         /* debug exception */
968         CALL _strayintr(SB); BYTE $0x02         /* NMI interrupt */
969         CALL _strayintr(SB); BYTE $0x03         /* breakpoint */
970         CALL _strayintr(SB); BYTE $0x04         /* overflow */
971         CALL _strayintr(SB); BYTE $0x05         /* bound */
972         CALL _strayintr(SB); BYTE $0x06         /* invalid opcode */
973         CALL _strayintr(SB); BYTE $0x07         /* no coprocessor available */
974         CALL _strayintrx(SB); BYTE $0x08        /* double fault */
975         CALL _strayintr(SB); BYTE $0x09         /* coprocessor segment overflow */
976         CALL _strayintrx(SB); BYTE $0x0A        /* invalid TSS */
977         CALL _strayintrx(SB); BYTE $0x0B        /* segment not available */
978         CALL _strayintrx(SB); BYTE $0x0C        /* stack exception */
979         CALL _strayintrx(SB); BYTE $0x0D        /* general protection error */
980         CALL _strayintrx(SB); BYTE $0x0E        /* page fault */
981         CALL _strayintr(SB); BYTE $0x0F         /*  */
982         CALL _strayintr(SB); BYTE $0x10         /* coprocessor error */
983         CALL _strayintrx(SB); BYTE $0x11        /* alignment check */
984         CALL _strayintr(SB); BYTE $0x12         /* machine check */
985         CALL _strayintr(SB); BYTE $0x13
986         CALL _strayintr(SB); BYTE $0x14
987         CALL _strayintr(SB); BYTE $0x15
988         CALL _strayintr(SB); BYTE $0x16
989         CALL _strayintr(SB); BYTE $0x17
990         CALL _strayintr(SB); BYTE $0x18
991         CALL _strayintr(SB); BYTE $0x19
992         CALL _strayintr(SB); BYTE $0x1A
993         CALL _strayintr(SB); BYTE $0x1B
994         CALL _strayintr(SB); BYTE $0x1C
995         CALL _strayintr(SB); BYTE $0x1D
996         CALL _strayintr(SB); BYTE $0x1E
997         CALL _strayintr(SB); BYTE $0x1F
998         CALL _strayintr(SB); BYTE $0x20         /* VectorLAPIC */
999         CALL _strayintr(SB); BYTE $0x21
1000         CALL _strayintr(SB); BYTE $0x22
1001         CALL _strayintr(SB); BYTE $0x23
1002         CALL _strayintr(SB); BYTE $0x24
1003         CALL _strayintr(SB); BYTE $0x25
1004         CALL _strayintr(SB); BYTE $0x26
1005         CALL _strayintr(SB); BYTE $0x27
1006         CALL _strayintr(SB); BYTE $0x28
1007         CALL _strayintr(SB); BYTE $0x29
1008         CALL _strayintr(SB); BYTE $0x2A
1009         CALL _strayintr(SB); BYTE $0x2B
1010         CALL _strayintr(SB); BYTE $0x2C
1011         CALL _strayintr(SB); BYTE $0x2D
1012         CALL _strayintr(SB); BYTE $0x2E
1013         CALL _strayintr(SB); BYTE $0x2F
1014         CALL _strayintr(SB); BYTE $0x30
1015         CALL _strayintr(SB); BYTE $0x31
1016         CALL _strayintr(SB); BYTE $0x32
1017         CALL _strayintr(SB); BYTE $0x33
1018         CALL _strayintr(SB); BYTE $0x34
1019         CALL _strayintr(SB); BYTE $0x35
1020         CALL _strayintr(SB); BYTE $0x36
1021         CALL _strayintr(SB); BYTE $0x37
1022         CALL _strayintr(SB); BYTE $0x38
1023         CALL _strayintr(SB); BYTE $0x39
1024         CALL _strayintr(SB); BYTE $0x3A
1025         CALL _strayintr(SB); BYTE $0x3B
1026         CALL _strayintr(SB); BYTE $0x3C
1027         CALL _strayintr(SB); BYTE $0x3D
1028         CALL _strayintr(SB); BYTE $0x3E
1029         CALL _strayintr(SB); BYTE $0x3F
1030         CALL _syscallintr(SB); BYTE $0x40       /* VectorSYSCALL */
1031         CALL _strayintr(SB); BYTE $0x41
1032         CALL _strayintr(SB); BYTE $0x42
1033         CALL _strayintr(SB); BYTE $0x43
1034         CALL _strayintr(SB); BYTE $0x44
1035         CALL _strayintr(SB); BYTE $0x45
1036         CALL _strayintr(SB); BYTE $0x46
1037         CALL _strayintr(SB); BYTE $0x47
1038         CALL _strayintr(SB); BYTE $0x48
1039         CALL _strayintr(SB); BYTE $0x49
1040         CALL _strayintr(SB); BYTE $0x4A
1041         CALL _strayintr(SB); BYTE $0x4B
1042         CALL _strayintr(SB); BYTE $0x4C
1043         CALL _strayintr(SB); BYTE $0x4D
1044         CALL _strayintr(SB); BYTE $0x4E
1045         CALL _strayintr(SB); BYTE $0x4F
1046         CALL _strayintr(SB); BYTE $0x50
1047         CALL _strayintr(SB); BYTE $0x51
1048         CALL _strayintr(SB); BYTE $0x52
1049         CALL _strayintr(SB); BYTE $0x53
1050         CALL _strayintr(SB); BYTE $0x54
1051         CALL _strayintr(SB); BYTE $0x55
1052         CALL _strayintr(SB); BYTE $0x56
1053         CALL _strayintr(SB); BYTE $0x57
1054         CALL _strayintr(SB); BYTE $0x58
1055         CALL _strayintr(SB); BYTE $0x59
1056         CALL _strayintr(SB); BYTE $0x5A
1057         CALL _strayintr(SB); BYTE $0x5B
1058         CALL _strayintr(SB); BYTE $0x5C
1059         CALL _strayintr(SB); BYTE $0x5D
1060         CALL _strayintr(SB); BYTE $0x5E
1061         CALL _strayintr(SB); BYTE $0x5F
1062         CALL _strayintr(SB); BYTE $0x60
1063         CALL _strayintr(SB); BYTE $0x61
1064         CALL _strayintr(SB); BYTE $0x62
1065         CALL _strayintr(SB); BYTE $0x63
1066         CALL _strayintr(SB); BYTE $0x64
1067         CALL _strayintr(SB); BYTE $0x65
1068         CALL _strayintr(SB); BYTE $0x66
1069         CALL _strayintr(SB); BYTE $0x67
1070         CALL _strayintr(SB); BYTE $0x68
1071         CALL _strayintr(SB); BYTE $0x69
1072         CALL _strayintr(SB); BYTE $0x6A
1073         CALL _strayintr(SB); BYTE $0x6B
1074         CALL _strayintr(SB); BYTE $0x6C
1075         CALL _strayintr(SB); BYTE $0x6D
1076         CALL _strayintr(SB); BYTE $0x6E
1077         CALL _strayintr(SB); BYTE $0x6F
1078         CALL _strayintr(SB); BYTE $0x70
1079         CALL _strayintr(SB); BYTE $0x71
1080         CALL _strayintr(SB); BYTE $0x72
1081         CALL _strayintr(SB); BYTE $0x73
1082         CALL _strayintr(SB); BYTE $0x74
1083         CALL _strayintr(SB); BYTE $0x75
1084         CALL _strayintr(SB); BYTE $0x76
1085         CALL _strayintr(SB); BYTE $0x77
1086         CALL _strayintr(SB); BYTE $0x78
1087         CALL _strayintr(SB); BYTE $0x79
1088         CALL _strayintr(SB); BYTE $0x7A
1089         CALL _strayintr(SB); BYTE $0x7B
1090         CALL _strayintr(SB); BYTE $0x7C
1091         CALL _strayintr(SB); BYTE $0x7D
1092         CALL _strayintr(SB); BYTE $0x7E
1093         CALL _strayintr(SB); BYTE $0x7F
1094         CALL _strayintr(SB); BYTE $0x80         /* Vector[A]PIC */
1095         CALL _strayintr(SB); BYTE $0x81
1096         CALL _strayintr(SB); BYTE $0x82
1097         CALL _strayintr(SB); BYTE $0x83
1098         CALL _strayintr(SB); BYTE $0x84
1099         CALL _strayintr(SB); BYTE $0x85
1100         CALL _strayintr(SB); BYTE $0x86
1101         CALL _strayintr(SB); BYTE $0x87
1102         CALL _strayintr(SB); BYTE $0x88
1103         CALL _strayintr(SB); BYTE $0x89
1104         CALL _strayintr(SB); BYTE $0x8A
1105         CALL _strayintr(SB); BYTE $0x8B
1106         CALL _strayintr(SB); BYTE $0x8C
1107         CALL _strayintr(SB); BYTE $0x8D
1108         CALL _strayintr(SB); BYTE $0x8E
1109         CALL _strayintr(SB); BYTE $0x8F
1110         CALL _strayintr(SB); BYTE $0x90
1111         CALL _strayintr(SB); BYTE $0x91
1112         CALL _strayintr(SB); BYTE $0x92
1113         CALL _strayintr(SB); BYTE $0x93
1114         CALL _strayintr(SB); BYTE $0x94
1115         CALL _strayintr(SB); BYTE $0x95
1116         CALL _strayintr(SB); BYTE $0x96
1117         CALL _strayintr(SB); BYTE $0x97
1118         CALL _strayintr(SB); BYTE $0x98
1119         CALL _strayintr(SB); BYTE $0x99
1120         CALL _strayintr(SB); BYTE $0x9A
1121         CALL _strayintr(SB); BYTE $0x9B
1122         CALL _strayintr(SB); BYTE $0x9C
1123         CALL _strayintr(SB); BYTE $0x9D
1124         CALL _strayintr(SB); BYTE $0x9E
1125         CALL _strayintr(SB); BYTE $0x9F
1126         CALL _strayintr(SB); BYTE $0xA0
1127         CALL _strayintr(SB); BYTE $0xA1
1128         CALL _strayintr(SB); BYTE $0xA2
1129         CALL _strayintr(SB); BYTE $0xA3
1130         CALL _strayintr(SB); BYTE $0xA4
1131         CALL _strayintr(SB); BYTE $0xA5
1132         CALL _strayintr(SB); BYTE $0xA6
1133         CALL _strayintr(SB); BYTE $0xA7
1134         CALL _strayintr(SB); BYTE $0xA8
1135         CALL _strayintr(SB); BYTE $0xA9
1136         CALL _strayintr(SB); BYTE $0xAA
1137         CALL _strayintr(SB); BYTE $0xAB
1138         CALL _strayintr(SB); BYTE $0xAC
1139         CALL _strayintr(SB); BYTE $0xAD
1140         CALL _strayintr(SB); BYTE $0xAE
1141         CALL _strayintr(SB); BYTE $0xAF
1142         CALL _strayintr(SB); BYTE $0xB0
1143         CALL _strayintr(SB); BYTE $0xB1
1144         CALL _strayintr(SB); BYTE $0xB2
1145         CALL _strayintr(SB); BYTE $0xB3
1146         CALL _strayintr(SB); BYTE $0xB4
1147         CALL _strayintr(SB); BYTE $0xB5
1148         CALL _strayintr(SB); BYTE $0xB6
1149         CALL _strayintr(SB); BYTE $0xB7
1150         CALL _strayintr(SB); BYTE $0xB8
1151         CALL _strayintr(SB); BYTE $0xB9
1152         CALL _strayintr(SB); BYTE $0xBA
1153         CALL _strayintr(SB); BYTE $0xBB
1154         CALL _strayintr(SB); BYTE $0xBC
1155         CALL _strayintr(SB); BYTE $0xBD
1156         CALL _strayintr(SB); BYTE $0xBE
1157         CALL _strayintr(SB); BYTE $0xBF
1158         CALL _strayintr(SB); BYTE $0xC0
1159         CALL _strayintr(SB); BYTE $0xC1
1160         CALL _strayintr(SB); BYTE $0xC2
1161         CALL _strayintr(SB); BYTE $0xC3
1162         CALL _strayintr(SB); BYTE $0xC4
1163         CALL _strayintr(SB); BYTE $0xC5
1164         CALL _strayintr(SB); BYTE $0xC6
1165         CALL _strayintr(SB); BYTE $0xC7
1166         CALL _strayintr(SB); BYTE $0xC8
1167         CALL _strayintr(SB); BYTE $0xC9
1168         CALL _strayintr(SB); BYTE $0xCA
1169         CALL _strayintr(SB); BYTE $0xCB
1170         CALL _strayintr(SB); BYTE $0xCC
1171         CALL _strayintr(SB); BYTE $0xCD
1172         CALL _strayintr(SB); BYTE $0xCE
1173         CALL _strayintr(SB); BYTE $0xCF
1174         CALL _strayintr(SB); BYTE $0xD0
1175         CALL _strayintr(SB); BYTE $0xD1
1176         CALL _strayintr(SB); BYTE $0xD2
1177         CALL _strayintr(SB); BYTE $0xD3
1178         CALL _strayintr(SB); BYTE $0xD4
1179         CALL _strayintr(SB); BYTE $0xD5
1180         CALL _strayintr(SB); BYTE $0xD6
1181         CALL _strayintr(SB); BYTE $0xD7
1182         CALL _strayintr(SB); BYTE $0xD8
1183         CALL _strayintr(SB); BYTE $0xD9
1184         CALL _strayintr(SB); BYTE $0xDA
1185         CALL _strayintr(SB); BYTE $0xDB
1186         CALL _strayintr(SB); BYTE $0xDC
1187         CALL _strayintr(SB); BYTE $0xDD
1188         CALL _strayintr(SB); BYTE $0xDE
1189         CALL _strayintr(SB); BYTE $0xDF
1190         CALL _strayintr(SB); BYTE $0xE0
1191         CALL _strayintr(SB); BYTE $0xE1
1192         CALL _strayintr(SB); BYTE $0xE2
1193         CALL _strayintr(SB); BYTE $0xE3
1194         CALL _strayintr(SB); BYTE $0xE4
1195         CALL _strayintr(SB); BYTE $0xE5
1196         CALL _strayintr(SB); BYTE $0xE6
1197         CALL _strayintr(SB); BYTE $0xE7
1198         CALL _strayintr(SB); BYTE $0xE8
1199         CALL _strayintr(SB); BYTE $0xE9
1200         CALL _strayintr(SB); BYTE $0xEA
1201         CALL _strayintr(SB); BYTE $0xEB
1202         CALL _strayintr(SB); BYTE $0xEC
1203         CALL _strayintr(SB); BYTE $0xED
1204         CALL _strayintr(SB); BYTE $0xEE
1205         CALL _strayintr(SB); BYTE $0xEF
1206         CALL _strayintr(SB); BYTE $0xF0
1207         CALL _strayintr(SB); BYTE $0xF1
1208         CALL _strayintr(SB); BYTE $0xF2
1209         CALL _strayintr(SB); BYTE $0xF3
1210         CALL _strayintr(SB); BYTE $0xF4
1211         CALL _strayintr(SB); BYTE $0xF5
1212         CALL _strayintr(SB); BYTE $0xF6
1213         CALL _strayintr(SB); BYTE $0xF7
1214         CALL _strayintr(SB); BYTE $0xF8
1215         CALL _strayintr(SB); BYTE $0xF9
1216         CALL _strayintr(SB); BYTE $0xFA
1217         CALL _strayintr(SB); BYTE $0xFB
1218         CALL _strayintr(SB); BYTE $0xFC
1219         CALL _strayintr(SB); BYTE $0xFD
1220         CALL _strayintr(SB); BYTE $0xFE
1221         CALL _strayintr(SB); BYTE $0xFF