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