;	[]===========================================================[]
;
;	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.
;
; 	[]===========================================================[]
;

;=============================================================================
; FILE: DMI_FUNC.INC
;
; DESC: DMI function support.  Please refer to the DMI BIOS Specification
;       Version 2.0 for complete information on each of these functions.
;
;
; BY:         Tim Markey
; DATE:       12/20/95
; NOTE:       This code is written for 5.10 MASM so that it can be used 
;             by both Award PowerBIOS and EliteBIOS with no modifications.
;
;=============================================================================
;Rev  Date     Author Description
;--------------------------------------------------------------------------
;R45  02/26/99 BAR    Support 32bit address to update Flash.
;R44B 02/12/99 STV    Fixed "Clear DMI EVENT LOG POOL" func.
;R38C 02/11/99 STV    Fixed 51h in PROT_MODE return data error.
;R44A 02/04/99 KVN    Fixed DMI function 54h error in POST
;R44  02/03/99 BAR    Support Flash_Part_Erase .
;R43  12/29/98 STV    Add func 52h Command(06h) - A block of information
;R38B 10/22/98 STV    Fixed run LDCM3.10 before reboot in post cmos checksum 
;		      error when have post error in event log.
;R38A 10/12/98 STV    Fixed SMBIOS V2.1 for LDCM in memory lost one DIMM.
;R42  10/09/98 STV    Fixed function 54h for clear event log.Only clear shadow
;		      pool not clear flash pool.
;R41  09/29/98 KVN    Release DMI and ESCD pool in flash ROM when not define
;		      "ESCD_SUPPORT" and "FLASH_SUPPORT" in BIOS.CFG
;R40  09/16/98 STV    Added define "SMBIOS_SUPPORT_VER" EQU for SMBIOS VER.
;R37F 09/15/98 KVN    Fixed coding mistake by R37E.That will cause system still
;		      hang in TESTVIEW.EXE program running
;R39  09/15/98 STV    Added SMBIOS 2.2 for define "SMBIOS_V22_Support"
;R38  09/02/98 STV    Fixed SMBIOS 2.1 for LDCM3.3 in NT not work.
;R37E 08/24/98 KVN    Fixed coding mistake by R37A.That will cause system hang
;		      during exeute TESTVIEW.EXE program(offer by GVC)
;R37D 08/14/98 KVN    Cancel last POST error type of GPNV when GPNV pool is full
;		      and new error is occur and to be store
;R37C 08/10/98 STV    Fixed R14 DMI_MAX_POOL_SIZE Define size
;R37B 06/30/98 STV    Fixed R37A save DMI Eveny Log error code not error 
;		      code string address.
;R30C 06/25/98 KVN    Return function successfully when function 54h of subfunction
;		      is 4000h-7fffh and control bit is 1.That to fixed OEMDMI.EXE
;		      utility write fail problem (issue by microstar)
;R37A 06/16/98 STV    1.Added DMI_GPNV_Support definition(DMI func 54h).
;		      2.Fixed DMI func 55h,56h,57h.
;R30B 05/28/98 STV    Fixed R30A the force support change to function 54h,
;		      definition "DMI_func54h_Force_Enable" not DMI_func55h_Force_Enable
;=============================================================================

.386P
    INCLUDE BIOS.CFG
    INCLUDE COMMON.EQU
    include bsetup.inc				
    INCLUDE PNP.EQU
    include dmi.equ
ifdef   DMI_ENABLED
ifdef	FLASH_SUPPORT	;R41
    extrn  F000_Shadow_W:Near    
    extrn  F000_Shadow_R:Near    
	extrn  Flash_Write:near	
DGROUP    GROUP  FCODE
FCODE    SEGMENT USE16 PARA PUBLIC 'CODE'	
    ASSUME  CS:DGROUP,DS:NOTHING

ifndef MASM611
  extrn  Get_CMOS:near
  extrn  Flash_Read:near
  extrn  Flash_Write:near
endif

;R37A start
ifdef	DMI_GPNV_support
  extrn	 Post_Flash_Read:near
  extrn	 Post_Flash_Write:near
endif	;DMI_GPNV_support
;R37A end

		align	16
		public	DMI_BIOS_Struct_Table
DMI_BIOS_Struct_Table:
;R40 ifdef SMBIOS_V21_Support
if DMI_BIOS_REV GE 21h		;R40
		db	'_SM_'			;header
		db	0			;checksum of SMBIOS entry point structure
;R38		db	1eh			;length of the Entry Point Structure
		db	DMI_BIOS_Struct_Table_Length	;R38 length of the Entry Point Structure
;R40		db	02h
;R40		db	01h
		db	DMI_BIOS_REV shr 4	 ;R40 Major Version
		db	(DMI_BIOS_REV and 0fh)	 ;R40 Minor Version
		dw	0
		db	0
		db	5 dup (?)
endif	;SMBIOS_V21_Support
		db	'_DMI_'			;header
		db	0			;checksum of DMI BIOS entry point structure
;R37C ifdef	DMI_GPNV_support			
;R37C 		dw	DMI_GPNV_MAX_POOL_SIZE	; total length of DMI BIOS structure table
;R37C else						;
		dw	DMI_MAX_POOL_SIZE	;total length of DMI BIOS structure table
;R37C endif	;DMI_GPNV_support			
		dw	offset Shadow_DMI_Address	;32-bit physical address (offset)
		dw	0fh			;segment
		dw	0			;Total number of structures in the DMI BIOS structure table
;R39 ifdef SMBIOS_V21_Support
;R39 		db	21h			;Revision of the SMBIOS extensions
;R39 else	;SMBIOS_V21_Support
;R39 		db	20h			;Revision of the DMI BIOS extensions
;R39 endif	;SMBIOS_V21_Support
		db	DMI_BIOS_REV		;R39
DMI_BIOS_Struct_Table_Length  equ  $-offset DMI_BIOS_Struct_Table		;R38

Public  BEGIN_DMI_RUNTIME           ; Used to track overall size of
BEGIN_DMI_RUNTIME LABEL BYTE           ;  DMI Post 

;=============================================================================
; Reserve space to copy DMI information into shadow area
;=============================================================================
		public	dmi_shadow_info	
dmi_shadow_info label byte
dmi_shadow_signature       dd 00000000h ; DMI Shadow of signature
dmi_shadow_struct_num      dw 0000h     ; DMI Shadow of number of structs
dmi_shadow_struct_max_size dw 0000h     ; DMI Shadow of max struct size

;=============================================================================
; FUNC: GET_DMI_INFORMATION (Function 50h - Get DMI Information)
;
; DESC: Returns number of DMI structures, largest DMI structure size,
;       the DMI BIOS revision, the DMI storage base, and storage size
;       used to hold DMI structures (this last one was proposed by me
;       to the DMI BIOS committee and hopefully will be approved).
;
; SYNOPSIS:
;
; short FAR (*entryPoint) (Function, DMIBIOSRev, NumStructures, \
;   StructureSize, BiosSelector);
;
; short Function;                   - PnP BIOS Function 50h
; unsigned char FAR *DMIBIOSRev     - Revision of the DMI BIOS Extension
; unsigned short FAR *NumStructures - Maximum num of structs BIOS will ret
; unsigned short FAR *StructureSize - Size of largest DMI Structure
; unsigned long FAR *DMIStorageBase - 32-bit phys addr of mem-mapped DMI data
; unsigned long FAR *DMIStorageSize - Size of block to store DMI/other info
; unsigned short BiosSelector       - PnP BIOS read/writable selector
;
; IN:   NONE
; OUT:  AX  - Error Code (0 if successful)
;=============================================================================
    public  get_dmi_information  
get_dmi_information proc  near
  gdi_func_num      equ [ebp+FN_OFS]     ; PnP BIOS Function 50h
  gdi_dmi_bios_rev  equ [ebp+FN_OFS+02h] ; Revision of DMI BIOS Extension
  gdi_num_dmi       equ [ebp+FN_OFS+06h] ; Max num of structs BIOS will ret
  gdi_dmi_size      equ [ebp+FN_OFS+0Ah] ; Size of largest DMI Structure
  gdi_storage_base  equ [ebp+FN_OFS+0Eh] ; 32-bit phys addr of mem-mapped DMI data
  gdi_storage_size  equ [ebp+FN_OFS+12h] ; Size of block to store DMI/other info
  gdi_bios_selector equ [ebp+FN_OFS+16h] ; PnP BIOS read/writable selector
  mov	gs,gdi_bios_selector	  	  ;R45

  mov   es,gdi_bios_selector
  mov   di,offset dmi_shadow_info
  cmp   es:[di],DMI_SIGNATURE
  je    short GDI_SIGNATURE_VALID
  xor	eax,eax				;zero out EAX
  jmp   short GDI_GET_INFO

GDI_SIGNATURE_VALID:
  add   di,4                        ; skip signature
  mov   eax,es:[di]                 ; get max size and num structures

GDI_GET_INFO:  
  lds   bx,gdi_num_dmi
  mov   word ptr [bx],ax            ;
  lds   bx,gdi_dmi_size             ; Size of largest DMI Structure
  shr   eax,16
  mov   word ptr [bx],ax            ; Maximum number of structures

  lds   bx,gdi_dmi_bios_rev
  mov   byte ptr [bx],DMI_BIOS_REV       ; DMI BIOS Rev
  lds   bx,gdi_storage_size
  mov   word ptr [bx],DMI_STORAGE_SIZE   ; physical block size

  mov   ax,DMI_SUCCESS

  ret

get_dmi_information endp


;=============================================================================
; FUNC: GET_DMI_STRUCT (Function 51h - Get DMI Structure)
;
; DESC: This function will copy the information for the specified
;       DMI Strucuture into the buffer specified by the caller.
;
; SYNOPSIS:
;
; short FAR (*entryPoint) (Function, Structure, devStructBuffer, \
;   BiosSelector)
;
; short Function                    - PnP BIOS Function 51h
; unsigned short FAR *Structure     - Struct number/handle to retrieve
; unsigned char FAR *dmiStrucBuffer - Buffer to copy device struc data to
; unsigned short BiosSelector       - PnP BIOS readable/writable selector
;
; IN:   NONE
; OUT:  AX  - Error Code (0 if successful)
;=============================================================================
    public  get_dmi_struct  
get_dmi_struct proc  near
  gds_func_num       equ [ebp+FN_OFS]     ; PnP BIOS Function 51h
  gds_structure      equ [ebp+FN_OFS+02h] ; Struct number/handle to retrieve
  gds_dmi_struct_buf equ [ebp+FN_OFS+06h] ; Buffer to copy device struc data to
  gds_dmi_selector   equ [ebp+FN_OFS+0Ah] ; Selector for DMI struct pool
  gds_bios_selector  equ [ebp+FN_OFS+0Ch] ; PnP BIOS read/writable selector
  mov	gs,gds_bios_selector	  	  ;R45

  cld

	push	esi
ifdef ESCD_M2
	mov	ax,cs		
	mov	ds,ax
	lea	si,dmi_shadow_info
	cmp	dword ptr ds:[si],DMI_SIGNATURE           ; check for valid pool
	jne	GDS_INVALID_HANDLE    ; return error
	add	si,4
else ;ESCD_M2
  mov   ax,cs		       
  mov   ds,ax                       ; get seg/selector of sys dmi tbl
  mov   si,DMI_OFFSET               ; get offset of DMI Structure Tbl

  les   di,gds_dmi_struct_buf       ; let check_dmi_signature use buffer
  call  check_dmi_signature         ; check DMI signature
  jc    GDS_INVALID_HANDLE    ; return error
endif ;ESCD_M2		       

  les   di,gds_structure            ; ES:DI = pointer to structure handle
  mov   bx,word ptr es:[di]         ; load BX with dmi struct handle number

ifdef ESCD_M2				
	mov	cx,ds:[si]		
else ;ESCD_M2				
  les   di,gds_dmi_struct_buf       ; get seg/selector of buffer
  mov   ax,4                              ; read in size & max
  call  read_dmi

ifdef MASM611
  assume di: ptr dmi_info_struct
endif
  mov   cx,es:[di].num_structs
endif ;ESCD_M2					

  or   cx,cx			
;R28  jz   short GDS_INVALID_HANDLE	;R20 if none any DMI structure then skip
  jz   GDS_INVALID_HANDLE	;if none any DMI structure then skip
  cmp  cx,MAX_STRUCTS
;R28  jge  short GDS_INVALID_HANDLE
  jge  GDS_INVALID_HANDLE	

ifdef ESCD_M2
	mov	si,Shadow_DMI_Len_Address
	shl	esi,16
	mov	si,Shadow_DMI_Address
else ;ESCD_M2
  add   si, size dmi_info_struct
endif ;ESCD_M2					
  cmp   bx,DMI_TERMINATOR           ; if struct handle is out of range
  jz    GDS_INVALID_HANDLE	

GDS_CHECK_NEXT_STRUCT:
	les   di,gds_dmi_struct_buf
ifdef ESCD_M2
	rol	esi,16
	mov	ax,ds:[si]		;get DMI structure length of single component
	add	si,2
	rol	esi,16
	mov	dx,ds:[si].dmi_handle
	push	cx
	mov	cx,ax
	rep	movsb
	pop	cx
else ;ESCD_M2
  mov   ax,2                        	
  call  read_dmi			
  mov   ax,word ptr es:[di]		
  add   si,2
  call  read_dmi
  mov   dx,es:[di].dmi_handle       ; get handle of current DMI
endif ;ESCD_M2					
  cmp   dx,DMI_TERMINATOR           ; check for terminator
  je    short GDS_INVALID_HANDLE

  or    bx,bx                       ; if handle == 0 then return first handle
  jz    short GDS_GET_NEXT_STRUCTURE_HANDLE 

  cmp   dx,bx                       ; correct handle found
  je    short GDS_GET_NEXT_STRUCTURE_HANDLE
ifndef ESCD_M2			       
  add   si,ax                       ; advance to next DMI structure
endif ;ESCD_M2			       
  loop  short GDS_CHECK_NEXT_STRUCT

  mov   ax,DMI_INVALID_HANDLE		
;R38C  jmp	short GDS_EXIT			
  jmp	GDS_EXIT			;R38C

GDS_GET_NEXT_STRUCTURE_HANDLE:

ifdef ESCD_M2				
	mov   dx,DMI_TERMINATOR		
	cmp	cx,1			
	je	short @F		
	mov	dx,ds:[si+2]		
@@:					
else ;ESCD_M2				
  mov   cx,ax                       ; get size of current DMI struct
  push  si
  add   si,cx                       ; advance to next DMI structure
  add   si,2                        ; skip size
  add   si,offset dmi_struct_hdr.dmi_handle
  mov   ax,2
  call  read_dmi
  mov   dx,word ptr es:[di]         ; get handle of next DMI struct
  pop   si

  mov   ax,cx
  call  read_dmi                    ; re-read in structure
endif ;ESCD_M2				
;LDCM start
	push	dx
	smsw	bx
	test	bl,1				;if in real mode?
	jz	short No_any_string		;Yes,skip LDCM progress
	les	di,gds_dmi_struct_buf
	push	es
	pop	ds
	movzx	bx,byte ptr es:[di+1]		;get component length
	add	di,bx
	sub	ax,bx
	jz	short No_any_string
	xor	dl,dl
Scan_Next_Loop:
	cmp	byte ptr es:[di],0
	jne	short Scan_Next_Byte1
	or	dl,dl
	jnz	short Scan_Next_Byte
	push	di
	push	ax		;R38C
;R38C	mov	si,di
	add	ax,di		;R38C
	mov	si,ax		;R38C
	mov	di,ax		;R38C
	inc	di
	pop	ax		;R38C
	mov	cx,ax
	inc	cx		;R38C
	std			;R38C
	rep	movsb
	pop	di
	mov	byte ptr es:[di],' '
	inc	di
Scan_Next_Byte:
	xor	dl,dl
	jmp	short @F
Scan_Next_Byte1:
	or	dl,1
@@:
	inc	di
	dec	ax
	cmp	ax,1				;if ending?
	jne	short Scan_Next_Loop		;no,continue.
No_any_string:
	pop	dx
;LDCM end

  mov   ax,DMI_SUCCESS              ; handle found and is being returned
  jmp   short GDS_LOAD_HANDLE

GDS_INVALID_HANDLE:
  mov   ax,DMI_INVALID_HANDLE
  mov   dx,DMI_TERMINATOR

GDS_LOAD_HANDLE:

;R37A start
ifdef	DMI_GPNV_support
  les	di,gds_dmi_struct_buf
  cmp	byte ptr es:[di],15		; ? type15
  jne	short @F			; no
  mov	byte ptr es:[di+10],4		; type15 Access Method (4:GPNV)
  mov	dword ptr es:[di+16],0		; type15 Access Method Address(Handle 0)
@@:
endif	;DMI_GPNV_support
;R37A end

  les   di,gds_structure            ; load ES:DI with dmi structure handle
  mov   word ptr es:[di],dx         ; update dmi handle

GDS_EXIT:
	pop	esi			

  ret

get_dmi_struct endp

;=============================================================================
; FUNC: SET_DMI_STRUCT (Function 52h - Set DMI Structure)
;
; DESC: This function will copy the information for the specified
;       DMI Strucuture into the buffer specified by the caller.
;
;       Internally, this function will read the 4K parameter block
;       into the dmiWorkBuffer provided by the caller.  The changes
;       to the DMI pool will be made to dmiWorkBuffer and then this
;       buffer will be written back out to the 4K paramter block.
;
; SYNOPSIS:
;
; short FAR (*entryPoint) (Function, dmiDataBuffer, dmiWorkBuffer, \
;         Control, DMISelector, BiosSelector);
;
; short Function                    - Function 52h
; unsigned char FAR* dmiDataBuffer  - Pntr to new/changed data
; unsigned char FAR* dmiWorkBuffer  - Pntr to dmi work buffer area
; unsigned char Control             - Conditions for setting struct
;   
; Add new control definitions for fast POST update
; Control Definitions:
;   
; Bit 0 - 0 = Validate Parameters, do not flash in ESCD
; Bit 1 - 1 = Do not read in ESCD, use ESCD presently in Work Buffer
; Bit 2 - 1 = Force Flash update of DMI Pool even if no change (For POST)
;
; unsigned short DMI Selector       - Selector for DMI struct pool
; unsigned short BiosSelector       - BIOS read/writable selector
;
; IN:   NONE
; OUT:  AX  - Error Code (0 if successful)
;=============================================================================
    public  set_dmi_struct  
set_dmi_struct proc near
  sds_func_num       equ [ebp+FN_OFS]     ; Function 52h
  sds_dmi_data_buf   equ [ebp+FN_OFS+02h] ; Pntr to new/changed data
  sds_dmi_work_buf   equ [ebp+FN_OFS+06h] ; Pntr to dmi work buffer area
  sds_control_flag   equ [ebp+FN_OFS+0Ah] ; Conditions for setting struct
  sds_dmi_selector   equ [ebp+FN_OFS+0Ch] ; Selector for DMI struct pool
  sds_bios_selector  equ [ebp+FN_OFS+0Eh] ; BIOS read/writeable selector
  mov	gs,sds_bios_selector	  	  ;R45

  pushf                             ; save flags
  cld                               ; clear direction
  cli                               ; disable interupts during operation

  ; Change validation code
  ; test word ptr sds_control_flag,SET_DMI_POOL
  ; jnz  sds_set_structure
  ; jmp  SDS_EXIT                    ; parameters are correct

sds_set_structure:

  les   di,sds_dmi_work_buf         ; load ES:DI with work buffer
  mov   ax,DMI_STORAGE_SIZE         ; change block size to match flash

  test  word ptr sds_control_flag,DONT_READ_IN_POOL 
  jnz   short sds_no_read1

ifndef	flash_in_smbase				;R44
ifdef ESCD_M2
	smsw	dx
	test	dl,1				;if in real mode?
	jz	short Read_Flash_DMI		;Yes,read from flash
	mov	ax,cs		
	mov	ds,ax
	lea	si,dmi_shadow_info
	cmp	dword ptr ds:[si],DMI_SIGNATURE           ; check for valid pool
	jne	short DMI_shadow_invalid
	push	di
	mov	dx,ds:[si+4]			;get DMI shadow structure number
	mov	cx,8
	rep	movsb
	mov	si,Shadow_DMI_Len_Address
	shl	esi,16
	mov	si,Shadow_DMI_Address
Get_DMI_shadow_data_Loop:
	rol	esi,16
	mov	cx,2
	rep	movsb
	mov	cx,ds:[si-2]			;get component size
	rol	esi,16
	rep	movsb
	dec	dx
	jnz	short Get_DMI_shadow_data_Loop
	pop	di
	jmp	short sds_no_read1
Read_Flash_DMI:
endif ;ESCD_M2
endif	;flash_in_smbase	;R44
	mov	si,cs		
	mov	ds,si                       ; get seg/selector of DMI pool
	mov	si,PARAM_BLOCK_BASE         ; start at beginning of parameter block

  call  read_dmi

sds_no_read1:

  add   di,DMI_TBL_OFFSET           ;

  mov   eax,es:[di]
  cmp   eax,DMI_SIGNATURE
  je    short SDS_SIGNATURE_VALID
DMI_shadow_invalid:			

  mov   dword ptr es:[di],DMI_SIGNATURE ; add signature
  add   di,DMI_SIGNATURE_SIZE       
ifdef MASM611
  assume di:ptr dmi_info_struct
endif
  xor   cx,cx
  mov   es:[di].num_structs,cx      ; set num structs to zero
  mov   es:[di].max_struct_size,cx  ; set max structs to zero
  jmp   short SDS_NUM_STRUCTS_OK

SDS_SIGNATURE_VALID:
ifdef MASM611
  assume di:ptr dmi_info_struct
endif
  add   di,DMI_SIGNATURE_SIZE       
  mov   cx,es:[di].num_structs      ; get number of structures in DMI TBL
  cmp   cx,MAX_STRUCTS              ; check to see if pool initialized yet
  jl    short SDS_NUM_STRUCTS_OK
  xor   cx,cx                       ; pool is not initialized, set to zero
  mov   es:[di].num_structs,cx      ; set num structs to zero
  mov   es:[di].max_struct_size,cx  ; set max structs to zero

SDS_NUM_STRUCTS_OK:
  add   di,size dmi_info_struct     ; skip table information
  lds   si,sds_dmi_data_buf         ; read into DS:SI dmiDataBuffer

ifdef MASM611
  assume si:ptr dmi_set_struct
endif
  cmp   [si].command,DMI_RESERVED_CMD ; if command is change and no structs
  jge   SDS_BAD_PARAMETER 	      ; bad command passed in

  or    cx,cx                       ; check to see if structures present
  jnz   short SDS_1

ifdef MASM611
  assume si:ptr dmi_set_struct
endif
  cmp   [si].command,DMI_CHANGE_DWORD ; if command is change and no structs
  jle   SDS_INVALID_HANDLE	      ;  exist then exit w/ error

SDS_1:
  mov   bx,[si].struc_handle        ; get current structure handle
  cmp   bx,DMI_TERMINATOR           ; compare with terminator
  je    SDS_INVALID_HANDLE          ; if equal to terminator then exit w/ error

;R43 start
if DMI_BIOS_REV GE 22h
	cmp	[si].command,DMI_CHANGE_BLOCK	; check for Change DMI block
	je	SDS_CHANGE_BLOCK		; change block
endif ;DMI_BIOS_REV
;R43 end

  call  get_structure               ; get the DMI structure into ES:DI
  jnc   short SDS_STRUCT_FOUND      ; DMI structure found

  cmp   [si].command,DMI_ADD_STRUCT ; check for Add DMI structure command
  je    short SDS_ADD_STRUCT        ; check if there is room to add
  jmp   SDS_INVALID_HANDLE          ; structure not found

SDS_STRUCT_FOUND:
  cmp   [si].command,DMI_CHANGE_DWORD ; check for Change DMI structure command
  jle   SDS_CHANGE_STRUCT           ; change structure byte, word or dword
  cmp   [si].command,DMI_ADD_STRUCT ; check for Add DMI structure command
  je    SDS_INVALID_HANDLE          ; structure already exists
  cmp   [si].command,DMI_DEL_STRUCT ; check for Delete DMI structure command
  je    short SDS_DELETE_STRUCT     ; delete structure
  cmp   [si].command,DMI_CHANGE_STRING ; check for Change DMI string
  je    SDS_CHANGE_STRING           ; change string

;=============================================================================
; ADD NEW DMI STRUCTURE
;=============================================================================
SDS_ADD_STRUCT:

SDS_CHECK_FOR_ROOM:
  mov   cx,di                       ; check for room
  push  di
  les   di,sds_dmi_work_buf         ; load ES:DI with work buffer
  add   di,DMI_TBL_OFFSET+DMI_SIGNATURE_SIZE       
  sub   cx,di
  pop   di
  add   cx,[si].data_length         ; add full length of struct
;R37C ifdef	DMI_GPNV_support	    
;R37C   cmp   cx,DMI_GPNV_MAX_POOL_SIZE   
;R37C else				    
  cmp   cx,DMI_MAX_POOL_SIZE
;R37C endif	;DMI_GPNV_support	    
  jb    short SDS_ADD_NEW_DMI_STRUCT
  mov   ax,DMI_ADD_STRUCTURE_FAILED ; pool full
  jmp   SDS_EXIT

SDS_ADD_NEW_DMI_STRUCT:
  mov   cx,[si].data_length         ; CX = full length of struct
  push  cx                          ; save struct size
  mov   word ptr es:[di],cx
  add   di,2
  add   si,offset dmi_set_struct.struc_type
  cld
  rep   movsb                       ; add new dmi structure to end
  mov   ax,DMI_TERMINATOR           ; AX = TERMINATOR
  stosw                             ; write terminator to size field
  stosw                             ; Write terminator to type, len
  stosw                             ; Write terminator to handle
  pop   cx                          ; restore struct size
  les   di,sds_dmi_work_buf         ; load ES:DI with work buffer
  add   di,DMI_TBL_OFFSET+DMI_SIGNATURE_SIZE       
ifdef MASM611
  assume  di:ptr dmi_info_struct
endif

  cmp   es:[di].max_struct_size,0FFFFh  ; compare new struct w/ max
  je    short SDS_SET_NEW_MAX_STRUCT

  cmp   cx,es:[di].max_struct_size  ; compare new struct w/ max
  jbe   short SDS_INCREMENT_NUM_STRUCTS

SDS_SET_NEW_MAX_STRUCT:
  mov   es:[di].max_struct_size,cx  ; new max struct

SDS_INCREMENT_NUM_STRUCTS:
	inc   word ptr es:[di].num_structs      
  jmp   SDS_WRITE_TO_FLASH

;=============================================================================
; DELETE EXISTING DMI STRUCTURE
; IN:  AX    - Length of current struct
;      ES:DI - points to structure to delete
;      CX    - number of structures left in DMI pool
;=============================================================================
SDS_DELETE_STRUCT:                  ; delete structure

  mov   dx,di                       ; save current string start location in DX
  sub   dx,2                        ; backup to length
  mov    ax,es:[di-2]                ; get component size in AX 
  add   ax,2                        ; account for length
  les   di,sds_dmi_work_buf         ; load ES:DI with work buffer
  add   di,DMI_TBL_OFFSET+DMI_SIGNATURE_SIZE       
  mov   cx,ax
  call  move_everything_up          ; delete structure
  jmp   SDS_WRITE_TO_FLASH          ; write back to flash

;=============================================================================
; CHANGE DMI STRUCTRE BYTE, WORD, OR DWORD
; IN:  AX    - Length of current struct
;      ES:DI - points to structure to change
;      CX    - number of structures left in DMI pool
;=============================================================================
SDS_CHANGE_STRUCT:

ifdef MASM611
  assume  si:ptr dmi_set_struct
endif
  mov   bl,[si].field_ofs           ; save field offset BL

ifdef MASM611
  assume  di:ptr dmi_struct_hdr
endif

  mov   al,[si].command             ; get command in AL
  mov   cl,al                       ; use this for the shift value in CL
  mov   dl,1
  shl   dl,cl                       ; DL contains number of bytes to change 
  mov   cl,es:[di].dmi_len          ; AL = struct length

SDS_CHECK_RANGE:

  add   bl,dl
  cmp   bl,cl                       ; check to see if offset out of range
  ja    SDS_BAD_PARAMETER            ;attempting to change structure
                                    ; which is out of range

  movzx bx,[si].field_ofs           ; load field offset into BX
  add   di,bx                       ; add field offset to DI
  mov   ecx,[si].change_mask        ; clear dword
  mov   ebx,[si].change_value       ; set dword

  cmp   al,DMI_CHANGE_BYTE          ; check for change byte command
  jne   short SDS_CHECK_FOR_CHANGE_WORD

  ; Compare new value with old, if same don't flash return error
  mov   al,byte ptr es:[di]         ; get the old value               
  and   byte ptr es:[di],cl         ; clear byte
  or    byte ptr es:[di],bl         ; set byte
  mov   ah,byte ptr es:[di]         ; get the new value               
  cmp   ah,al                       ; compare the old and new values  
  je    short SDS_NO_CHANGE         ; Signal no change in value       
  jmp   short SDS_WRITE_CHANGED_VALUE     ; just write out new BYTE

SDS_CHECK_FOR_CHANGE_WORD:
  cmp   al,DMI_CHANGE_WORD          ; check for change word command
  jne   short SDS_CHANGE_DWORD
  mov   ax,word ptr es:[di]         ; get the old value          
  and   word ptr es:[di],cx         ; clear word
  or    word ptr es:[di],bx         ; set word
  mov   bx,word ptr es:[di]         ; Get new value              
  cmp   ax,bx                       ; Compare old and new value  
  je    short SDS_NO_CHANGE         ; Signal no change in value  
  jmp   short SDS_WRITE_CHANGED_VALUE     ; just write out new WORD

SDS_CHANGE_DWORD:
  mov   eax,dword ptr es:[di]       ; get the old value           
  and   es:[di],ecx                 ; clear dword
  or    es:[di],ebx                 ; set dword
  mov   ebx,dword ptr es:[di]       ; Get new value               
  cmp   eax,ebx                     ; Compare old and new value   
  je    short SDS_NO_CHANGE               ; Signal no change in value 
  jmp   short SDS_WRITE_CHANGED_VALUE     ; just write out new DWORD

SDS_NO_CHANGE:                      ; Signal no change in value   

  test  word ptr sds_control_flag,FORCE_UPDATE ; Test for force update 
  jnz   short SDS_WRITE_CHANGED_VALUE     ; just write out new DWORD   
  mov   ax,DMI_NO_CHANGE            ; Signal old value same as new     
  jmp   SDS_EXIT                    ; exit

SDS_WRITE_CHANGED_VALUE:

  jmp   SDS_WRITE_TO_FLASH          ; Don't optimize for Intel parts 


;=============================================================================
; CHANGE DMI STRUCTURE STRING
; IN:  AX    - Length of current struct
;      CX    - number of structures left in DMI pool
;      DS:SI - points to new/change data information
;      ES:DI - points to structure to change
;=============================================================================
SDS_CHANGE_STRING:
ifdef MASM611
  assume  si:ptr dmi_set_struct
endif
  
  movzx bx,[si].field_ofs           ; move field offset into BX
  push  di                          ; save DI

ifdef MASM611
  assume  di:ptr dmi_struct_hdr
endif

  movzx ax,byte ptr es:[di].dmi_len ; get offset to start of string info

ifdef MASM611
  assume  di:ptr nothing
endif

  add   di,bx                       ; add field offset to DI to point to string
  movzx cx,byte ptr es:[di]         ; get string number
  pop   di                          ; restore DI to start of structure

  mov   dx,di                       ; save start of structure
  shl   edx,16                      ; save DI in upper word of EDX
  add   di,ax                       ; skip to start of dmi data
  xor   ax,ax                       ; set AX to terminating zero
  cmp   cx,1                        ; check if first string
  jle   short SDS_STRING_FOUND      ; if first string don't search for 0
  dec   cx

SDS_NEXT_STRING:
  push  cx
  mov   cx,MAX_STRING_LEN
  cld
  repne scasb                       ; scan ES:DI to find terminating zero
  pop   cx
  loop  SDS_NEXT_STRING             ; process next string

SDS_STRING_FOUND:
  push  di
  mov   cx,di
  push  cx
  mov   cx,MAX_STRING_LEN
  repne scasb                       ; scan ES:DI to find terminating zero
  pop   cx
  mov   ax,di
  sub   ax,cx                       ; AX contains size of old string
  pop   di

  mov   cx,[si].data_length         ; get new string length
  mov   dx,di                       ; save current string start location in DX
  cmp   cx,ax                       ; determine if new string larger or smaller
  je    short COPY_NEW_STRING       ; if strings equal size then straight copy

  les   di,sds_dmi_work_buf         ; load ES:DI with work buffer
  add   di,DMI_TBL_OFFSET+DMI_SIGNATURE_SIZE       
  cmp   cx,ax
  jg    short NEW_STRING_LARGER     ; new string is larger
  jl    short NEW_STRING_SMALLER    ; new string is smaller

NEW_STRING_LARGER:

  push  cx                          ; save length
  sub   cx,ax                       ; CX = length to increase

  call  move_everything_down        ; make room for new string

  push  dx
  shr   edx,16                      ; restore from upper word of DX
  mov   di,dx                       ; ES:DI points to string to increase
  sub   di,2                        ; backup to length
  mov   ax,es:[di]                  ; read length into AX
  add   ax,cx                       ; length to increase
  mov   es:[di],ax                  ; write back new length
  pop   dx

  pop   cx                          ; restore length
  jmp   short COPY_NEW_STRING       ; copy new string in

NEW_STRING_SMALLER:

  push  cx                          ; save length
  sub   ax,cx
  mov   cx,ax                       ; CX = length to decrease

  call  move_everything_up          ; make room for new string

  push  dx
  shr   edx,16                      ; restore from upper word of DX
  mov   di,dx                       ; ES:DI points to string to decrease
  sub   di,2                        ; backup to length
  mov   ax,es:[di]                  ; read length into AX
  sub   ax,cx                       ; length to increase
  mov   es:[di],ax                  ; write back new length
  pop   dx

  pop   cx                          ; restore length
  jmp   short COPY_NEW_STRING

COPY_NEW_STRING:

  mov   di,dx                       ; restore current string start location in DX
  lds   si,sds_dmi_data_buf         ; read into DS:SI dmiDataBuffer
  add   si,size dmi_set_struct      ; jump to string to be added
  cld
  rep   movsb
  jmp   short SDS_WRITE_TO_FLASH

;R43 start
if DMI_BIOS_REV GE 22h
;=============================================================================
; CHANGE DMI STRUCTURE BLOCK
;=============================================================================
SDS_CHANGE_BLOCK:
	cmp	word ptr [si].data_length,DMI_MAX_POOL_SIZE
	jbe	short SDS_CHANGE_BLOCK_STRUCT
	mov	ax,DMI_ADD_STRUCTURE_FAILED	; pool full
	jmp	SDS_EXIT

SDS_CHANGE_BLOCK_STRUCT:
	les	di,sds_dmi_work_buf		; load ES:DI with work buffer

;----- clear DMI pool first -----
	mov	cx,DMI_MAX_POOL_SIZE-1		;get DMI pool size - 1(checksum byte)
	mov	al,0ffh
@@:
	mov     byte ptr es:[di],al
	inc	di
	loop	@B				;next loop
;--------------------------------

	mov	cx,word ptr [si].data_length	; will move of size
	les	di,sds_dmi_work_buf		; load ES:DI with work buffer
	lds	si,sds_dmi_data_buf		; read into DS:SI dmiDataBuffer
	add	si,(size dmi_set_struct) - (size dmi_struct_hdr)	;point to StructureHeader of DMIDataBuffer (0ch)
	rep	movsb				; move it
endif ;DMI_BIOS_REV
;R43 end
;=============================================================================
; WRITE TO FLASH
;=============================================================================
SDS_WRITE_TO_FLASH:

  lds   si,sds_dmi_work_buf         ; load DS:SI with work buffer
  call  set_max_and_num_structs     ; adjust Max Struct Size and Num Structs

  mov   ax,sds_dmi_selector
  mov   es,ax                       ; ES:DI = get seg/selector of DMI pool
;  mov   cx,ESCD_SIZE                ; CX = size in bytes RXX
  mov   di,PARAM_BLOCK_BASE         ; start at beginning of parameter block

;LDCM  test  word ptr sds_control_flag,SET_DMI_POOL  
;LDCM  jz    short sds_no_flash2                           

;R45  call  Flash_Write                 ; write to flash
  call	Write_DMI		    ;R45
  jnc   short SDS_SUCCESS
  mov   ax,DMI_NO_CHANGE
  jmp   short SDS_EXIT

sds_no_flash2:                      
  jmp   short SDS_SUCCESS

SDS_SUCCESS:                        ; common success exit point
  mov   ax,DMI_SUCCESS              ; handle found and is being returned
  jmp   short SDS_EXIT                    ; exit

SDS_INVALID_HANDLE:
  mov   ax,DMI_INVALID_HANDLE       ; invalid handle (handle already used)
  jmp   short SDS_EXIT                    ; exit

SDS_BAD_PARAMETER:                  ; bad command passed in
  mov   ax,DMI_BAD_PARAMETER        ; 
  jmp   short SDS_EXIT                    ; exit

SDS_EXIT:


;=============================================================================
; Update Shadow RAM with Max and Num Structs
;=============================================================================
  cmp   ax,DMI_SUCCESS              ; handle found and is being returned
  je    short UPDATE_SHADOW_MEM
  cmp   ax,DMI_NO_CHANGE            ; Signal old value same as new    
  je    short UPDATE_SHADOW_MEM
  jmp   short NO_UPDATE_SHADOW

UPDATE_SHADOW_MEM:

  lds   si,sds_dmi_work_buf         ; load DS:SI with work buffer
  mov   es,sds_bios_selector        ; BiosSelector has base of 0F0000h
  mov   di,offset dmi_shadow_info   ; point to reserved shadow area 

  pusha
  call  F000_Shadow_W               ; Enable F000 shadow writeable
  mov   cx,8                        ; size of signature+max size+num structs
  rep   movsb                       ; move signature, max size and num structs to shadow
  call	Store_DMI_to_Flash		
  call	Store_DMI_to_Shadow		
  call  F000_Shadow_R               ; Enable F000 shadow readonly
  popa

NO_UPDATE_SHADOW:

  popf                              ; restore flags (including interupts)

  ret

set_dmi_struct endp

Store_DMI_To_Flash:
		push	ds			;store register
		push	es
		push	si

ifdef	ESCD_M2
		mov	ax,DMI_STORAGE_BASE
else	;ESCD_M2
		mov	ax,DMI_STORAGE_BASE_16
endif	;ESCD_M2
		mov	es,ax			;get DMI pool base

		sub	si,8			;set SI to start offset of DMI
;R37C ifdef	DMI_GPNV_support
;R37C 		mov	cx,DMI_GPNV_MAX_POOL_SIZE-1	;get DMI pool size - 1(checksum byte)
;R37C else
		mov	cx,DMI_MAX_POOL_SIZE-1		;get DMI pool size - 1(checksum byte)
;R37C endif	;DMI_GPNV_support
		xor	ah,ah			;clear value
@@:
		lodsb				;get data
		add	ah,al			;count
		loop	@B			;next loop
		mov	ds:[si],ah		;store to checksum byte
		pop	si			;restore original SI offset
		push	si
		sub	si,8			;set SI to start offset of DMI
		mov	di,PARAM_BLOCK_BASE+DMI_TBL_OFFSET	;set to DMI pool offset in flash ROM
		mov	cx,DMI_STORAGE_SIZE	;get dmi pool size
		call	Write_DMI		;R45
;R45		call	Flash_Write		;reflash it

		pop	si			;restore register
		pop	es
		pop	ds
		ret
		public	Store_DMI_to_Shadow
Store_DMI_to_Shadow:
	push	word ptr ds:[si-4]	;store number of structure
	mov	di,Shadow_DMI_Address
	xor	dx,dx
	mov	bx,Shadow_DMI_Len_Address
@@:
	lodsw
	or	ax,ax
	jz	short @F
	cmp	ax,0ffffh
	je	short @F
	mov	es:[bx],ax
	mov	cx,ax
	rep	movsb

;R38A strat
	sub	si,ax
	movzx	cx,byte ptr ds:[si+1]
	add	si,ax
	cmp	cx,ax
	jne	short have_str
	mov	word ptr es:[di],0
	add	di,2
	add	word ptr es:[bx],2
	add	ax,2
have_str:
;R38A end

	add	dx,ax
	add	bx,2
;R37C ifdef	DMI_GPNV_support			
;R37C 	cmp	dx,DMI_GPNV_MAX_POOL_SIZE	
;R37C else						
	cmp	dx,DMI_MAX_POOL_SIZE		
;R37C endif	;DMI_GPNV_support			
	jb	short @B
@@:
	pop	ax			;restore number of structure
	lea	di,DMI_BIOS_Struct_Table
;R40 ifdef SMBIOS_V21_Support
if DMI_BIOS_REV GE 21h		;R40
	mov	es:[di+01ch],ax		;write total number to DMI table
	mov	es:[di+16h],dx		;write total length to DMI table
	xor	al,al
	mov	es:[di+15h],al		;clear checksum
	push	di
	mov	cx,15
@@:
	add	al,es:[di+10h]
	inc	di
	loop	@B
	not	al
	inc	al
	pop	di
	mov	es:[di+15h],al		;set checksum byte


	lea	si,dmi_shadow_info
;R38 start
	add	si,4
	mov	eax,es:[si]
	shr	eax,16
;R38 end
;R38	mov	ax,es:[si]
	mov	es:[di+08h],ax
	xor	al,al
	mov	es:[di+4],al		;clear checksum
	push	di
	mov	cx,16
@@:
	add	al,es:[di]
	inc	di
	loop	@B
	not	al
	inc	al
	pop	di
	mov	es:[di+4],al		;set checksum byte
else	;SMBIOS_V21_Support
	mov	es:[di+0ch],ax		;write total number to DMI table
	mov	es:[di+6],dx		;write total length to DMI table
	xor	al,al
	mov	es:[di+5],al		;clear checksum
	push	di
	mov	cx,15
@@:
	add	al,es:[di]
	inc	di
	loop	@B
	not	al
	inc	al
	pop	di
	mov	es:[di+5],al		;set checksum byte
endif	;SMBIOS_V21_Support			
	ret
;=============================================================================
; FUNC: DMI_GET_STRUCT_CHNG_INFO (Function 53h - Get DMI Struct Change Info)
;
; DESC:  This function will allow system software to get information
; about what type of DMI event occured.  The DMI event information will be
; returned in the 16 byte memory buffer pointed to by dmiEventStructure in
; the following format:
;
; SYNOPSIS:
;
; short FAR (*entryPoint)(Function, dmiChangeStructure, BiosSelector);
;
; short Function;                       - PnP BIOS Function 53h
; unsigned char FAR *dmiChangeStructure - Pointer to DMI Change Structure
; unsigned short BiosSelector;          - PnP BIOS read/writable selector
;
; IN:   NONE
; OUT:  AX  - Error Code (0 if successful)
;=============================================================================
		public	dmi_get_struct_chng_info 	
dmi_get_struct_chng_info proc near
  gsci_func_num          equ [ebp+FN_OFS]     ; PnP BIOS Function 53h
  gsci_dmi_change_struct equ [ebp+FN_OFS+02h] ; Pointer to DMI Change Structure
  gsci_bios_selector     equ [ebp+FN_OFS+06h] ; BIOS read/writeable selector
  mov	gs,gsci_bios_selector	  ;R45

;  lds   si,gsci_dmi_change_struct
;  mov   al,DMI_CMOS_CHANGE_STATUS   ; the spec defines a word for this
;  call  Get_cmos                    ; although only a byte is needed
;  mov   [si].change_status,ax
;
;  cmp al,DMI_SINGLE_STRUC_CHANGE
;  jne short DGSCI_1
;  mov   al,DMI_CMOS_STRUC_HNDL_BYTE1
;  call  Get_cmos                    ; read high byte
;  mov   ah,al
;  mov   al,DMI_CMOS_STRUC_HNDL_BYTE0
;  call  Get_cmos                  read low byte
;  mov   [si].struct_handle,ax
;
;DGSCI_1:

  mov   ax,DMI_FUNCTION_NOT_SUPPORTED
  ret

dmi_get_struct_chng_info endp

;=============================================================================
; FUNC: DMI_CONTROL (Function 54h - DMI Control)
;
; DESC: Provides the interface to perform implementation-specific functions
;       for the systen, as defined by the SubFunction parameter and its
;       optional data values
;
; SYNOPSIS:
;
; short FAR (*entryPoint) (Function, SubFunction, Data, Control, \
;   BiosSelector);
;
; short Function;                   - PnP BIOS Function 53h
; short SubFunction;                - Defines the specific operation
; void FAR *Data;                   - Input/Output data buffer, Subfunc specific
; unsigned char Control             - Conditions for performing operation
; unsigned short BiosSelector;      - PnP BIOS read/writable selector
;
; IN:   NONE
; OUT:  AX  - Error Code (0 if successful)
;=============================================================================
		public	dmi_control 	
dmi_control proc near
  dc_func_num            equ [ebp+FN_OFS]     ; PnP BIOS Function 54h
  dc_sub_func_num        equ [ebp+FN_OFS+02h] ; Defines the specific operation
  dc_data                equ [ebp+FN_OFS+04h] ; Input/Output data buffer, Subfunc specific
  dc_control             equ [ebp+FN_OFS+08h] ; Conditions for performing operation
  dc_DMI_selector        equ [ebp+FN_OFS+0Ah] ; DMI read/writeable selector	;R37A
;R37A  dc_bios_selector       equ [ebp+FN_OFS+0Ah] ; BIOS read/writeable selector
  dc_bios_selector       equ [ebp+FN_OFS+0Ch] ; BIOS read/writeable selector	;R37A
  mov	gs, dc_bios_selector	  	      ;R45

ifdef	DMI_OEM_Security
		push	es
		push	ebx
		push	si

		mov	ebx, dc_data
		mov	si, bx
		shr	ebx, 16
		mov	es, bx

		mov	ax, dc_sub_func_num
		cmp	ax, 8000h
		jne	short @F
		xor	ah, ah
	 	call	GetSupervisorStatus
		mov	es:[si], al
		mov	ax, DMI_SUCCESS
		jmp	short Endp_Tulip_Password
	@@:
		cmp	ax, 8001h
		jne	short @F
		xor	ah, ah

		call	CheckSupervisorPassword
		cmp	al, 1
		mov	ax, DMI_SUCCESS
		je	short @F
		mov	ax, DMI_BAD_PARAMETER
	@@:

	Endp_Tulip_Password:

		pop	si
		pop	ebx
		pop	es
		ret
endif	;DMI_OEM_Security

;  mov   ax,dc_func_num
;  .if   ax == DMI_CLEAR_EVENT_LOG
;  .elseif ax == DMI_CONTROL_LOGGING
;  .endif
;
;  cmp ax,DMI_CLEAR_EVENT_LOG
;  jne  short DC_2
;  ; do some processing for equal case
;DC_2:
;  cmp ax,DMI_CONTROL_LOGGING
;  jne short DC_3
;  ; do some processing here for equal case
;DC_3:
;  mov   ax,DMI_FUNCTION_NOT_SUPPORTED

;R37A start
ifdef DMI_GPNV_support
public	Clear_post_mark0
ifndef	flash_in_smbase		;R44A
public	Clear_post_mark1
endif	;flash_in_smbase	;R44A

  cmp	word ptr dc_sub_func_num, DMI_CLEAR_EVENT_LOG
  je	short Clear_Event_Log
  cmp	word ptr dc_sub_func_num, DMI_CONTROL_LOGGING
;R30C  je	short Control_Logging
;R30C start
  je	Control_Logging
  cmp	word ptr dc_sub_func_num,4000h
  jb	short DMI_INVALID_Ret
  cmp	word ptr dc_sub_func_num,7fffh
  ja	short DMI_INVALID_Ret
  cmp	word ptr dc_control,1
;R42  je	short DMI_CONTROL_SUCCESS
  je	DMI_CONTROL_SUCCESS		;R42
DMI_INVALID_Ret:
;R30C end
  mov	ax,DMI_INVALID_SUBFUNCTION
  ret
Clear_Event_Log:
  cmp	word ptr dc_control, 1
  je	short Clear_Event_Log_Data
  cmp	word ptr dc_control, 0
;R42  jne	short Exit_Not_SUPPORTED
;R42  jmp	short DMI_CONTROL_SUCCESS
  jne	Exit_Not_SUPPORTED			;R42
  jmp	DMI_CONTROL_SUCCESS			;R42
Clear_Event_Log_Data:				; 
;R44A;R44 - start
;R44B	cmp	dword ptr dc_data,0		;buffer must be 0 in subfunction 0
;R44B	je	short @F
;R44B	mov	ax,DMI_BAD_PARAMETER
;R44B	ret
;R44B @@:
;R44Aifdef	flash_in_smbase
;R44A	mov	eax,DMI_STORAGE_BASE shl 4  
;R44A	mov	ax, DMI_ADDR
;R44A	add	ax, DMI_MAX_POOL_SIZE
;R44A	mov	edi,eax				;clear address
;R44A	mov	cx, GPNV_MIN_BUF_SIZE		;clear length
;R44Aextrn	flash_part_erase:near
;R44A	call	flash_part_erase
;R44A	mov   ax,DMI_SUCCESS
;R44A	ret
;R44Aendif	;flash_in_smbase
;R44A;R44 - end

clear_post_mark0:				; in e0post.asm change NOP
  jmp	short in_post_clear			; jmp if in post
;;;;;;;;;; Clear shadow for run time
  mov	ax,cs
  mov	ds,ax
;;;;;  mov	si,Shadow_DMI_Address + DMI_GPNV_MAX_POOL_SIZE
  mov	si,Shadow_DMI_Len_Address - GPNV_MIN_BUF_SIZE	; 0ffset 0E00h
  call  F000_Shadow_W			; Enable F000 shadow writeable
;R42  jmp   short @F
;R42 start
  mov	bx,Event_Log_Handle
  call	Find_handle_fun				; find valid handle
  jc	short Exit_Not_SUPPORTED		; CF not find
  add	si,2
  mov	cx,GPNV_BLOCK_SIZE
Clear_data_loop_shadow:
  mov	ax,0ffffh
  mov	word ptr ds:[si],ax
  add	si,2
  loop	Clear_data_loop_shadow
  call	F000_Shadow_R			; Enable F000 shadow readonly

ifndef	flash_in_smbase			;R44A
  mov	ax, DMI_STORAGE_BASE
  mov	ds, ax
  mov   si, DMI_OFFSET
  les	di, dc_data
  mov	cx, DMI_STORAGE_SIZE
  call	Flash_Read			; Read DMI pool for run time
  jmp	short not_post_clear		; jmp clear flash for run time
endif	;flash_in_smbase			;R44A
;R42 end
;;;;;;;;;; Clear flash pool
in_post_clear:					; in post
;R44A start
ifdef	flash_in_smbase
	cmp	dword ptr dc_data,0		;buffer must be 0 in subfunction 0
	je	short @F
	mov	ax,DMI_BAD_PARAMETER
	ret
@@:
	mov	eax,DMI_STORAGE_BASE shl 4  
	mov	ax, DMI_ADDR
	add	ax, DMI_MAX_POOL_SIZE
	mov	edi,eax				;clear address
	mov	cx, GPNV_MIN_BUF_SIZE		;clear length
extrn	flash_part_erase:near
	call	flash_part_erase
	jmp	short DMI_CONTROL_SUCCESS
else	;flash_in_smbase
;R44A end
  mov	ax, DMI_STORAGE_BASE
  mov	ds, ax
  mov   si, DMI_OFFSET
  les	di, dc_data
  mov	cx, DMI_STORAGE_SIZE
  call	Post_Flash_Read
not_post_clear:					;R42
;R37C  add	di,DMI_GPNV_MAX_POOL_SIZE
  add	di,DMI_MAX_POOL_SIZE		;R37C
  push	es
  pop	ds
  push	di
  pop	si
@@:
  mov	bx,Event_Log_Handle
  call	Find_handle_fun				; find valid handle
  jc	short Exit_Not_SUPPORTED		; CF not find
  add	si,2
  mov	cx,GPNV_BLOCK_SIZE
Clear_data_loop:
  mov	ax,0ffffh
  mov	word ptr ds:[si],ax
  add	si,2
  loop	Clear_data_loop
  mov	ax, DMI_STORAGE_BASE
  mov	es, ax
  mov   di, DMI_OFFSET
  mov	cx, DMI_STORAGE_SIZE
  lds	si, dc_data				;R42 DS:SI => work buffer
Clear_post_mark1:
  jmp	short in_post_clear1
;R42  call	F000_Shadow_R			; Enable F000 shadow readonly
;;;;;  mov	si,Shadow_DMI_Address + DMI_GPNV_MAX_POOL_SIZE
;R42  mov	si,Shadow_DMI_Len_Address - GPNV_MIN_BUF_SIZE	; 0ffset 0E00h
  call  Flash_Write
  jmp	short @F
in_post_clear1:
;R42  lds	si, dc_data
  call  Post_Flash_Write
@@:
  jmp	short DMI_CONTROL_SUCCESS
endif	;flash_in_smbase			;R44A
Control_Logging:
  jmp	short Exit_Not_SUPPORTED
DMI_CONTROL_SUCCESS:
  mov   ax,DMI_SUCCESS
  ret
Exit_Not_SUPPORTED:
	mov   ax,DMI_FUNCTION_NOT_SUPPORTED
;R30Celse	;DMI_GPNV_support
;R30C;R37A end
;R30C
;R30C;R30B start
;R30Cifdef DMI_func54h_Force_Enable
;R30C	mov   ax,DMI_SUCCESS
;R30Celse ;DMI_func54h_Force_Enable
;R30C	mov   ax,DMI_FUNCTION_NOT_SUPPORTED
;R30Cendif ;DMI_func54h_Force_Enable
;R30B end
endif	;DMI_GPNV_support	;R37A
  ret

dmi_control endp

ifdef	DMI_OEM_Security
;[]----------------------------------------------------------------[]
;GetSupervisorStatus
;	Read CMOS value
;Input : AX = function number
;Outpu : AX = return value   = 0 Disable
;			     = 1 Enable
;			     =81 Invalid
;[]----------------------------------------------------------------[]
GetSupervisorStatus	Proc	Near

		or	ax,ax				;check function number
		jnz	short Function_Invalid		;No,skip

		pusha					;Return used 
		mov	al,11h				;SECURITY_FLAGS 
		call	Get_CMOS			;
		test	al,02				;SECURITY_FLAGS bit
		popa

		mov	ax,1
		jnz	short Password_Enable
		xor	ax,ax

	Password_Enable:

		ret

	Function_Invalid:

		mov	ax,81h				;return invalid function parameter
		ret

GetSupervisorStatus 	endp

;[]----------------------------------------------------------------[]
;CheckSupervisorPassword       
;	Read CMOS value
;Input : AX     = function number
;	 ES:DI	= Password String
;Outpu : AX     = return value   = 0 incorrect
;		 		 = 1 Correct
;			     	 =81 Invalid
;[]----------------------------------------------------------------[]
CheckSupervisorPassword 	Proc	Near

		cmp	ax, 1			;check function number
		jne	short Function_Invalid	;No,skip

 		pusha
		call	Hash_Password
		mov	bx, ax
		mov	al, 1dh				;CMOS password addr
		call	Get_CMOS			;get low byte
		mov	ah, al				;keep value 
		mov	al, 1ch				;CMOS password addr
		call	Get_CMOS			;get high byte value
		cmp	ax, bx
		popa
		mov	ax, 1
		je	short @F
		xor	ax, ax
	@@:
		ret

CheckSupervisorPassword 	endp

;[]========================================================================[]
;Function :	Encode the password using hash algorithm
;
;Input	:	KEYIN_BUF[bp]
;
;Output	:	AX - hashed password
;[]========================================================================[]
Hash_Password	Proc    Near

		push    si 			; save regs
		push    bx
		push    cx
		push    dx

		xor     bx, bx			; clear current hash value
		xor	ah, ah
		mov     cx, 8			; set length counter
	@@:
		mov     al, es:[si]
		or	al, al			; last byte = 0?
		jz	short @F		; skip to quit if so
		rol	bx, 1			; adjust
		rol	bx, 1
		add	bx, ax			; add in current char
		inc	si			; bump index
		loop	short @B		; do for all significant password chars
	@@:
		xchg	ax, bx			; return result in ax

		pop     dx			; restore regs
		pop     cx
		pop     bx
		pop     si
		ret

Hash_Password	Endp
endif	;DMI_OEM_Security

;=============================================================================
; FUNC: GET_GPNV_INFO (Function 55h - Get General-Purpose NonVolatile Info)
;
; DESC:  This function provides information about a General Purpose
; nonvolatile area (GPNV).  The handle is a pointer to a number that ident-
; ifies which GPNV's information is requested, a value of zero accesses the
; first (or only) area.
;
; SYNOPSIS:
;
; short FAR (*entryPoint) (Function, Handle, MinGPNVWSize, GPNVSize, \
;   NVStorageBase, BiosSelector);
;
; short Function;                         - PnP BIOS Function 55h
; unsigned short FAR *Handle              - Identifies which GPNV to access
; unsiged short FAR *MinGPNVWriteSize;    - Min buf size for writing NVS
; unsigned short FAR *GPNVSize;           - Size allocated for the GPNV
; unsigned long FAR *NVStorageBase;       - 32-bit physical base addr for NVS
; unsigned short BiosSelector;            - PnP BIOS read/writable selector
;
;
; IN:   NONE
; OUT:  AX  - Error Code (0 if successful)
;=============================================================================
		public	get_gpnv_info
get_gpnv_info proc near
  ggi_func_num      equ [ebp+FN_OFS]       ; short Function
  ggi_handle	    equ [ebp+FN_OFS+02h]   ; Identifies which GPNV to access
  ggi_min_gpnv_size equ [ebp+FN_OFS+06h]   ; unsiged short FAR *MinGPNVWriteSize
  ggi_gpnv_size     equ [ebp+FN_OFS+0Ah]   ; unsigned short FAR *GPNVSize
  ggi_nvs_storeBase equ [ebp+FN_OFS+0Eh]   ; unsigned long FAR *NVStorageBase
  ggi_bios_selector equ [ebp+FN_OFS+012h]   ; BIOS read/writeable selector
  mov	gs,ggi_bios_selector	           ;R45

;;  les   di,ggi_handle        ; load ES:DI with handle
;;  mov   dx,es:[di]
;;	lea	si,Shadow_DMI_Address
;;  mov	cx,word ptr cs:[DMI_BIOS_Struct_Table+12]
;;	lea	bx,Shadow_DMI_Len_Address
;;Check_next_handle:
;;  mov	ax,cs:[si+2]
;;  add	si,cs:[bx]
;;  add	bx,2
;;  cmp	ax,0ffffh
;;  je	short Got_struct
;;  cmp	dx,ax
;;  jne	short Check_next_handle
;;  mov	ax,cs:[si+2]
;;Got_struct:
;;  mov	es:[di],ax
;;
;;  les   di,ggi_min_gpnv_size        ; load ES:DI with MinGPNVWriteSize
;;  mov	cx,word ptr cs:[DMI_BIOS_Struct_Table+6]
;;  mov   word ptr es:[di],cx
;;
;;  les   di,ggi_gpnv_size            ; load ES:DI with GPNVSize
;;  mov   word ptr es:[di],PARAM_BLOCK_SIZE
;;
;;  les   di,ggi_nvs_storeBase        ; load ES:DI with NVStorageBase
;;  mov   dword ptr es:[di],DMI_STORAGE_BASE
ifdef DMI_GPNV_support
  les   di,ggi_handle			; load ES:DI with handle
  mov	bx,word ptr es:[di]
  cmp	bx,0ffffh
  jae	short GET_GPNV_INVALID_HANDLE

;R37A  mov	ax,DMI_STORAGE_BASE
;R37A  mov	ds,ax
;R37A  mov   si,DMI_OFFSET + DMI_GPNV_MAX_POOL_SIZE
;R37A  mov	cx,8
  mov	ax,cs						;R37A
  mov	ds,ax						;R37A
;;;;;  mov	si,Shadow_DMI_Address + DMI_GPNV_MAX_POOL_SIZE	;R37A
  mov	si,Shadow_DMI_Len_Address - GPNV_MIN_BUF_SIZE	; 0ffset 0E00h
GET_GPNV_Loop:
;R37A  push	cx
;R37A  mov	cx,2
;R37A  call  Flash_Read
;R37A  pop	cx
;R37A  cmp	word ptr es:[di],bx
  cmp	word ptr ds:[si],bx				;R37A
  je	short GET_GPNV_SUCCESS
;R37F  cmp	bx,Event_Log_Handle				;R37A
  cmp	word ptr ds:[si],Event_Log_Handle	;R37F
  jne	short not_dmi_event_logo			;R37A
  add	si,GPNV_BLOCK_SIZE + 2				;R37A
not_dmi_event_logo:					;R37A
  add	si,GPNV_BLOCK_SIZE
;R37A  loop  GET_GPNV_Loop
  cmp	si,Shadow_DMI_Len_Address			;R37A ;;;;;
  jbe	short GET_GPNV_Loop				;R37A
  mov	es:[di],0ffffh
  jmp	@F
GET_GPNV_SUCCESS:
  add	si,GPNV_BLOCK_SIZE
;R37F start
  cmp	bx,Event_Log_Handle
  jne	short aaaaa
  add	si,GPNV_BLOCK_SIZE+2
aaaaa:
;R37F end
  mov	cx,2
  rep	movsb						;R37A
;R37A  call  Flash_Read
@@:
  les   di,ggi_min_gpnv_size        	; load ES:DI with MinGPNVWriteSize
  mov   word ptr es:[di], DMI_STORAGE_SIZE

  les   di,ggi_gpnv_size            	; load ES:DI with GPNVSize
  mov   word ptr es:[di], GPNV_BLOCK_SIZE - 2
  cmp	bx,Event_Log_Handle		     		;R37A
  jne	short not_event_logo				;R37A
  add   word ptr es:[di], GPNV_BLOCK_SIZE + 2		;R37A
not_event_logo:						;R37A

  les   di,ggi_nvs_storeBase        	; load ES:DI with NVStorageBase
;R37C  mov   dword ptr es:[di], DMI_STORAGE_BASE + DMI_GPNV_MAX_POOL_SIZE
  mov   dword ptr es:[di], DMI_STORAGE_BASE + DMI_MAX_POOL_SIZE		;R37C
  mov   ax,DMI_SUCCESS
  ret
GET_GPNV_INVALID_HANDLE:
  mov   ax,DMI_INVALID_HANDLE
else
;R30B ifdef DMI_func55h_Force_Enable
;R30B 	mov   ax,DMI_SUCCESS
;R30B else ;DMI_func55h_Force_Enable
  mov   ax,DMI_FUNCTION_NOT_SUPPORTED	
;R30B endif ;DMI_func55h_Force_Enable	

endif	;DMI_GPNV_support	
  ret

get_gpnv_info endp

;=============================================================================
; FUNC: 56h - Read Extended System Configuration Data (GPNV)
;
; SYNOPSIS:
;
; short FAR (*entryPoint)(Function, GPNVBuffer, GPNVSelector, BiosSelector)
;
; short Function;                /* PnP BIOS Function 042h */
; unsigned short FAR *Handle              - Identifies which GPNV to access
; char FAR *GPNVBuffer;        /* Addr of caller's buffer for storing GPNV */
; unsigned short GPNVSelector;   /* GPNV read/writable selector */
; unsigned short BiosSelector;   /* PnP BIOS read/writable selector */
;
; DESC:
;
; Optional.  This function is used to read the GPNV data from nonvolatile
; storage on the system into the buffer specified by GPNVBuffer.
; The caller should use the output from Function 41 (the GPNVSize field)
; when calculating the size of the GPNVBuffer.  The system BIOS will return
; the entire GPNV, including information about system board devices.
; In protected mode, the GPNVSelector has base = NVStorageBase and limit of
; at least NVStorageSize. In real mode, the GPNVSelector is a segment that
; points to NVStorageBase.
;
; IN:   NONE
; OUT:  AX  - Error Code (0 if successful)
;=============================================================================
		public	read_gpnv 	
read_gpnv proc near
  rg_func_num      equ [ebp+FN_OFS]       ; short Function
  rg_handle	   equ [ebp+FN_OFS+02h]   ; Identifies which GPNV to access
  rg_gpnv_buffer   equ [ebp+FN_OFS+04h]   ; char FAR *GPNVBuffer
  rg_gpnv_lock	   equ [ebp+FN_OFS+08h]	  ; short FAR *GPNVLock
  rg_gpnv_selector equ [ebp+FN_OFS+0Ch]   ; unsigned short GPNVSelector
  rg_bios_selector equ [ebp+FN_OFS+0Eh]   ; BIOS read/writeable selector
  mov	gs,rg_bios_selector	  	  ;R45

;  les   di,rg_gpnv_buffer           ; load ES:DI with GPNVBuffer
;
;  mov   ax,rg_gpnv_selector
;  mov   ds,ax                       ; put GPNVSelector in DS
;  mov   si,GPNV_OFFSET              ; put offset of GPNV in SI
;
;  mov   cx,GPNV_BLOCK_SIZE
;  call  Flash_Read
;  mov   ax,DMI_SUCCESS
ifdef	DMI_GPNV_support
;R37A  mov   bx,rg_handle
;R37A  cmp	bx,0FFFFh
;R37A  jae	short READ_GPNV_INVALID_HANDLE
;R37A  mov	ax,DMI_STORAGE_BASE
;R37A  mov	ds,ax
;R37A  mov   si,DMI_OFFSET + DMI_GPNV_MAX_POOL_SIZE
;R37A  les	di,rg_gpnv_buffer
;R37A  mov	cx,8
;R37AGPNV_Read_Loop:
;R37A  push	cx
;R37A  mov	cx,2
;R37A  call  Flash_Read
;R37A  pop	cx
;R37A  cmp	word ptr es:[di],bx
;R37A  je	short READ_GPNV_SUCCESS
;R37A  cmp	word ptr es:[di],0FFFFh
;R37A  je	short READ_GPNV_SUCCESS
;R37A  add	si,GPNV_BLOCK_SIZE
;R37A  loop  GPNV_Read_Loop
;R37A  jmp	short READ_GPNV_INVALID_HANDLE
;R37AREAD_GPNV_SUCCESS:
;R37A  add	si,2
;R37A  mov	cx,GPNV_BLOCK_SIZE - 2
;R37A  call  Flash_Read
;R37A  mov   ax,DMI_SUCCESS
;R37A  ret
;R37AREAD_GPNV_INVALID_HANDLE:
;R37A  mov	ax,DMI_INVALID_HANDLE
;R37Aelse
;R37A  mov   ax,DMI_FUNCTION_NOT_SUPPORTED

;R37A start
public	Read_post_mark0

  mov   bx,rg_handle
  cmp	bx,0FFFFh
  jae	short READ_GPNV_INVALID_HANDLE
Read_post_mark0:
  jmp	short in_post_read_data
  mov	ax,cs
  mov	ds,ax
;;;;;  mov	si,Shadow_DMI_Address + DMI_GPNV_MAX_POOL_SIZE
  mov	si,Shadow_DMI_Len_Address - GPNV_MIN_BUF_SIZE	; 0ffset 0E00h
  les	di,rg_gpnv_buffer
  jmp	short @F
in_post_read_data:
  mov	ax,DMI_STORAGE_BASE
  mov	ds,ax
;R37C  mov   si,DMI_OFFSET + DMI_GPNV_MAX_POOL_SIZE
  mov   si,DMI_OFFSET + DMI_MAX_POOL_SIZE		;R37C
  les	di,rg_gpnv_buffer
;R37C  mov	cx,DMI_STORAGE_SIZE - DMI_GPNV_MAX_POOL_SIZE
  mov	cx,DMI_STORAGE_SIZE - DMI_MAX_POOL_SIZE		;R37C
  call	post_flash_read
  push	es
  pop	ds
  push	di
  pop	si
@@:
  call	Find_handle_fun
  jc	short READ_GPNV_INVALID_HANDLE
  add	si,2
  mov	cx,GPNV_BLOCK_SIZE - 2
  cmp	word ptr rg_handle, Event_Log_Handle
  jne	short Read_Not_Event_Logo
  add	cx,GPNV_BLOCK_SIZE + 2
Read_Not_Event_Logo:
  rep	movsb
  mov	word ptr es:[di],0ffffh				;R37F
  mov   ax,DMI_SUCCESS
  ret
READ_GPNV_INVALID_HANDLE:
  mov	ax,DMI_INVALID_HANDLE
else
  mov   ax,DMI_FUNCTION_NOT_SUPPORTED
;R37A end

endif	;DMI_GPNV_support
  ret

read_gpnv endp

;=============================================================================
; FUNC: 57h - Write general-purpose nv data (GPNV)
;
; SYNOPSIS:
;
; short FAR (*entryPoint)(Function, Handle, GPNVBuffer, GPNVSelector, BiosSelector);
;
; short Function;                /* PnP BIOS Function 043h */
; unsigned short FAR *Handle              - Identifies which GPNV to access
; char FAR *GPNVBuffer;        /* Buffer containing complete GPNV to write... */
; unsigned short GPNVSelector;   /* GPNV read/writable selector */
; unsigned short BiosSelector;   /* PnP BIOS read/writable selector */
;
; DESC:  This function will write the entire (GPNV) from the GPNVBuffer
;               into the nonvolatile storage area.
;
; IN:   NONE
; OUT:  AX  - Error Code (0 if successful)
;=============================================================================
		public	write_gpnv 	
write_gpnv proc near
  wg_func_num      equ [ebp+FN_OFS]       ; short Function
  wg_handle	   equ [ebp+FN_OFS+02h]   ; Identifies which GPNV to access
  wg_gpnv_buffer   equ [ebp+FN_OFS+04h]   ; char FAR *GPNVBuffer
  wg_gpnv_lock     equ [ebp+FN_OFS+08h]   ; short GPNVLock
  wg_gpnv_selector equ [ebp+FN_OFS+0Ch]   ; unsigned short GPNVSelector
  wg_bios_selector equ [ebp+FN_OFS+0Eh]   ; BIOS read/writeable selector
  mov	gs, wg_bios_selector	  	  ;R45

;  mov   ax,wg_gpnv_selector
;  mov   es,ax                       ; get seg/selector of GPNV
;  mov   di,GPNV_OFFSET              ; get offset of GPNV
;  lds   si,wg_gpnv_buffer           ; load DS:SI with GPNVBuffer
;  mov   cx,GPNV_BLOCK_SIZE          ; get size of block
;  call  Flash_Write
;  mov   ax,DMI_SUCCESS
ifdef	DMI_GPNV_support
;R37A  mov	ax, DMI_STORAGE_BASE
;R37A  mov	ds, ax
;R37A  mov   si, DMI_OFFSET + DMI_GPNV_MAX_POOL_SIZE
;R37A  mov   bx, rg_handle
;R37A  cmp	bx, 0FFFFh
;R37A  jae	short EXIT_WRITE_GPNV
;R37A  les	di, wg_gpnv_buffer
;R37A  add	di, DMI_GPNV_MAX_POOL_SIZE
;R37A  mov	cx, DMI_STORAGE_SIZE - DMI_GPNV_MAX_POOL_SIZE
;R37A  call	Flash_Read
;R37A
;R37A  mov	cx,8
;R37AGPNV_Write_Loop:
;R37A  cmp	word ptr es:[di],bx
;R37A  je	short Write_to_flash
;R37A  cmp	word ptr es:[di],0FFFFh
;R37A  je	short Write_to_flash
;R37A  add	di, GPNV_BLOCK_SIZE
;R37A  loop  GPNV_Write_Loop
;R37A  jmp	short EXIT_WRITE_GPNV
;R37AWrite_to_flash:
;R37A  lds	si, wg_gpnv_buffer
;R37A  mov	word ptr es:[di], bx
;R37A  add	di, 2
;R37A  mov	cx, GPNV_BLOCK_SIZE - 2
;R37A  rep   movsb
;R37A
;R37A  les	di, wg_gpnv_buffer
;R37A  mov	ax, DMI_STORAGE_BASE
;R37A  mov	ds, ax
;R37A  mov   si, DMI_OFFSET
;R37A  mov	cx, DMI_GPNV_MAX_POOL_SIZE
;R37A  call	Flash_Read
;R37A
;R37A  push	ds
;R37A  pop	es
;R37A  push	si
;R37A  pop	di
;R37A  lds	si, wg_gpnv_buffer
;R37A  mov	cx, DMI_STORAGE_SIZE
;R37A  call  Flash_Write
;R37A  jnc   short GPNV_WRITE_SUCCESS
;R37A  mov	ax,DMI_READ_ONLY
;R37A  ret
;R37AGPNV_WRITE_SUCCESS:
;R37A  mov   ax,DMI_SUCCESS
;R37A  ret
;R37AEXIT_WRITE_GPNV:
;R37A  mov   ax,DMI_INVALID_HANDLE


;R37A start
public	Write_post_mark0
public	Write_post_mark1
public	Write_post_mark2

  mov	ax, DMI_STORAGE_BASE
  mov	ds, ax
;R37C  mov   si, DMI_OFFSET + DMI_GPNV_MAX_POOL_SIZE
  mov   si, DMI_OFFSET + DMI_MAX_POOL_SIZE		;R37C
  mov   bx, rg_handle					; cmp handle
  cmp	bx, 0FFFFh					; ? invalid
  jae	EXIT_WRITE_GPNV

  les	di, wg_gpnv_buffer
;R37C  add	di, DMI_GPNV_MAX_POOL_SIZE
  add	di, DMI_MAX_POOL_SIZE		;R37C
;R37C  mov	cx, DMI_STORAGE_SIZE - DMI_GPNV_MAX_POOL_SIZE
  mov	cx, DMI_STORAGE_SIZE - DMI_MAX_POOL_SIZE	;R37C
Write_post_mark0:
  jmp	short In_post_FR

  cmp   Word ptr rg_handle, Event_Log_Handle		; cmp event log handle
  je	EXIT_WRITE_GPNV

;R45  call	Flash_Read
  mov	ax,cx			;R45
  call	Read_DMI		;R45
  jmp	short @F
In_post_FR:
  call	Post_Flash_Read
@@:
  push	es
  pop	ds
  push	di
  pop	si
find_handle:
  call	Find_handle_fun					; find valid handle
  jc	EXIT_WRITE_GPNV					; CF not find

  mov	word ptr ds:[si], bx
  add	si, 2

  cmp	word ptr rg_handle, Event_Log_Handle
  jne	short Write_Not_Event_Logo
;R38B start
  cmp	word ptr ds:[si],0AA55h		; have type1 header
  add	si,10h				; add type1 header length
  je	short type1_header		; yes
  sub	si,10h				; sub type1 header length
  push	si
  pop	di
  push	ds
  pop	es
  push  cs
  pop	ds
  mov	si,offset heder_buffer		; save type1 header
  mov	cx,10h
  rep	movsb
  push	es
  pop	ds
  push	di
  pop	si
type1_header:
;R38B end
  xor	ax,ax
Find_Event_Logo:
  cmp	word ptr ds:[si],0ffffh
  je	short Write_Event_Logo
;R37D  xor	bx,bx
;R37D  mov	bl,byte ptr ds:[si+1]
  movzx	bx,byte ptr ds:[si+1]	;R37D
  add	ax,bx
;R37D  cmp	ax,GPNV_BLOCK_SIZE * 2
;R37B  ja	short EXIT_WRITE_GPNV
;R37D  ja	EXIT_WRITE_GPNV				;R37B
  add	si,bx
;R37D  jmp	short Find_Event_Logo
;R37D start
	cmp	ax,GPNV_BLOCK_SIZE * 2
	jb	short Find_Event_Logo
	sub	si,ax			;SI = GPNV pool of start offset
	mov	di,si			;store to DI
	movzx	bx,byte ptr ds:[si+1]	;get first handle size to BX
	add	si,bx			;get second type of offset
	mov	cx,ax			;get total size
	sub	cx,bx			;sub first size
	rep	movsb
	mov	si,di
;R37D end
Write_Event_Logo:
  mov   byte ptr ds:[si],Post_Error
  inc	si
  mov   byte ptr ds:[si],10h
  inc	si
;R37B  add	si,6
  push	ds					;R37B
  pop	es					;R37B
  push	si					;R37B
  pop	di					;R37B
;R37B  les	di, wg_gpnv_buffer
  lds	si,wg_gpnv_buffer			;R37B
;R37B  mov	eax,es:[di]
;R37B  mov	ds:[si],eax
  push	si					;R37B
  add	si,8					;R37B
  mov	cx,3					;R37B
  rep	movsw					;R37B
  pop	si					;R37B
  mov	cx,4					;R37B
  rep	movsw					;R37B
  jmp	short @F
Write_Not_Event_Logo:
  push	ds
  pop	es
  push	si
  pop	di
  lds	si, wg_gpnv_buffer
  mov	cx, GPNV_BLOCK_SIZE - 2
  rep	movsb
@@:
  les	di, wg_gpnv_buffer
  mov	ax, DMI_STORAGE_BASE
  mov	ds, ax
  mov   si, DMI_OFFSET
;R37C  mov	cx, DMI_GPNV_MAX_POOL_SIZE
  mov	cx, DMI_MAX_POOL_SIZE	;R37C
Write_post_mark1:
  jmp	short in_post_FR1
;R45  call	Flash_Read
  mov	ax,cx			;R45
  call	Read_DMI		;R45
  jmp	short @F
in_post_FR1:
  call	Post_Flash_Read
@@:

  push	ds
  pop	es
  push	si
  pop	di
  lds	si, wg_gpnv_buffer
  mov	cx, DMI_STORAGE_SIZE
Write_post_mark2:
  jmp	short in_post_FW
;R45  call  Flash_Write        ; write to flash
  call	Write_DMI		;R45
  call  F000_Shadow_W		; Enable F000 shadow writeable
  mov	ax,cs
  mov	es,ax
;;;;;  mov	di,Shadow_DMI_Address + DMI_GPNV_MAX_POOL_SIZE
  mov	di,Shadow_DMI_Len_Address - GPNV_MIN_BUF_SIZE	; 0ffset 0E00h
  lds	si, wg_gpnv_buffer
;R37C  add	si, DMI_GPNV_MAX_POOL_SIZE
  add	si, DMI_MAX_POOL_SIZE		;R37C
  mov	cx, GPNV_MIN_BUF_SIZE
  rep	movsb
  call	F000_Shadow_R		; Enable F000 shadow readonly
  jmp	short @F
in_post_FW:
  call  Post_Flash_Write
@@:

GPNV_WRITE_SUCCESS:
  mov   ax,DMI_SUCCESS
  ret
EXIT_WRITE_GPNV:
  mov   ax,DMI_INVALID_HANDLE
;R37A end

else
  mov   ax,DMI_FUNCTION_NOT_SUPPORTED
endif	;DMI_GPNV_support
  ret
;R38B start
heder_buffer:			; type1 header
	db	55h		; OEM Reserved
	db	0AAh		; OEM Reserved
	db	08h		; OEM Reserved
	db	0cbh		; OEM Reserved
	db	0a3h		; OEM Reserved
	db	00h		; multiple event time windows
	db	01h		; multiple event count increment
	db	0ffh		; pre-boot event log reset-CMOS address
	db	00h		; pre-boot event log reset-CMOS Bit address
	db	0ffh		; CMOS checksum - starting offset
	db	01h		; CMOS checksum - byte count
	db	0ffh		; CMOS checksum - checksum offset
	db	00h		; Reserved
	db	00h		; Reserved
	db	00h		; Reserved
	db	01h		; Header revision
;R38B end
write_gpnv endp

;R37A start
ifdef	DMI_GPNV_support
;=============================================================================
; FUNC: Find_handle_fun
;
; DESC: Find the handle in the GPNV pool
; 
; IN:   DS:SI - Start Buffer
;	   BX - Handle
;
; OUT:  CF    - Not Found
;=============================================================================
		public	Find_handle_fun
Find_handle_fun	proc	near
  mov	ax,si
  add	ax,GPNV_MIN_BUF_SIZE	;;;;;
GPNV_Read_Loop:
  cmp	word ptr ds:[si],bx
  je	short Find_Handle_Success
  cmp	word ptr ds:[si],0FFFFh
  je	short Find_Handle_Success
  cmp	word ptr ds:[si],Event_Log_Handle
  jne	short Read_Not_DMI_Event_Logo
  add	si,GPNV_BLOCK_SIZE + 2
Read_Not_DMI_Event_Logo:
  add	si,GPNV_BLOCK_SIZE
  cmp	si,ax
  jbe	short GPNV_Read_Loop
  stc
  ret
Find_Handle_Success:
  clc
  ret
Find_handle_fun	endp
endif	;DMI_GPNV_support
;R37A end

;=============================================================================
;                             UTILITY FUNCTIONS
;=============================================================================

;=============================================================================
; FUNC: SET_MAX_AND_NUM_STRUCTS
;
; DESC: Find the maximum structure size in the DMI pool and set max struct
;       size to this value
; 
; IN:   DS:SI - Start of 4K Buffer
; OUT:  CX    - Size of block to update (to the nearest granularity)
; ASSUMES THAT DMI POOL HAS A VALID TERMINATOR OF 0FFFFh AT END
; DESTROYED: DX
;=============================================================================
set_max_and_num_structs proc near

  push  si                          ; save start of buffer
  add   si,DMI_TBL_OFFSET+DMI_SIGNATURE_SIZE       

ifdef MASM611
  assume si:ptr dmi_info_struct
endif

  push  si
  xor   cx,cx                       ; clear num structs to zero
  xor   dx,dx                       ; clear max struct to zero
  add   si,size dmi_info_struct     ; skip table information

SMSS_CHECK_NEXT_STRUCT:
  mov   ax,word ptr ds:[si]         ; read in length

  or	ax,ax				
  je    short SMSS_END_OF_POOL
  add   si,2
ifdef MASM611
  assume si: ptr dmi_struct_hdr
endif
  mov   bx,ds:[si].dmi_handle       ; check for terminator
  cmp   bx,DMI_TERMINATOR
  je    short SMSS_END_OF_POOL

  cmp   ax,dx
  jle   short SMSS_STRUCT_NOT_BIGGER
  mov   dx,ax                       ; struct is bigger
SMSS_STRUCT_NOT_BIGGER:

  add   si,ax
  inc   cx                          ; increment number of structs
  jmp   short SMSS_CHECK_NEXT_STRUCT

SMSS_END_OF_POOL:

  mov   ax,si
  pop   si


ifdef MASM611
  assume si:ptr dmi_info_struct
endif

  mov   ds:[si].num_structs,cx      ; get num structs
  mov   ds:[si].max_struct_size,dx  ; get max structs

  pop   si                          ; restore start of buffer

  mov   cx,DMI_STORAGE_SIZE         ; size needed to hold block
smn_exit:

  ret

set_max_and_num_structs endp

;=============================================================================
; FUNC: MOVE_EVERYTHING_UP
;
; DESC: Move everything up (Shrink DMI Pool)
;       
; IN:   CX    - Amount in bytes to decrease 
;       DX    - Current offset of start of String to overwrite
;       ES:DI - Start of DMI pool
; OUT:  NONE
;=============================================================================
move_everything_up proc

  pusha                             ; save all general registers

  push  cx                          ; save number of bytes to decrease
  mov   ax,dx                       ; 
  sub   ax,di                       ; AX - offset from beginning of pool
  mov	di,dx
  xor	bx,bx
  mov	bl,byte ptr es:[di+3]
  add	ax,bx
  inc	ax
  mov   cx,ax                       
;R37C ifdef	DMI_GPNV_support	    
;R37C   mov   ax,DMI_GPNV_MAX_POOL_SIZE   
;R37C else				    
  mov   ax,DMI_MAX_POOL_SIZE
;R37C endif	;DMI_GPNV_support	    
  sub   ax,cx                       ; AX - number of bytes to move
  mov   cx,ax                       ; CX - number of bytes to move
  pop   ax                          ; restore number of bytes to decrease

  push  es
  pop   ds                          ; 
  mov   di,dx                       ; restore current location
  mov   si,di
  add   si,ax                       ; 

  cld
  rep   movsb                       ; mov strings down further

  popa                              ; restore all general registers

  ret

move_everything_up endp

;=============================================================================
; FUNC: MOVE_EVERYTHING_DOWN (Grow DMI Pool)
;
; DESC: Move everything down - need to check to see if it will fit
;       1.  Move Structures down
;       2.  Move Strings Down
;       
; 
; IN:   CX    - Amount in bytes to increase
;       DX    - Current offset of start of String to overwrite
;       ES:DI - Start of DMI pool
; OUT:  CY    - Move failed
;=============================================================================
move_everything_down proc near

  pusha                             ; save all general registers

  push  cx                          ; save length to move
  mov   bx,DMI_TERMINATOR           ; goto end of pool
ifdef MASM611
  assume di: ptr dmi_info_struct
endif
  mov   cx,es:[di].num_structs      ; get number of structures in DMI TBL
  push  di                          ; save offset of beginning of pool
  add   di,size dmi_info_struct     ; skip table information
  call  get_structure               ; point ES:DI to end of DMI pool
  pop   si                          ; restore offset from beggining of pool
  pop   cx                          ; restore length to move
  call  check_for_room              ; verify that there is room to add
  jc    short MED_FAILED            ; quit if no room to add

  push  cx                          ; save number of bytes to increase
  mov   ax,di                       ; AX = end of used pool
  sub   ax,dx                       ; AX = end - current
  mov   cx,ax                       ; CX = number of bytes to copy
  inc   cx                          ; increase number of bytes to copy by one
  pop   dx                          ; restore number of bytes to increase

  mov   si,di                       ; SI = end of pool
  add   di,dx                       ; DI = end of pool + num bytes to add
  push  es                          ; push destination segment
  pop   ds                          ; destination segment same as source

  std                               ; set direction as backward
  rep   movsb                       ; mov strings down further

MED_FAILED:
  stc                               ; move failed
  jmp   short MED_EXIT

MED_SUCCESS:
  clc                               ; move successfull

MED_EXIT:

  popa                              ; restore all general registers

  ret

move_everything_down endp


;=============================================================================
; FUNC: CHECK_FOR_ROOM
;
; DESC: Check for room to move down
; 
; IN:   SI    - Offset from beggining of DMI Work Buffer
;       DI    - Current end of used pool area
;       CX    - length to add
; OUT:  CY    - No room to move
; DESTROYED: AX
;=============================================================================
check_for_room proc near

  push  di
  sub   di,si                       ; DI = offset from begining
  xor   ax,ax                       ; clear size
  add   ax,di                       ; add offset of last structure
  add   ax,cx                       ; add length to move down
;R37C ifdef	DMI_GPNV_support	    
;R37C   cmp   ax,DMI_GPNV_MAX_POOL_SIZE   ; check if there is room to move
;R37C else				    ;
  cmp   ax,DMI_MAX_POOL_SIZE        ; check if there is room to move
;R37C endif	;DMI_GPNV_support	    
  jae   short CFR_NO_ROOM
  clc
  jmp   short CFR_EXIT

CFR_NO_ROOM:
  stc   

CFR_EXIT:
  pop   di

  ret

check_for_room endp

ifndef ESCD_M2				
;=============================================================================
; FUNC: CHECK_DMI_SIGNATURE
;
; DESC: Check for valid DMI signature
; 
; IN:   DS:SI - Start of Pool - Points to Signature location
;       ES:DI - Buffer of atleast 4 Bytes for use by check DMI signature
; OUT:  CY    - Signature invalid
;       DS:SI - Moved to beginning of Structure Information
; DESTROYED:  EAX,ECX
;=============================================================================
check_dmi_signature proc

  mov   ax,DMI_SIGNATURE_SIZE       
  call  read_dmi
  mov   eax,es:[di]
  mov   ecx,DMI_SIGNATURE           ; check for valid pool
  add   si,DMI_SIGNATURE_SIZE       
  cmp   eax,ecx                     ; compare high byte
  je    short CDS_SIGNATURE_OK

CDS_INVALID_POOL:
  stc                               ; signal signature not found
  jmp   short CDS_EXIT

CDS_SIGNATURE_OK:
  clc                               ; signal signature found

CDS_EXIT:

  ret

check_dmi_signature endp
endif ;ESCD_M2				


;=============================================================================
; FUNC: READ_DMI
;
; DESC: Read information into buffer at ES:DI
;
; IN:   AX    - Size
;       DS:SI - Source
;       ES:DI - Destination
; OUT:  NONE
;=============================================================================
		public Read_DMI			;R45
read_dmi proc near

  push  ds
  push  si
  push  di
  push  cx
  mov   cx,ax
;R45 - start
ifdef	ESCD_32bits
  and	esi, 00000FFFFh
  or	esi, DMI_STORAGE_BASE_32
endif;	ESCD_32bits
;R45 - end
  call  Flash_Read
  pop   cx
  pop   di
  pop   si
  pop   ds

  ret

read_dmi endp

;R45 - start
;=============================================================================
; FUNC: Write_DMI
;
; DESC: Write information into Flash at ES:EDI
;
; IN:   AX    - Size
;       DS:SI - Source
;       ES:EDI - Destination
; OUT:  NONE
;=============================================================================
		public Write_DMI
Write_DMI	Proc	Near
	push	edi
ifdef	ESCD_32bits
	and	edi, 0000FFFFh
	or	edi, DMI_STORAGE_BASE_32	;if 64k_unit dmi in fff80000h
endif;	ESCD_32bits
	call	Flash_Write
	pop	edi
	ret
Write_DMI	endp

;R45 - end


;=============================================================================
; FUNC: GET_STRUCTURE
;
; DESC: Get a DMI Structure out of the pool
;
; IN:   BX    - Structure Handle to Find
;       ES:DI - Start of first structure
;       CX    - Number of structures in pool
; OUT:  ES:DI - Start of structure to find
;       NC    - Structure has been found
;       CY    - Structure not found
;=============================================================================
get_structure proc near

  push  ax
  push  dx
  push  cx                          ; save number of structures

  or    cx,cx                       ; if no structures present,
  jz    short GS_STRUCT_NOT_FOUND  ;  then skip search

GS_CHECK_NEXT_STRUCT:
  mov   ax,word ptr es:[di]         ; read in length
  add   di,2                        ; advance DI to structure header

  cmp   ax,0                        ; if struct length is zero
  je    short GS_STRUCT_NOT_FOUND   ; struct not found

ifdef MASM611
  assume di: ptr dmi_struct_hdr
endif
  mov   dx,es:[di].dmi_handle
  cmp   dx,DMI_TERMINATOR
  je    short GS_STRUCT_NOT_FOUND

  cmp   bx,dx
  jz    short GS_STRUCT_FOUND 
  add   di,ax
  loop  short GS_CHECK_NEXT_STRUCT

GS_STRUCT_NOT_FOUND:
  stc
  jmp   short GS_EXIT

GS_STRUCT_FOUND:
  clc

GS_EXIT:

  pop   cx                          ; restore number of structures
  pop   dx
  pop   ax

  ret

get_structure endp

Public  END_DMI_RUNTIME              ; Used to track overall size of
END_DMI_RUNTIME LABEL BYTE           ;  DMI Post 

FCODE    ENDS
endif	;FLASH_SUPPORT	;R41
endif;   DMI_ENABLED
    END
