]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/l.s
multiboot: use initrd for config
[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    index+0(FP), CX
542         RDMSR
543         MOVL    vlong+4(FP), CX                 /* &vlong */
544         MOVL    AX, 0(CX)                       /* lo */
545         MOVL    DX, 4(CX)                       /* hi */
546         RET
547
548 TEXT tryrdmsr(SB), $0                           /* model-specific register */
549         MOVL    $0, BP
550         MOVL    index+0(FP), CX
551 TEXT _tryrdmsrinst(SB), $0
552         RDMSR
553         MOVL    vlong+4(FP), CX                 /* &vlong */
554         MOVL    AX, 0(CX)                       /* lo */
555         MOVL    DX, 4(CX)                       /* hi */
556         MOVL    BP, AX
557         RET
558         
559 TEXT wrmsr(SB), $0
560         MOVL    index+0(FP), CX
561         MOVL    lo+4(FP), AX
562         MOVL    hi+8(FP), DX
563         WRMSR
564         RET
565
566 TEXT trywrmsr(SB), $0
567         MOVL    $0, BP
568         MOVL    index+0(FP), CX
569         MOVL    lo+4(FP), AX
570         MOVL    hi+8(FP), DX
571 TEXT _trywrmsrinst(SB), $0
572         WRMSR
573         MOVL    BP, AX
574         RET
575
576 /*
577  * Try to determine the CPU type which requires fiddling with EFLAGS.
578  * If the Id bit can be toggled then the CPUID instruction can be used
579  * to determine CPU identity and features. First have to check if it's
580  * a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be
581  * toggled then it's an older 486 of some kind.
582  *
583  *      cpuid(fun, regs[4]);
584  */
585 TEXT cpuid(SB), $0
586         MOVL    $0x240000, AX
587         PUSHL   AX
588         POPFL                                   /* set Id|Ac */
589         PUSHFL
590         POPL    BX                              /* retrieve value */
591         MOVL    $0, AX
592         PUSHL   AX
593         POPFL                                   /* clear Id|Ac, EFLAGS initialised */
594         PUSHFL
595         POPL    AX                              /* retrieve value */
596         XORL    BX, AX
597         TESTL   $0x040000, AX                   /* Ac */
598         JZ      _cpu386                         /* can't set this bit on 386 */
599         TESTL   $0x200000, AX                   /* Id */
600         JZ      _cpu486                         /* can't toggle this bit on some 486 */
601         MOVL    fn+0(FP), AX
602         CPUID
603         JMP     _cpuid
604 _cpu486:
605         MOVL    $0x400, AX
606         JMP     _maybezapax
607 _cpu386:
608         MOVL    $0x300, AX
609 _maybezapax:
610         CMPL    fn+0(FP), $1
611         JE      _zaprest
612         XORL    AX, AX
613 _zaprest:
614         XORL    BX, BX
615         XORL    CX, CX
616         XORL    DX, DX
617 _cpuid:
618         MOVL    regs+4(FP), BP
619         MOVL    AX, 0(BP)
620         MOVL    BX, 4(BP)
621         MOVL    CX, 8(BP)
622         MOVL    DX, 12(BP)
623         RET
624
625 /*
626  * Basic timing loop to determine CPU frequency.
627  */
628 TEXT aamloop(SB), $0
629         MOVL    count+0(FP), CX
630 _aamloop:
631         AAM
632         LOOP    _aamloop
633         RET
634
635 /*
636  * Floating point.
637  * Note: the encodings for the FCLEX, FINIT, FSAVE, FSTCW, FSENV and FSTSW
638  * instructions do NOT have the WAIT prefix byte (i.e. they act like their
639  * FNxxx variations) so WAIT instructions must be explicitly placed in the
640  * code as necessary.
641  */
642 #define FPOFF(l)                                                 ;\
643         MOVL    CR0, AX                                          ;\
644         ANDL    $0xC, AX                        /* EM, TS */     ;\
645         CMPL    AX, $0x8                                         ;\
646         JEQ     l                                                ;\
647         WAIT                                                     ;\
648 l:                                                               ;\
649         MOVL    CR0, AX                                          ;\
650         ANDL    $~0x4, AX                       /* EM=0 */       ;\
651         ORL     $0x28, AX                       /* NE=1, TS=1 */ ;\
652         MOVL    AX, CR0
653
654 #define FPON                                                     ;\
655         MOVL    CR0, AX                                          ;\
656         ANDL    $~0xC, AX                       /* EM=0, TS=0 */ ;\
657         MOVL    AX, CR0
658         
659 TEXT fpoff(SB), $0                              /* disable */
660         FPOFF(l1)
661         RET
662
663 TEXT fpinit(SB), $0                             /* enable and init */
664         FPON
665         FINIT
666         WAIT
667         /* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */
668         /* note that low 6 bits are masks, not enables, on this chip */
669         PUSHW   $0x0232
670         FLDCW   0(SP)
671         POPW    AX
672         WAIT
673         RET
674
675 TEXT fpsave(SB), $0                             /* save state and disable */
676         MOVL    p+0(FP), AX
677         FSAVE   0(AX)                           /* no WAIT */
678         FPOFF(l2)
679         RET
680
681 TEXT fprestore(SB), $0                          /* enable and restore state */
682         FPON
683         MOVL    p+0(FP), AX
684         FRSTOR  0(AX)
685         WAIT
686         RET
687
688 TEXT fpstatus(SB), $0                           /* get floating point status */
689         FSTSW   AX
690         RET
691
692 TEXT fpenv(SB), $0                              /* save state without waiting */
693         MOVL    p+0(FP), AX
694         FSTENV  0(AX)
695         RET
696
697 TEXT fpclear(SB), $0                            /* clear pending exceptions */
698         FPON
699         FCLEX                                   /* no WAIT */
700         FPOFF(l3)
701         RET
702
703 /*
704  */
705 TEXT splhi(SB), $0
706 shi:
707         PUSHFL
708         POPL    AX
709         TESTL   $0x200, AX
710         JZ      alreadyhi
711         MOVL    $(MACHADDR+0x04), CX            /* save PC in m->splpc */
712         MOVL    (SP), BX
713         MOVL    BX, (CX)
714 alreadyhi:
715         CLI
716         RET
717
718 TEXT spllo(SB), $0
719 slo:
720         PUSHFL
721         POPL    AX
722         TESTL   $0x200, AX
723         JNZ     alreadylo
724         MOVL    $(MACHADDR+0x04), CX            /* clear m->splpc */
725         MOVL    $0, (CX)
726 alreadylo:
727         STI
728         RET
729
730 TEXT splx(SB), $0
731         MOVL    s+0(FP), AX
732         TESTL   $0x200, AX
733         JNZ     slo
734         JMP     shi
735
736 TEXT spldone(SB), $0
737         RET
738
739 TEXT islo(SB), $0
740         PUSHFL
741         POPL    AX
742         ANDL    $0x200, AX                      /* interrupt enable flag */
743         RET
744
745 /*
746  * Test-And-Set
747  */
748 TEXT tas(SB), $0
749         MOVL    $0xDEADDEAD, AX
750         MOVL    lock+0(FP), BX
751         XCHGL   AX, (BX)                        /* lock->key */
752         RET
753
754 TEXT _xinc(SB), $0                              /* void _xinc(long*); */
755         MOVL    l+0(FP), AX
756         LOCK;   INCL 0(AX)
757         RET
758
759 TEXT _xdec(SB), $0                              /* long _xdec(long*); */
760         MOVL    l+0(FP), BX
761         XORL    AX, AX
762         LOCK;   DECL 0(BX)
763         JLT     _xdeclt
764         JGT     _xdecgt
765         RET
766 _xdecgt:
767         INCL    AX
768         RET
769 _xdeclt:
770         DECL    AX
771         RET
772
773 TEXT mb386(SB), $0
774         POPL    AX                              /* return PC */
775         PUSHFL
776         PUSHL   CS
777         PUSHL   AX
778         IRETL
779
780 TEXT mb586(SB), $0
781         XORL    AX, AX
782         CPUID
783         RET
784
785 TEXT sfence(SB), $0
786         BYTE $0x0f
787         BYTE $0xae
788         BYTE $0xf8
789         RET
790
791 TEXT lfence(SB), $0
792         BYTE $0x0f
793         BYTE $0xae
794         BYTE $0xe8
795         RET
796
797 TEXT mfence(SB), $0
798         BYTE $0x0f
799         BYTE $0xae
800         BYTE $0xf0
801         RET
802
803 TEXT xchgw(SB), $0
804         MOVL    v+4(FP), AX
805         MOVL    p+0(FP), BX
806         XCHGW   AX, (BX)
807         RET
808
809 TEXT cmpswap486(SB), $0
810         MOVL    addr+0(FP), BX
811         MOVL    old+4(FP), AX
812         MOVL    new+8(FP), CX
813         LOCK
814         BYTE $0x0F; BYTE $0xB1; BYTE $0x0B      /* CMPXCHGL CX, (BX) */
815         JNZ didnt
816         MOVL    $1, AX
817         RET
818 didnt:
819         XORL    AX,AX
820         RET
821
822 TEXT mul64fract(SB), $0
823 /*
824  * Multiply two 64-bit number s and keep the middle 64 bits from the 128-bit result
825  * See ../port/tod.c for motivation.
826  */
827         MOVL    r+0(FP), CX
828         XORL    BX, BX                          /* BX = 0 */
829
830         MOVL    a+8(FP), AX
831         MULL    b+16(FP)                        /* a1*b1 */
832         MOVL    AX, 4(CX)                       /* r2 = lo(a1*b1) */
833
834         MOVL    a+8(FP), AX
835         MULL    b+12(FP)                        /* a1*b0 */
836         MOVL    AX, 0(CX)                       /* r1 = lo(a1*b0) */
837         ADDL    DX, 4(CX)                       /* r2 += hi(a1*b0) */
838
839         MOVL    a+4(FP), AX
840         MULL    b+16(FP)                        /* a0*b1 */
841         ADDL    AX, 0(CX)                       /* r1 += lo(a0*b1) */
842         ADCL    DX, 4(CX)                       /* r2 += hi(a0*b1) + carry */
843
844         MOVL    a+4(FP), AX
845         MULL    b+12(FP)                        /* a0*b0 */
846         ADDL    DX, 0(CX)                       /* r1 += hi(a0*b0) */
847         ADCL    BX, 4(CX)                       /* r2 += carry */
848         RET
849
850 /*
851  *  label consists of a stack pointer and a PC
852  */
853 TEXT gotolabel(SB), $0
854         MOVL    label+0(FP), AX
855         MOVL    0(AX), SP                       /* restore sp */
856         MOVL    4(AX), AX                       /* put return pc on the stack */
857         MOVL    AX, 0(SP)
858         MOVL    $1, AX                          /* return 1 */
859         RET
860
861 TEXT setlabel(SB), $0
862         MOVL    label+0(FP), AX
863         MOVL    SP, 0(AX)                       /* store sp */
864         MOVL    0(SP), BX                       /* store return pc */
865         MOVL    BX, 4(AX)
866         MOVL    $0, AX                          /* return 0 */
867         RET
868
869 /*
870  * Attempt at power saving. -rsc
871  */
872 TEXT halt(SB), $0
873         CLI
874         CMPL    nrdy(SB), $0
875         JEQ     _nothingready
876         STI
877         RET
878
879 _nothingready:
880         STI
881         HLT
882         RET
883
884 TEXT mwait(SB), $0
885         MOVL    addr+0(FP), AX
886         MOVL    (AX), CX
887         ORL     CX, CX
888         JNZ     _mwaitdone
889         XORL    DX, DX
890         BYTE $0x0f; BYTE $0x01; BYTE $0xc8      /* MONITOR */
891         MOVL    (AX), CX
892         ORL     CX, CX
893         JNZ     _mwaitdone
894         XORL    AX, AX
895         BYTE $0x0f; BYTE $0x01; BYTE $0xc9      /* MWAIT */
896 _mwaitdone:
897         RET
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 TEXT vectortable(SB), $0
949         CALL _strayintr(SB); BYTE $0x00         /* divide error */
950         CALL _strayintr(SB); BYTE $0x01         /* debug exception */
951         CALL _strayintr(SB); BYTE $0x02         /* NMI interrupt */
952         CALL _strayintr(SB); BYTE $0x03         /* breakpoint */
953         CALL _strayintr(SB); BYTE $0x04         /* overflow */
954         CALL _strayintr(SB); BYTE $0x05         /* bound */
955         CALL _strayintr(SB); BYTE $0x06         /* invalid opcode */
956         CALL _strayintr(SB); BYTE $0x07         /* no coprocessor available */
957         CALL _strayintrx(SB); BYTE $0x08        /* double fault */
958         CALL _strayintr(SB); BYTE $0x09         /* coprocessor segment overflow */
959         CALL _strayintrx(SB); BYTE $0x0A        /* invalid TSS */
960         CALL _strayintrx(SB); BYTE $0x0B        /* segment not available */
961         CALL _strayintrx(SB); BYTE $0x0C        /* stack exception */
962         CALL _strayintrx(SB); BYTE $0x0D        /* general protection error */
963         CALL _strayintrx(SB); BYTE $0x0E        /* page fault */
964         CALL _strayintr(SB); BYTE $0x0F         /*  */
965         CALL _strayintr(SB); BYTE $0x10         /* coprocessor error */
966         CALL _strayintrx(SB); BYTE $0x11        /* alignment check */
967         CALL _strayintr(SB); BYTE $0x12         /* machine check */
968         CALL _strayintr(SB); BYTE $0x13
969         CALL _strayintr(SB); BYTE $0x14
970         CALL _strayintr(SB); BYTE $0x15
971         CALL _strayintr(SB); BYTE $0x16
972         CALL _strayintr(SB); BYTE $0x17
973         CALL _strayintr(SB); BYTE $0x18
974         CALL _strayintr(SB); BYTE $0x19
975         CALL _strayintr(SB); BYTE $0x1A
976         CALL _strayintr(SB); BYTE $0x1B
977         CALL _strayintr(SB); BYTE $0x1C
978         CALL _strayintr(SB); BYTE $0x1D
979         CALL _strayintr(SB); BYTE $0x1E
980         CALL _strayintr(SB); BYTE $0x1F
981         CALL _strayintr(SB); BYTE $0x20         /* VectorLAPIC */
982         CALL _strayintr(SB); BYTE $0x21
983         CALL _strayintr(SB); BYTE $0x22
984         CALL _strayintr(SB); BYTE $0x23
985         CALL _strayintr(SB); BYTE $0x24
986         CALL _strayintr(SB); BYTE $0x25
987         CALL _strayintr(SB); BYTE $0x26
988         CALL _strayintr(SB); BYTE $0x27
989         CALL _strayintr(SB); BYTE $0x28
990         CALL _strayintr(SB); BYTE $0x29
991         CALL _strayintr(SB); BYTE $0x2A
992         CALL _strayintr(SB); BYTE $0x2B
993         CALL _strayintr(SB); BYTE $0x2C
994         CALL _strayintr(SB); BYTE $0x2D
995         CALL _strayintr(SB); BYTE $0x2E
996         CALL _strayintr(SB); BYTE $0x2F
997         CALL _strayintr(SB); BYTE $0x30
998         CALL _strayintr(SB); BYTE $0x31
999         CALL _strayintr(SB); BYTE $0x32
1000         CALL _strayintr(SB); BYTE $0x33
1001         CALL _strayintr(SB); BYTE $0x34
1002         CALL _strayintr(SB); BYTE $0x35
1003         CALL _strayintr(SB); BYTE $0x36
1004         CALL _strayintr(SB); BYTE $0x37
1005         CALL _strayintr(SB); BYTE $0x38
1006         CALL _strayintr(SB); BYTE $0x39
1007         CALL _strayintr(SB); BYTE $0x3A
1008         CALL _strayintr(SB); BYTE $0x3B
1009         CALL _strayintr(SB); BYTE $0x3C
1010         CALL _strayintr(SB); BYTE $0x3D
1011         CALL _strayintr(SB); BYTE $0x3E
1012         CALL _strayintr(SB); BYTE $0x3F
1013         CALL _syscallintr(SB); BYTE $0x40       /* VectorSYSCALL */
1014         CALL _strayintr(SB); BYTE $0x41
1015         CALL _strayintr(SB); BYTE $0x42
1016         CALL _strayintr(SB); BYTE $0x43
1017         CALL _strayintr(SB); BYTE $0x44
1018         CALL _strayintr(SB); BYTE $0x45
1019         CALL _strayintr(SB); BYTE $0x46
1020         CALL _strayintr(SB); BYTE $0x47
1021         CALL _strayintr(SB); BYTE $0x48
1022         CALL _strayintr(SB); BYTE $0x49
1023         CALL _strayintr(SB); BYTE $0x4A
1024         CALL _strayintr(SB); BYTE $0x4B
1025         CALL _strayintr(SB); BYTE $0x4C
1026         CALL _strayintr(SB); BYTE $0x4D
1027         CALL _strayintr(SB); BYTE $0x4E
1028         CALL _strayintr(SB); BYTE $0x4F
1029         CALL _strayintr(SB); BYTE $0x50
1030         CALL _strayintr(SB); BYTE $0x51
1031         CALL _strayintr(SB); BYTE $0x52
1032         CALL _strayintr(SB); BYTE $0x53
1033         CALL _strayintr(SB); BYTE $0x54
1034         CALL _strayintr(SB); BYTE $0x55
1035         CALL _strayintr(SB); BYTE $0x56
1036         CALL _strayintr(SB); BYTE $0x57
1037         CALL _strayintr(SB); BYTE $0x58
1038         CALL _strayintr(SB); BYTE $0x59
1039         CALL _strayintr(SB); BYTE $0x5A
1040         CALL _strayintr(SB); BYTE $0x5B
1041         CALL _strayintr(SB); BYTE $0x5C
1042         CALL _strayintr(SB); BYTE $0x5D
1043         CALL _strayintr(SB); BYTE $0x5E
1044         CALL _strayintr(SB); BYTE $0x5F
1045         CALL _strayintr(SB); BYTE $0x60
1046         CALL _strayintr(SB); BYTE $0x61
1047         CALL _strayintr(SB); BYTE $0x62
1048         CALL _strayintr(SB); BYTE $0x63
1049         CALL _strayintr(SB); BYTE $0x64
1050         CALL _strayintr(SB); BYTE $0x65
1051         CALL _strayintr(SB); BYTE $0x66
1052         CALL _strayintr(SB); BYTE $0x67
1053         CALL _strayintr(SB); BYTE $0x68
1054         CALL _strayintr(SB); BYTE $0x69
1055         CALL _strayintr(SB); BYTE $0x6A
1056         CALL _strayintr(SB); BYTE $0x6B
1057         CALL _strayintr(SB); BYTE $0x6C
1058         CALL _strayintr(SB); BYTE $0x6D
1059         CALL _strayintr(SB); BYTE $0x6E
1060         CALL _strayintr(SB); BYTE $0x6F
1061         CALL _strayintr(SB); BYTE $0x70
1062         CALL _strayintr(SB); BYTE $0x71
1063         CALL _strayintr(SB); BYTE $0x72
1064         CALL _strayintr(SB); BYTE $0x73
1065         CALL _strayintr(SB); BYTE $0x74
1066         CALL _strayintr(SB); BYTE $0x75
1067         CALL _strayintr(SB); BYTE $0x76
1068         CALL _strayintr(SB); BYTE $0x77
1069         CALL _strayintr(SB); BYTE $0x78
1070         CALL _strayintr(SB); BYTE $0x79
1071         CALL _strayintr(SB); BYTE $0x7A
1072         CALL _strayintr(SB); BYTE $0x7B
1073         CALL _strayintr(SB); BYTE $0x7C
1074         CALL _strayintr(SB); BYTE $0x7D
1075         CALL _strayintr(SB); BYTE $0x7E
1076         CALL _strayintr(SB); BYTE $0x7F
1077         CALL _strayintr(SB); BYTE $0x80         /* Vector[A]PIC */
1078         CALL _strayintr(SB); BYTE $0x81
1079         CALL _strayintr(SB); BYTE $0x82
1080         CALL _strayintr(SB); BYTE $0x83
1081         CALL _strayintr(SB); BYTE $0x84
1082         CALL _strayintr(SB); BYTE $0x85
1083         CALL _strayintr(SB); BYTE $0x86
1084         CALL _strayintr(SB); BYTE $0x87
1085         CALL _strayintr(SB); BYTE $0x88
1086         CALL _strayintr(SB); BYTE $0x89
1087         CALL _strayintr(SB); BYTE $0x8A
1088         CALL _strayintr(SB); BYTE $0x8B
1089         CALL _strayintr(SB); BYTE $0x8C
1090         CALL _strayintr(SB); BYTE $0x8D
1091         CALL _strayintr(SB); BYTE $0x8E
1092         CALL _strayintr(SB); BYTE $0x8F
1093         CALL _strayintr(SB); BYTE $0x90
1094         CALL _strayintr(SB); BYTE $0x91
1095         CALL _strayintr(SB); BYTE $0x92
1096         CALL _strayintr(SB); BYTE $0x93
1097         CALL _strayintr(SB); BYTE $0x94
1098         CALL _strayintr(SB); BYTE $0x95
1099         CALL _strayintr(SB); BYTE $0x96
1100         CALL _strayintr(SB); BYTE $0x97
1101         CALL _strayintr(SB); BYTE $0x98
1102         CALL _strayintr(SB); BYTE $0x99
1103         CALL _strayintr(SB); BYTE $0x9A
1104         CALL _strayintr(SB); BYTE $0x9B
1105         CALL _strayintr(SB); BYTE $0x9C
1106         CALL _strayintr(SB); BYTE $0x9D
1107         CALL _strayintr(SB); BYTE $0x9E
1108         CALL _strayintr(SB); BYTE $0x9F
1109         CALL _strayintr(SB); BYTE $0xA0
1110         CALL _strayintr(SB); BYTE $0xA1
1111         CALL _strayintr(SB); BYTE $0xA2
1112         CALL _strayintr(SB); BYTE $0xA3
1113         CALL _strayintr(SB); BYTE $0xA4
1114         CALL _strayintr(SB); BYTE $0xA5
1115         CALL _strayintr(SB); BYTE $0xA6
1116         CALL _strayintr(SB); BYTE $0xA7
1117         CALL _strayintr(SB); BYTE $0xA8
1118         CALL _strayintr(SB); BYTE $0xA9
1119         CALL _strayintr(SB); BYTE $0xAA
1120         CALL _strayintr(SB); BYTE $0xAB
1121         CALL _strayintr(SB); BYTE $0xAC
1122         CALL _strayintr(SB); BYTE $0xAD
1123         CALL _strayintr(SB); BYTE $0xAE
1124         CALL _strayintr(SB); BYTE $0xAF
1125         CALL _strayintr(SB); BYTE $0xB0
1126         CALL _strayintr(SB); BYTE $0xB1
1127         CALL _strayintr(SB); BYTE $0xB2
1128         CALL _strayintr(SB); BYTE $0xB3
1129         CALL _strayintr(SB); BYTE $0xB4
1130         CALL _strayintr(SB); BYTE $0xB5
1131         CALL _strayintr(SB); BYTE $0xB6
1132         CALL _strayintr(SB); BYTE $0xB7
1133         CALL _strayintr(SB); BYTE $0xB8
1134         CALL _strayintr(SB); BYTE $0xB9
1135         CALL _strayintr(SB); BYTE $0xBA
1136         CALL _strayintr(SB); BYTE $0xBB
1137         CALL _strayintr(SB); BYTE $0xBC
1138         CALL _strayintr(SB); BYTE $0xBD
1139         CALL _strayintr(SB); BYTE $0xBE
1140         CALL _strayintr(SB); BYTE $0xBF
1141         CALL _strayintr(SB); BYTE $0xC0
1142         CALL _strayintr(SB); BYTE $0xC1
1143         CALL _strayintr(SB); BYTE $0xC2
1144         CALL _strayintr(SB); BYTE $0xC3
1145         CALL _strayintr(SB); BYTE $0xC4
1146         CALL _strayintr(SB); BYTE $0xC5
1147         CALL _strayintr(SB); BYTE $0xC6
1148         CALL _strayintr(SB); BYTE $0xC7
1149         CALL _strayintr(SB); BYTE $0xC8
1150         CALL _strayintr(SB); BYTE $0xC9
1151         CALL _strayintr(SB); BYTE $0xCA
1152         CALL _strayintr(SB); BYTE $0xCB
1153         CALL _strayintr(SB); BYTE $0xCC
1154         CALL _strayintr(SB); BYTE $0xCD
1155         CALL _strayintr(SB); BYTE $0xCE
1156         CALL _strayintr(SB); BYTE $0xCF
1157         CALL _strayintr(SB); BYTE $0xD0
1158         CALL _strayintr(SB); BYTE $0xD1
1159         CALL _strayintr(SB); BYTE $0xD2
1160         CALL _strayintr(SB); BYTE $0xD3
1161         CALL _strayintr(SB); BYTE $0xD4
1162         CALL _strayintr(SB); BYTE $0xD5
1163         CALL _strayintr(SB); BYTE $0xD6
1164         CALL _strayintr(SB); BYTE $0xD7
1165         CALL _strayintr(SB); BYTE $0xD8
1166         CALL _strayintr(SB); BYTE $0xD9
1167         CALL _strayintr(SB); BYTE $0xDA
1168         CALL _strayintr(SB); BYTE $0xDB
1169         CALL _strayintr(SB); BYTE $0xDC
1170         CALL _strayintr(SB); BYTE $0xDD
1171         CALL _strayintr(SB); BYTE $0xDE
1172         CALL _strayintr(SB); BYTE $0xDF
1173         CALL _strayintr(SB); BYTE $0xE0
1174         CALL _strayintr(SB); BYTE $0xE1
1175         CALL _strayintr(SB); BYTE $0xE2
1176         CALL _strayintr(SB); BYTE $0xE3
1177         CALL _strayintr(SB); BYTE $0xE4
1178         CALL _strayintr(SB); BYTE $0xE5
1179         CALL _strayintr(SB); BYTE $0xE6
1180         CALL _strayintr(SB); BYTE $0xE7
1181         CALL _strayintr(SB); BYTE $0xE8
1182         CALL _strayintr(SB); BYTE $0xE9
1183         CALL _strayintr(SB); BYTE $0xEA
1184         CALL _strayintr(SB); BYTE $0xEB
1185         CALL _strayintr(SB); BYTE $0xEC
1186         CALL _strayintr(SB); BYTE $0xED
1187         CALL _strayintr(SB); BYTE $0xEE
1188         CALL _strayintr(SB); BYTE $0xEF
1189         CALL _strayintr(SB); BYTE $0xF0
1190         CALL _strayintr(SB); BYTE $0xF1
1191         CALL _strayintr(SB); BYTE $0xF2
1192         CALL _strayintr(SB); BYTE $0xF3
1193         CALL _strayintr(SB); BYTE $0xF4
1194         CALL _strayintr(SB); BYTE $0xF5
1195         CALL _strayintr(SB); BYTE $0xF6
1196         CALL _strayintr(SB); BYTE $0xF7
1197         CALL _strayintr(SB); BYTE $0xF8
1198         CALL _strayintr(SB); BYTE $0xF9
1199         CALL _strayintr(SB); BYTE $0xFA
1200         CALL _strayintr(SB); BYTE $0xFB
1201         CALL _strayintr(SB); BYTE $0xFC
1202         CALL _strayintr(SB); BYTE $0xFD
1203         CALL _strayintr(SB); BYTE $0xFE
1204         CALL _strayintr(SB); BYTE $0xFF