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