; 	[]===========================================================[]
;
;	NOTICE: THIS PROGRAM BELONGS TO AWARD SOFTWARE INTERNATIONAL(R)
;	        INC. IT IS CONSIDERED A TRADE SECRET AND IS NOT TO BE
;	        DIVULGED OR USED BY PARTIES WHO HAVE NOT RECEIVED
;	        WRITTEN AUTHORIZATION FROM THE OWNER.
;
; 	[]===========================================================[]
;
;----------------------------------------------------------------------------
;Rev  	Date	 Name	Description
;----------------------------------------------------------------------------
;R04	04/19/99 RCH	Fixed wrong MTRR programming if the total memory is
;			512Mbytes with 1MBytes shared memory on UMA P6 class
;			platform.
;
;R0401	04/01/99 RCH	Rewrite for supporting other vendor's CPU.
;
;R03	03/29/99 RCH	Discard unused code for P6 class BIOS
;
;R02	03/24/99 RCH	Added routine for K7 CPU stepping bug patch.
;
;R01	03/22/99 RAY	Pentium III CPU processor number selection does
;			not apply to Pentium PRO.
;
;R00	03/15/99 RAY	Initial revision in which the code is extracted from
;			the original CPUPOST.ASM. The code in this file will
;			only be compliled if "P6_BIOS_ONLY" is defined in
;			BIOS.CFG

IF	COMPILE_FOR_E0
if	STR_function	EQ	1
		extrn	CT_OPEN_SM_RAM:near
		extrn	CT_CLOSE_SM_RAM:near
		extrn	Get_SMBASE_ADD:near
endif	;STR_function	EQ	1

 ifdef	L2ECC_CMOS
		extrn	L2Ecc_Item:near
 endif;	L2ECC_CMOS

 ifndef	NO_P3_CPU_SNO_SELECT
  ifndef	K7_CPU_SUPPORT
  IF	BIOS_SUPPORT_KLAMATH				;R01
		extrn	PSN_Item:near
  ENDIF	;BIOS_SUPPORT_KLAMATH				;R01
  endif;	K7_CPU_SUPPORT
 endif;	NO_P3_CPU_SNO_SELECT

		extrn	POST_decompress:near
		extrn	F000_GetItem_Value:near
		extrn	ExtCache_Item:near

		EXTRN	ROM_AND_CMOS:NEAR
		EXTRN	ROM_OR_CMOS:NEAR
		extrn	POST_func_end:Near
		extrn	POST_VECT:Near

		extrn	Check_Cyrix_Cpu:near
		extrn	Init_Cyrix_Reg:near
		extrn	Get_Cmos:near
		extrn	Set_Cmos:near
		extrn	F000_call_proc:near
		extrn	F000_Shadow_W:Near
		extrn	F000_Shadow_R:Near

		extrn	LOCK_CYRIX:Near
		extrn	UNLOCK_CYRIX:Near
		extrn	LOCK_CYRIX:Near
		extrn	SET_CYRIX:Near
		extrn	GET_CYRIX:Near
		extrn	F000_Get_Cmos:near
		extrn	F000_Set_Cmos:near

ifdef	ESCD_SUPPORT
ifndef	ESCD_M2
IF BUS_TYPE NE EISA_BUS
		extrn	P5_BtB_Loc:near
endif; BUS_TYPE NE EISA_BUS
endif;	ESCD_M2
endif;	ESCD_SUPPORT

		extrn	Cpu_Cache:near
		extrn	Read_CpuID:Near
		extrn	P6_L2Cache_Control:near
		extrn	Ct_MemHole_Status:Near
ifdef	CYRIX_GOBI_SUPPORT
		extrn	CheckIfGobiCpu:near
endif;	CYRIX_GOBI_SUPPORT

ifdef	Special_CPU_Clock_Table
		extrn	Ct_Int_Clock_Tbl:Near
endif	;Special_CPU_Clock_Table

.LIST

EGROUP		GROUP	ECODE
ECODE		SEGMENT USE16 PARA PUBLIC 'ECODE'
		ASSUME	CS:EGROUP, DS:EGROUP

;=============================================================================
;FUNC:	CYRIX_INIT
;
;DESC:	Handles the initialization of the CYRIX CPU.
;
;IN:	NONE
;OUT:	NONE
;
;SAVES:	NONE + NO STACK
;
;BY:	Richard Chen
;DATE:	18 May 1992
;=============================================================================
FLAGS_MASK	EQU	08D5H

		public	CYRIX_INIT
CYRIX_INIT	proc	near

		ret

CYRIX_INIT	endp

;[]------------------------------------------------------------------------[]
;[]------------------------------------------------------------------------[]
		Public	Chk_Intel_S_CPU
Chk_Intel_S_CPU	Proc	Near

		push	ds
		pushad

	;replace the original int 06h with a temparary
	;one to prevent trap accurs in some CPUs

		xor	eax, eax			;input value = 1
		mov	ds, ax

		push	dword ptr ds:[4*6]		;save int 06h vector
		mov	word ptr ds:[4*6], offset Temp_Int06

		push	cs
		pop	word ptr ds:[4*6+2]		;segment address

	;issue special OP code: CPUID(0Fh, 0A2h)

		db	0Fh, 0A2h		;OP code: CPUID with eax=0

		mov	si, offset Cpu_Vendor_Tbl
Chk_Nxt_Vendor:
		cmp	word ptr cs:[si], -1 	;last of CPU vendor table
		je	short Finish_Cpu_ID 	;yes, over !

		cmp	ebx, cs:[si+2]		;check 1st identifier string
		jne	short Next_Vendor

		cmp	ecx, cs:[si+6]		;check 2nd identifier string
		jne	short Next_Vendor

		cmp	edx, cs:[si+10]		;check 3th identifier string
		je	short Good_Vendor

Next_Vendor:
		add	si, SIZE_VENDOR_TBL	;check next vendor
		jmp	short Chk_Nxt_Vendor

Good_Vendor:
		mov	si, cs:[si]	 	;get vendor's CPU patch routine

	;Now , we got correct identifier of CPU, next step is to get CPU ID

		mov	eax, 1			;eax = 1 to read CPU ID
		db	0fh, 0A2h		;CPU ID instruction

		call	si			;invoke CPU init. or patch

	Finish_Cpu_ID:
		mov	dx, CPU_P6		;get CPU ID
		call	Set_CPU_Type_Bits

		pop	dword ptr ds:[4*6]	;restore int 06h vector

		call	Prepare_CPU_Info
		popad
		pop	ds
		ret

;-------------------------------------------------------
; Temporary Int 06 handler for Non-(Intel S-Series) CPU
;-------------------------------------------------------

		public	Temp_Int06

Temp_Int06	Label	Near
		push	bp
		mov	bp, sp
		add	word ptr ss:[bp+2], 2
		pop	bp
		iret

Chk_Intel_S_CPU	Endp

DisableLApic	proc	near
ifndef	MP_SUPPORT
	;disable local APIC if not support MP
		pushad
		mov	ecx, 27			;MSR index 27
		RDMSR
		and	ah, NOT 08H		;disable CPU APIC
		WRMSR
		popad
endif;	MP_SUPPORT
		ret
DisableLApic	endp


;R02 - start
;Function : Patch for bug of K7 CPU stepping
;Input    : si  - pointer of CPUID table address
;	  : eax - CPUID
;Output   : none
;
K7_CpuPatch	proc	near

ifdef	K7_CPU_SUPPORT
		pushad

	;Program bit[12] of HWCR for all K7 stepping
		push	eax			;save CPUID
		mov	ecx, 0C0010015h		;HWCR MSR
		RDMSR				;read MSR value
		or	ax, (1 SHL 12)		;set bit 12
		WRMSR
		pop	eax			;restore CPUID

		and	ah, 0FH			;low nibble is significant
		cmp	ax, 0610H		;stepping below C1 ?
		ja	short NotK7CpuID

	;Program bit[18] of BU_CFG(Bus Unit Config. Reg.) MSR for
	;CPUID <= 0610H
		mov	ecx, 0C0011023H		;BU_CFG MSR
		mov	edi, 09C5A203AH		;password for accessing MSR
		RDMSR		       		;read MSR value
		or	eax, (1 SHL 18)		;set bit 18
		WRMSR				;write MSR

	NotK7CpuID:
		popad
endif;	K7_CPU_SUPPORT

		ret
K7_CpuPatch	endp

;R02 - end

Cpu_Vendor_Tbl:
		dw	offset Cpu_INTELs  	;table of INTEL CPUs
		dd	756E6547h	   	;Identifer string 1
		dd	6C65746eh	   	;Identifer string 2
		dd	49656E69h	   	;Identifer string 3
SIZE_VENDOR_TBL	EQU	$ - offset Cpu_Vendor_Tbl

		dw	offset Cpu_AMDs	   	;table of AMD CPUs
		dd	68747541h	   	;Identifer string 1
		dd	444d4163h	   	;Identifer string 2
		dd	69746e65h	   	;Identifer string 3

ifdef	CYRIX_GOBI_SUPPORT
		dw	offset Cpu_Cyrixs   	;table of Cyrix CPUs
		dd	'iryC'		   	;Identifer string 1(ebx)
		dd	'daet'		   	;Identifer string 2(edx)
		dd	'snIx'		   	;Identifer string 3(ecx)
endif;	CYRIX_GOBI_SUPPORT

		dw	-1		   	;last of CPU venders table

;Function : Program necessary feature or patch for Intel CPUs
;Input    : EAX - CPUID information
;Output   : none
Cpu_INTELs	proc	near
	   	call	DisableLApic		;disable CPU local APIC
		ret
Cpu_INTELs	endp

;Function : Program necessary feature or patch for AMD CPUs
;Input    : EAX - CPUID information
;Output   : none
Cpu_AMDs	proc	near
	   	call	DisableLApic		;disable CPU local APIC
		call	K7_CpuPatch
		ret
Cpu_AMDs	endp

;Function : Program necessary feature or patch for Intel CPUs
;Input    : EAX - CPUID information
;Output   : none
Cpu_Cyrixs	proc	near
	   	
		ret
Cpu_Cyrixs	endp

;[]==========================================================[]
;Input : DL = Value for CMOS_AWARD_2  (03DH)
;        DH = Value for CMOS_OVERRIDE (03FH)
;[]==========================================================[]
Set_CPU_Type_Bits:
		mov	al, CMOS_AWARD_2 NMI_OFF
		mov	ah, dl

		call	F000_Set_Cmos

		mov	ah, CMOS_OVERRIDE NMI_OFF
		mov	al, ah

		call	F000_Get_Cmos
		and	al, NOT (CLOCK_MODE+((SMICPU+WBCPU) SHR 8))
		or	al, dh
		xchg	ah, al

		call	F000_Set_Cmos
		ret

;[]------------------------------------------------------------------------[]
;[]------------------------------------------------------------------------[]
		public	Intel_To_AMD
Intel_To_AMD	proc	near

		ret

Intel_To_AMD	endp

;[]------------------------------------------------------------------------[]
;Procedur	:	Prepare_CPU_Info
;
;Input		:	None
;
;Output		:	None
;
;Description	:	- This routine is called after the BIOS has issued
;			  the CPUID instruction & all the CPUs are identified.
;
;			- There are 2 variables in the stack area namely
;			  CPU_BRAND[bp] & CPU_SMI_TYPE[bp]
;			  This routine will place appropriate values into
;			  these 2 [BP] variables
;			  The BIOS engineers can easily reference to them
;			  for their own programming
;
;			- please refer to BSETUP.INC for the definitions
;			  of CPU_BRAND[bp] & CPU_SMI_TYPE[bp]
;
;Note		:	BIOS engineers should use instruction "test" to
;			check SMI type & "cmp" for CPU brand
;
;			e.g.
;			    cmp   CPU_BRAND[bp], CPU_BRAND_CYRIX
;			    test  CPU_SMI_TYPE[bp], SMI_TYPE_CYRIX
;
;[]------------------------------------------------------------------------[]
		Public	Prepare_CPU_Info
Prepare_CPU_Info	Proc	Near

		mov	dx, (SMI_TYPE_INTEL SHL 8) + CPU_BRAND_INTEL
		mov	word ptr CPU_BRAND[bp], dx

		mov	byte ptr CPU_LEVEL[bp], LEVEL_686
		ret

Prepare_CPU_Info	Endp

		ALIGN	4
;
;CPU clock detection for Pentium Pro, Pentium II and Deschutes
;
	Public	MOV_SHAD_SEG
MOV_SHAD_SEG	EQU	5000h
		;Clock ratio table for P6 class CPU
		Public	P6_ClkRatio

 ifdef	K7_CPU_SUPPORT
P6_ClkRatio	db	2	;x1	;0000, reserved
		db	2	;x1	;0001, reserved
		db	8	;x4	;0010
		db	9	;x4.5	;0011
		db	10	;x5	;0100
		db	11	;x5.5	;0101
		db	12	;x6.0	;0110
		db	13	;x6.5	;0111
		db	14	;x7.0	;1000
		db	15	;x7.5	;1001
		db	16	;x8.0	;1010
		db	17	;x8.5	;1011
		db	18	;x9.0	;1100
		db	19	;x9.5	;1101
		db	20	;x10	;1110
		db	2	;x1	;1111, reserved
 else;	K7_CPU_SUPPORT

P6_ClkRatio	db	10	;x5	;0000
		db	6	;x3	;0001
		db	8	;x4	;0010
		db	4	;x2	;0011
		db	11	;x5.5	;0100
		db	7	;x3.5	;0101
		db	9	;x4.5	;0110
		db	5	;x2.5	;0111
		db	7	;reserve;1000
		db	14	;x7	;1001
		db	16	;x8	;1010
		db	12	;x6	;1011
		db	4	;x2	;1100
		db	15	;x7.5	;1101
		db	3	;x1.5	;1110
		db	13	;x6.5	;1111

  ifdef	CYRIX_GOBI_SUPPORT
   Gobi_ClkRatio:
		db	5	;rev.	;80h
		db	5	;rev.	;81h
		db	5	;x2.5	;82h
		db	6	;x3.0	;83h
		db	7	;x3.5	;84h
		db	8	;x4.0	;85h
		db	9	;x4.5	;86h
		db	10	;x5	;87h
		db	5	;rev.	;88h
		db	5	;rev.	;88h
		db	5	;x2.5	;8ah
		db	6	;x3.0	;8bh
		db	7	;x3.5	;8ch
		db	8	;x4.0	;8dh
		db	9	;x4.5	;8eh
		db	10	;x5	;8fh
  endif;CYRIX_GOBI_SUPPORT

 endif;	K7_CPU_SUPPORT

		;possible host clock table for P6 class CPU
P6_HostClk:

		db	148, 150, CPU66	;150Mhz
		dw	1500		;for real CPU frequency calculation
HOSTCLK_SIZE	EQU	($ - offset P6_HostClk)

		db	139, 140, CPU66	;140Mhz
		dw	1400		;for real CPU frequency calculation

		db	136, 138, CPU66	;138Mhz
		dw	1380		;for real CPU frequency calculation

	 	db	131, 133, CPU66	;133Mhz
		dw	1333	;for real CPU frequency calculation

		db	127, 129, CPU66	;129Mhz
		dw	1290		;for real CPU frequency calculation

		db	122, 124, CPU66	;124Mhz
		dw	1240		;for real CPU frequency calculation

		db	115, 117, CPU66	;117Mhz
		dw	1170		;for real CPU frequency calculation

		db	110, 112, CPU66	;112Mhz
		dw	1120

		db	102, 103, CPU66	;103Mhz
		dw	1030

		db	96, 100, CPU66	;100Mhz
		dw	1000		;for real CPU frequency calculation

		db	92, 95, CPU66	;95Mhz
		dw	950

		db	80, 83, CPU66	;83Mhz
		dw	832

		db	71, 75, CPU66	;75Mhz
		dw	750

ifndef	P6_NO_68MHz

		db	68, 68, CPU66	;68.5Mhz
		dw	685
endif;	P6_NO_68MHz

		db	64, 66, CPU66	;66Mhz

		dw	666

		db	57, 60, CPU60	;60Mhz
		dw	600

		db	45, 50, CPU50	;50Mhz
		dw	500

		db	0		;end of table

;Function : Return CPU clock ratio value
;Input    : none
;Output   : SI - point to offset of clock ratio table
GetClkRatio	proc	near


 ifdef	K7_CPU_SUPPORT
		mov	ecx, 0C0010015H		;Hardware Config. Register
		RDMSR				;read MSR
		shr	eax, 24			;get clock ratio in AL bit3-0
		and	ax, 0fH			;only low nibble useful
		mov	si, ax
		add	si, offset P6_ClkRatio
 else;	K7_CPU_SUPPORT

  ifdef	CYRIX_GOBI_SUPPORT
		call	CheckIfGobiCpu		;check if Cyrix Gobi CPU ?
		jnz	short NotGobiCpu	;no

		mov	al,0feh			;DIR 0 register
		out	22h,al
		in	al,23H			;read CPU device ID

		and	ax, 0FH			;use low nibble
		mov	si, ax
		add	si, offset Gobi_ClkRatio;clock ratio table for Gobi
		jmp	short GetClkRatioExit
	NotGobiCpu:
  endif;CYRIX_GOBI_SUPPORT

		mov	ecx, 2AH		;power on config. register
		RDMSR				;read MSR
		shr	eax, 22			;get clock ratio in AL bit3-0
		and	ax, 0fH			;only low nibble useful
		mov	si, ax
		add	si, offset P6_ClkRatio
 endif;	K7_CPU_SUPPORT
	GetClkRatioExit:


		ret
GetClkRatio	endp

		Public	Measure_CPU_Speed
Measure_CPU_Speed	proc	near
;The Pentium Pro, Pentium II and future Intel's CPU have a readable
;clock ratin in MSR register. BIOS use this ration to calculate the host(bus)
;clock and use this clock to calculate real CPU clock.
;Use new algorithm for CPU clock detection if CPU have RDTSC instruction
;(0fh, 31h)
		call	New_CpuClk_Detection	;use new method to check
;		jc	Cpu_NoRdtsc		;CPU clock ?
						;carry set, use old method

		call	GetClkRatio		;read CPU clock ratio

		movzx	cx, byte ptr cs:[si] 	;get clock ratio
		mov	ax, bx
		shl	ax, 1			;multipler by 2
		idiv	cx			;get host clock in AL

	;now AL contains raw host clock
	;look for formal host clock
		mov	di, offset P6_HostClk
NextHostClk:
		cmp	byte ptr cs:[di+HOSTCLK_SIZE],0	;end of host clock table ?
		je	HostClkExit			;yes

		cmp	al, cs:[di]			;match ?
		jae	HostClkExit

		add	di, HOSTCLK_SIZE		;point to next entry
		jmp	NextHostClk
HostClkExit:

	;Record Host clock of P6 in shadow memory for future usage
		extrn	P6HostClock:near
		pushad
		push	ds
		F000_call F000_Shadow_W		;F-segment shadow R/W

		mov	ax, DGROUP		;DS=F000
		mov	ds, ax
		mov	si, offset DGROUP:P6HostClock
		mov	al, cs:[di+1]		;get host clock frequency
		mov	[si], al		;save clock value in shadow

		F000_call F000_Shadow_R		;F-segment shadow Readonly
		pop	ds
		popad

	;Calculate CPU real clock by multipling host clock by clock ratio
		mov	ax, cs:[di+3]		;get factor to calculate clock

		movzx	cx, byte ptr cs:[si]	;get clock ration in /2
		mul	cx
		shr	ax, 1
		add	ax, 5			;for round off
		mov	cx, 10
		idiv	cx

		call	ChkIf_X99Mhz		;Add 1 if x99Mhz

		call	P6ClkByTable		;translate clock by look-up table

		push	G_RAM
		pop	es
		mov	CPU_INT_CLOCK[bp], ax	;actual internal CPU clock
 ifdef	L2ECC_CMOS
  ifdef	KLAMATH_CPU_ONLY


	;Don't turn off L2 ECC if clock is over 333Mhz and allow user
	;to select disable for L2 ECC to get performance benefit
		cmp	ax, 330			;clock 333Mhz and above ?
		jae	Below333

  ifdef	CYRIX_GOBI_SUPPORT
		call	CheckIfGobiCpu		;check if Cyrix Gobi CPU ?
		jz	short Below333		;yes, skip ECC checking
  endif;CYRIX_GOBI_SUPPORT

		;Don't turn ECC off if host clock is 100MHz
		mov	ecx, 2AH		;Power on Config. Reg.
		RDMSR

		test	eax, 0C0000H		;bit 19,18 = 00 : 66Mhz
						;            01 : 100Mhz
						;	     10 : 133Mhz
						;            11 : reserved

		jnz	Below333		;ECC always on

		mov	si, offset L2Ecc_Item
		call	F000_GetItem_Value  	;get CMOS value
		or	al, al			;ECC enabled
		jz	Below333		;yes

		or	byte ptr es:[SYSTEM_FLAG], L2ECC_OFF	;mark flag
Below333:
  endif;	KLAMATH_CPU_ONLY
 endif;	L2ECC_CMOS

		mov	cl, cs:[di+2]	 	;get formal host clock
		mov	byte ptr es:[CPU_CLOCK], cl

  ifdef	KLAMATH_CPU_ONLY

 ifndef	NO_P3_CPU_SNO_SELECT
  ifndef	K7_CPU_SUPPORT
  IF	BIOS_SUPPORT_KLAMATH				;R01
	;Disable setup item if the CPU plugged is not Pentium III .
		call	Read_CpuID		;CPUID instruction
		and	ah, 0FH
		cmp	ax, 0670H		;Pentium III ?
		jae	short Yes_P3Cpu

		push	ds
		push	seg DGROUP
		pop	ds
		ASSUME	CS:EGROUP, DS:DGROUP

		;Disable setup item
		F000_call	F000_Shadow_W
		or	word ptr DGROUP:[PSN_ITEM].ITEMSTAT, ITEMDISABLE
		F000_call	F000_Shadow_R
		pop	ds
	Yes_P3Cpu:

	;Mark Processor Serial Number instruction flag
		mov	si, offset PSN_Item	;PSN setup item
		call	F000_GetItem_Value  	;get CMOS value
		or	al, al			;PSN enabled
		jz	short Psn_On		;yes

		or	byte ptr es:[SYSTEM_FLAG], PSN_OFF	;No CPU serial
	Psn_On:						  	; No. support
  ENDIF	;BIOS_SUPPORT_KLAMATH				;R01
  endif	;K7_CPU_SUPPORT
 endif;	NO_P3_CPU_SNO_SELECT

  endif;	KLAMATH_CPU_ONLY

		clc
		ret
Measure_CPU_Speed	endp

;Function : Increment by one if measured frequency is x99Mhz
;Input    : ax - CPU frequency in Mhz
;Output   : ax - modified CPU frequency
ChkIf_X99Mhz	proc	near

		push	bx
		push	ax		;save original frequency
		mov	bx, 100

Sub100:
		cmp	ax, bx		;value below 100 ?
		jbe	Less100	;yes

		sub	ax, bx		;no, subtract 100 until the value
		jmp	Sub100	;below 100

Less100:
		cmp	al, 99		;x99Mhz ?
		pop	ax		;restore original value
		jne	Not_X99Mhz
		inc	ax		;increment by 1 if x99Mhz
Not_X99Mhz:
		pop	bx

		ret
ChkIf_X99Mhz	endp

;Function : Calculate CPU clock and host clock by pre-define table.
;	    Intel Pentium Pro & II CPUs have clock mode register strapped
;	    by LINT[1], LINT[0], IGNNE# and A20M# during reset. But some
;	    old CPUs only running with lower clock. In this situation, 
;	    the clock register is not match with real clock mode. To fix
;	    problem, BIOS refer to pre-defined table to calculate clock
;	    as 586 did.
;Input  : bx - raw clock value
;	  ax - Clock calculated by CPU clock mode register
;Output : ax - translated CPU clock
;	  cs:[di+2] - host clock pointer
P6ClkByTable	proc	near

		mov	dx, ax		;calculated clock
		push	bx		;save raw clock measured
		cmp	bx, dx 		;real clock is bigger than calculated ?
		jae	NoSwapVal
		xchg	bx, dx
NoSwapVal:
		sub	bx, dx		;clock difference
		cmp	bx, 5		;difference too big ?
		pop	bx		;restore raw clock
		jb	GoodClkMode;CPU clock register is OK

	;Use look-up table to calculate host clock when CPU clock register
	;is wrong
		mov	di, offset P6ClkBelow256	;table below 256MHz
		cmp	bx, 255				;above 256?
		jbe	P6Below_255
		mov	di, offset P6ClkOver256		;table below 256MHz
P6Below_255:
		cmp	byte ptr cs:[di], 0		;end of table
		je	ExitP6ClkTbl

		cmp	bl, cs:[di+1]			;match ?
		jae	TableMatch

		add	di, 3				;next table
		jmp	P6Below_255
ExitP6ClkTbl:
		sub	di, 3
TableMatch:

		mov	ah, bh				;high byte
		mov	al, cs:[di]			;get CPU clock low byte

GoodClkMode:
		ret
P6ClkOver256:
		db	450-256, 450-256-2, 	CPU66	;103x4.5
		db	400-256, 400-256-2, 	CPU66 	;66x6, 103*4
		db	366-256, 366-256-2, 	CPU66 	;66x5.5
		db	352-256, 352-256-2, 	CPU66	;103x3.5
		db	333-256, 333-256-2, 	CPU66 	;66x5
		db	300-256, 300-256-2, 	CPU66 	;60x4.5
		db	266-256, 266-256-2, 	CPU66 	;66x4
		db	0			      	;end of table

P6ClkBelow256:
		db	250, 	246, 	CPU66		;83*3
		db	233, 	228, 	CPU66		;66x3.5
		db	225, 	223, 	CPU66		;75x3
		db	200, 	194, 	CPU66		;66x3
		db	188, 	185, 	CPU66		;75*2.5
		db	166, 	163, 	CPU66		;66x2.5
		db	150, 	147, 	CPU66		;75*2
		db	133, 	128, 	CPU66		;66x2
		db	120, 	118, 	CPU60		;60x2
		db	100,     98,    CPU50		;50x2
		db	0
P6ClkByTable	endp

IF	BIOS_SUPPORT_586 OR BIOS_SUPPORT_686
;[]==============================================================[]
;
;CpuClk_Int08:
;
;	Temporary interrupt service routine for caculating CPU clock
;
;Saves: NONE
;
;Entry: NONE
;Exit:	NONE
;
;[]==============================================================[]
		ALIGN	4
CpuClk_Int08	PROC	NEAR

		push	edx

		db	0fh, 31h			;ReaD Time Stamp Counter
		cmp	dword ptr ds:[4fch], -1		;high 32 bit value
		je	First_Int

		cmp	byte ptr ds:[4f0h], 0aaH	;second INT ?
		je	Finish_Int

		mov	edi, dword ptr ds:[4fch]	;high 32 bit value
		mov	esi, dword ptr ds:[4f8h]	;low 32 bit value

		sub	edx, edi			;high 32-bit value
		sub	eax, esi			;low 32-bit value
		jnc	No_Dec_High32
		dec	edx
No_Dec_High32:
		mov	dword ptr ds:[4fch], edx	;high 32 bit value
		mov	dword ptr ds:[4f8h], eax	;low 32 bit value

		mov	byte ptr ds:[4f0h], 0aaH;mark for second INT
		jmp	Finish_Int

First_Int:
		mov	dword ptr ds:[4fch], edx	;high 32 bit value
		mov	dword ptr ds:[4f8h], eax	;low 32 bit value

Finish_Int:
		pop	edx

		NEWIODELAY
		mov	al, END_OF_INT			; eoi command
		out	a8259, al			; tell controller
		NEWIODELAY

		iret

CpuClk_Int08	ENDP

;-----------------------------------------------------------------
;Input	:	None
;Output :	carry set - this CPU don't have instruction RDTSC
;		carry clear - this CPU have instruction RDTSC and
;		BX : CPU clock detected (0-65535Mhz) return
;Destroy:	use 0:4f8H - 0:4ffH as temporary memory
;-----------------------------------------------------------------
;
New_CpuClk_Detection	proc	near
;use RDTSC to check CPU clock if 586 level CPU
		cli
;		cmp	byte ptr CPU_LEVEL[bp], LEVEL_686
;		je	Yes_Rdtsc
;		cmp	byte ptr CPU_LEVEL[bp], LEVEL_586
;		stc				;assume CPU no counter
;		jne	No_Rdtsc
;
;Yes_Rdtsc:
		xor	edx, edx
		xor	eax, eax		;input value = 1
		mov	ds, ax
		push	dword ptr ds:[4*6]	;save int 06h vector
		mov	word ptr ds:[4*6], offset Temp_Int06
		mov	word ptr ds:[4*6+2], cs

		db	0fh, 31h		;ReaD Time Stamp Counter

		pop	dword ptr ds:[4*6]	;restore int 06h vector

		or	eax, edx		;counter changed ?
		stc				;assume CPU no counter
		jz	No_Rdtsc		;no , this CPU don't have
						;counter

		mov	ax, G_RAM		; seg_0
		mov	ds, ax
		assume	ds:G_RAM

		mov	byte ptr ds:[4f8h], 0	;init flag
		mov	dword ptr ds:[4f8h], 0	;init low dword value
		mov	dword ptr ds:[4fch], -1	;init high dword value

;
;	Move INT 08h vector to a temporary routine
;

		mov	dx, word ptr [int08]	; save vector
		mov	bx, word ptr [int08+2]

		mov	word ptr [int08], offset CpuClk_Int08; tmr isr entry
		mov	word ptr [int08+2], cs	; code segment

;
;	Enable just the timer interrupt
;

		mov	al, 0ffh 		; mask all interrupts on controller 2
		out	B8259+1, al		; tell controller
		NEWIODELAY
		dec	al			; mask all except timer (IRQ 8)
		out	A8259+1, al		; tell controller

;
;	Set up timer 0
;

		mov	al, 36h			; setup timer counter 0
		out	43h, al			; select counter 0
		NEWIODELAY

		xor	ax, ax			; INT every 1/18 seconds
		out	40h, al			; write lsb
		NEWIODELAY
		out	40h, al			; write msb

;
;	Wait for interrupts
;

		xor	ax, ax			; clear interrupt flag
		sti				; enable interrupt
Wait_Irq0:
		cmp	byte ptr ds:[4f0h], 0aaH;second INT occured ?
		jne	Wait_Irq0
		cli				; disable interrupts

;
;	Turn off all of the interrupts
;
		mov	al, 0ffh 		; mask all interrupts
		out	A8259+1, al		; tell controller
		NEWIODELAY

;
;	Restore INT 08h vector
;

		mov	word ptr [int08], dx	; restore old vector
		mov	word ptr [int08+2], bx

;Now , the content of 0:[4f8h] contain counter value
		mov	bx, 1
		mov	eax, dword ptr ds:[4f8h]
		mov	ecx, 55100		;factor to calculate
Next_Div:
		sub	eax, ecx
		jc	short Finish_Div
		inc	bx
		jmp	short Next_Div
Finish_Div:
		clc
No_Rdtsc:
		ret
New_CpuClk_Detection	endp

ENDIF	;BIOS_SUPPORT_586 OR BIOS_SUPPORT_686

;Function : Program MTRR for CPUs like P6 or P55CT
;Input	  : AL = 0 - program MTRR for conventional memory (0-640K)
;	       = 1 - program MTRR for extended memory (1Mb to top of memory)
;	    Bit 7 = 1 - 15-16MB memory hole is disabled(P6 only)
;	    esi - extended memory size
;	    BL = 0 - L2 cache status (0-disabled, 1-enabled)

;	    BH = L2 Cacheable range 000=512Mb , 001=1Gb, 010=2Gb, 011=4Gb
;				    100=8Gb   , 101=16Gb, 110=32Gb, 111=64Gb
;		 only for Pentium II CPUs

;Output   : none
ifdef	Special_Align_for_M1_Clock_unstable

		ALIGN	16
endif;	Special_Align_for_M1_Clock_unstable
		Public	Set_Cpu_MtRR
Set_Cpu_MtRR	proc	near

 ifdef	K7_CPU_SUPPORT
		ret
 endif;	K7_CPU_SUPPORT

;Set 0-640K MTRR for P6 type CPUs

		test	al, 01H		;for base memory ?
		jnz	Set_1MbAbove

;Set A0000-BFFFF as uncache region
		xor	eax, eax 	;set uncache of low 32bit
		mov	edx, eax 	;set uncache of high 32bit
		mov	ecx, 259H	;region for A0000-BFFFF
		WRMSR

;Set C0000-FFFFF as uncache region ( 268H - 26FH )
		mov	cl, 68H		;start from C0000H
SetUc_Nxt32K:
		WRMSR
		inc	cl		;next 32k
		cmp	cl, 6FH		;f8000-fffff ?
		jbe	SetUc_Nxt32K

;Clear all Variable Range MTRRs (200H - 20FH)
		xor	cl, cl		;start from register 200H
Clear_VarMtrr:
		WRMSR
		inc	cl		;next MTRR
		cmp	cl, 0FH		;last MTRR ?
		jbe	Clear_VarMtrr

;Enable write back of 0-640K for P6 CPU
		mov	eax, 06060606H	;set memory type to WB in lower 32bit
		mov	edx, eax 	;higher 32bit
		mov	ecx, 250H	;address(250H) for 0-512K
		WRMSR
		mov	cl, 58H		;address(258H) for 512K-640K
		WRMSR

;Enable caching for memory
		mov	eax, 00000C00h
		xor	edx, edx
		mov	cl, 0ffH 	;address(2ffH) to enable caching
		WRMSR
		jmp	Flush_Cache_TLB

Set_1MbAbove:

		push	ax

;Program C0000-C7FFF to WriteProtect for P6 CPU
		push	ds
		mov	ax, 0c000h	;segment address
		mov	ds, ax
		cmp	word ptr ds:[0], 0aa55h	;video ROM existed ?
		pop	ds
		jne	NoVideoROM;no, no video ROM
					;yes, program MTRR
		mov	eax, 05050505H	;set memory type to WP in lower 32bit
		mov	edx, eax 	;higher 32bit
		mov	ecx, 268H	;for C0000H-C7FFFFH MTRR
		WRMSR
NoVideoROM:

;Qualify cacheable range for Pentium II CPU accroding to BBL_CR_CTL3[22:20]
;Now, the value of this three bits is "000" , that is maximum - 512MB
;We don't know the meaning of other values except "000"
;So, Set 512Mb as maximum cacheable range. One day, if CPU can support
;cacheable range beyond 512Mb , we have to re-write this code.
ifdef	KLAMATH_CPU_ONLY
 ifdef	BOTH_P6_KLAMATH_CPU
		call	Read_CpuID		;get CPU ID
		cmp	al, 30h			;klamath ?
		jb	Below512M		;It's Pentium Pro
 endif;	BOTH_P6_KLAMATH_CPU

;Now, we know the definition of BBL_CR_CTL3[22:20], BIOS need to
;program cacheable range according to this value. But note that this
;value is valid only the L2 cache is initiated.
		mov	edx, 512*1024		;base is 512Mb
		mov	cl, bh			;cacheable range value
		shl	edx, cl			;get maximum cacheable range
		sub	edx, 1024		;maximum extended mem. range
		cmp	esi, edx		;over cacheable range ?
		jbe	GoodCacheRange		;no

		or	bl, bl			;L2 cache disabled ?
		jz	GoodCacheRange		;yes, no range limit

		mov	esi, edx		;set maximum cacheable range
GoodCacheRange:

Below512M:
endif;	KLAMATH_CPU_ONLY

		pop	bx			;restore flag

		mov	eax, esi			;get extended memory size
		or	eax, eax 		;zero size ?
		jz	No_Need_MTRR

		add	eax, 1024		;add 1Mb base address
		shl	eax, 10			;convert to flat address

	;Program 0-Top of Memory as WB(write-back)
		push	bx
		mov	esi, 200H		;MTRRphybas0
		mov	edi, 06H		;start from addr 0 and WriteBack
		call	SetP6MemMtrr		;program MTRR registers;R04
;R04		call	SetP6ExtMemMtrr		;program MTRR registers
		pop	bx

		cmp	eax, 16*1024*1024	;Mem size smaller than 16Mb
		jb	GoSetP6Mtrr

		test	bl, 80H			;15-16Mb memory hole enabled ?
		jz	GoSetP6Mtrr

	;program 15-16MB as UC (Uncached) if memory is enabled
		mov	edi, 15*1024*1024+0	;range 15-16Mb, UC
		mov	eax, 1*1024*1024	;size 1Mb
		call	SetP6ExtMemMtrr		;program MTRR registers

GoSetP6Mtrr:

Only16Mb:

Flush_Cache_TLB:
;Invalidate TLB and flush cache
		WBINVD
		mov	eax, cr3
		mov	cr3, eax 	;Invalidate TLB by loading CR3.
No_Need_MTRR:
		ret

Set_Cpu_MtRR	endp

;R04 - start
;Function : Program MTRR of P6 class CPUs(Pentium Pro & II) according to
;	    memory size
;Input    : esi - starting MTRRbase register
;	    edi - starting base address
;	    di[7:0]  - cache type (00-UC, 06-WB, etc...)
;	    eax - memory size
;Output   : esi - next MTRR register to program
SetP6MemMtrr	proc	near
	;Algorithm for MTRR cacheability registers programming are :
	; 1. Use positive method if 2-3 significant bits in mem. size
	;    for example : 16 MBytes = 1000000H --> one bit
	;			1st MTRR = 16MB at address 0000000H with WB
	;		   24 MBytes = 1800000H --> two bits
	;			1st MTRR = 16MB at address 0000000H with WB
	;			2nd MTRR = 8MB  at address 1000000H with WB
	; 2. Use subtractive method if 4 significatn bits in mem. size
	;    for example : 15 MBytes = 0F00000H --> four bits
	;			1st MTRR = 16MB at address 0000000H with WB
	;			2nd MTRR = 1MB  at address 0F00000H with UC
	;		   14.5MBytes= 0E80000H --> four bits
	;			1st MTRR = 16MB at address 0000000H with WB
	;			2nd MTRR = 1MB  at address 0F00000H with UC
	;			3rd MTRR = 0.5MB at address 0E8000H with UC

		push	eax			;save memory size
		mov	dh, 32
		xor	dl, dl			;zero count of bit is 1's
		mov	cx, 16			;check A31-A16
	ChkBitOne:
		rol	eax, 1			;check bit value
		jnc	short RollNextBit	;bit set ?

		inc	dl			;yes, increment count value
		jmp	short NextBitRoll

	RollNextBit:

		or	dl, dl			;first 1's met ?
		jnz	short NextBitRoll

		dec	dh

	NextBitRoll:
		loop	short ChkBitOne		;loop to check next bit value
		pop	eax			;restore memory size

		push	eax
		cmp	dl, 4			;four bits with value "1" ?
		jb	short PositiveMTRR	;positive MTRR programming
		
		mov	cl, dh
		mov	ebx, 1
		shl	ebx, cl			;get round off value

		xchg	ebx, eax
		push	ebx
		call	SetP6ExtMemMtrr		;eax = size, edi = address
		pop	ebx

		sub	eax, ebx		;ebx = size to set for UC
		mov	edi, ebx		;starting address for UC

;R04A - start
		mov	cx, 32			;check A31-A0
		mov	ebx, -1

Next_Addr_Bit0:

		ror	eax, 1
		jnc	NotBitSet

		call	Set_Mtrr_Base
NotBitSet:

		shl	ebx, 1

		loop	Next_Addr_Bit0		;next address bit to check
		jmp	SetP6MemMtrrExit
;R04A - end

	PositiveMTRR:
		call	SetP6ExtMemMtrr		;eax = size, edi = address
	SetP6MemMtrrExit:			;R04A
		pop	eax
		ret
SetP6MemMtrr	endp
;R04 - end

;Function : Program MTRR of P6 class CPUs(Pentium Pro & II) according
;	    memory size
;Input    : esi - starting MTRRbase register
;	    edi - starting base address
;	    di[7:0]  - cache type (00-UC, 06-WB, etc...)
;	    eax - memory size
;Output   : esi - next MTRR register to program
SetP6ExtMemMtrr	proc	near
		push	eax			;save memory size

		mov	cx, 16			;check A31-A16
		xor	ebx, ebx 		;start from MTRR mask 0

Next_Addr_Bit:

		or	bl, 1			;set mask bit
		ror	ebx, 1

		rol	eax, 1
;R04A		jc	Set_Mtrr_Base
		jnc	short NoMtrrSet		;R04A
		call	Set_Mtrr_Base		;R04A
	NoMtrrSet:				;R04A

		loop	Next_Addr_Bit		;next address bit to check

		pop	eax			;restore memory size

		ret				;end of MTRR programming
SetP6ExtMemMtrr	endp				;R04A

Set_Mtrr_Base:
		push	eax
		push	ecx

		mov	ecx, esi 		;address of MTRR
		mov	eax, edi 		;memory type

		xor	edx, edx 		;top 32bit of MTRR
		WRMSR

		inc	ecx			;address mask of MTRR
		mov	edx, 0FH			;mask bit for A35-A32
		mov	eax, ebx
		or	ah, 08H			;enable valid bit
		WRMSR

	;setup next base address by examine mask address
		xor	eax, eax
		mov	al, 1
		mov	ecx, ebx

NextShift_Bit:

		ror	ecx, 1
		jc	Shift_Ok

		shl	eax, 1
		jmp	NextShift_Bit
Shift_Ok:
		add	edi, eax

		pop	ecx
		pop	eax

		inc	si			;next base address
		inc	si			;next base address
		ret				;R04A
;R04A		jmp	Next_Addr_Bit
;R04A
;R04ASetP6ExtMemMtrr	endp

;Function : return current CPU L2 cacheable range
;Input    : none
;Output   : bh - cacheable range
		public	P2_L2_CacheRange
P2_L2_CacheRange	proc	near
 ifdef	K7_CPU_SUPPORT
		mov	bh, 011B		;4GB cache range
 else;	K7_CPU_SUPPORT
		mov	ecx, 11EH   		;BBL_CR_CTL3 control reg. 3
		RDMSR
		shr	eax, 20	   		;L2 cacheable range bit[22-20]
		and	al, 111b	   	;3 bits valid
		mov	bh, al	   		;cacheable range in BH
 endif;	K7_CPU_SUPPORT
		ret
P2_L2_CacheRange	endp

;Function : Program 1st CPU's MTRR
;Input    : bh - cacheable range
;Output   : none
		public	Prg_1stCpu_Mtrr
Prg_1stCpu_Mtrr	proc	near

	;Don't access CTL3 (11EH) if Pentium Pro is used, otherwise CPU hang
		call	Read_CpuID		;get CPU ID
		cmp	al, 30h			;Pentium II ?
		jb	NotPentiumII	; skip reading CTL3 for Pentium Pro

	;No cacheable range limit if Cavington CPU plugged
	        mov     ecx, 11EH		;L2 control register 3 (CTL3).
        	RDMSR
		xor	bl, bl			;assume L2 is disabled
	        test    eax, 00800000h		;hardware disable bit 23.
		jnz	NoP2L2cache		;CPU without L2 cache
NotPentiumII:

		mov	si, offset ExtCache_Item;get CMOS status of L2 cache
		call	F000_GetItem_Value
		mov	bl, al			;for Set_Cpu_Mtrr use
NoP2L2cache:

		F000_CALL Ct_MemHole_Status	;get 15-16MB memory hole status
		or	al, al			;memory hole enabled ?
		mov	al, 1			;program MTRR without hole
		jz	MemHoleDisabled
		or	al, 80H			;mark memory hole enabled
MemHoleDisabled:

		mov	esi, EXT_MEM_SIZE[bp]	;extended memory size

		call	Set_Cpu_MtRR

		ret
Prg_1stCpu_Mtrr	endp

 ifdef	MP_SUPPORT
;Function : Program 2nd CPU's MTRR
;Input    : bh - cacheable range
;Output   : none
Prg_2ndCpu_Mtrr	proc	near

		xor	ax, ax
		mov	ds, ax			;segment
		mov	esi, dword ptr ds:[50CH];get extended memory size

		mov	bl, ds:[502h]		;get L2 CMOS status
						;bl = L2 cache status

		mov	al, 1			;program cache address
		call	Set_Cpu_MtRR		;for above 1Mb
		ret
Prg_2ndCpu_Mtrr	endp
 endif;	MP_SUPPORT

ifdef	MP_SUPPORT
		public	Init_Mtrr
Init_Mtrr	proc	far

		xor	al, al			;program cache address
		call	Set_Cpu_MtRR		;for 0-640k

		xor	bh, bh			;assume 512Mb max.
		call	Prg_2ndCpu_Mtrr		;program MTRR

		call	P6_BiosUpdate		;update P6 patch codes

ifdef	KLAMATH_CPU_ONLY

		call	ConfigurePProL2Cache

	;We get L2 maximum cacheable range after L2 initialization
	;Re-program MTRR if the maximum cacheable range is not 512Mb only
	;and we also need to choice the smallest cacheablity with different
	;cacheable range of multi-processor.

		call	P2_L2_CacheRange	;get L2 Max. Cacheable Range

		xor	ax, ax			;get 1st CPU's range
		mov	ds, ax
		cmp	bh, byte ptr ds:[4FFH] 	;which CPU's range is bigger
		jb	FirstCPUBigger

		mov	al, bh			;swap bh
		xchg	byte ptr ds:[4FFH], al 	;Choice small range for 1st
						;CPU to set MTRR again
		mov	bh, al
FirstCPUBigger:
		or	bh, bh			;512Mb Max. Cacheable Range?
		jz	NoRe_Program

		call	Prg_2ndCpu_Mtrr		;program MTRR
NoRe_Program:

endif;	KLAMATH_CPU_ONLY

;Disable second CPU L2 cache if CMOS disable it.

		xor	ax, ax
		mov	ds, ax			;segment

		mov	bl, ds:[502h]		;get L2 CMOS
		or	bl, bl			;L2 cache disabed
		jnz	CpuL2Enabled

		mov	al, False		;disable L2 cache
		call	P6_L2Cache_Control
		jmp	Set_CpuL2_Done
CpuL2Enabled:

		mov	al, True			;Enable L2 cache
		call	P6_L2Cache_Control
Set_CpuL2_Done:

		ret

Init_Mtrr	endp
endif;	MP_SUPPORT

		Public	P6_BiosUpdate
P6_BiosUpdate	proc	near
;Execute BIOS Update data to fix P6 bugs

ifdef	CYRIX_GOBI_SUPPORT
 ifndef	K7_CPU_SUPPORT
		call	CheckIfGobiCpu		;check if Cyrix Gobi CPU ?
		jz	short No_Patch_Data	;skip ucode update if Gobi CPU
 endif;	K7_CPU_SUPPORT
endif;	CYRIX_GOBI_SUPPORT

	;Now , read CPU ID , don't execute BIOS Update data if mismatch
		mov	eax, 1			;eax = 1 to read CPU ID
		db	0fh, 0A2h		;CPU ID instruction

ifdef	FLASH_SUPPORT

;----- Check P6 updata micro code is match or not for current CPU ID -----
		mov	bx, 2000h
		mov	ds, bx
		mov	bx, P6_Block_Start_Seg
		cmp	ax, word ptr ds:[bx].Processor_Version

 ifdef	SUPPORT_SLOT1_AND_SLOT2
		jne	short ChkNextMicroCode0	;CPUID not match

		call	CheckMatchCPUType	;check if right CPU slot ?
		je	short Go_Patch		;yes, load the micro code

 ChkNextMicroCode0:
 else;	SUPPORT_SLOT1_AND_SLOT2
		je	short Go_Patch		;yes patch it
 endif;	SUPPORT_SLOT1_AND_SLOT2

ifdef	MP_SUPPORT
		mov	bx, P6_Sec_Block_Start_Seg
		cmp	ax, word ptr ds:[bx].Processor_Version
		je	Go_Patch		;yes patch it
endif	;MP_SUPPORT
;-------------------------------------------------------------------------
endif	;FLASH_SUPPORT

;----- Check P6 default micro code is match or not for current CPU ID -----

		push	eax
		mov	di, (MicroCode_Expand_Address+1)*4
		call	POST_decompress
		pop	eax

		jc	No_Patch_Data

		shr	ebx, 11			;compressed data in 2Kb unit
		mov	ecx, ebx		;No. of u-code to search

		mov	bx, Temp_CBROM_Segment
		mov	ds, bx
		xor	bx, bx

Check_Next_P6:
		cmp	ax, word ptr ds:[bx].Processor_Version

 ifdef	SUPPORT_SLOT1_AND_SLOT2
		jne	short ChkNextMicroCode	;CPUID not match

		call	CheckMatchCPUType	;check if right CPU slot ?
		je	short Go_Patch		;yes, load the micro code

 ChkNextMicroCode:
 else;	SUPPORT_SLOT1_AND_SLOT2
		je	short Go_Patch		;yes patch it
 endif;	SUPPORT_SLOT1_AND_SLOT2

		add	bx, 800h

		loop	Check_Next_P6
		jmp	No_Patch_Data

Go_Patch:

if	STR_function	EQ	1
	;Copy 2Kb micro code into SMmemory in order to patch CPU after
	;resuming from "Suspend To RAM(STR)".
		pusha
		push	es
		push	ds

		call	CT_OPEN_SM_RAM

		mov	si, bx			;micro code source address

		call	Get_SMBASE_ADD  	;get destination address

		shr	eax, 4
		mov	es, ax  	  	;destination segment address
		mov	di, offset P6_Microcode_Save
		mov	cx, 800h/4	       	;Restore 2K
		rep	movsd			;Move codes

		call	CT_CLOSE_SM_RAM

		pop	ds
		pop	es
		popa
endif	;STR_function	EQ	1

 ifdef	K7_CPU_SUPPORT
	;K7 Microcode patch
		mov	ecx, 0C0010020H		;patch loader MSR
		xor	eax, eax
		mov	ax, ds
		shl	eax, 4			;segment of data
		add	bx, 40			;point to data area
		mov	ax, bx
		WRMSR
 else;	K7_CPU_SUPPORT

		mov	ecx, 79H		;CPU register
		xor	eax, eax
		xor	edx, edx
		mov	ax, ds

		shl	eax, 4			;segment of data

		add	bx, 48			;point to data area
		mov	ax, bx
		WRMSR
 endif;	K7_CPU_SUPPORT
No_Patch_Data:

		ret
P6_BiosUpdate	endp

 ifdef	SUPPORT_SLOT1_AND_SLOT2
;
;Function : Check if the current micro code's CPU type match with current
;	    CPU to be executed with micro code patch. This routine only
;	    be used for platform that support both SLOT1 & SLOT2 CPUs.
;Input    : DS:BX = pointer of micro code
;Output   : zero set = CPU match with micro code
;	    non-zero = CPU not match with micro code
;
CheckMatchCPUType	proc	near

		pushad			;save all registers

		mov	ecx, 17H	;BBL_CR_OVRD MSR register
        	RDMSR			;read MSR register value in EDX:EAX

		shr	edx, 18		;bit 52:50 means 000 - Slot 1 CPU
					;		 001 - Mobile CPU
					;		 010 - Slot 2 CPU
					;		 011 - Mobile CPU
		and	dl, 111B	;take 3 bits
		mov	cl, dl

		mov	al, 1 		;get bit set position
		shl	al, cl		;bit conversion

	;Note : the "Product" byte in CPU micro code for Slot 1 CPU have two
	;	kinds of value "00" & "01"
		mov	ah, Byte Ptr ds:[bx].Reserved 	;CPU type in micro code
					;Byte 24 bit 0  - Slot 1 CPU if "1"
					;	 bit 1	- Mobile CPU if "1"
					;	 bit 2	- Slot 2 CPU if "1"
					;	 bit 3	- Mobile CPU if "1"
		cmp	al, 100B	;slot 2 CPU ?
		je	short ChkSlot2

	;for Slot 1 & other CPUs checking
	;Note : The product value in micro code is either "00"(old u-code) or
	; "01"(new u-code)
		or	ah, ah		; product ID = 0 ?
		jz	short RightMCode

ChkSlot2:
		cmp	al, ah		;"product" ID match ?
RightMCode:
		popad			;restore all registers
		ret

CheckMatchCPUType	endp
 endif;	SUPPORT_SLOT1_AND_SLOT2

		Public	Enable_M1_FarHit
Enable_M1_FarHit	proc	near
		ret
Enable_M1_FarHit	endp

		public	F000_Set_Cyrix
F000_Set_Cyrix	Proc	Near
		F000_Call Set_Cyrix
		ret
F000_Set_Cyrix	Endp

F000_Get_Cyrix	Proc	Near
		F000_Call Get_Cyrix
		ret
F000_Get_Cyrix	Endp

ifdef	KLAMATH_CPU_ONLY
 ifdef	K7_CPU_SUPPORT
		include	K7L2cach.inc
 else;	K7_CPU_SUPPORT
		include	P6L2cach.inc
 endif;	K7_CPU_SUPPORT
endif;	KLAMATH_CPU_ONLY

;[]========================================================================[]
;Name	  :	Prg_K5_Write_Allocate
;
;Function :	To enable the AMD K5 CPU's write allocation function
;
;Input	  :	dword ptr EXT_MEM_SIZE[bp] in terms of 1K
;
;Output	  :	None
;[]========================================================================[]
		Public	Prg_K5_Write_Allocate
Prg_K5_Write_Allocate	Proc	Near

		ret

Prg_K5_Write_Allocate	Endp

ECODE		ENDS

ENDIF	;COMPILE_FOR_E0

IFE     COMPILE_FOR_E0

		extrn	F000_call_proc:near
		extrn	Ct_MemHole_Status:Near
		extrn	F000_Shadow_W:Near
		extrn	F000_Shadow_R:Near

 ifndef	No_need_videocache
		extrn	VideoCache_Item:near
 endif;	No_need_videocache
 ifdef	SEPARATE_P6_VIDEO_ITEM
		extrn	VideoRom_Item:near
 endif;	SEPARATE_P6_VIDEO_ITEM

		extrn	F000_GetItem_Value:near

		extrn	F000_Display_Char:Near
		extrn	F000_Display_String:Near

		extrn	DISPLAY_CS_STRING:Near
		extrn	SYSCFG_CPU_CLOCK1:Near

		extrn	fProc_Disp_Word_Int3:far
		extrn	fProc_Disp_Byte_Int2:far
		extrn	X_Display_Char:near
		extrn	X_Display_CS_String:near

.LIST
EGROUP		GROUP	ECODE
ECODE		SEGMENT USE16 PARA PUBLIC 'ECODE'
		ASSUME	CS:EGROUP, DS:G_RAM, ES:EGROUP

;Function : return cache size in AL for display
;Input    : DL - CPU register value to indicate cache size
;		 40H - No L2 cache
;		 41H - 128K
;		 42H - 256K
;		 43H - 512K
;		 44H - 1Mb
;		 45H - 2Mb
;Output   : AL - cache size for BIOS to display
;           AL -  0 = 0K, 1=16K , 2=32K , 3=64K , 4=128K , 5=256K
;	          6 =512K, 7=1024K , etc...
		Public	Convert_P6L2_Cache
Convert_P6L2_Cache	proc	near
 ifdef	K7_CPU_SUPPORT

        	mov     eax, 80000006h           ;read L2 cache
        	db	0Fh, 0A2h
        	shr     ecx, 16			;now cx is size of L2 cache
						;cx=200H means size is 512Kb
		xor	al, al			;assume no L2 cache
ChkL2CacheBit:
		or	cx, cx			;no L2 cache
		jz	short K7L2SizeExit
		inc	al
		shr	cx, 1			;next bit
		jmp	short ChkL2CacheBit
K7L2SizeExit:
		or	al, al
		jz	short NoK7L2Cache
		sub	al, 4
NoK7L2Cache:

 else;	K7_CPU_SUPPORT

		xor	al, al			;assume no L2 cache
		cmp	dl, 40H			;no L2 cache(40H) ?
		jbe	P6L2Cache_Exit

		mov	al, dl
		sub	al, (41H-4)		;cache size(41H=128K)
P6L2Cache_Exit:

 endif;	K7_CPU_SUPPORT

		ret

Convert_P6L2_Cache	endp

;=============================================================================
;FUNC:	CPU_DISPLAY
;
;DESC:	Returns the length and description string for the CPU.
;
;IN:	NONE
;OUT:	CS:SI	String pointer
;
;SAVES:	DX
;=============================================================================
		PUBLIC	CPU_DISPLAY
CPU_DISPLAY	PROC	Near

		mov	si, offset Cpu_P6_Str	;P6 class CPU	;R03

 ifndef	K7_CPU_SUPPORT


ifdef	KLAMATH_CPU_ONLY

		call	Read_CpuID		;get CPU ID
		cmp	al, 06Ah
		jne	short Not_Dixon
if	P6_MOBILE_UCODE	EQ	1
	extrn	ConfigurePProL2Cache:near
		Call	ConfigurePProL2Cache
		mov	eax, 2
		db	0Fh, 0A2h

		cmp	dl, 042h
		jne	short YesMendocino
endif	;P6_MOBILE_UCODE	EQ	1
		mov	si, offset MobileDixon
		jmp	short Not_Cavington
	Not_Dixon:
		and	al, 11110000b		;mask stepping
		cmp	al, 60H			;066XH ?
		je	YesMendocino

	        mov     ecx, 11EH	        ; L2 control register 3 (CTL3).
		RDMSR
	        and     eax, 00800000h          ; CTL3, hardware disable bit 23.
	        jz      Not_Cavington
YesMendocino:
		mov	si, offset CeleronStr
Not_Cavington:
endif;	KLAMATH_CPU_ONLY

		call	Read_CpuID		;get CPU ID
		cmp	al, 30h			;klamath ?
		jae	Not_P6Cpu
		mov	si, offset Cpu_Ppro_Str	;it's PENTIUM PRO CPU
Not_P6Cpu:

 endif;	K7_CPU_SUPPORT

Cpu_Str_Ok:

		ret

CPU_DISPLAY	ENDP

;-------------------------- 686 CPU Strings --------------------------

 ifdef	K7_CPU_SUPPORT
	Cpu_P6_Str:		db	"K7(tm)", 0
 else;	K7_CPU_SUPPORT

	Xeon_Str		db	"I XEON(tm)", 0
  ifdef	KLAMATH_CPU_ONLY

	Cpu_P6_Str:		db	"PENTIUM II", 0
	CeleronStr:		db	"INTEL(R) CELERON(TM)", 0

	MobileDixon		db	"Mobile Pentium II", 0

 	Cpu_Ppro_Str:		db	"PENTIUM PRO", 0

  else;	KLAMATH_CPU_ONLY

	Cpu_P6_Str:		db	"PENTIUM II", 0
 	Cpu_Ppro_Str:		db	"PENTIUM PRO", 0
  endif;KLAMATH_CPU_ONLY
endif;	K7_CPU_SUPPORT

;Function : Enable/Disable P6 L2 cache
;Input    : AL = TRUE  - enable L2 cache
;	       = FALSE - disable L2 cache
		Public	P6_L2Cache_Control
P6_L2Cache_Control	proc	near
		pushad

ifdef	K7_CPU_SUPPORT
else;	K7_CPU_SUPPORT

ifdef	KLAMATH_CPU_ONLY

 ifdef	BOTH_P6_KLAMATH_CPU
 		push	ax
		call	Read_CpuID		;read CPU ID
		cmp	al, 30H			;Klamath ?
		pop	ax
		jae	Yes_Klamath

;L2 cache control for PENTIUM PRO CPU
		mov	bl, al
		mov	ecx, 119h
		RDMSR
		and	eax, NOT (1 SHL 19)	;assume L2 enable
		cmp	bl, TRUE
		je	Yes_EnablePpro
		or	eax, (1 SHL 19)		;disable L2 cache
Yes_EnablePpro:
		WRMSR
		jmp	L2CacheExit
 Yes_Klamath:
 endif;	BOTH_P6_KLAMATH_CPU

;L2 cache control for KLAMATH CPU
		mov	bl, al
		mov	ecx, 11eh
		RDMSR
		or	eax, (1 SHL 8)		;assume L2 enable
		cmp	bl, TRUE
		je	Yes_Enable
		and	eax, NOT (1 SHL 8)	;disable L2 cache
Yes_Enable:
		WRMSR
else;	KLAMATH_CPU_ONLY
;L2 cache control for PENTIUM PRO CPU
		mov	bl, al
		mov	ecx, 119h
		RDMSR
		and	eax, NOT (1 SHL 19)	;assume L2 enable
		cmp	bl, TRUE
		je	Yes_Enable
		or	eax, (1 SHL 19)		;disable L2 cache
Yes_Enable:
		WRMSR
endif;	KLAMATH_CPU_ONLY
endif;	K7_CPU_SUPPORT
L2CacheExit:

		popad
		ret
P6_L2Cache_Control	endp

;[]=================================================================[]
;Procedure   :	Disp_Extra_CPU_Info
;Input	     :	None
;Ouput	     :	None
;Description :	If CPU Type:
;
;		. PENTIUM PRO & PENTIUM
;
;		   IF   ODP CPU show 'ODP-S' on screen
;		   IF   MMX CPU show 'MMX' on screen
;		   IF   ODP-MMX CPU show 'ODP-MMX' on screen
;		   ELSE show '-S' on screen to indicate SMI
;
;		. Cyrix 6x86L CPU
;
;		  Append a 'L' to '6x86'
;
;		. Other CPUs
;
;		  show '-S' on screen to indicate SMI
;
;[]=================================================================[]
		public	Disp_Extra_CPU_Info
Disp_Extra_CPU_Info	Proc	Near

 ifdef	FOR_SLOT2_CPU
	;Show "Pentium III Xeon" for slot 2 CPU
		mov	ecx, 17H	;BBL_CR_OVRD MSR register
        	RDMSR			;read MSR register value in EDX:EAX
	;Note : This instruction is not implemented in 063x CPU and will
	;	cause system hang up.

		shr	edx, 18		;bit 52:50 means 000 - Slot 1 CPU
					;		 001 - Mobile CPU
					;		 010 - Slot 2 CPU
					;		 011 - Mobile CPU
		and	dl, 111B	;take 3 bits
		cmp	dl, 010B	;slot 2 CPU(Xeon) ?
		jne	short NotSlot2Cpu
		mov	si, offset Xeon_Str	;show extra "I Xeon"
		call	Display_CS_String
		jmp	short Not_Pentium_III
	NotSlot2Cpu:
 endif;	FOR_SLOT2_CPU

		call	Read_CPUID
		and	al, 0F0h

		cmp	al, 70h
		jb	Not_Pentium_III
		mov	al, 'I'
		call	F000_Display_Char
Not_Pentium_III:

;---------------------------------------------------------------
; Display CPU type as "6x86L" if the revision number is 20h-2fh, 
; regular 6x86 is 00h-1fh
;---------------------------------------------------------------

;---------------------------------------------------------------
; Show -MMX & -ODP for all 586 or above CPU
;---------------------------------------------------------------
IF	BIOS_SUPPORT_586 OR BIOS_SUPPORT_686

		call	Read_CpuID		;read CPU ID
		and	ah, 0f0H		;get CPU type
		cmp	ah, 010H		;override drive processor
		jne	Not_Odp

		mov	si, offset Odp_String	;ODP string
		call	Display_CS_String

	Not_Odp:
		cmp	al, 06ah
		je	No_ODP_MMX
		jmp	Disp_S_CPU_Exit	;skip "-S" display

No_ODP_MMX:
ENDIF	;BIOS_SUPPORT_586 OR BIOS_SUPPORT_686

;-------------------------------------------------------
;Try to skip '-S' for all AMD & Cyrix 586 level CPU
;-------------------------------------------------------

;-------------------------------------------------------
; This is for special customer
; If the CPU is Cyrix then don't show S-serial
;-------------------------------------------------------

;-------------------------------------------------------
; Display '-S' on screen
;-------------------------------------------------------

Disp_S_CPU_Exit:

		ret

Disp_Extra_CPU_Info	Endp

;Function : Read CPU ID
;Input    : none
;Output   : EAX - CPU ID information
;	    EDX - CPU features
		Public	fPROC_Read_CpuID
fPROC_Read_CpuID	PROC	FAR
		call	Read_CpuID
		ret
fPROC_Read_CpuID	ENDP
		Public	Read_CpuID
Read_CpuID	proc	near
		push	ebx
		mov	eax, 1			;read cache isze
		db	0Fh, 0A2h		;OP code: CPUID
		pop	ebx
		ret
Read_CpuID	endp

ifdef	CYRIX_GOBI_SUPPORT
;
;Function : Check if Cyrix Gobi CPU 
;Input    : none
;Output   : zero set - it's a Cryix Gobi CPU
;	    non-zero - Not a Cryix Gobi CPU
		public	CheckIfGobiCpu
CheckIfGobiCpu	proc	near

		pushad
		xor	eax, eax
		db	0Fh, 0A2h		;OP code: CPUID

		cmp	ebx, 'iryC'		;Cyrix CPU's identifier
		popad

		ret
CheckIfGobiCpu	endp
endif;	CYRIX_GOBI_SUPPORT

Odp_String		db	' ODP', 0

;[]=================================================================[]
;Input	:	DI = 1 --> show P-Rating with '-'
;		DI = 0 --> show P-Rating without '-'
;
;Output	:	NC - Show P-Rating successfully
;		CF - Show P-Rating not successful
;[]=================================================================[]
		Public	Try_Show_PRating
Try_Show_PRating	Proc	Near
		stc		;defaut no show P-Rating
		ret
Try_Show_PRating	Endp

;Function : Program USWC for P6-class CPU according user's CMOS select
;Input    : none
;Output   : none
		public	Prg_P6_USWC
Prg_P6_USWC	proc	near

ifdef	SEPARATE_P6_VIDEO_ITEM
		mov	si, offset VideoRom_Item
		call	F000_GetItem_Value
		or	al, al			;video ROM cache enabled ?
		jz	NoVideoRomCache

;Set C0000-C7fff region cacheability to Write Protect (WP).
 		mov	ecx, 268H   	;address(268H) for C0000-C8000
 		mov	edx, 05050505H	;set memory type to WP in higher 32bit
		mov	eax, edx
 		WRMSR

NoVideoRomCache:
endif;	SEPARATE_P6_VIDEO_ITEM

;Set A0000-BFFFF region cacheability according to CMOS setup
 ifndef	No_need_videocache
		mov	si, offset VideoCache_Item
		call	F000_GetItem_Value
		xor	edx, edx		;assume UC

		or	al, al			;video cache enabled ?
		jz	UnCache_Video
 else;	No_need_videocache
		xor	edx, edx		;assume UC
		jmp	UnCache_Video
 endif;	No_need_videocache

ifndef	SEPARATE_P6_VIDEO_ITEM
;Set C0000-C8000 region cacheability to Write Protect (WP).
 		mov	ecx, 268H   	;address(268H) for C0000-C8000
 		mov	edx, 05050505H	;set memory type to WP in higher 32bit
		mov	eax, edx
 		WRMSR
endif;	SEPARATE_P6_VIDEO_ITEM

		mov	di, offset VideoCard_Tbl

Check_NextCard:
		mov	dx, cs:[di]		;get vendor ID
		mov	cx, cs:[di+2]		;get device ID
		or	dx, dx			;end of table ?
		jz	Go_USWC

		xor     si, si			;first device
		mov     ax, 0b102H		;find PCI device func. call
		int     1AH

		jnc     CardTo_Check
		add	di, 6			;next card to check
		jmp	Check_NextCard

CardTo_Check:
		mov	ax, cs:[di+4]		;get qualify routine to run
		call	ax
		jnc	No_CacheVideoRam

Go_USWC:
 		mov	edx, 01010101H	;set memory type to WB in higher 32bit

UnCache_Video:
 		mov	ecx, 259H	;address(259H) for A0000-BFFFF
		xor	eax, eax	;set A0000-AFFFF always UC
 					;set B0000-BFFFF according to setup
 		WRMSR

No_CacheVideoRam:

		ret
Prg_P6_USWC	endp

VideoCard_Tbl:		;vendor  device
		dw	100CH	, 3208H		;ET6000
		dw	offset NoQualify_Rev

		dw	1142H	, 6424H		;Aliance 6424
		dw	offset Ali6424_Rev

		dw	0			;end of table

;Input  : none
;Output : carry clear - always disable USWC
;	  carry	set   - USWC is allowed
NoQualify_Rev	proc	near
		clc				;always disable USWC
		ret
NoQualify_Rev	endp

;Input  : none
;Output : carry clear - always disable USWC
;	  carry	set   - USWC is allowed
Ali6424_Rev	proc	near
;Only revision of 6424 is not allowed for USWC
		push	di
		mov	ax, 0b108h		;read PCI byte
		mov	di, 08H			;revision reg.
		int	1aH
		pop	di
		or	cl, cl			;revision = 00H
		clc
		jz	No_6424Uswc		;yes , no video buffer cache
	    	stc				;USWC is allowed
No_6424Uswc:
		ret
Ali6424_Rev	endp

ECODE		ENDS

;;;;; XGROUP		GROUP	XCODE
;;;;; XCODE		SEGMENT USE16 PARA PUBLIC 'XCODE'
;;;;; 		ASSUME	CS:XGROUP, ES:XGROUP
;;;;; XCODE		ENDS

ENDIF	;COMPILE_FOR_E0

