-
Notifications
You must be signed in to change notification settings - Fork 782
/
Copy pathlocore.s
2356 lines (1917 loc) · 50.6 KB
/
locore.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright 2011 Joyent, Inc. All rights reserved.
*/
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1987, 1988 Microsoft Corporation */
/* All Rights Reserved */
#include <sys/asm_linkage.h>
#include <sys/asm_misc.h>
#include <sys/regset.h>
#include <sys/privregs.h>
#include <sys/psw.h>
#include <sys/reboot.h>
#include <sys/x86_archext.h>
#include <sys/machparam.h>
#if defined(__lint)
#include <sys/types.h>
#include <sys/thread.h>
#include <sys/systm.h>
#include <sys/lgrp.h>
#include <sys/regset.h>
#include <sys/link.h>
#include <sys/bootconf.h>
#include <sys/bootsvcs.h>
#else /* __lint */
#include <sys/segments.h>
#include <sys/pcb.h>
#include <sys/trap.h>
#include <sys/ftrace.h>
#include <sys/traptrace.h>
#include <sys/clock.h>
#include <sys/cmn_err.h>
#include <sys/pit.h>
#include <sys/panic.h>
#if defined(__xpv)
#include <sys/hypervisor.h>
#endif
#include "assym.h"
/*
* Our assumptions:
* - We are running in protected-paged mode.
* - Interrupts are disabled.
* - The GDT and IDT are the callers; we need our copies.
* - The kernel's text, initialized data and bss are mapped.
*
* Our actions:
* - Save arguments
* - Initialize our stack pointer to the thread 0 stack (t0stack)
* and leave room for a phony "struct regs".
* - Our GDT and IDT need to get munged.
* - Since we are using the boot's GDT descriptors, we need
* to copy them into our GDT before we switch to ours.
* - We start using our GDT by loading correct values in the
* selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL,
* gs=KGS_SEL).
* - The default LDT entry for syscall is set.
* - We load the default LDT into the hardware LDT register.
* - We load the default TSS into the hardware task register.
* - Check for cpu type, i.e. 486 vs. P5 vs. P6 etc.
* - mlsetup(%esp) gets called.
* - We change our appearance to look like the real thread 0.
* (NOTE: making ourselves to be a real thread may be a noop)
* - main() gets called. (NOTE: main() never returns).
*
* NOW, the real code!
*/
/*
* The very first thing in the kernel's text segment must be a jump
* to the os/fakebop.c startup code.
*/
.text
jmp _start
/*
* Globals:
*/
.globl _locore_start
.globl mlsetup
.globl main
.globl panic
.globl t0stack
.globl t0
.globl sysp
.globl edata
/*
* call back into boot - sysp (bootsvcs.h) and bootops (bootconf.h)
*/
.globl bootops
.globl bootopsp
/*
* NOTE: t0stack should be the first thing in the data section so that
* if it ever overflows, it will fault on the last kernel text page.
*/
.data
.comm t0stack, DEFAULTSTKSZ, 32
.comm t0, 4094, 32
#endif /* __lint */
#if defined(__amd64)
#if defined(__lint)
/* ARGSUSED */
void
_locore_start(struct boot_syscalls *sysp, ulong_t rsi, struct bootops *bop)
{}
#else /* __lint */
/*
* kobj_init() vectors us back to here with (note) a slightly different
* set of arguments than _start is given (see lint prototypes above).
*
* XXX Make this less vile, please.
*/
ENTRY_NP(_locore_start)
/*
* %rdi = boot services (should die someday)
* %rdx = bootops
* end
*/
leaq edata(%rip), %rbp /* reference edata for ksyms */
movq $0, (%rbp) /* limit stack back trace */
/*
* Initialize our stack pointer to the thread 0 stack (t0stack)
* and leave room for a "struct regs" for lwp0. Note that the
* stack doesn't actually align to a 16-byte boundary until just
* before we call mlsetup because we want to use %rsp to point at
* our regs structure.
*/
leaq t0stack(%rip), %rsp
addq $_CONST(DEFAULTSTKSZ - REGSIZE), %rsp
#if (REGSIZE & 15) == 0
subq $8, %rsp
#endif
/*
* Save call back for special x86 boot services vector
*/
movq %rdi, sysp(%rip)
movq %rdx, bootops(%rip) /* save bootops */
movq $bootops, bootopsp(%rip)
/*
* Save arguments and flags, if only for debugging ..
*/
movq %rdi, REGOFF_RDI(%rsp)
movq %rsi, REGOFF_RSI(%rsp)
movq %rdx, REGOFF_RDX(%rsp)
movq %rcx, REGOFF_RCX(%rsp)
movq %r8, REGOFF_R8(%rsp)
movq %r9, REGOFF_R9(%rsp)
pushf
popq %r11
movq %r11, REGOFF_RFL(%rsp)
#if !defined(__xpv)
/*
* Enable write protect and alignment check faults.
*/
movq %cr0, %rax
orq $_CONST(CR0_WP|CR0_AM), %rax
andq $_BITNOT(CR0_WT|CR0_CE), %rax
movq %rax, %cr0
#endif /* __xpv */
/*
* (We just assert this works by virtue of being here)
*/
bts $X86FSET_CPUID, x86_featureset(%rip)
/*
* mlsetup() gets called with a struct regs as argument, while
* main takes no args and should never return.
*/
xorl %ebp, %ebp
movq %rsp, %rdi
pushq %rbp
/* (stack pointer now aligned on 16-byte boundary right here) */
movq %rsp, %rbp
call mlsetup
call main
/* NOTREACHED */
leaq __return_from_main(%rip), %rdi
xorl %eax, %eax
call panic
SET_SIZE(_locore_start)
#endif /* __amd64 */
#endif /* __lint */
#if !defined(__lint)
__return_from_main:
.string "main() returned"
__unsupported_cpu:
.string "486 style cpu detected - no longer supported!"
#endif /* !__lint */
#if !defined(__amd64)
#if defined(__lint)
/* ARGSUSED */
void
_locore_start(struct boot_syscalls *sysp, struct bootops *bop)
{}
#else /* __lint */
/*
* kobj_init() vectors us back to here with (note) a slightly different
* set of arguments than _start is given (see lint prototypes above).
*
* XXX Make this less vile, please.
*/
ENTRY_NP(_locore_start)
/*
* %ecx = boot services (should die someday)
* %ebx = bootops
*/
mov $edata, %ebp / edata needs to be defined for ksyms
movl $0, (%ebp) / limit stack back trace
/*
* Initialize our stack pointer to the thread 0 stack (t0stack)
* and leave room for a phony "struct regs".
*/
movl $t0stack + DEFAULTSTKSZ - REGSIZE, %esp
/*
* Save call back for special x86 boot services vector
*/
mov %ecx, sysp / save call back for boot services
mov %ebx, bootops / save bootops
movl $bootops, bootopsp
/*
* Save all registers and flags
*/
pushal
pushfl
#if !defined(__xpv)
/*
* Override bios settings and enable write protect and
* alignment check faults.
*/
movl %cr0, %eax
/*
* enable WP for detecting faults, and enable alignment checking.
*/
orl $_CONST(CR0_WP|CR0_AM), %eax
andl $_BITNOT(CR0_WT|CR0_CE), %eax
movl %eax, %cr0 / set the cr0 register correctly and
/ override the BIOS setup
/*
* If bit 21 of eflags can be flipped, then cpuid is present
* and enabled.
*/
pushfl
popl %ecx
movl %ecx, %eax
xorl $PS_ID, %eax / try complemented bit
pushl %eax
popfl
pushfl
popl %eax
cmpl %eax, %ecx
jne have_cpuid
/*
* cpuid may be disabled on Cyrix, try to detect Cyrix by the 5/2 test
* div does not modify the cc flags on Cyrix, even though this may
* also be true for other vendors, this is generally true only for
* newer models from those vendors that support and do not disable
* cpuid (usually because cpuid cannot be disabled)
*/
/*
* clear cc flags
*/
xorb %ah, %ah
sahf
/*
* perform 5/2 test
*/
movw $5, %ax
movb $2, %bl
divb %bl
lahf
cmpb $2, %ah
jne cpu_486
/*
* div did not modify the cc flags, chances are the vendor is Cyrix
* assume the vendor is Cyrix and use the CCR's to enable cpuid
*/
.set CYRIX_CRI, 0x22 / CR Index Register
.set CYRIX_CRD, 0x23 / CR Data Register
.set CYRIX_CCR3, 0xc3 / Config Control Reg 3
.set CYRIX_CCR4, 0xe8 / Config Control Reg 4
.set CYRIX_DIR0, 0xfe / Device Identification Reg 0
.set CYRIX_DIR1, 0xff / Device Identification Reg 1
/*
* even if the cpu vendor is Cyrix and the motherboard/chipset
* vendor decided to ignore lines A1-A4 for I/O addresses, I/O port
* 0x21 corresponds with 0x23 and since 0x22 is still untouched,
* the reads and writes of 0x21 are guaranteed to be off-chip of
* the cpu
*/
/*
* enable read of ISR at I/O port 0x20
*/
movb $0xb, %al
outb $MCMD_PORT
/*
* read IMR and store in %bl
*/
inb $MIMR_PORT
movb %al, %bl
/*
* mask out all interrupts so that ISR will not change
*/
movb $0xff, %al
outb $MIMR_PORT
/*
* reads of I/O port 0x22 on Cyrix are always directed off-chip
* make use of I/O pull-up to test for an unknown device on 0x22
*/
inb $CYRIX_CRI
cmpb $0xff, %al
je port_22_free
/*
* motherboard/chipset vendor may be ignoring line A1 of I/O address
*/
movb %al, %cl
/*
* if the ISR and the value read from 0x22 do not match then we have
* detected some unknown device, probably a chipset, at 0x22
*/
inb $MCMD_PORT
cmpb %al, %cl
jne restore_IMR
port_22_free:
/*
* now test to see if some unknown device is using I/O port 0x23
*
* read the external I/O port at 0x23
*/
inb $CYRIX_CRD
/*
* Test for pull-up at 0x23 or if I/O address line A1 is being ignored.
* IMR is 0xff so both tests are performed simultaneously.
*/
cmpb $0xff, %al
jne restore_IMR
/*
* We are a Cyrix part. In case we are some model of Cx486 or a Cx586,
* record the type and fix it later if not.
*/
movl $X86_VENDOR_Cyrix, x86_vendor
movl $X86_TYPE_CYRIX_486, x86_type
/*
* Try to read CCR3. All Cyrix cpu's which support cpuid have CCR3.
*
* load CCR3 index into CCR index register
*/
movb $CYRIX_CCR3, %al
outb $CYRIX_CRI
/*
* If we are not a Cyrix cpu, then we have performed an external I/O
* cycle. If the CCR index was not valid for this Cyrix model, we may
* have performed an external I/O cycle as well. In these cases and
* if the motherboard/chipset vendor ignores I/O address line A1,
* then the PIC will have IRQ3 set at the lowest priority as a side
* effect of the above outb. We are reasonalbly confident that there
* is not an unknown device on I/O port 0x22, so there should have been
* no unpredictable side-effect of the above outb.
*/
/*
* read CCR3
*/
inb $CYRIX_CRD
/*
* If we are not a Cyrix cpu the inb above produced an external I/O
* cycle. If we are a Cyrix model that does not support CCR3 wex
* produced an external I/O cycle. In all known Cyrix models 6x86 and
* above, bit 3 of CCR3 is reserved and cannot be set to 1. In all
* Cyrix models prior to the 6x86 that supported CCR3, bits 4-7 are
* reserved as well. It is highly unlikely that CCR3 contains the value
* 0xff. We test to see if I/O port 0x23 is pull-up or the IMR and
* deduce we are not a Cyrix with support for cpuid if so.
*/
cmpb $0xff, %al
je restore_PIC
/*
* There exist 486 ISA Cyrix chips that support CCR3 but do not support
* DIR0 and DIR1. If we try to read DIR0, we may generate external I/O
* cycles, the exact behavior is model specific and undocumented.
* Unfortunately these external I/O cycles may confuse some PIC's beyond
* recovery. Fortunatetly we can use the following undocumented trick:
* if bit 4 of CCR3 can be toggled, then DIR0 and DIR1 are supported.
* Pleasantly MAPEN contains bit 4 of CCR3, so this trick is guaranteed
* to work on all Cyrix cpu's which support cpuid.
*/
movb %al, %dl
xorb $0x10, %dl
movb %al, %cl
/*
* write back CRR3 with toggled bit 4 to CCR3
*/
movb $CYRIX_CCR3, %al
outb $CYRIX_CRI
movb %dl, %al
outb $CYRIX_CRD
/*
* read CCR3
*/
movb $CYRIX_CCR3, %al
outb $CYRIX_CRI
inb $CYRIX_CRD
movb %al, %dl
/*
* restore CCR3
*/
movb $CYRIX_CCR3, %al
outb $CYRIX_CRI
movb %cl, %al
outb $CYRIX_CRD
/*
* if bit 4 was not toggled DIR0 and DIR1 are not supported in which
* case we do not have cpuid anyway
*/
andb $0x10, %al
andb $0x10, %dl
cmpb %al, %dl
je restore_PIC
/*
* read DIR0
*/
movb $CYRIX_DIR0, %al
outb $CYRIX_CRI
inb $CYRIX_CRD
/*
* test for pull-up
*/
cmpb $0xff, %al
je restore_PIC
/*
* Values of 0x20-0x27 in DIR0 are currently reserved by Cyrix for
* future use. If Cyrix ever produces a cpu that supports cpuid with
* these ids, the following test will have to change. For now we remain
* pessimistic since the formats of the CRR's may be different then.
*
* test for at least a 6x86, to see if we support both MAPEN and CPUID
*/
cmpb $0x30, %al
jb restore_IMR
/*
* enable MAPEN
*/
movb $CYRIX_CCR3, %al
outb $CYRIX_CRI
andb $0xf, %cl
movb %cl, %al
orb $0x10, %al
outb $CYRIX_CRD
/*
* select CCR4
*/
movb $CYRIX_CCR4, %al
outb $CYRIX_CRI
/*
* read CCR4
*/
inb $CYRIX_CRD
/*
* enable cpuid
*/
orb $0x80, %al
movb %al, %dl
/*
* select CCR4
*/
movb $CYRIX_CCR4, %al
outb $CYRIX_CRI
/*
* write CCR4
*/
movb %dl, %al
outb $CYRIX_CRD
/*
* select CCR3
*/
movb $CYRIX_CCR3, %al
outb $CYRIX_CRI
/*
* disable MAPEN and write CCR3
*/
movb %cl, %al
outb $CYRIX_CRD
/*
* restore IMR
*/
movb %bl, %al
outb $MIMR_PORT
/*
* test to see if cpuid available
*/
pushfl
popl %ecx
movl %ecx, %eax
xorl $PS_ID, %eax / try complemented bit
pushl %eax
popfl
pushfl
popl %eax
cmpl %eax, %ecx
jne have_cpuid
jmp cpu_486
restore_PIC:
/*
* In case the motherboard/chipset vendor is ignoring line A1 of the
* I/O address, we set the PIC priorities to sane values.
*/
movb $0xc7, %al / irq 7 lowest priority
outb $MCMD_PORT
restore_IMR:
movb %bl, %al
outb $MIMR_PORT
jmp cpu_486
have_cpuid:
/*
* cpuid instruction present
*/
bts $X86FSET_CPUID, x86_featureset / Just to set; Ignore the CF
movl $0, %eax
cpuid
movl %ebx, cpu_vendor
movl %edx, cpu_vendor+4
movl %ecx, cpu_vendor+8
/*
* early cyrix cpus are somewhat strange and need to be
* probed in curious ways to determine their identity
*/
leal cpu_vendor, %esi
leal CyrixInstead, %edi
movl $12, %ecx
repz
cmpsb
je vendor_is_cyrix
/ let mlsetup()/cpuid_pass1() handle everything else in C
jmp cpu_done
is486:
/*
* test to see if a useful cpuid
*/
testl %eax, %eax
jz isa486
movl $1, %eax
cpuid
movl %eax, %ebx
andl $0xF00, %ebx
cmpl $0x400, %ebx
je isa486
rep; ret /* use 2 byte return instruction */
/* AMD Software Optimization Guide - Section 6.2 */
isa486:
/*
* lose the return address
*/
popl %eax
jmp cpu_486
vendor_is_cyrix:
call is486
/*
* Processor signature and feature flags for Cyrix are insane.
* BIOS can play with semi-documented registers, so cpuid must be used
* cautiously. Since we are Cyrix that has cpuid, we have DIR0 and DIR1
* Keep the family in %ebx and feature flags in %edx until not needed
*/
/*
* read DIR0
*/
movb $CYRIX_DIR0, %al
outb $CYRIX_CRI
inb $CYRIX_CRD
/*
* First we handle the cases where we are a 6x86 or 6x86L.
* The 6x86 is basically a 486, the only reliable bit in the
* feature flags is for FPU. The 6x86L is better, unfortunately
* there is no really good way to distinguish between these two
* cpu's. We are pessimistic and when in doubt assume 6x86.
*/
cmpb $0x40, %al
jae maybeGX
/*
* We are an M1, either a 6x86 or 6x86L.
*/
cmpb $0x30, %al
je maybe6x86L
cmpb $0x31, %al
je maybe6x86L
cmpb $0x34, %al
je maybe6x86L
cmpb $0x35, %al
je maybe6x86L
/*
* although it is possible that we are a 6x86L, the cpu and
* documentation are so buggy, we just do not care.
*/
jmp likely6x86
maybe6x86L:
/*
* read DIR1
*/
movb $CYRIX_DIR1, %al
outb $CYRIX_CRI
inb $CYRIX_CRD
cmpb $0x22, %al
jb likely6x86
/*
* We are a 6x86L, or at least a 6x86 with honest cpuid feature flags
*/
movl $X86_TYPE_CYRIX_6x86L, x86_type
jmp coma_bug
likely6x86:
/*
* We are likely a 6x86, or a 6x86L without a way of knowing
*
* The 6x86 has NO Pentium or Pentium Pro compatible features even
* though it claims to be a Pentium Pro compatible!
*
* The 6x86 core used in the 6x86 may have most of the Pentium system
* registers and largely conform to the Pentium System Programming
* Reference. Documentation on these parts is long gone. Treat it as
* a crippled Pentium and hope for the best.
*/
movl $X86_TYPE_CYRIX_6x86, x86_type
jmp coma_bug
maybeGX:
/*
* Now we check whether we are a MediaGX or GXm. We have particular
* reason for concern here. Even though most of the GXm's
* report having TSC in the cpuid feature flags, the TSC may be
* horribly broken. What is worse, is that MediaGX's are basically
* 486's while the good GXm's are more like Pentium Pro's!
*/
cmpb $0x50, %al
jae maybeM2
/*
* We are either a MediaGX (sometimes called a Gx86) or GXm
*/
cmpb $41, %al
je maybeMediaGX
cmpb $44, %al
jb maybeGXm
cmpb $47, %al
jbe maybeMediaGX
/*
* We do not honestly know what we are, so assume a MediaGX
*/
jmp media_gx
maybeGXm:
/*
* It is still possible we are either a MediaGX or GXm, trust cpuid
* family should be 5 on a GXm
*/
cmpl $0x500, %ebx
je GXm
/*
* BIOS/Cyrix might set family to 6 on a GXm
*/
cmpl $0x600, %ebx
jne media_gx
GXm:
movl $X86_TYPE_CYRIX_GXm, x86_type
jmp cpu_done
maybeMediaGX:
/*
* read DIR1
*/
movb $CYRIX_DIR1, %al
outb $CYRIX_CRI
inb $CYRIX_CRD
cmpb $0x30, %al
jae maybeGXm
/*
* we are a MediaGX for which we do not trust cpuid
*/
media_gx:
movl $X86_TYPE_CYRIX_MediaGX, x86_type
jmp cpu_486
maybeM2:
/*
* Now we check whether we are a 6x86MX or MII. These cpu's are
* virtually identical, but we care because for the 6x86MX, we
* must work around the coma bug. Also for 6x86MX prior to revision
* 1.4, the TSC may have serious bugs.
*/
cmpb $0x60, %al
jae maybeM3
/*
* family should be 6, but BIOS/Cyrix might set it to 5
*/
cmpl $0x600, %ebx
ja cpu_486
/*
* read DIR1
*/
movb $CYRIX_DIR1, %al
outb $CYRIX_CRI
inb $CYRIX_CRD
cmpb $0x8, %al
jb cyrix6x86MX
cmpb $0x80, %al
jb MII
cyrix6x86MX:
/*
* It is altogether unclear how the revision stamped on the cpu
* maps to the values in DIR0 and DIR1. Just assume TSC is broken.
*/
movl $X86_TYPE_CYRIX_6x86MX, x86_type
jmp coma_bug
MII:
movl $X86_TYPE_CYRIX_MII, x86_type
likeMII:
jmp cpu_done
maybeM3:
/*
* We are some chip that we cannot identify yet, an MIII perhaps.
* We will be optimistic and hope that the chip is much like an MII,
* and that cpuid is sane. Cyrix seemed to have gotten it right in
* time for the MII, we can only hope it stayed that way.
* Maybe the BIOS or Cyrix is trying to hint at something
*/
cmpl $0x500, %ebx
je GXm
cmpb $0x80, %al
jae likelyM3
/*
* Just test for the features Cyrix is known for
*/
jmp MII
likelyM3:
/*
* DIR0 with values from 0x80 to 0x8f indicates a VIA Cyrix III, aka
* the Cyrix MIII. There may be parts later that use the same ranges
* for DIR0 with special values in DIR1, maybe the VIA CIII, but for
* now we will call anything with a DIR0 of 0x80 or higher an MIII.
* The MIII is supposed to support large pages, but we will believe
* it when we see it. For now we just enable and test for MII features.
*/
movl $X86_TYPE_VIA_CYRIX_III, x86_type
jmp likeMII
coma_bug:
/*
* With NO_LOCK set to 0 in CCR1, the usual state that BIOS enforces, some
* bus cycles are issued with LOCK# asserted. With NO_LOCK set to 1, all bus
* cycles except page table accesses and interrupt ACK cycles do not assert
* LOCK#. xchgl is an instruction that asserts LOCK# if NO_LOCK is set to 0.
* Due to a bug in the cpu core involving over-optimization of branch
* prediction, register renaming, and execution of instructions down both the
* X and Y pipes for the xchgl instruction, short loops can be written that
* never de-assert LOCK# from one invocation of the loop to the next, ad
* infinitum. The undesirable effect of this situation is that interrupts are
* not serviced. The ideal workaround to this bug would be to set NO_LOCK to
* 1. Unfortunately bus cycles that would otherwise have asserted LOCK# no
* longer do, unless they are page table accesses or interrupt ACK cycles.
* With LOCK# not asserted, these bus cycles are now cached. This can cause
* undesirable behaviour if the ARR's are not configured correctly. Solaris
* does not configure the ARR's, nor does it provide any useful mechanism for
* doing so, thus the ideal workaround is not viable. Fortunately, the only
* known exploits for this bug involve the xchgl instruction specifically.
* There is a group of undocumented registers on Cyrix 6x86, 6x86L, and
* 6x86MX cpu's which can be used to specify one instruction as a serializing
* instruction. With the xchgl instruction serialized, LOCK# is still
* asserted, but it is the sole instruction for which LOCK# is asserted.
* There is now some added penalty for the xchgl instruction, but the usual
* bus locking is preserved. This ingenious workaround was discovered by
* disassembling a binary provided by Cyrix as a workaround for this bug on
* Windows, but its not documented anywhere by Cyrix, nor is the bug actually
* mentioned in any public errata! The only concern for this workaround is
* that there may be similar undiscovered bugs with other instructions that
* assert LOCK# that may be leveraged to similar ends. The fact that Cyrix
* fixed this bug sometime late in 1997 and no other exploits other than
* xchgl have been discovered is good indication that this workaround is
* reasonable.
*/
.set CYRIX_DBR0, 0x30 / Debug Register 0
.set CYRIX_DBR1, 0x31 / Debug Register 1
.set CYRIX_DBR2, 0x32 / Debug Register 2
.set CYRIX_DBR3, 0x33 / Debug Register 3
.set CYRIX_DOR, 0x3c / Debug Opcode Register
/*
* What is known about DBR1, DBR2, DBR3, and DOR is that for normal
* cpu execution DBR1, DBR2, and DBR3 are set to 0. To obtain opcode
* serialization, DBR1, DBR2, and DBR3 are loaded with 0xb8, 0x7f,
* and 0xff. Then, DOR is loaded with the one byte opcode.
*/
/*
* select CCR3
*/
movb $CYRIX_CCR3, %al
outb $CYRIX_CRI
/*
* read CCR3 and mask out MAPEN
*/
inb $CYRIX_CRD
andb $0xf, %al
/*
* save masked CCR3 in %ah
*/
movb %al, %ah
/*
* select CCR3
*/
movb $CYRIX_CCR3, %al
outb $CYRIX_CRI
/*
* enable MAPEN
*/
movb %ah, %al
orb $0x10, %al
outb $CYRIX_CRD
/*
* read DBR0
*/
movb $CYRIX_DBR0, %al
outb $CYRIX_CRI
inb $CYRIX_CRD
/*
* disable MATCH and save in %bh
*/
orb $0x80, %al
movb %al, %bh
/*
* write DBR0
*/
movb $CYRIX_DBR0, %al
outb $CYRIX_CRI
movb %bh, %al
outb $CYRIX_CRD
/*
* write DBR1
*/
movb $CYRIX_DBR1, %al
outb $CYRIX_CRI
movb $0xf8, %al
outb $CYRIX_CRD