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