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