summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/Txt/TxtInit/Pei/Ia32/TxtPeiBsp.asm
blob: 066aedcd3747139a815e88c50c66541a74b5e34c (plain)
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
;/*++                                                             
;  This file contains an 'Intel Peripheral Driver' and uniquely   
;  identified as "Intel Reference Module" and is                  
;  licensed for Intel CPUs and chipsets under the terms of your   
;  license agreement with Intel or your vendor.  This file may    
;  be modified by the user, subject to additional terms of the    
;  license agreement                                              
;--*/                                                             
;                                                                 
;/*++                                                             
;                                                                 
; Copyright (c)  1999 - 2011 Intel Corporation. All rights reserved
; This software and associated documentation (if any) is furnished
; under a license and may only be used or copied in accordance
; with the terms of the license. Except as permitted by such
; license, no part of this software or documentation may be
; reproduced, stored in a retrieval system, or transmitted in any
; form or by any means without the express written consent of
; Intel Corporation.
; 
; 
; Module Name:
; 
;   TxtPeiBsp.asm
; 
; Abstract:
; 
;   This file contains the code to launch BIOS ACM functions in PEI phase
;
;--*/

    .XLIST
    include txt.inc
    .LIST

    .686P
    .MMX
    .XMM
    .MODEL FLAT,C
    .CODE

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	LaunchBiosAcmSclean
; 
;  Input:	None
; 
;  Output:	None
; 
;  Registers:	None are preserved
; 
;  Description:	Setup GETSEC environment (protected mode, mtrrs, etc) and
;		  invoke GETSEC:ENTERACCS with requested BIOS ACM entry point.
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

LaunchBiosAcmSclean PROC PUBLIC
        ;
        ; Tell where we are
        ;
        mov     eax, 11110000h
        in      ax, 80h
        mov     ah, PORT80_CODE_PREFIX + TXT_LAUNCH_SCLEAN
        out     80h, eax
        
        ;		   
        ; Enable SMXE, SSE and debug extensions always. 
        ;
        mov     eax, CR4
        or      eax, CR4_OSFXSR + CR4_DE + CR4_SMXE
        mov     CR4, eax

        ;
        ; Prepare cache of BSP
        ;
        mov     esi, TXT_PUBLIC_BASE + BIOACM_ADDR
        mov     edi, 0
        
        CALL_NS	PrepareCacheForAcModuleRetNS
	
        CALL_NS	CleanMcaRetNS

ifdef MKF_TXT_RLP_INIT
  if MKF_TXT_RLP_INIT
        CALL_NS InitializeApsRetNS
  endif
endif

        
        ;
        ; Call GETSEC[ENTERACCS]
        ;
        cli
        mov     eax, ENTERACCS          ; eax = ENTERACCS
        mov     ebx, TXT_PUBLIC_BASE + BIOACM_ADDR
        mov     ebx, [ebx]
        mov     ecx, [ebx].ACM_HEADER.AcmSize
        shl     ecx, 2
        xor     edx, edx
        xor     edi, edi
        mov     esi, 0

        _GETSEC

        jmp     DoPowerCycleReset
LaunchBiosAcmSclean  ENDP

DoGlobalReset PROC PUBLIC
        mov     dx, 0CF8h               ; Make warm system reset through port 0CF9h
        mov     eax, 8000F8ACh          ; to be global system reset - set bit 20
        out     dx, eax                 ; of device 1F
        mov     dx, 0CFCh
        in      eax, dx
        or      eax, (1 SHL 20)
        out     dx, eax

        mov     dx, 0CF9h               ; After return from SCLEAN function 
        mov     al, 0                   ; system must be reset.
        out     dx, al
        mov     dx, 0CF9h               ; After return from SCLEAN function 
        mov     al, 6                   ; system must be reset.
        out     dx, al
        cli
        hlt
        jmp     $
        
DoGlobalReset ENDP

DoPowerCycleReset PROC PUBLIC
        mov     dx, 0CF8h               ; Make warm system reset through port 0CF9h
        mov     eax, 8000F8ACh          ; to be global system reset - set bit 20
        out     dx, eax                 ; of device 1F
        mov     dx, 0CFCh
        in      eax, dx
        and     eax, NOT (1 SHL 20)
        out     dx, eax

        mov     dx, 0CF9h               ; After return from SCLEAN function 
        mov     al, 0                   ; system must be reset.
        out     dx, al
        mov     dx, 0CF9h               ; After return from SCLEAN function 
        mov     al, 0Eh                 ; system must be reset.
        out     dx, al
        cli
        hlt
        jmp     $
        
DoPowerCycleReset ENDP

DoHostReset PROC PUBLIC
        mov     dx, 0CF8h               ; Make warm system reset through port 0CF9h
        mov     eax, 8000F8ACh          ; to be global system reset - set bit 20
        out     dx, eax                 ; of device 1F
        mov     dx, 0CFCh
        in      eax, dx
        and     eax, NOT (1 SHL 20)
        out     dx, eax

        mov     dx, 0CF9h               ; After return from SCLEAN function 
        mov     al, 0                   ; system must be reset.
        out     dx, al
        mov     dx, 0CF9h               ; After return from SCLEAN function 
        mov     al, 6                   ; system must be reset.
        out     dx, al
        cli
        hlt
        jmp     $
        
DoHostReset ENDP

DoCpuReset PROC PUBLIC
        mov     dx, 0CF8h               ; Make warm system reset through port 0CF9h
        mov     eax, 8000F8ACh          ; to be global system reset - clear bit 20
        out     dx, eax                 ; of device 1F
        mov     dx, 0CFCh
        in      eax, dx
        and     eax, NOT (1 SHL 20)
        out     dx, eax

        mov     dx, 0CF9h               ; Issue a CPU only reset by CF9h
        mov     al, 0                   ; toggle bit2 from 0 to 1
        out     dx, al
        mov     dx, 0CF9h               ; Issue a CPU only reset by CF9h
        mov     al, 4                   ;
        out     dx, al
        cli
        hlt
        jmp     $
        
DoCpuReset ENDP

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	PrepareCacheForAcModuleRetNS
; 
;  Input:	esi - bios acm address
;               edi - in memory flag
; 
;  Output:	None
; 
;  Registers:	None are preserved
; 
;  Description: MTRRs are set per BIOS spec	
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

PrepareCacheForAcModuleRetNS PROC FAR PUBLIC
        ;
        ; Enable local APIC
        ;		   
        mov	ecx, IA32_APIC_BASE
        rdmsr				; Get APIC Base
        and	eax, BASE_ADDR_MASK	; Just need the address
        mov	DWORD PTR [eax+SPURIOUS_VECTOR_1], 1FFh	; Enable APIC, keep spurious vector
        ;
        ; Disable cache
        ;
        mov	eax, cr0	; set CR0:CD and CR0:NE, clear CR0:NW
        or	eax, CR0_CD_MASK OR CR0_NE_MASK
        and	eax, NOT CR0_NW_MASK
        mov	cr0, eax    
        cmp     edi, 0
        je      @F                      ; JIf stackless environment
        wbinvd                          ; Invalidate the cache
        jmp     disableMtrrs
        
@@:
        invd
                                              
disableMtrrs:        
        ;
        ; Disable all MTRRs
        ;
        xor	eax, eax	
        xor	edx, edx
        mov	ecx, IA32_MTRR_DEF_TYPE
        wrmsr

        ;
        ; Disable NEM
        ;
        mov     ecx, NO_EVICT_MODE
        rdmsr
        and     eax, NOT (BIT1)
        wrmsr                           ; Clear No-Eviction Mode Run bit
        mov     ecx, NO_EVICT_MODE
        rdmsr
        and     eax, NOT (BIT0)
        wrmsr                           ; Clear No-Eviction Mode SETUP bit

        invd

        ;
        ; Clear all variable MTRRs
        ;
        mov     ecx, IA32_MTRR_CAP
        rdmsr
        and     eax, 0FFh
        shl     eax, 1
        mov     ecx, eax
        xor	eax, eax	
        xor	edx, edx
@@:        
        add     ecx, IA32_MTRR_PHYSBASE0 - 1
        wrmsr
        sub     ecx, IA32_MTRR_PHYSBASE0 - 1
        loop    @B
        
        ;
        ; Determine size of AC module
        ;
        mov     esi, [esi]
        mov	eax, [esi].ACM_HEADER.AcmSize
        shl	eax, 2			;  ...in bytes (ACM header has size in dwords)
        ;
        ; Round up to page size
        ;
        mov	ecx, eax		; Save
        and	ecx, 0FFFFF000h		; Number of pages in AC module
        and	eax, 0FFFh		; Number of "less-than-page" bytes
        jz	rounded
        mov	eax, 1000h		; Add the whole page size

rounded:	   
        add	eax, ecx		; eax - rounded up AC module size

	;
	; Define "local" vars for this routine
	;
	ACM_SIZE_TO_CACHE	TEXTEQU	<mm0>				       
	ACM_BASE_TO_CACHE	TEXTEQU	<mm1>				       
	NEXT_MTRR_INDEX		TEXTEQU	<mm2>
	NEXT_MTRR_SIZE		TEXTEQU	<mm3>
	;
	; Initialize "locals"
	;		      
	sub	ecx, ecx
	movd	NEXT_MTRR_INDEX, ecx	; Start from MTRR0
		     
	;
	; Save remaining size to cache
	;
	movd	ACM_SIZE_TO_CACHE, eax	; Size of ACM that must be cached
	movd	ACM_BASE_TO_CACHE, esi	; Base ACM address
		      
nextMtrr:
	;
	; Get remaining size to cache
	;
	movd	eax, ACM_SIZE_TO_CACHE
        and     eax, eax
	jz	done			; If no left size - we are done
        ;
        ; Determine next size to cache.
        ; We start from bottom up. Use the following algorythm:
        ; 1. Get our own alignment. Max size we can cache equals to our alignment
        ; 2. Determine what is bigger - alignment or remaining size to cache.
        ;    If aligment is bigger - cache it.
        ;      Adjust remaing size to cache and base address
        ;      Loop to 1.
        ;    If remaining size to cache is bigger
        ;      Determine the biggest 2^N part of it and cache it.
        ;      Adjust remaing size to cache and base address
        ;      Loop to 1.
        ; 3. End when there is no left size to cache or no left MTRRs
        ;
        movd    esi, ACM_BASE_TO_CACHE
        bsf     ecx, esi                ; Get index of lowest bit set in base address
	;
	; Convert index into size to be cached by next MTRR
	;
	mov	edx, 1h
	shl	edx, cl			; Alignment is in edx
        cmp     edx, eax                ; What is bigger, alignment or remaining size?
        jbe     gotSize                 ; JIf aligment is less
        ;
        ; Remaining size is bigger. Get the biggest part of it, 2^N in size
        ;
	bsr	ecx, eax		; Get index of highest set bit
	;
	; Convert index into size to be cached by next MTRR
	;
	mov	edx, 1
	shl	edx, cl			; Size to cache
        
gotSize:
        mov     eax, edx
	movd	NEXT_MTRR_SIZE, eax	; Save

	;
	; Compute MTRR mask value:  Mask = NOT (Size - 1)
	;						      
	dec	eax			; eax - size to cache less one byte
	not	eax			; eax contains low 32 bits of mask
	or	eax, MTRR_VALID		; Set valid bit

	;
	; Program mask register
	;
	mov	ecx, IA32_MTRR_PHYSMASK0 ; setup variable mtrr
	movd	ebx, NEXT_MTRR_INDEX
	add	ecx, ebx
	
	mov	edx, 0Fh	; 8K range (FFFFFFE800)
	wrmsr
	;
	; Program base register
	;
	sub	edx, edx
	mov	ecx, IA32_MTRR_PHYSBASE0 ; setup variable mtrr
	add	ecx, ebx		; ebx is still NEXT_MTRR_INDEX
	
	movd	eax, ACM_BASE_TO_CACHE
	or	eax, WB			; set type to write back
	wrmsr	
	;
	; Advance and loop
	; Reduce remaining size to cache
	;
	movd	ebx, ACM_SIZE_TO_CACHE
	movd	eax, NEXT_MTRR_SIZE
	sub	ebx, eax
	movd	ACM_SIZE_TO_CACHE, ebx

	;
	; Increment MTRR index
	;
	movd	ebx, NEXT_MTRR_INDEX
	add	ebx, 2
	movd	NEXT_MTRR_INDEX, ebx
	;
	; Increment base address to cache
	;
	movd	ebx, ACM_BASE_TO_CACHE 
	movd	eax, NEXT_MTRR_SIZE
	add	ebx, eax
	movd	ACM_BASE_TO_CACHE, ebx 

	jmp	nextMtrr

done:	
	;
	; Enable variable MTRRs
	;
	xor	edx, edx
	mov	eax, MTRR_ENABLE; enable mtrrs (but not fixed ones)
	mov	ecx, IA32_MTRR_DEF_TYPE
	wrmsr
	;
	; Enable cache
	;
	mov	eax, cr0	; Enable caching - WB (NW stays clear)
	and	eax, NOT CR0_CD_MASK
	mov	cr0, eax
		      
	RET_NS
PrepareCacheForAcModuleRetNS ENDP 
                                              
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	CleanMcaRetNS
; 
;  Input:	None
; 
;  Output:	None
; 
;  Registers:	None are preserved
; 
;  Description:	Setup GETSEC environment (protected mode, mtrrs, etc)
;		  invoke GETSEC:ENTERACCS with requested module
; 							 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

CleanMcaRetNS PROC NEAR PUBLIC
			     
	;
	; Clean all MCi_STATUS MSR registers
	; SCLEAN will generate GPF otherwise
	;
	mov	ecx, MCG_CAP
	rdmsr
	movzx	ebx, al			; Bank count to ebx
	sub	eax, eax		; Write 0 into all MCi_STATUS registers
	sub	edx, edx					     
	mov	ecx, MC0_STATUS

McaErrorCleanLoopStart:	
	wrmsr
	dec	ebx
	jz	exit
	add	ecx, 4			; Number of MSRs per bank
	jmp	McaErrorCleanLoopStart

exit:
	RET_NS
CleanMcaRetNS ENDP


;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	InitializeApsRetNS
; 
;  Input:	None
; 
;  Output:	None
; 
;  Registers:	None are preserved
; 
;  Description:	
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
InitializeApsRetNS PROC NEAR
        mov     eax, 1
        cpuid
	shr	ebx, 16			; Total Logical Proc Count in BL
        cmp	bl, 1			; If 1 thread - nothing to do
	je	exit    

        ;
        ; Init Timer 1
        ;             
        mov     al, 54h
        out     43h, al
        mov     al, 12h
        out     41h, al
        
        ;
	; More than one thread
        ; Get APIC address
        ;
	mov	ecx, IA32_APIC_BASE
	rdmsr				; Get APIC Base
	and	eax, BASE_ADDR_MASK	; Just need the address
        mov     edi, eax                ; edi points to APIC base

        mov     esi, TXT_PUBLIC_BASE    ; esi  points to public space

        ;
        ; Wait for  APIC ready
        ;
        mov	edx, IcrStatusRetNs
	mov	ecx, 15
	CALL_NS	ltWaitStatusRetNS

	;
	; Broadcast INIT message to put all APs into Wait for SIPI state
	; C0500 -> Destination = All excl self, Delivery = INIT
	;
	mov	DWORD PTR ICR_LOW[edi], 000C0500h
	mov	edx, NeverStatusRetNS
	mov	ecx, 667
	CALL_NS	ltWaitStatusRetNS	; Wait full 10ms
	;
	; Create vector used in the following SIPI message
	; Below address is the real mode address of AP code in Boot Block
	; LTCACHE.BIN containg AP thread code must be placed at the above address
	; in Boot block (FFFF0000h). See file LTCACHE.ASM
	;

        mov     ebx, [esi+APINIT_ADDR] 
        shr     ebx, 12
        and     ebx, 0FFh
        or      ebx, 0C0600h            ; This is message

	;
	; Broadcast SIPI message with our vector
        ; Wait for  APIC ready
	;       
        mov	edx, IcrStatusRetNs
	mov	ecx, 15
	CALL_NS	ltWaitStatusRetNS
        ;
        ; Send message
        ;
	mov	ICR_LOW[edi], ebx
        ;
        ; Wait 200us as recommended
        ;
	mov	edx, NeverStatusRetNS
	mov	ecx, 14
	CALL_NS	ltWaitStatusRetNS	
	;
	; Broadcast second SIPI message with our vector
        ; Wait for  APIC ready
	; 
        mov	edx, IcrStatusRetNs
	mov	ecx, 15
	CALL_NS	ltWaitStatusRetNS
        ;
        ; Send message
        ;
	mov	ICR_LOW[edi], ebx
        ;
        ; Wait for semaphore reflect number of CPUs
        ;
        mov     eax, 1
        cpuid
	shr	ebx, 16			; Total Logical Proc Count in BL
        dec     bl                      ; bl is number of APs
        
	mov	edx, SemaphoreStatusRetNS
	mov	ecx, 6670
	CALL_NS	ltWaitStatusRetNS	; Wait for up to 100ms
	
	;	      	   
	; Broadcast INIT message to put all APs back into Wait for SIPI state
        ; Wait for  APIC ready
	;
        mov	edx, IcrStatusRetNs
	mov	ecx, 15
	CALL_NS	ltWaitStatusRetNS
        ;
        ; Send message
        ;
        mov	DWORD PTR ICR_LOW[edi], 000C0500h
        
	mov	edx, NeverStatusRetNS
	mov	ecx, 667
	CALL_NS	ltWaitStatusRetNS	; Wait full 10ms   

exit:
	RET_NS				   
InitializeApsRetNS ENDP
      

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	SaveApConfig
; 
;  Input:	ApCfg - pointer to save area
; 
;  Output:	None
; 
;  Registers:	All are preserved
; 
;  Description: Function is called in memory present environment on S3 resume
;               path. Saves contents of all MTRRs into table plus some registers.
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
SaveApConfig PROC NEAR PUBLIC, ApCfg:PTR QWORD
             
        pushad
        
        mov     esi, ApCfg
        mov     ecx, IA32_MTRR_CAP
	rdmsr
        and     eax, 0FFh
        shl     eax, 1
        mov     ecx, eax

@@:        
        add     ecx, IA32_MTRR_PHYSBASE0 - 1
	rdmsr
	mov	[esi], eax
	mov	[esi+4], edx
	add	esi, SIZEOF QWORD
        sub     ecx, IA32_MTRR_PHYSBASE0 - 1
        loop    @B                                           

        mov     ecx, IA32_MTRR_DEF_TYPE
	rdmsr  
	mov	[esi], eax
	mov	[esi+4], edx 

	sidt	[esi+8] 

	mov	ecx, IA32_MISC_ENABLE_MSR
	rdmsr
	mov	[esi+010h], eax
	mov	[esi+014h], edx
        
        popad
	ret
SaveApConfig ENDP	     
         
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	StartupAllAPs
; 
;  Input:	pFunction - pointer to function to execute on AP
;               pParam - pointre to pFunction parameters
; 
;  Output:	None
; 
;  Registers:	All are preserved
; 
;  Description:	Procedure is called in memmory present enironment on S3
;               resume path and is executed on BSP
;               It saves memory at address 1000h into buffer
;               It then copies AP start-up code into address 1000h
;               Then variables in the 1000h area are updated and APs are started
;               After APs finish execution of function passed as parameter they
;               are halted.  BSP restores contents 1000h area from buffer and
;               returns.
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

Func TYPEDEF PROTO 

PFUNC TYPEDEF PTR Func  

StartUp STRUCT 
                db      0FAh                    ; cli 
                db      066h, 0BBh              ; mov	ebx, OFFSET gdtLim
                db      StartUp.gdtLim, 0,0,0
                db	066h
                db      067h, 02Eh, 00Fh, 001h, 013h ; lgdt    FWORD PTR cs:[ebx]
                db      00Fh, 020h, 0C0h        ; mov	eax, CR0
                db      00Ch, 001h              ; or	al, 01
                db      00Fh, 022h, 0C0h        ; mov	CR0, eax
					;
					; 32 bit jump to 32 bit Function handler
					;
                db	066h                                        
                db	0eah                                                        
fOff            dd	0   
fCs             dw	0

        ALIGN   16
fDs             dw	0
gdtLim          dw	?                       ; Size of LT GDT in bytes    
gdtBas          dd	?                       ; Physical address of LT GDT 
fParam          dd      ?
smphr           dd      ?
StartUp ENDS
              
             
StartupAllAPs PROC NEAR, pFunction:PFUNC, pParam:PTR QWORD
        LOCAL   buffer:StartUp    
        LOCAL   savedESP:DWORD
        
        pushad
        mov     savedESP, esp
        mov     eax, 1
        cpuid
	shr	ebx, 16			; Total Logical Proc Count in BL
        cmp	bl, 1			; If 1 thread - nothing to do
	je	exit    

        ;
        ; Init Timer 1
        ;             
        mov     al, 54h
        out     43h, al
        mov     al, 12h
        out     41h, al
        
        ;
	; More than one thread. Prepare Startup area
        ;
        mov     esi, 1000h              ; Source
        lea     edi, buffer             ; Destination
        mov     ecx, sizeof StartUp / 4
        CALL_NS MemCopyRetNS     

        mov     esi, offset ApHandler16 ; Source
        mov     edi, 1000h              ; Destination
        mov     ecx, sizeof StartUp / 4
        CALL_NS MemCopyRetNS             
        ;
        ; Update Srartup area variables
        ;                                           
        mov     edi, 1000h              
	mov	ds:[edi].StartUp.fCs, cs
	mov	ds:[edi].StartUp.fDs, ds
        mov     eax, pFunction
	mov	ds:[edi].StartUp.fOff, eax
        sub     eax, eax
	mov	ds:[edi].StartUp.smphr, eax
        mov     eax, pParam
	mov	ds:[edi].StartUp.fParam, eax
	sgdt	ds:[edi].StartUp.gdtLim
              
        ;
        ; Get APIC address
        ;
	mov	ecx, IA32_APIC_BASE
	rdmsr				; Get APIC Base
	and	eax, BASE_ADDR_MASK	; Just need the address
        mov     edi, eax                ; edi points to APIC base

        ;
        ; Wait for  APIC ready
        ;
        mov	edx, IcrStatusRetNs
	mov	ecx, 15
	CALL_NS	ltWaitStatusRetNS

	;
	; Broadcast INIT message to put all APs into Wait for SIPI state
	; C0500 -> Destination = All excl self, Delivery = INIT
	;
	mov	DWORD PTR ICR_LOW[edi], 000C0500h
	mov	edx, NeverStatusRetNS
	mov	ecx, 667
	CALL_NS	ltWaitStatusRetNS	; Wait full 10ms
	;
	; Create vector used in the following SIPI message
	;
        mov     ebx, 0C0600h + (1000h SHR 12)
	;
	; Broadcast SIPI message with our vector
        ; Wait for  APIC ready
	;       
        mov	edx, IcrStatusRetNs
	mov	ecx, 15
	CALL_NS	ltWaitStatusRetNS
        ;
        ; Send message
        ;
	mov	ICR_LOW[edi], ebx
        ;
        ; Wait 200us as recommended
        ;
	mov	edx, NeverStatusRetNS
	mov	ecx, 14
	CALL_NS	ltWaitStatusRetNS	
	;
	; Broadcast second SIPI message with our vector
        ; Wait for  APIC ready
	; 
        mov	edx, IcrStatusRetNs
	mov	ecx, 15
	CALL_NS	ltWaitStatusRetNS
        ;
        ; Send message
        ;
	mov	ICR_LOW[edi], ebx
        ;
        ; Wait for semaphore reflect number of CPUs
        ;
        mov     eax, 1
        cpuid
	shr	ebx, 16			; Total Logical Proc Count in BL
        dec     bl                      ; bl is number of APs
        
	mov	edx, SemaphoreStatus2RetNS
	mov	ecx, 6670
	CALL_NS	ltWaitStatusRetNS	; Wait for up to 100ms
        ;
        ; Restore StartUp area
        ;
        lea     esi, buffer             ; Source
        mov     edi, 1000h              ; Destination
        mov     ecx, sizeof StartUp / 4
        CALL_NS MemCopyRetNS     
	
exit:   
        mov     esp, savedESP
        popad
	ret                                         
        
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Section:	ApHandler16
; 
;  Input:	None
; 
;  Output:	None
; 
;  Registers:	Irrelevant
; 
;  Description:	This code is copied over address 0:1000. After recieving SIPI
;	AP is directed to this address where it starts execution in real mode.
;	AP first switches to protected mode, loads the same GDT which is used
;	by BSP and jumps to Procedure at fCs:fOff
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

        ALIGN	16
        ;
        ; Note After coppying this code must be aligned on page boundary!
        ;

ApHandler16  StartUp <>

StartupAllAPs ENDP
             

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	PutApsInWfs
; 
;  Input:	None
; 
;  Output:	None
; 
;  Registers:	All are preserved
; 
;  Description: Procedure is called in memory present environment on S3 resume path.
;               INIT SIPI message is sent to all APs.
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
                
PutApsInWfs PROC PUBLIC
        LOCAL   savedESP:DWORD
        pushad 
        mov     savedESP, esp
        
        mov     eax, 1
        cpuid
	shr	ebx, 16			; Total Logical Proc Count in BL
        cmp	bl, 1			; If 1 thread - nothing to do
	je	exit    

        ;
        ; Get APIC address
        ;
	mov	ecx, IA32_APIC_BASE
	rdmsr				; Get APIC Base
	and	eax, BASE_ADDR_MASK	; Just need the address
        mov     edi, eax                ; edi points to APIC base
	;	      	   
	; Broadcast INIT message to put all APs back into Wait for SIPI state
        ; Wait for  APIC ready
	;
        mov	edx, IcrStatusRetNs
	mov	ecx, 15
	CALL_NS	ltWaitStatusRetNS
        ;
        ; Send message
        ;
        mov	DWORD PTR ICR_LOW[edi], 000C0500h
        
	mov	edx, NeverStatusRetNS
	mov	ecx, 667
	CALL_NS	ltWaitStatusRetNS	; Wait full 10ms   

exit:   
        mov     esp, savedESP
        popad
        ret
PutApsInWfs ENDP

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	LaunchBiosAcmScheck
; 
;  Input:	None
; 
;  Output:	None
; 
;  Registers:	None are preserved
; 
;  Description:	Setup GETSEC environment (protected mode, mtrrs, etc) and
;		  invoke GETSEC:ENTERACCS with requested BIOS ACM entry point.
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

LaunchBiosAcmScheck PROC PUBLIC, BiosAcAddr:PTR QWORD

	LOCAL	SavedGdtr:QWORD 
	LOCAL	SavedSS:dword 
	LOCAL	SavedESP:dword 
	LOCAL	SavedCS:dword 
	LOCAL	SavedCR3:dword   
	pushf                    
        cli
	pushad
        ;
        ; Tell where we are
        ;                  
        in      ax, 80h
        mov     ah, PORT80_CODE_PREFIX + TXT_LAUNCH_SCHECK
        out     80h, ax
        ;
        ; Save control registers
        ;                       
        mov     eax, cr4
        push    eax
        mov     eax, cr0
        push    eax
        ;
        ; Save segment registers
        ;
        push    ds
        push    es
        push    gs
        push    fs
        ;
        ; Save CS
        ;
        sub     eax, eax                ; Clean upper word
        mov     ax, cs
        mov     SavedCS, eax
        ;
        ; Save stack at this level
        ;                         
        mov     ax, ss
        mov     SavedSS, eax
        mov     SavedESP, esp
        mov     eax, cr3
        mov     SavedCR3, eax
        
        ;
        ; Save GDT
        ;
	sgdt	SavedGdtr ; save value of gdtr in local variable
	;
	; Define "local" vars for this routine
	;
	SAVED_EBP	TEXTEQU	<mm4>
        ;
        ; Save ebp in MMX register
        ;
	movd	SAVED_EBP, ebp          ; Size of ACM that must be cached
                     
        ;       	        
        ; Enable SMXE, SSE and debug extensions always. 
        ;                                   
	mov	eax, CR4 
	or	eax, CR4_OSFXSR + CR4_DE + CR4_SMXE 
	mov	CR4, eax 
        ;
        ; Prepare cache of BSP
        ;
        mov     esi, BiosAcAddr
        mov     edi, 1
        
	CALL_NS	PrepareCacheForAcModuleRetNS 

	CALL_NS	CleanMcaRetNS

        ;                                   
        ; Call GETSEC[ENTERACCS]
        ;                                   
	mov	eax, ENTERACCS ; eax = ENTERACCS
	mov	ebx, BiosAcAddr
	mov	ebx, [ebx] 
	mov	ecx, [ebx].ACM_HEADER.AcmSize 
	shl	ecx, 2 
	xor	edx, edx 
        mov     edi, S3_RESUME_PATH
	mov	esi, 4 

	_GETSEC  
               
        ;
	; Return point after ACEXIT. 
	;
        movd    ebp, SAVED_EBP
        lea     eax, SavedGdtr
        lgdt    FWORD PTR [eax]
        mov     eax, SavedSS
        mov     ss, ax
        mov     esp, SavedESP
        mov     eax, SavedCR3
        mov     cr3, eax
        ;                     
        ; Restore segment registers
        ;
        pop     fs
        pop     gs
        pop     es
        pop     ds
        ;
        ; Restore control registers
        ;
	pop	eax 
	;
	;remain cache disabled until MTRRs restored
	;
	or	eax, CR0_CD_MASK
	and	eax, NOT CR0_NW_MASK
	wbinvd
;
	mov	cr0, eax 
	pop	eax 
	mov	cr4, eax 
        ;
        ; Restore CS
        ;
        mov     eax, SavedCS
        push    eax
 	push	OFFSET ReloadCS
 	retf

ReloadCS:
	popad 
	popf 
        emms
         
        ret
LaunchBiosAcmScheck ENDP 

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	RestoreMtrrProgramming
; 
;  Input:	ApMtrrTab - pointer to save area
; 
;  Output:	None
; 
;  Registers:	All are preserved
; 
;  Description:	Function is executed on BSP in memory present environment on S3
;               resume path. Restores contents of all MTRRs from table
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
RestoreMtrrProgramming PROC NEAR PUBLIC, ApMtrrTab:PTR QWORD
        LOCAL   savedESP:DWORD
        pushad
        mov     savedESP, esp
        
        mov     esi, ApMtrrTab
        CALL_NS RestoreMtrrProgrammingRetNS

        mov     esp, savedESP
        popad
	ret
RestoreMtrrProgramming ENDP
                

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	RestoreMtrrProgrammingRetNS
; 
;  Input:	esi - pointer to save area
; 
;  Output:	None
; 
;  Registers:	None are preserved
; 
;  Description:	Restores contents of all MTRRs from table
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
RestoreMtrrProgrammingRetNS PROC NEAR PUBLIC
	mov	eax, cr0	; set CR0:CD and CR0:NE, clear CR0:NW
	or	eax, CR0_CD_MASK OR CR0_NE_MASK
	and	eax, NOT CR0_NW_MASK
	mov	cr0, eax
	wbinvd			; flush and invalidate the cache

	xor	edx, edx
	mov	eax, MTRR_ENABLE + MTRR_FIXED_ENABLE ; enable mtrrs
	mov	ecx, 2FFh
	wrmsr

        mov     ecx, IA32_MTRR_CAP
	rdmsr
        and     eax, 0FFh
        shl     eax, 1
        mov     ecx, eax

@@:
        add     ecx, IA32_MTRR_PHYSBASE0 - 1
	mov	eax, [esi]
	mov	edx, [esi+4]				 
	wrmsr
	add	esi, SIZEOF QWORD
        sub     ecx, IA32_MTRR_PHYSBASE0 - 1
        loop    @B                         

	mov	ecx, IA32_MTRR_DEF_TYPE 
	mov	eax, [esi]
	mov	edx, [esi+4]				 
	wrmsr
	mov	ecx, IA32_MISC_ENABLE_MSR
	mov	eax, [esi+010h]
	mov	edx, [esi+014h]
	wrmsr

	mov	eax, cr0	; Enable caching - WB (NW stays clear)
	and	eax, NOT CR0_CD_MASK
	mov	cr0, eax
	
	RET_NS
RestoreMtrrProgrammingRetNS ENDP

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	RestoreApConfig
; 
;  Input:	esi - pointer to save area
; 
;  Output:	None
; 
;  Registers:	None are preserved
; 
;  Description:	Function is executed on AP in memory present environment on S3
;               resume path. Restores contents of all MTRRs from table
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
RestoreApConfig PROC NEAR PUBLIC
	mov	eax, CR4
	or	eax, CR4_OSFXSR + CR4_DE
	mov	CR4, eax

        mov     esi, 1000h
        mov     ds, cs:[esi].StartUp.fDs
        mov     es, cs:[esi].StartUp.fDs
        mov     fs, cs:[esi].StartUp.fDs
        mov     gs, cs:[esi].StartUp.fDs
        mov     ss, cs:[esi].StartUp.fDs
                 
        mov     esi, [esi].StartUp.fParam

        CALL_NS RestoreMtrrProgrammingRetNS

        lidt    FWORD PTR [esi+8]
        
        jmp     updateSemaphore

RestoreApConfig ENDP

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	DoApInit
; 
;  Input:	Contents of startup area at 1000h
; 
;  Output:	None
; 
;  Registers:	None are preserved
; 
;  Description:	Executed on AP. Persforms CPU initialization for running
;               of GETSEC
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
DoApInit PROC NEAR PUBLIC
	mov	eax, CR4
	or	eax, CR4_OSFXSR + CR4_DE + CR4_SMXE
	mov	CR4, eax

        mov     esi, 1000h
        mov     ds, cs:[esi].StartUp.fDs

        mov     esi, [esi].StartUp.fParam
        mov     edi, 1
                                            
	CALL_NS	PrepareCacheForAcModuleRetNS 

	CALL_NS	CleanMcaRetNS
                
updateSemaphore::        
        mov     ecx, 1000h + StartUp.smphr
        lock    inc  DWORD PTR [ecx]
        
hltLoop:
        cli
	hlt
	jmp	hltLoop

DoApInit ENDP
                         
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	MemCopyRetNS
; 
;  Input:	esi - from linear address
;		edi - to linear address
;		ecx - swap size in dwords
;		ds - flat segment
; 		       
;  Output:	None
; 
;  Registers:	None	
; 
;  Description:	Swaps contents of two input buffers.
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

MemCopyRetNS PROC NEAR
	
start:
	mov	eax, ds:[esi]		; source
	mov	ds:[edi], eax
	add	esi, 4
	add	edi, 4
	loop	start
	RET_NS
MemCopyRetNS ENDP

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	ltWaitStatusRetNS
; 
;  Input:	cx  - Refresh bit Toggle count
;		750000us = 50000 toggles
;		edx  - offset of Status procedure
; 
;  Output:	Z if status is met			
;		NZ - timeout occured				 
;		NC - always
; 
;  Stack:	Not available
; 
;  Registers:	cx, ax, esp
; 
;  Description:	Calls status procedure. If status is met - returns Z and
;		NZ otherwise.
;		Status procedure is required to return Z if status is met and
;		NZ if not
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
ltWaitStatusRetNS PROC NEAR

	in	al, PORTB		; Read initial setting.
	and	al, PORTBMASK		; Keep what we care about.
	mov	ah, al			; Keep a copy of the data.

waitLoop:	    
	CALL_NS edx			; Call status procedure.
	jz	exit			; Z - status met
	
waitLoop0:	    
	in	al, PORTB
	and	al, PORTBMASK
	cmp	al, ah			; Refresh bit changed ?
	je	waitLoop0

	mov	ah, al
	loop	waitLoop
	or	ax, 1			; Clear the ZERO flag - timeout.
					; This also clears C flag
exit:	
	RET_NS
ltWaitStatusRetNS ENDP			      

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	IcrStatusRetNS
; 
;  Input:	ds: Flat, edi - xAPIC Base Address
; 
;  Output:	Z if status is met			
; 
;  Stack:	Not available
; 
;  Registers:	all are preserved
; 
;  Description:	Returns Z if ICR is idle
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
IcrStatusRetNS PROC NEAR PUBLIC
	test	DWORD PTR ICR_LOW[edi], BIT12
	RET_NS
IcrStatusRetNS ENDP

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	SemaphoreStatusRetNS
; 
;  Input:	ds: Flat
; 
;  Output:	Z if status is met			
; 
;  Stack:	Not available
; 
;  Registers:	all are preserved
; 
;  Description:	Returns Z if semaphore is 0
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
SemaphoreStatusRetNS PROC NEAR PUBLIC
	bswap	eax
        mov     al, BYTE PTR [esi+SEMAPHORE]
        cmp     al, bl
	bswap	eax
	RET_NS	   
SemaphoreStatusRetNS ENDP

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	SemaphoreStatus2RetNS
; 
;  Input:	ds: Flat
; 
;  Output:	Z if status is met			
; 
;  Stack:	Not available
; 
;  Registers:	Upper byte of eax is modified
; 
;  Description:	Returns Z if semaphore is 0
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
SemaphoreStatus2RetNS PROC NEAR PUBLIC
	bswap	eax
        mov     al, BYTE PTR [esi].StartUp.smphr
        cmp     al, bl
	bswap	eax
	RET_NS	   
SemaphoreStatus2RetNS ENDP

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;  Procedure:	NeverStatusRetNS
; 
;  Input:	
; 
;  Output:	Z if status is met			
; 
;  Stack:	Not available
; 
;  Registers:	All are preserved
; 
;  Description:	Returns Z if ICR is idle
; 
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
NeverStatusRetNS PROC NEAR PUBLIC
	or	dx, dx			; dx is never 0 so return is NZ
        RET_NS
NeverStatusRetNS ENDP



END