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