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