2894 lines
101 KiB
C
2894 lines
101 KiB
C
/** @file
|
|
Implementation for EFI_HII_IMAGE_PROTOCOL.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2021, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
|
|
Copyright (c) 2007 - 2008, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
*/
|
|
|
|
#include "HiiDatabase.h"
|
|
#include <Protocol/JpegDecoder.h>
|
|
|
|
|
|
EFI_JPEG_DECODER_PROTOCOL *mJpegDecoder = NULL;
|
|
|
|
/**
|
|
Get the imageid of last image block: EFI_HII_IIBT_END_BLOCK when input
|
|
ImageId is zero, otherwise return the address of the
|
|
corresponding image block with identifier specified by ImageId.
|
|
|
|
This is a internal function.
|
|
|
|
@param[in] ImageBlock Points to the beginning of a series of image blocks stored in order.
|
|
@param[in, out] ImageId If input ImageId is 0, output the image id of the EFI_HII_IIBT_END_BLOCK;
|
|
else use this id to find its corresponding image block address.
|
|
|
|
@return The image block address when input ImageId is not zero; otherwise return NULL.
|
|
**/
|
|
UINT8*
|
|
GetImageIdOrAddress (
|
|
IN UINT8 *ImageBlock,
|
|
IN OUT EFI_IMAGE_ID *ImageId
|
|
)
|
|
{
|
|
EFI_IMAGE_ID ImageIdCurrent;
|
|
UINT8 *ImageBlockHdr;
|
|
UINT8 Length8;
|
|
UINT16 Length16;
|
|
UINT32 Length32;
|
|
EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit;
|
|
EFI_HII_IIBT_IMAGE_4BIT_BLOCK Iibt4bit;
|
|
EFI_HII_IIBT_IMAGE_8BIT_BLOCK Iibt8bit;
|
|
UINT16 Width;
|
|
UINT16 Height;
|
|
|
|
ASSERT (ImageBlock != NULL && ImageId != NULL);
|
|
|
|
ImageBlockHdr = ImageBlock;
|
|
ImageIdCurrent = 1;
|
|
|
|
while (((EFI_HII_IMAGE_BLOCK *) ImageBlock)->BlockType != EFI_HII_IIBT_END) {
|
|
if (*ImageId > 0) {
|
|
if (*ImageId == ImageIdCurrent) {
|
|
//
|
|
// If the found image block is a duplicate block, update the ImageId to
|
|
// find the previous defined image block.
|
|
//
|
|
if (((EFI_HII_IMAGE_BLOCK *) ImageBlock)->BlockType == EFI_HII_IIBT_DUPLICATE) {
|
|
CopyMem (ImageId, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (EFI_IMAGE_ID));
|
|
ASSERT (*ImageId != ImageIdCurrent);
|
|
ImageBlock = ImageBlockHdr;
|
|
ImageIdCurrent = 1;
|
|
continue;
|
|
}
|
|
|
|
return ImageBlock;
|
|
}
|
|
if (*ImageId < ImageIdCurrent) {
|
|
//
|
|
// Can not find the specified image block in this image.
|
|
//
|
|
return NULL;
|
|
}
|
|
}
|
|
switch (((EFI_HII_IMAGE_BLOCK *) ImageBlock)->BlockType) {
|
|
case EFI_HII_IIBT_EXT1:
|
|
Length8 = *(ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT8));
|
|
ImageBlock += Length8;
|
|
break;
|
|
case EFI_HII_IIBT_EXT2:
|
|
CopyMem (
|
|
&Length16,
|
|
ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT8),
|
|
sizeof (UINT16)
|
|
);
|
|
ImageBlock += Length16;
|
|
|
|
break;
|
|
case EFI_HII_IIBT_EXT4:
|
|
CopyMem (
|
|
&Length32,
|
|
ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT8),
|
|
sizeof (UINT32)
|
|
);
|
|
ImageBlock += Length32;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_1BIT:
|
|
case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
|
|
CopyMem (&Iibt1bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
|
|
ImageBlock += sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
|
|
BITMAP_LEN_1_BIT (Iibt1bit.Bitmap.Width, Iibt1bit.Bitmap.Height);
|
|
ImageIdCurrent++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_4BIT:
|
|
case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
|
|
CopyMem (&Iibt4bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK));
|
|
ImageBlock += sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
|
|
BITMAP_LEN_4_BIT (Iibt4bit.Bitmap.Width, Iibt4bit.Bitmap.Height);
|
|
ImageIdCurrent++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_8BIT:
|
|
case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
|
|
CopyMem (&Iibt8bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK));
|
|
ImageBlock += sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
|
|
BITMAP_LEN_8_BIT (Iibt8bit.Bitmap.Width, Iibt8bit.Bitmap.Height);
|
|
ImageIdCurrent++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_24BIT:
|
|
case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
|
|
CopyMem (&Width, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT16));
|
|
CopyMem (
|
|
&Height,
|
|
ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT16),
|
|
sizeof (UINT16)
|
|
);
|
|
ImageBlock += sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
|
|
BITMAP_LEN_24_BIT (Width, Height);
|
|
ImageIdCurrent++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_DUPLICATE:
|
|
ImageBlock += sizeof (EFI_HII_IIBT_DUPLICATE_BLOCK);
|
|
ImageIdCurrent++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_JPEG:
|
|
CopyMem (&Length32, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT32));
|
|
ImageBlock += Length32 + sizeof (EFI_HII_IIBT_JPEG_BLOCK) - sizeof (UINT8);
|
|
ImageIdCurrent++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_SKIP1:
|
|
Length8 = *(ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK));
|
|
ImageBlock += sizeof (EFI_HII_IIBT_SKIP1_BLOCK);
|
|
ImageIdCurrent = (UINT16) (ImageIdCurrent + Length8);
|
|
break;
|
|
|
|
case EFI_HII_IIBT_SKIP2:
|
|
CopyMem (&Length16, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT16));
|
|
ImageBlock += sizeof (EFI_HII_IIBT_SKIP2_BLOCK);
|
|
ImageIdCurrent = (UINT16) (ImageIdCurrent + Length16);
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Unknown image blocks can not be skipped, processing halts.
|
|
//
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// When ImageId is zero, return the imageid of last image block: EFI_HII_IIBT_END_BLOCK.
|
|
//
|
|
if (*ImageId == 0) {
|
|
*ImageId = ImageIdCurrent;
|
|
return ImageBlock;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Convert pixels from EFI_GRAPHICS_OUTPUT_BLT_PIXEL to EFI_HII_RGB_PIXEL style.
|
|
|
|
This is a internal function.
|
|
|
|
@param[out] BitMapOut Pixels in EFI_HII_RGB_PIXEL format.
|
|
@param[in] BitMapIn Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
|
|
@param[in] PixelNum The number of pixels to be converted.
|
|
**/
|
|
VOID
|
|
CopyGopToRgbPixel (
|
|
OUT EFI_HII_RGB_PIXEL *BitMapOut,
|
|
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapIn,
|
|
IN UINTN PixelNum
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
ASSERT (BitMapOut != NULL && BitMapIn != NULL);
|
|
|
|
for (Index = 0; Index < PixelNum; Index++) {
|
|
CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
|
|
}
|
|
}
|
|
|
|
/**
|
|
Convert pixels from EFI_HII_RGB_PIXEL to EFI_GRAPHICS_OUTPUT_BLT_PIXEL style.
|
|
|
|
This is a internal function.
|
|
|
|
@param[out] BitMapOut Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
|
|
@param[in] BitMapIn Pixels in EFI_HII_RGB_PIXEL format.
|
|
@param[in] PixelNum The number of pixels to be converted.
|
|
**/
|
|
VOID
|
|
CopyRgbToGopPixel (
|
|
OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapOut,
|
|
IN EFI_HII_RGB_PIXEL *BitMapIn,
|
|
IN UINTN PixelNum
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
ASSERT (BitMapOut != NULL && BitMapIn != NULL);
|
|
|
|
for (Index = 0; Index < PixelNum; Index++) {
|
|
CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
|
|
}
|
|
}
|
|
|
|
/**
|
|
Output pixels in "1 bit per pixel" format to an image.
|
|
|
|
This is a internal function.
|
|
|
|
@param[in, out] Image Points to the image which will store the pixels.
|
|
@param[in] Data Stores the value of output pixels, 0 or 1.
|
|
@param[in] PaletteInfo PaletteInfo which stores the color of the output
|
|
pixels. First entry corresponds to color 0 and
|
|
second one to color 1.
|
|
@retval EFI_SUCCESS The new image was generated successfully.
|
|
@retval EFI_OUT_OF_RESOURCES The bitmap could not be generated because there was not enough memory.
|
|
**/
|
|
EFI_STATUS
|
|
Output1bitPixel (
|
|
IN OUT EFI_IMAGE_INPUT *Image,
|
|
IN UINT8 *Data,
|
|
IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
|
|
)
|
|
{
|
|
UINT16 Xpos;
|
|
UINT16 Ypos;
|
|
UINTN OffsetY;
|
|
UINT8 Index;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[2];
|
|
EFI_HII_IMAGE_PALETTE_INFO *Palette;
|
|
UINT16 PaletteSize;
|
|
UINT8 Byte;
|
|
|
|
ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
|
|
|
|
BitMapPtr = Image->Bitmap;
|
|
|
|
//
|
|
// First entry corresponds to color 0 and second entry corresponds to color 1.
|
|
//
|
|
CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
|
|
PaletteSize += sizeof (UINT16);
|
|
Palette = AllocateZeroPool (PaletteSize);
|
|
ASSERT (Palette != NULL);
|
|
if (Palette == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyMem (Palette, PaletteInfo, PaletteSize);
|
|
|
|
ZeroMem (PaletteValue, sizeof (PaletteValue));
|
|
CopyRgbToGopPixel (&PaletteValue[0], &Palette->PaletteValue[0], 1);
|
|
CopyRgbToGopPixel (&PaletteValue[1], &Palette->PaletteValue[1], 1);
|
|
FreePool (Palette);
|
|
|
|
//
|
|
// Convert the pixel from one bit to corresponding color.
|
|
//
|
|
for (Ypos = 0; Ypos < Image->Height; Ypos++) {
|
|
OffsetY = BITMAP_LEN_1_BIT (Image->Width, Ypos);
|
|
//
|
|
// All bits in these bytes are meaningful
|
|
//
|
|
for (Xpos = 0; Xpos < Image->Width / 8; Xpos++) {
|
|
Byte = *(Data + OffsetY + Xpos);
|
|
for (Index = 0; Index < 8; Index++) {
|
|
if ((Byte & (1 << Index)) != 0) {
|
|
BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[1];
|
|
} else {
|
|
BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Image->Width % 8 != 0) {
|
|
//
|
|
// Padding bits in this byte should be ignored.
|
|
//
|
|
Byte = *(Data + OffsetY + Xpos);
|
|
for (Index = 0; Index < Image->Width % 8; Index++) {
|
|
if ((Byte & (1 << (8 - Index - 1))) != 0) {
|
|
BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[1];
|
|
} else {
|
|
BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Output pixels in "4 bit per pixel" format to an image.
|
|
|
|
This is a internal function.
|
|
|
|
@param[in, out] Image Points to the image which will store the pixels.
|
|
@param[in] Data Stores the value of output pixels, 0 ~ 15.
|
|
@param[in] PaletteInfo PaletteInfo which stores the color of the output
|
|
pixels. Each entry corresponds to a color within [0, 15].
|
|
@retval EFI_SUCCESS The new image was generated successfully.
|
|
@retval EFI_OUT_OF_RESOURCES The bitmap could not be generated because there was not enough memory.
|
|
**/
|
|
EFI_STATUS
|
|
Output4bitPixel (
|
|
IN OUT EFI_IMAGE_INPUT *Image,
|
|
IN UINT8 *Data,
|
|
IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
|
|
)
|
|
{
|
|
UINT16 Xpos;
|
|
UINT16 Ypos;
|
|
UINTN OffsetY;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[16];
|
|
EFI_HII_IMAGE_PALETTE_INFO *Palette;
|
|
UINT16 PaletteSize;
|
|
UINT16 PaletteNum;
|
|
UINT8 Byte;
|
|
|
|
ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
|
|
|
|
BitMapPtr = Image->Bitmap;
|
|
|
|
//
|
|
// The bitmap should allocate each color index starting from 0.
|
|
//
|
|
CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
|
|
PaletteSize += sizeof (UINT16);
|
|
Palette = AllocateZeroPool (PaletteSize);
|
|
ASSERT (Palette != NULL);
|
|
if (Palette == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyMem (Palette, PaletteInfo, PaletteSize);
|
|
PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
|
|
|
|
ZeroMem (PaletteValue, sizeof (PaletteValue));
|
|
CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, MIN (PaletteNum, ARRAY_SIZE (PaletteValue)));
|
|
FreePool (Palette);
|
|
|
|
//
|
|
// Convert the pixel from 4 bit to corresponding color.
|
|
//
|
|
for (Ypos = 0; Ypos < Image->Height; Ypos++) {
|
|
OffsetY = BITMAP_LEN_4_BIT (Image->Width, Ypos);
|
|
//
|
|
// All bits in these bytes are meaningful
|
|
//
|
|
for (Xpos = 0; Xpos < Image->Width / 2; Xpos++) {
|
|
Byte = *(Data + OffsetY + Xpos);
|
|
BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4];
|
|
BitMapPtr[Ypos * Image->Width + Xpos * 2 + 1] = PaletteValue[Byte & 0x0F];
|
|
}
|
|
|
|
if (Image->Width % 2 != 0) {
|
|
//
|
|
// Padding bits in this byte should be ignored.
|
|
//
|
|
Byte = *(Data + OffsetY + Xpos);
|
|
BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4];
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Output pixels in "8 bit per pixel" format to an image.
|
|
|
|
This is a internal function.
|
|
|
|
@param[in, out] Image Points to the image which will store the pixels.
|
|
@param[in] Data Stores the value of output pixels, 0 ~ 255.
|
|
@param[in] PaletteInfo PaletteInfo which stores the color of the output
|
|
pixels. Each entry corresponds to a color within [0, 255].
|
|
@retval EFI_SUCCESS The new image was generated successfully.
|
|
@retval EFI_OUT_OF_RESOURCES The bitmap could not be generated because there was not enough memory.
|
|
**/
|
|
EFI_STATUS
|
|
Output8bitPixel (
|
|
IN OUT EFI_IMAGE_INPUT *Image,
|
|
IN UINT8 *Data,
|
|
IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
|
|
)
|
|
{
|
|
UINT16 Xpos;
|
|
UINT16 Ypos;
|
|
UINTN OffsetY;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[256];
|
|
EFI_HII_IMAGE_PALETTE_INFO *Palette;
|
|
UINT16 PaletteSize;
|
|
UINT16 PaletteNum;
|
|
UINT8 Byte;
|
|
|
|
ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
|
|
|
|
BitMapPtr = Image->Bitmap;
|
|
|
|
//
|
|
// The bitmap should allocate each color index starting from 0.
|
|
//
|
|
CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
|
|
PaletteSize += sizeof (UINT16);
|
|
Palette = AllocateZeroPool (PaletteSize);
|
|
ASSERT (Palette != NULL);
|
|
if (Palette == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyMem (Palette, PaletteInfo, PaletteSize);
|
|
PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
|
|
ZeroMem (PaletteValue, sizeof (PaletteValue));
|
|
CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, MIN (PaletteNum, ARRAY_SIZE (PaletteValue)));
|
|
FreePool (Palette);
|
|
|
|
//
|
|
// Convert the pixel from 8 bits to corresponding color.
|
|
//
|
|
for (Ypos = 0; Ypos < Image->Height; Ypos++) {
|
|
OffsetY = BITMAP_LEN_8_BIT (Image->Width, Ypos);
|
|
//
|
|
// All bits are meaningful since the bitmap is 8 bits per pixel.
|
|
//
|
|
for (Xpos = 0; Xpos < Image->Width; Xpos++) {
|
|
Byte = *(Data + OffsetY + Xpos);
|
|
BitMapPtr[OffsetY + Xpos] = PaletteValue[Byte];
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Output pixels in "24 bit per pixel" format to an image.
|
|
|
|
This is a internal function.
|
|
|
|
@param[in, out] Image Points to the image which will store the pixels.
|
|
@param[in] Data Stores the color of output pixels, allowing 16.8
|
|
millions colors.
|
|
**/
|
|
VOID
|
|
Output24bitPixel (
|
|
IN OUT EFI_IMAGE_INPUT *Image,
|
|
IN EFI_HII_RGB_PIXEL *Data
|
|
)
|
|
{
|
|
UINT16 Ypos;
|
|
UINTN OffsetY;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
|
|
|
|
ASSERT (Image != NULL && Data != NULL);
|
|
|
|
BitMapPtr = Image->Bitmap;
|
|
|
|
for (Ypos = 0; Ypos < Image->Height; Ypos++) {
|
|
OffsetY = BITMAP_LEN_8_BIT (Image->Width, Ypos);
|
|
CopyRgbToGopPixel (&BitMapPtr[OffsetY], &Data[OffsetY], Image->Width);
|
|
}
|
|
|
|
}
|
|
|
|
#define muldiv255(a,b) ((unsigned char)((((a)+1)*(b))>>8)) /* very fast, 92% accurate*/
|
|
|
|
/**
|
|
Convert the image from EFI_IMAGE_INPUT to EFI_IMAGE_OUTPUT format.
|
|
|
|
This is a internal function.
|
|
|
|
@param[in] BltBuffer Buffer points to bitmap data of incoming image.
|
|
@param[in] BltX Specifies the offset from the left and top edge of
|
|
the output image of the first pixel in the image.
|
|
@param[in] BltY Specifies the offset from the left and top edge of
|
|
the output image of the first pixel in the image.
|
|
@param[in] Width Width of the incoming image, in pixels.
|
|
@param[in] Height Height of the incoming image, in pixels.
|
|
@param[in] Transparent If TRUE, all "off" pixels in the image will be
|
|
drawn using the pixel value from blt and all other
|
|
pixels will be copied.
|
|
@param[in, out] Blt Buffer points to bitmap data of output image.
|
|
|
|
@retval EFI_SUCCESS The image was successfully converted.
|
|
@retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
|
|
**/
|
|
EFI_STATUS
|
|
ImageToBlt (
|
|
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
|
|
IN UINTN BltX,
|
|
IN UINTN BltY,
|
|
IN UINTN Width,
|
|
IN UINTN Height,
|
|
IN BOOLEAN Transparent,
|
|
IN BOOLEAN AlphaSupport,
|
|
IN OUT EFI_IMAGE_OUTPUT **Blt
|
|
)
|
|
{
|
|
EFI_IMAGE_OUTPUT *ImageOut;
|
|
UINTN Xpos;
|
|
UINTN Ypos;
|
|
UINTN OffsetY1; // src buffer
|
|
UINTN OffsetY2; // dest buffer
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL SrcPixel;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL ZeroPixel;
|
|
UINT8 Alpha;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL DstPixel;
|
|
|
|
if (BltBuffer == NULL || Blt == NULL || *Blt == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ImageOut = *Blt;
|
|
|
|
if (Width + BltX > ImageOut->Width) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (Height + BltY > ImageOut->Height) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ZeroMem (&ZeroPixel, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
|
|
|
|
if (AlphaSupport) {
|
|
for (Ypos = 0; Ypos < Height; Ypos++) {
|
|
OffsetY1 = Width * Ypos;
|
|
OffsetY2 = ImageOut->Width * (BltY + Ypos);
|
|
for (Xpos = 0; Xpos < Width; Xpos++) {
|
|
SrcPixel = BltBuffer[OffsetY1 + Xpos];
|
|
DstPixel = ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos];
|
|
Alpha = SrcPixel.Reserved;
|
|
DstPixel.Blue += muldiv255 (Alpha, SrcPixel.Blue - DstPixel.Blue);
|
|
DstPixel.Green += muldiv255 (Alpha, SrcPixel.Green - DstPixel.Green);
|
|
DstPixel.Red += muldiv255 (Alpha, SrcPixel.Red - DstPixel.Red);
|
|
ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = DstPixel;
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
for (Ypos = 0; Ypos < Height; Ypos++) {
|
|
OffsetY1 = Width * Ypos;
|
|
OffsetY2 = ImageOut->Width * (BltY + Ypos);
|
|
for (Xpos = 0; Xpos < Width; Xpos++) {
|
|
SrcPixel = BltBuffer[OffsetY1 + Xpos];
|
|
if (Transparent) {
|
|
if (CompareMem (&SrcPixel, &ZeroPixel, 3) != 0) {
|
|
ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel;
|
|
}
|
|
} else {
|
|
ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function adds the image Image to the group of images owned by PackageList, and returns
|
|
a new image identifier (ImageId).
|
|
|
|
@param[in] This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
|
|
@param[in] PackageList Handle of the package list where this image will
|
|
be added.
|
|
@param[out] ImageId On return, contains the new image id, which is
|
|
unique within PackageList.
|
|
@param[in] Image Points to the image.
|
|
|
|
@retval EFI_SUCCESS The new image was added successfully.
|
|
@retval EFI_NOT_FOUND The specified PackageList could not be found in
|
|
database.
|
|
@retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources.
|
|
@retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HiiNewImage (
|
|
IN CONST EFI_HII_IMAGE_PROTOCOL *This,
|
|
IN EFI_HII_HANDLE PackageList,
|
|
OUT EFI_IMAGE_ID *ImageId,
|
|
IN CONST EFI_IMAGE_INPUT *Image
|
|
)
|
|
{
|
|
HII_DATABASE_PRIVATE_DATA *Private;
|
|
LIST_ENTRY *Link;
|
|
HII_DATABASE_RECORD *DatabaseRecord;
|
|
HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
|
|
HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
|
|
UINT8 *ImageBlock;
|
|
UINTN BlockSize;
|
|
UINT8 *NewBlock;
|
|
UINT8 *NewBlockPtr;
|
|
UINTN NewBlockSize;
|
|
EFI_IMAGE_INPUT *ImageIn;
|
|
|
|
if (This == NULL || ImageId == NULL || Image == NULL || Image->Bitmap == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!IsHiiHandleValid (PackageList)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
//
|
|
// Get the specified package list
|
|
//
|
|
|
|
PackageListNode = NULL;
|
|
|
|
for (Link = Private->DatabaseList.ForwardLink;
|
|
Link != &Private->DatabaseList;
|
|
Link = Link->ForwardLink
|
|
) {
|
|
DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
|
|
if (DatabaseRecord->Handle == PackageList) {
|
|
PackageListNode = DatabaseRecord->PackageList;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (PackageListNode == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ImageIn = (EFI_IMAGE_INPUT *) Image;
|
|
|
|
NewBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
|
|
BITMAP_LEN_24_BIT (ImageIn->Width, ImageIn->Height);
|
|
|
|
//
|
|
// Get the image package in the package list,
|
|
// or create a new image package if image package does not exist.
|
|
//
|
|
if (PackageListNode->ImagePkg != NULL) {
|
|
ImagePackage = PackageListNode->ImagePkg;
|
|
|
|
//
|
|
// Output the image id of the incoming image being inserted, which is the
|
|
// image id of the EFI_HII_IIBT_END block of old image package.
|
|
//
|
|
*ImageId = 0;
|
|
GetImageIdOrAddress (ImagePackage->ImageBlock, ImageId);
|
|
|
|
//
|
|
// Update the package's image block by appending the new block to the end.
|
|
//
|
|
BlockSize = ImagePackage->ImageBlockSize + NewBlockSize;
|
|
ImageBlock = (UINT8 *) AllocateZeroPool (BlockSize);
|
|
if (ImageBlock == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// Copy the original content.
|
|
//
|
|
CopyMem (
|
|
ImageBlock,
|
|
ImagePackage->ImageBlock,
|
|
ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK)
|
|
);
|
|
FreePool (ImagePackage->ImageBlock);
|
|
ImagePackage->ImageBlock = ImageBlock;
|
|
ImageBlock += ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK);
|
|
//
|
|
// Temp memory to store new block.
|
|
//
|
|
NewBlock = AllocateZeroPool (NewBlockSize);
|
|
if (NewBlock == NULL) {
|
|
FreePool (ImagePackage->ImageBlock);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
NewBlockPtr = NewBlock;
|
|
|
|
//
|
|
// Update the length record.
|
|
//
|
|
ImagePackage->ImageBlockSize = (UINT32) BlockSize;
|
|
ImagePackage->ImagePkgHdr.Header.Length += (UINT32) NewBlockSize;
|
|
PackageListNode->PackageListHdr.PackageLength += (UINT32) NewBlockSize;
|
|
|
|
} else {
|
|
//
|
|
// The specified package list does not contain image package.
|
|
// Create one to add this image block.
|
|
//
|
|
ImagePackage = (HII_IMAGE_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IMAGE_PACKAGE_INSTANCE));
|
|
if (ImagePackage == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// Output the image id of the incoming image being inserted, which is the
|
|
// first image block so that id is initially to one.
|
|
//
|
|
*ImageId = 1;
|
|
BlockSize = sizeof (EFI_HII_IIBT_END_BLOCK) + NewBlockSize;
|
|
//
|
|
// Fill in image package header.
|
|
//
|
|
ImagePackage->ImagePkgHdr.Header.Length = (UINT32) BlockSize + sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
|
|
ImagePackage->ImagePkgHdr.Header.Type = EFI_HII_PACKAGE_IMAGES;
|
|
ImagePackage->ImagePkgHdr.ImageInfoOffset = sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
|
|
ImagePackage->ImagePkgHdr.PaletteInfoOffset = 0;
|
|
|
|
//
|
|
// Fill in palette info.
|
|
//
|
|
ImagePackage->PaletteBlock = NULL;
|
|
ImagePackage->PaletteInfoSize = 0;
|
|
|
|
//
|
|
// Fill in image blocks.
|
|
//
|
|
ImagePackage->ImageBlockSize = (UINT32) BlockSize;
|
|
ImagePackage->ImageBlock = (UINT8 *) AllocateZeroPool (BlockSize);
|
|
if (ImagePackage->ImageBlock == NULL) {
|
|
FreePool (ImagePackage);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
ImageBlock = ImagePackage->ImageBlock;
|
|
|
|
//
|
|
// Temp memory to store new block.
|
|
//
|
|
NewBlock = AllocateZeroPool (NewBlockSize);
|
|
if (NewBlock == NULL) {
|
|
FreePool (ImagePackage->ImageBlock);
|
|
FreePool (ImagePackage);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
NewBlockPtr = NewBlock;
|
|
|
|
//
|
|
// Insert this image package.
|
|
//
|
|
PackageListNode->ImagePkg = ImagePackage;
|
|
PackageListNode->PackageListHdr.PackageLength += ImagePackage->ImagePkgHdr.Header.Length;
|
|
}
|
|
|
|
//
|
|
// Append the new block here
|
|
//
|
|
if (ImageIn->Flags == EFI_IMAGE_TRANSPARENT) {
|
|
*NewBlock = EFI_HII_IIBT_IMAGE_24BIT_TRANS;
|
|
} else {
|
|
*NewBlock = EFI_HII_IIBT_IMAGE_24BIT;
|
|
}
|
|
NewBlock++;
|
|
CopyMem (NewBlock, &ImageIn->Width, sizeof (UINT16));
|
|
NewBlock += sizeof (UINT16);
|
|
CopyMem (NewBlock, &ImageIn->Height, sizeof (UINT16));
|
|
NewBlock += sizeof (UINT16);
|
|
CopyGopToRgbPixel ((EFI_HII_RGB_PIXEL *) NewBlock, ImageIn->Bitmap, (UINTN) ImageIn->Width * ImageIn->Height);
|
|
|
|
CopyMem (ImageBlock, NewBlockPtr, NewBlockSize);
|
|
FreePool (NewBlockPtr);
|
|
|
|
//
|
|
// Append the block end
|
|
//
|
|
ImageBlock += NewBlockSize;
|
|
((EFI_HII_IIBT_END_BLOCK *) (ImageBlock))->Header.BlockType = EFI_HII_IIBT_END;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function retrieves the image specified by ImageId which is associated with
|
|
the specified PackageList and copies it into the buffer specified by Image.
|
|
|
|
@param[in] This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
|
|
@param[in] PackageList Handle of the package list where this image will
|
|
be searched.
|
|
@param[in] ImageId The image's id,, which is unique within
|
|
PackageList.
|
|
@param[out] Image Points to the image.
|
|
|
|
@retval EFI_SUCCESS The new image was returned successfully.
|
|
@retval EFI_NOT_FOUND The image specified by ImageId is not in the database.
|
|
The specified PackageList is not in the database.
|
|
@retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to hold the image.
|
|
@retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
|
|
@retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not enough memory.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HiiGetImage (
|
|
IN CONST EFI_HII_IMAGE_PROTOCOL *This,
|
|
IN EFI_HII_HANDLE PackageList,
|
|
IN EFI_IMAGE_ID ImageId,
|
|
OUT EFI_IMAGE_INPUT *Image
|
|
)
|
|
{
|
|
HII_DATABASE_PRIVATE_DATA *Private;
|
|
LIST_ENTRY *Link;
|
|
HII_DATABASE_RECORD *DatabaseRecord;
|
|
HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
|
|
HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
|
|
UINT8 *ImageBlock;
|
|
EFI_IMAGE_ID LocalImageId;
|
|
UINT8 BlockType;
|
|
EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit;
|
|
UINT16 Width;
|
|
UINT16 Height;
|
|
UINTN ImageLength;
|
|
BOOLEAN Flag;
|
|
UINT8 *PaletteInfo;
|
|
UINT8 PaletteIndex;
|
|
UINT16 PaletteSize;
|
|
EFI_STATUS Status;
|
|
EFI_JPEG_DECODER_STATUS DecoderStatus;
|
|
UINT8 *Blt;
|
|
UINTN BltSize;
|
|
UINTN BltWidth;
|
|
UINTN BltHeight;
|
|
EFI_HII_IIBT_JPEG_BLOCK *JpegBlock;
|
|
EFI_HII_IIBT_EXT4_BLOCK *Ext4Block;
|
|
H2O_HII_IIBT_IMAGE_32BIT_BLOCK *Iibt32Bit;
|
|
|
|
if (This == NULL || Image == NULL || ImageId < 1) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!IsHiiHandleValid (PackageList)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
//
|
|
// Get the specified package list and image package.
|
|
//
|
|
PackageListNode = NULL;
|
|
for (Link = Private->DatabaseList.ForwardLink;
|
|
Link != &Private->DatabaseList;
|
|
Link = Link->ForwardLink
|
|
) {
|
|
DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
|
|
if (DatabaseRecord->Handle == PackageList) {
|
|
PackageListNode = DatabaseRecord->PackageList;
|
|
break;
|
|
}
|
|
}
|
|
if (PackageListNode == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
ImagePackage = PackageListNode->ImagePkg;
|
|
if (ImagePackage == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Find the image block specified by ImageId
|
|
//
|
|
LocalImageId = ImageId;
|
|
|
|
ImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &LocalImageId);
|
|
if (ImageBlock == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Flag = FALSE;
|
|
BlockType = *ImageBlock;
|
|
ZeroMem (Image, sizeof(EFI_IMAGE_INPUT));
|
|
|
|
switch (BlockType) {
|
|
|
|
case EFI_HII_IIBT_EXT4:
|
|
Ext4Block = (EFI_HII_IIBT_EXT4_BLOCK *) ImageBlock;
|
|
if (Ext4Block->BlockType2 != H2O_HII_IIBT_IMAGE_32BIT) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Iibt32Bit = (H2O_HII_IIBT_IMAGE_32BIT_BLOCK *) ImageBlock;
|
|
Width = Iibt32Bit->Width;
|
|
Height = Iibt32Bit->Height;
|
|
ImageLength = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * ((UINTN) Width * Height);
|
|
Image->Bitmap = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocateCopyPool (ImageLength, Iibt32Bit->Bitmap);
|
|
if (Image->Bitmap == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Image->Flags = H2O_IMAGE_ALPHA_CHANNEL;
|
|
Image->Width = Width;
|
|
Image->Height = Height;
|
|
|
|
return EFI_SUCCESS;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_JPEG:
|
|
if (mJpegDecoder == NULL) {
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiJpegDecoderProtocolGuid,
|
|
NULL,
|
|
(VOID **)&mJpegDecoder
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
Blt = NULL;
|
|
BltSize = 0;
|
|
JpegBlock = (EFI_HII_IIBT_JPEG_BLOCK *) ImageBlock;
|
|
Status = mJpegDecoder->DecodeImage (
|
|
mJpegDecoder,
|
|
JpegBlock->Data,
|
|
JpegBlock->Size,
|
|
&Blt,
|
|
&BltSize,
|
|
&BltHeight,
|
|
&BltWidth,
|
|
&DecoderStatus
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
Image->Bitmap = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)Blt;
|
|
Image->Width = (UINT16)BltWidth;
|
|
Image->Height = (UINT16)BltHeight;
|
|
Image->Flags = 0;
|
|
return EFI_SUCCESS;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
|
|
case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
|
|
case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
|
|
Flag = TRUE;
|
|
//
|
|
// fall through
|
|
//
|
|
case EFI_HII_IIBT_IMAGE_1BIT:
|
|
case EFI_HII_IIBT_IMAGE_4BIT:
|
|
case EFI_HII_IIBT_IMAGE_8BIT:
|
|
//
|
|
// Use the common block code since the definition of these structures is the same.
|
|
//
|
|
CopyMem (&Iibt1bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
|
|
ImageLength = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) *
|
|
((UINTN) Iibt1bit.Bitmap.Width * Iibt1bit.Bitmap.Height);
|
|
Image->Bitmap = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocateZeroPool (ImageLength);
|
|
if (Image->Bitmap == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (Flag) {
|
|
Image->Flags = EFI_IMAGE_TRANSPARENT;
|
|
}
|
|
Image->Width = Iibt1bit.Bitmap.Width;
|
|
Image->Height = Iibt1bit.Bitmap.Height;
|
|
|
|
PaletteInfo = ImagePackage->PaletteBlock + sizeof (EFI_HII_IMAGE_PALETTE_INFO_HEADER);
|
|
for (PaletteIndex = 1; PaletteIndex < Iibt1bit.PaletteIndex; PaletteIndex++) {
|
|
CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
|
|
PaletteInfo += PaletteSize + sizeof (UINT16);
|
|
}
|
|
ASSERT (PaletteIndex == Iibt1bit.PaletteIndex);
|
|
|
|
//
|
|
// Output bitmap data
|
|
//
|
|
if (BlockType == EFI_HII_IIBT_IMAGE_1BIT || BlockType == EFI_HII_IIBT_IMAGE_1BIT_TRANS) {
|
|
Status = Output1bitPixel (
|
|
Image,
|
|
(UINT8 *) (ImageBlock + sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8)),
|
|
(EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
|
|
);
|
|
} else if (BlockType == EFI_HII_IIBT_IMAGE_4BIT || BlockType == EFI_HII_IIBT_IMAGE_4BIT_TRANS) {
|
|
Status = Output4bitPixel (
|
|
Image,
|
|
(UINT8 *) (ImageBlock + sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8)),
|
|
(EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
|
|
);
|
|
} else {
|
|
Status = Output8bitPixel (
|
|
Image,
|
|
(UINT8 *) (ImageBlock + sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8)),
|
|
(EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
|
|
Flag = TRUE;
|
|
//
|
|
// fall through
|
|
//
|
|
case EFI_HII_IIBT_IMAGE_24BIT:
|
|
CopyMem (&Width, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT16));
|
|
CopyMem (
|
|
&Height,
|
|
ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT16),
|
|
sizeof (UINT16)
|
|
);
|
|
ImageLength = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * ((UINTN) Width * Height);
|
|
Image->Bitmap = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocateZeroPool (ImageLength);
|
|
if (Image->Bitmap == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (Flag) {
|
|
Image->Flags = EFI_IMAGE_TRANSPARENT;
|
|
}
|
|
Image->Width = Width;
|
|
Image->Height = Height;
|
|
|
|
//
|
|
// Output the bimap data directly.
|
|
//
|
|
Output24bitPixel (
|
|
Image,
|
|
(EFI_HII_RGB_PIXEL *) (ImageBlock + sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))
|
|
);
|
|
return EFI_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
return EFI_NOT_FOUND;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function updates the image specified by ImageId in the specified PackageListHandle to
|
|
the image specified by Image.
|
|
|
|
@param[in] This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
|
|
@param[in] PackageList The package list containing the images.
|
|
@param[in] ImageId The image's id,, which is unique within PackageList.
|
|
@param[in] Image Points to the image.
|
|
|
|
@retval EFI_SUCCESS The new image was updated successfully.
|
|
@retval EFI_NOT_FOUND The image specified by ImageId is not in the database.
|
|
The specified PackageList is not in the database.
|
|
@retval EFI_INVALID_PARAMETER The Image was NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HiiSetImage (
|
|
IN CONST EFI_HII_IMAGE_PROTOCOL *This,
|
|
IN EFI_HII_HANDLE PackageList,
|
|
IN EFI_IMAGE_ID ImageId,
|
|
IN CONST EFI_IMAGE_INPUT *Image
|
|
)
|
|
{
|
|
HII_DATABASE_PRIVATE_DATA *Private;
|
|
LIST_ENTRY *Link;
|
|
HII_DATABASE_RECORD *DatabaseRecord;
|
|
HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
|
|
HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
|
|
UINT8 *ImageBlock;
|
|
EFI_IMAGE_ID LocalImageId;
|
|
UINT8 BlockType;
|
|
EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit;
|
|
EFI_HII_IIBT_IMAGE_4BIT_BLOCK Iibt4bit;
|
|
EFI_HII_IIBT_IMAGE_8BIT_BLOCK Iibt8bit;
|
|
UINT16 Width;
|
|
UINT16 Height;
|
|
UINT32 BlockSize;
|
|
UINT32 NewBlockSize;
|
|
UINT32 OldBlockSize;
|
|
EFI_IMAGE_INPUT *ImageIn;
|
|
UINT8 *NewBlock;
|
|
UINT8 *NewBlockPtr;
|
|
UINT8 *Block;
|
|
UINT8 *BlockPtr;
|
|
UINT32 Part1Size;
|
|
UINT32 Part2Size;
|
|
|
|
if (This == NULL || Image == NULL || ImageId < 1 || Image->Bitmap == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!IsHiiHandleValid (PackageList)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
//
|
|
// Get the specified package list and image package.
|
|
//
|
|
PackageListNode = NULL;
|
|
for (Link = Private->DatabaseList.ForwardLink;
|
|
Link != &Private->DatabaseList;
|
|
Link = Link->ForwardLink
|
|
) {
|
|
DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
|
|
if (DatabaseRecord->Handle == PackageList) {
|
|
PackageListNode = DatabaseRecord->PackageList;
|
|
break;
|
|
}
|
|
}
|
|
if (PackageListNode == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
ImagePackage = PackageListNode->ImagePkg;
|
|
if (ImagePackage == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Find the image block specified by ImageId
|
|
//
|
|
LocalImageId = ImageId;
|
|
ImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &LocalImageId);
|
|
if (ImageBlock == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
BlockType = *ImageBlock;
|
|
|
|
//
|
|
// Get the size of original image block. Use some common block code here
|
|
// since the definition of some structures is the same.
|
|
//
|
|
switch (BlockType) {
|
|
case EFI_HII_IIBT_IMAGE_JPEG:
|
|
OldBlockSize = sizeof (EFI_HII_IIBT_JPEG_BLOCK) - sizeof (UINT8) +
|
|
((EFI_HII_IIBT_JPEG_BLOCK *)ImageBlock)->Size;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_1BIT:
|
|
case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
|
|
CopyMem (&Iibt1bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
|
|
OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
|
|
BITMAP_LEN_1_BIT (Iibt1bit.Bitmap.Width, Iibt1bit.Bitmap.Height);
|
|
break;
|
|
case EFI_HII_IIBT_IMAGE_4BIT:
|
|
case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
|
|
CopyMem (&Iibt4bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK));
|
|
OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
|
|
BITMAP_LEN_4_BIT (Iibt4bit.Bitmap.Width, Iibt4bit.Bitmap.Height);
|
|
break;
|
|
case EFI_HII_IIBT_IMAGE_8BIT:
|
|
case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
|
|
CopyMem (&Iibt8bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK));
|
|
OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
|
|
BITMAP_LEN_8_BIT (Iibt8bit.Bitmap.Width, Iibt8bit.Bitmap.Height);
|
|
break;
|
|
case EFI_HII_IIBT_IMAGE_24BIT:
|
|
case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
|
|
CopyMem (&Width, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT16));
|
|
CopyMem (
|
|
&Height,
|
|
ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT16),
|
|
sizeof (UINT16)
|
|
);
|
|
OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
|
|
BITMAP_LEN_24_BIT (Width , Height);
|
|
break;
|
|
default:
|
|
return EFI_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create the new image block according to input image.
|
|
//
|
|
ImageIn = (EFI_IMAGE_INPUT *) Image;
|
|
NewBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
|
|
BITMAP_LEN_24_BIT (ImageIn->Width, ImageIn->Height);
|
|
NewBlock = (UINT8 *) AllocateZeroPool (NewBlockSize);
|
|
if (NewBlock == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
NewBlockPtr = NewBlock;
|
|
if ((ImageIn->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
|
|
*NewBlockPtr = EFI_HII_IIBT_IMAGE_24BIT_TRANS;
|
|
} else {
|
|
*NewBlockPtr = EFI_HII_IIBT_IMAGE_24BIT;
|
|
}
|
|
NewBlockPtr++;
|
|
|
|
CopyMem (NewBlockPtr, &ImageIn->Width, sizeof (UINT16));
|
|
NewBlockPtr += sizeof (UINT16);
|
|
CopyMem (NewBlockPtr, &ImageIn->Height, sizeof (UINT16));
|
|
NewBlockPtr += sizeof (UINT16);
|
|
|
|
CopyGopToRgbPixel ((EFI_HII_RGB_PIXEL *) NewBlockPtr, ImageIn->Bitmap, (UINTN)ImageIn->Width * ImageIn->Height);
|
|
|
|
//
|
|
// Adjust the image package to remove the original block firstly then add the new block.
|
|
//
|
|
BlockSize = ImagePackage->ImageBlockSize + NewBlockSize - OldBlockSize;
|
|
Block = (UINT8 *) AllocateZeroPool (BlockSize);
|
|
if (Block == NULL) {
|
|
FreePool (NewBlock);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
BlockPtr = Block;
|
|
Part1Size = (UINT32) (ImageBlock - ImagePackage->ImageBlock);
|
|
Part2Size = ImagePackage->ImageBlockSize - Part1Size - OldBlockSize;
|
|
CopyMem (BlockPtr, ImagePackage->ImageBlock, Part1Size);
|
|
BlockPtr += Part1Size;
|
|
CopyMem (BlockPtr, NewBlock, NewBlockSize);
|
|
BlockPtr += NewBlockSize;
|
|
CopyMem (BlockPtr, ImageBlock + OldBlockSize, Part2Size);
|
|
|
|
FreePool (ImagePackage->ImageBlock);
|
|
FreePool (NewBlock);
|
|
ImagePackage->ImageBlock = Block;
|
|
ImagePackage->ImageBlockSize = BlockSize;
|
|
ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize - OldBlockSize;
|
|
PackageListNode->PackageListHdr.PackageLength += NewBlockSize - OldBlockSize;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
#define muldiv255(a,b) ((unsigned char)((((a)+1)*(b))>>8)) /* very fast, 92% accurate*/
|
|
|
|
/**
|
|
This function renders an image to a bitmap or the screen using the specified
|
|
color and options. It draws the image on an existing bitmap, allocates a new
|
|
bitmap or uses the screen. The images can be clipped.
|
|
|
|
@param[in] This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
|
|
@param[in] Flags Describes how the image is to be drawn.
|
|
@param[in] Image Points to the image to be displayed.
|
|
@param[in, out] Blt If this points to a non-NULL on entry, this points
|
|
to the image, which is Width pixels wide and
|
|
Height pixels high. The image will be drawn onto
|
|
this image and EFI_HII_DRAW_FLAG_CLIP is implied.
|
|
If this points to a NULL on entry, then a buffer
|
|
will be allocated to hold the generated image and
|
|
the pointer updated on exit. It is the caller's
|
|
responsibility to free this buffer.
|
|
@param[in] BltX Specifies the offset from the left and top edge of
|
|
the output image of the first pixel in the image.
|
|
@param[in] BltY Specifies the offset from the left and top edge of
|
|
the output image of the first pixel in the image.
|
|
|
|
@retval EFI_SUCCESS The image was successfully drawn.
|
|
@retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
|
|
@retval EFI_INVALID_PARAMETER The Image or Blt was NULL.
|
|
@retval EFI_INVALID_PARAMETER Any combination of Flags is invalid.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HiiDrawImage (
|
|
IN CONST EFI_HII_IMAGE_PROTOCOL *This,
|
|
IN EFI_HII_DRAW_FLAGS Flags,
|
|
IN CONST EFI_IMAGE_INPUT *Image,
|
|
IN OUT EFI_IMAGE_OUTPUT **Blt,
|
|
IN UINTN BltX,
|
|
IN UINTN BltY
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
HII_DATABASE_PRIVATE_DATA *Private;
|
|
BOOLEAN Transparent;
|
|
EFI_IMAGE_INPUT *ImageIn;
|
|
EFI_IMAGE_OUTPUT *ImageOut;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
|
|
UINTN BufferLen;
|
|
UINTN Width;
|
|
UINTN Height;
|
|
UINTN Xpos;
|
|
UINTN Ypos;
|
|
UINTN OffsetY1;
|
|
UINTN OffsetY2;
|
|
EFI_FONT_DISPLAY_INFO *FontInfo;
|
|
UINTN Index;
|
|
BOOLEAN AlphaChannel;
|
|
UINT8 Alpha;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Src;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Dst;
|
|
|
|
|
|
if (This == NULL || Image == NULL || Blt == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Flags & EFI_HII_DRAW_FLAG_CLIP) == EFI_HII_DRAW_FLAG_CLIP && *Blt == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_TRANSPARENT) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ImageIn = (EFI_IMAGE_INPUT *) Image;
|
|
|
|
//
|
|
// Check whether the image will be drawn transparently or opaquely.
|
|
//
|
|
Transparent = FALSE;
|
|
if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_TRANS) {
|
|
Transparent = TRUE;
|
|
} else if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_OPAQUE){
|
|
Transparent = FALSE;
|
|
} else {
|
|
//
|
|
// Now EFI_HII_DRAW_FLAG_DEFAULT is set, whether image will be drawn depending
|
|
// on the image's transparency setting.
|
|
//
|
|
if ((ImageIn->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
|
|
Transparent = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if EFI_HII_DRAW_FLAG_FORCE_OPAQUE is set in Flags,
|
|
// it sill need processing alpha channel
|
|
//
|
|
AlphaChannel = FALSE;
|
|
if ((ImageIn->Flags & H2O_IMAGE_ALPHA_CHANNEL) == H2O_IMAGE_ALPHA_CHANNEL) {
|
|
AlphaChannel = TRUE;
|
|
}
|
|
|
|
//
|
|
// Image cannot be drawn transparently if Blt points to NULL on entry.
|
|
// Currently output to Screen transparently is not supported, either.
|
|
//
|
|
if (Transparent) {
|
|
if (*Blt == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
//
|
|
// When Blt points to a non-NULL on entry, this image will be drawn onto
|
|
// this bitmap or screen pointed by "*Blt" and EFI_HII_DRAW_FLAG_CLIP is implied.
|
|
// Otherwise a new bitmap will be allocated to hold this image.
|
|
//
|
|
if (*Blt != NULL) {
|
|
//
|
|
// Clip the image by (Width, Height)
|
|
//
|
|
|
|
Width = ImageIn->Width;
|
|
Height = ImageIn->Height;
|
|
|
|
if (Width > (*Blt)->Width - BltX) {
|
|
Width = (*Blt)->Width - BltX;
|
|
}
|
|
if (Height > (*Blt)->Height - BltY) {
|
|
Height = (*Blt)->Height - BltY;
|
|
}
|
|
|
|
BufferLen = Width * Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
|
|
BltBuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocateZeroPool (BufferLen);
|
|
if (BltBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if ((AlphaChannel || Transparent) && ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN)) {
|
|
//
|
|
// Read image from screen
|
|
//
|
|
Status = (*Blt)->Image.Screen->Blt (
|
|
(*Blt)->Image.Screen,
|
|
BltBuffer,
|
|
EfiBltVideoToBltBuffer,
|
|
BltX,
|
|
BltY,
|
|
0,
|
|
0,
|
|
Width,
|
|
Height,
|
|
0
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (AlphaChannel) {
|
|
for (Ypos = 0; Ypos < Height; Ypos++) {
|
|
OffsetY1 = ImageIn->Width * Ypos;
|
|
OffsetY2 = Width * Ypos;
|
|
for (Xpos = 0; Xpos < Width; Xpos++) {
|
|
Src = &ImageIn->Bitmap[OffsetY1 + Xpos];
|
|
Dst = &BltBuffer[OffsetY2 + Xpos];
|
|
|
|
Alpha = Src->Reserved;
|
|
Dst->Blue += muldiv255 (Alpha, Src->Blue - Dst->Blue);
|
|
Dst->Green += muldiv255 (Alpha, Src->Green - Dst->Green);
|
|
Dst->Red += muldiv255 (Alpha, Src->Red - Dst->Red);
|
|
}
|
|
}
|
|
} else {
|
|
if (Width == ImageIn->Width && Height == ImageIn->Height) {
|
|
CopyMem (BltBuffer, ImageIn->Bitmap, BufferLen);
|
|
} else {
|
|
for (Ypos = 0; Ypos < Height; Ypos++) {
|
|
OffsetY1 = ImageIn->Width * Ypos;
|
|
OffsetY2 = Width * Ypos;
|
|
for (Xpos = 0; Xpos < Width; Xpos++) {
|
|
BltBuffer[OffsetY2 + Xpos] = ImageIn->Bitmap[OffsetY1 + Xpos];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Draw the image to existing bitmap or screen depending on flag.
|
|
//
|
|
if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
|
|
//
|
|
// Caller should make sure the current UGA console is grarphic mode.
|
|
//
|
|
|
|
//
|
|
// Write the image directly to the output device specified by Screen.
|
|
//
|
|
Status = (*Blt)->Image.Screen->Blt (
|
|
(*Blt)->Image.Screen,
|
|
BltBuffer,
|
|
EfiBltBufferToVideo,
|
|
0,
|
|
0,
|
|
BltX,
|
|
BltY,
|
|
Width,
|
|
Height,
|
|
0
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
} else {
|
|
//
|
|
// Draw the image onto the existing bitmap specified by Bitmap.
|
|
//
|
|
Status = ImageToBlt (
|
|
BltBuffer,
|
|
BltX,
|
|
BltY,
|
|
Width,
|
|
Height,
|
|
Transparent,
|
|
AlphaChannel,
|
|
Blt
|
|
);
|
|
|
|
}
|
|
|
|
FreePool (BltBuffer);
|
|
return Status;
|
|
|
|
} else {
|
|
//
|
|
// Allocate a new bitmap to hold the incoming image.
|
|
//
|
|
Width = ImageIn->Width + BltX;
|
|
Height = ImageIn->Height + BltY;
|
|
|
|
BufferLen = Width * Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
|
|
BltBuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocateZeroPool (BufferLen);
|
|
if (BltBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ImageOut = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
|
|
if (ImageOut == NULL) {
|
|
FreePool (BltBuffer);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
ImageOut->Width = (UINT16) Width;
|
|
ImageOut->Height = (UINT16) Height;
|
|
ImageOut->Image.Bitmap = BltBuffer;
|
|
|
|
//
|
|
// BUGBUG: Now all the "blank" pixels are filled with system default background
|
|
// color. Not sure if it need to be updated or not.
|
|
//
|
|
Status = GetSystemFont (Private, &FontInfo, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (BltBuffer);
|
|
FreePool (ImageOut);
|
|
return Status;
|
|
}
|
|
for (Index = 0; Index < Width * Height; Index++) {
|
|
BltBuffer[Index] = FontInfo->BackgroundColor;
|
|
}
|
|
FreePool (FontInfo);
|
|
|
|
//
|
|
// Draw the incoming image to the new created image.
|
|
//
|
|
*Blt = ImageOut;
|
|
return ImageToBlt (
|
|
ImageIn->Bitmap,
|
|
BltX,
|
|
BltY,
|
|
ImageIn->Width,
|
|
ImageIn->Height,
|
|
Transparent,
|
|
AlphaChannel,
|
|
Blt
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function renders an image to a bitmap or the screen using the specified
|
|
color and options. It draws the image on an existing bitmap, allocates a new
|
|
bitmap or uses the screen. The images can be clipped.
|
|
|
|
@param[in] This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
|
|
@param[in] Flags Describes how the image is to be drawn.
|
|
@param[in] PackageList The package list in the HII database to search for
|
|
the specified image.
|
|
@param[in] ImageId The image's id, which is unique within
|
|
PackageList.
|
|
@param[in, out] Blt If this points to a non-NULL on entry, this points
|
|
to the image, which is Width pixels wide and
|
|
Height pixels high. The image will be drawn onto
|
|
this image and
|
|
EFI_HII_DRAW_FLAG_CLIP is implied. If this points
|
|
to a NULL on entry, then a buffer will be
|
|
allocated to hold the generated image and the
|
|
pointer updated on exit. It is the caller's
|
|
responsibility to free this buffer.
|
|
@param[in] BltX Specifies the offset from the left and top edge of
|
|
the output image of the first pixel in the image.
|
|
@param[in] BltY Specifies the offset from the left and top edge of
|
|
the output image of the first pixel in the image.
|
|
|
|
@retval EFI_SUCCESS The image was successfully drawn.
|
|
@retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
|
|
@retval EFI_INVALID_PARAMETER The Blt was NULL.
|
|
@retval EFI_NOT_FOUND The image specified by ImageId is not in the database.
|
|
The specified PackageList is not in the database.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HiiDrawImageId (
|
|
IN CONST EFI_HII_IMAGE_PROTOCOL *This,
|
|
IN EFI_HII_DRAW_FLAGS Flags,
|
|
IN EFI_HII_HANDLE PackageList,
|
|
IN EFI_IMAGE_ID ImageId,
|
|
IN OUT EFI_IMAGE_OUTPUT **Blt,
|
|
IN UINTN BltX,
|
|
IN UINTN BltY
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_IMAGE_INPUT Image;
|
|
|
|
//
|
|
// Check input parameter.
|
|
//
|
|
if (This == NULL || Blt == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!IsHiiHandleValid (PackageList)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Get the specified Image.
|
|
//
|
|
Status = HiiGetImage (This, PackageList, ImageId, &Image);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Draw this image.
|
|
//
|
|
Status = HiiDrawImage (This, Flags, &Image, Blt, BltX, BltY);
|
|
if (Image.Bitmap != NULL) {
|
|
FreePool (Image.Bitmap);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Insyde multi board image package extension.
|
|
|
|
A destructor function of H2O_HII_BOARD_IMAGE_BLOCK_LIST.
|
|
This function is called when list H2O_HII_BOARD_IMAGE_BLOCK_LIST is nolonger required.
|
|
This function traverse whole data structure of input list, free all the allocated memory.
|
|
If total "malloc" count greater than "free" count, it means mamory leak.
|
|
This is an internal function.
|
|
|
|
@param[in, out] List A pointer to the first entry of abstract data type
|
|
that built in heap.
|
|
**/
|
|
VOID
|
|
BoardImageTableListDestructor (
|
|
IN OUT H2O_HII_IMAGE_TABLE_ENTRY *List
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
LIST_ENTRY *Node;
|
|
H2O_HII_IMAGE_TABLE_ENTRY *CurrentImageTableEntry;
|
|
H2O_HII_IMAGE_BLOCK_NODE *CurrentImageBlockNode;
|
|
|
|
if (List != NULL) {
|
|
while (!IsListEmpty (&List->TableEntry)) {
|
|
Entry = List->TableEntry.ForwardLink;
|
|
CurrentImageTableEntry = GET_H2O_HII_IMAGE_TABLE_ENTRY_FROM_THIS (Entry);
|
|
if (!CurrentImageTableEntry->IsSlaveEntry && \
|
|
CurrentImageTableEntry->AssociateImageBlockList != NULL) {
|
|
//
|
|
// Free current AssociateImageBlockList.
|
|
//
|
|
while (!IsListEmpty (CurrentImageTableEntry->AssociateImageBlockList)) {
|
|
Node = CurrentImageTableEntry->AssociateImageBlockList->ForwardLink;
|
|
CurrentImageBlockNode = GET_H2O_HII_IMAGE_BLOCK_NODE_FROM_THIS (Node);
|
|
RemoveEntryList (&CurrentImageBlockNode->ImageBlockNodeEntry);
|
|
ZeroMem ((VOID *)CurrentImageBlockNode, sizeof (H2O_HII_IMAGE_BLOCK_NODE));
|
|
FreePool (CurrentImageBlockNode);
|
|
}
|
|
CurrentImageBlockNode = GET_H2O_HII_IMAGE_BLOCK_NODE_FROM_THIS (CurrentImageTableEntry->AssociateImageBlockList);
|
|
ZeroMem ((VOID *)CurrentImageBlockNode, sizeof (H2O_HII_IMAGE_BLOCK_NODE));
|
|
FreePool (CurrentImageBlockNode);
|
|
}
|
|
RemoveEntryList (&CurrentImageTableEntry->TableEntry);
|
|
ZeroMem ((VOID *)CurrentImageTableEntry, sizeof (H2O_HII_IMAGE_TABLE_ENTRY));
|
|
FreePool (CurrentImageTableEntry);
|
|
}
|
|
//
|
|
// The last remaining image table entry should be destroyed too.
|
|
//
|
|
CurrentImageTableEntry = GET_H2O_HII_IMAGE_TABLE_ENTRY_FROM_THIS (&List->TableEntry);
|
|
//
|
|
// The AssociateImageBlockList of this last remaining entry should be destroyed too.
|
|
//
|
|
if (!CurrentImageTableEntry->IsSlaveEntry && \
|
|
CurrentImageTableEntry->AssociateImageBlockList != NULL) {
|
|
while (!IsListEmpty (CurrentImageTableEntry->AssociateImageBlockList)) {
|
|
Node = CurrentImageTableEntry->AssociateImageBlockList->ForwardLink;
|
|
CurrentImageBlockNode = GET_H2O_HII_IMAGE_BLOCK_NODE_FROM_THIS (Node);
|
|
RemoveEntryList (&CurrentImageBlockNode->ImageBlockNodeEntry);
|
|
ZeroMem ((VOID *)CurrentImageBlockNode, sizeof (H2O_HII_IMAGE_BLOCK_NODE));
|
|
FreePool (CurrentImageBlockNode);
|
|
}
|
|
CurrentImageBlockNode = GET_H2O_HII_IMAGE_BLOCK_NODE_FROM_THIS (CurrentImageTableEntry->AssociateImageBlockList);
|
|
ZeroMem (CurrentImageBlockNode, sizeof (H2O_HII_IMAGE_BLOCK_NODE));
|
|
FreePool (CurrentImageBlockNode);
|
|
}
|
|
ZeroMem ((VOID *)CurrentImageTableEntry, sizeof (H2O_HII_IMAGE_TABLE_ENTRY));
|
|
FreePool (CurrentImageTableEntry);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
Insyde multi board image package extension.
|
|
|
|
Search within image table entries using board id as key to check if corresponding entry exsists.
|
|
|
|
This is an internal function.
|
|
|
|
@param[in] List A pointer to the first entry.
|
|
It also means caller want to search within this list.
|
|
@param[in] BoardId The value indicate that which board user want to check.
|
|
@param[out] Entry Update a pointer to corresponding entry if match found,
|
|
or NULL if target not exist.
|
|
|
|
@retval EFI_SUCCESS Find a match and successfully updated a pointer to entry.
|
|
@retval EFI_INVALID_PARAMETER List is NULL or Entry is NULL in your args.
|
|
@retval EFI_NOT_FOUND Entry not found or get failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SelectImageEntryWorker (
|
|
IN H2O_HII_IMAGE_TABLE_ENTRY *List,
|
|
IN H2O_BOARD_ID BoardId,
|
|
OUT H2O_HII_IMAGE_TABLE_ENTRY **Entry
|
|
)
|
|
{
|
|
H2O_HII_IMAGE_TABLE_ENTRY *CurrentImageTableEntry;
|
|
LIST_ENTRY *Link;
|
|
LIST_ENTRY *FirstTableEntry;
|
|
|
|
CurrentImageTableEntry = NULL;
|
|
|
|
//
|
|
// If List is NULL, it means no entry has been created.
|
|
//
|
|
if (List != NULL) {
|
|
//
|
|
// Check first image table entry.
|
|
// (H2O_HII_BOARD_IMAGE_BLOCK_LIST.ImageTableEntry point to first H2O_HII_IMAGE_TABLE_ENTRY)
|
|
//
|
|
if (List->ThisBoard == BoardId) {
|
|
if (Entry != NULL) {
|
|
*Entry = List;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Check the others.
|
|
//
|
|
FirstTableEntry = &List->TableEntry;
|
|
for (Link = FirstTableEntry->ForwardLink; Link != FirstTableEntry; Link = Link->ForwardLink) {
|
|
CurrentImageTableEntry = GET_H2O_HII_IMAGE_TABLE_ENTRY_FROM_THIS (Link);
|
|
if (CurrentImageTableEntry->ThisBoard == BoardId) {
|
|
if (Entry != NULL) {
|
|
*Entry = CurrentImageTableEntry;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Insyde multi board image package extension.
|
|
|
|
Select a entry in input list ADT using board id as key.
|
|
Create a node and append it to the specified entry.
|
|
This entry should be master who has the authority to control the AssociateImageBlockList.
|
|
This is an internal function.
|
|
|
|
@param[in, out] List A pointer to the first entry.
|
|
@param[in] Length The size of corresponding block in source package.
|
|
@param[in] Type The type of corresponding block in source package.
|
|
@param[in] ImageBlockHeader The address of corresponding block in source package.
|
|
@param[in] ImageInstance The address of image of corresponding block in
|
|
source package. NULL is valid if this block contains
|
|
no image.
|
|
@param[in] VirtualImageId The image id in whole package view.
|
|
@param[in] BoardId The board id to specify which entry to append.
|
|
|
|
@retval EFI_SUCCESS Image block node is created and successfully
|
|
appended to specified board entry.
|
|
@retval EFI_INVALID_PARAMETER List is NULL or ImageBlockHeader is NULL or
|
|
ImageInstance is NULL.
|
|
The entry found by board id is not a master entry.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES Unable to allocate memory for new node.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
AppendImageBlockWorker (
|
|
IN OUT H2O_HII_IMAGE_TABLE_ENTRY *List,
|
|
IN UINT32 Length,
|
|
IN UINT8 Type,
|
|
IN UINT8 *ImageBlockHeader,
|
|
IN UINT8 *ImageInstance,
|
|
IN EFI_IMAGE_ID VirtualImageId,
|
|
IN H2O_BOARD_ID BoardId
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_HII_IMAGE_TABLE_ENTRY *CurrentImageTableEntry;
|
|
H2O_HII_IMAGE_BLOCK_NODE *Node;
|
|
|
|
if (List == NULL || ImageBlockHeader == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
CurrentImageTableEntry = NULL;
|
|
Node = NULL;
|
|
|
|
Status = SelectImageEntryWorker (
|
|
List,
|
|
BoardId,
|
|
&CurrentImageTableEntry
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Only the master entries are allowed to hold image block list.
|
|
// It means image block node can only be appended to master entry.
|
|
// Appending a node to slave entry could be a violation of this method.
|
|
//
|
|
if (CurrentImageTableEntry->IsSlaveEntry == TRUE) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Node = AllocateZeroPool (sizeof (H2O_HII_IMAGE_BLOCK_NODE));
|
|
if (Node == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Node->Signature = H2O_HII_IMAGE_BLOCK_NODE_SIGNATURE;
|
|
Node->ImageBlockSize = Length;
|
|
Node->ImageBlockType = Type;
|
|
Node->ImageBlock = ImageBlockHeader;
|
|
Node->ImageInstance = ImageInstance;
|
|
Node->VirtualImageId = VirtualImageId;
|
|
InitializeListHead (&Node->ImageBlockNodeEntry);
|
|
if (CurrentImageTableEntry->AssociateImageBlockList == NULL) {
|
|
//
|
|
// Make sure this is the first node appended to this entry.
|
|
//
|
|
if (CurrentImageTableEntry->ImageBlockListNodeCount != 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
CurrentImageTableEntry->AssociateImageBlockList = &Node->ImageBlockNodeEntry;
|
|
CurrentImageTableEntry->ImageBlockListNodeCount += 1;
|
|
} else {
|
|
InsertTailList (CurrentImageTableEntry->AssociateImageBlockList, &Node->ImageBlockNodeEntry);
|
|
CurrentImageTableEntry->ImageBlockListNodeCount += 1;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Insyde multi board image package extension.
|
|
|
|
This function helps create entry instances, appends it to prior existed entry
|
|
when first entry is created.
|
|
This is an internal function.
|
|
|
|
@param[in, out] List The address of the pointer to the first entry.
|
|
When it is the first time creating this list,
|
|
the point will be updated with the addr of the first entry.
|
|
@param[in] BoardId The board id indicate that which board this new entry belongs to.
|
|
@param[in] VirtualImageId The image id in whole package view.
|
|
@param[out] NewEntry Update a pointer to new created entry.
|
|
|
|
@retval EFI_SUCCESS New entry created successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Unable to allocate resource for new entry.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
AddImageEntryWorker (
|
|
IN OUT H2O_HII_IMAGE_TABLE_ENTRY **List,
|
|
IN H2O_BOARD_ID BoardId,
|
|
IN EFI_IMAGE_ID VirtualImageId,
|
|
OUT H2O_HII_IMAGE_TABLE_ENTRY **NewEntry
|
|
)
|
|
{
|
|
H2O_HII_IMAGE_TABLE_ENTRY *ImageTableEntry;
|
|
H2O_HII_IMAGE_TABLE_ENTRY *PriorImageTableEntry;
|
|
|
|
ImageTableEntry = NULL;
|
|
PriorImageTableEntry = NULL;
|
|
|
|
ImageTableEntry = AllocateZeroPool (sizeof (H2O_HII_IMAGE_TABLE_ENTRY));
|
|
if (ImageTableEntry == NULL) {
|
|
*NewEntry = NULL;
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Initialize this new entry.
|
|
//
|
|
ImageTableEntry->Signature = H2O_HII_IMAGE_TABLE_ENTRY_SIGNATURE;
|
|
ImageTableEntry->ImageBlockListNodeCount = 0;
|
|
ImageTableEntry->AssociateImageBlockList = NULL;
|
|
InitializeListHead (&ImageTableEntry->TableEntry);
|
|
ImageTableEntry->ThisBoard = BoardId;
|
|
ImageTableEntry->IsSlaveEntry = TRUE;
|
|
|
|
//
|
|
// Output a pointer to this new entry.
|
|
//
|
|
*NewEntry = ImageTableEntry;
|
|
|
|
//
|
|
// ImageTableEntry will point to the first created entry,
|
|
// the others should be appendded one by one follow the first entry.
|
|
//
|
|
if (*List == NULL) {
|
|
*List = ImageTableEntry;
|
|
} else {
|
|
PriorImageTableEntry = *List;
|
|
InsertTailList (&PriorImageTableEntry->TableEntry, &ImageTableEntry->TableEntry);
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO, "--------New entry created--------[Board ID : 0x%02X]\n", ImageTableEntry->ThisBoard));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Insyde multi board image package extension.
|
|
|
|
This function classify all info provided by a image block,
|
|
Entry and node are created and placed in correct place base on these info.
|
|
This is an internal function.
|
|
|
|
"*ImageTableEntry" "*AssociateImageBlockList"
|
|
+----------------------+
|
|
\Entry(default 0x00) >--[node]-[node]-...
|
|
+----------------------+
|
|
\
|
|
+----------------------+
|
|
\Entry(URvp7 0x0B) >--[node]-[node]-...
|
|
+----------------------+
|
|
\
|
|
+----------------------+
|
|
\Entry(A0Rvp3 0x04) >--[node]-[node]-...
|
|
+----------------------+ \
|
|
\ \ (Co-use)
|
|
+----------------------+ \
|
|
\Entry(ULpddr3Rvp5 0x0A)>-----+
|
|
+----------------------+
|
|
|
|
@param[in, out] List The address of the pointer to the first entry,
|
|
all the entries and nodes will be added under this list.
|
|
@param[in] Length The size of corresponding block in source package.
|
|
@param[in] Type The type of corresponding block in source package.
|
|
@param[in] ImageBlockHeader The address of corresponding block in source package.
|
|
@param[in] ImageInstance The address of image of corresponding block in
|
|
source package. NULL is valid if this block contains
|
|
no image.
|
|
@param[in] AssociateBoardsBlock The address of corresponding boards block that tells
|
|
what boards this block belongs to.
|
|
@param[in] VirtualImageId The image id in whole package view.
|
|
|
|
@retval EFI_SUCCESS Input info of a specific image block classified successfully.
|
|
@retval EFI_UNSUPPORTED The data AssociateBoardsBlock point to is incorrect.
|
|
Any other wrong input data cause incorrect data structure created.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ClassifyImageBlockWorker (
|
|
IN OUT H2O_HII_IMAGE_TABLE_ENTRY **List,
|
|
IN UINT32 Length,
|
|
IN UINT8 Type,
|
|
IN UINT8 *ImageBlockHeader,
|
|
IN UINT8 *ImageInstance,
|
|
IN H2O_HII_IIBT_BOARDS_BLOCK *AssociateBoardsBlock,
|
|
IN EFI_IMAGE_ID VirtualImageId
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_HII_IMAGE_TABLE_ENTRY *CurrentImageTableEntry;
|
|
H2O_HII_IMAGE_TABLE_ENTRY *MasterImageTableEntry;
|
|
UINT32 Count;
|
|
UINT32 Index;
|
|
H2O_BOARD_ID CurrentBoardId;
|
|
H2O_BOARD_ID MasterBoardId;
|
|
LIST_ENTRY *OriginalImageBlockList;
|
|
|
|
Status = EFI_SUCCESS;
|
|
CurrentImageTableEntry = NULL;
|
|
MasterImageTableEntry = NULL;
|
|
|
|
//
|
|
// typedef struct _H2O_HII_IIBT_BOARDS_BLOCK {
|
|
// EFI_HII_IIBT_EXT1_BLOCK Hdr;
|
|
// EFI_IMAGE_ID ImageId;
|
|
// H2O_BOARD_ID Boards[...];
|
|
// } H2O_HII_IIBT_BOARDS_BLOCK;
|
|
//
|
|
// Calculate length of Boards[...].
|
|
//
|
|
Count = AssociateBoardsBlock->Hdr.Length - sizeof (EFI_HII_IIBT_EXT1_BLOCK) - sizeof (EFI_IMAGE_ID);
|
|
|
|
//
|
|
// If Count >= sizeof(H2O_BOARD_ID), it means AssociateBoardsBlock is the H2O_HII_IIBT_BOARDS_BLOCK.
|
|
// It needs to calculate the Boards number.
|
|
//
|
|
Count = (Count >= sizeof (H2O_BOARD_ID)) ? (Count / sizeof (H2O_BOARD_ID)):Count;
|
|
|
|
//
|
|
// Iterate all associate board id of this current block.
|
|
//
|
|
for (Index = 0; Index < Count; Index++) {
|
|
|
|
CurrentBoardId = AssociateBoardsBlock->Boards[Index];
|
|
//
|
|
// Each entry only created once.
|
|
//
|
|
if (SelectImageEntryWorker (*List, CurrentBoardId, NULL) == EFI_NOT_FOUND) {
|
|
//
|
|
// ImageTableEntry will point to first created entry,
|
|
// the others should append to the first entry one by one.
|
|
//
|
|
Status = AddImageEntryWorker (
|
|
List,
|
|
CurrentBoardId,
|
|
VirtualImageId,
|
|
&CurrentImageTableEntry
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Image block should be appended to only one entry, the one is master.
|
|
// The rest of entries who co-use AssociateImageBlockList with master are slaves.
|
|
//
|
|
|
|
//
|
|
// NOTE :
|
|
// All boards within a same associate boards block co-use AssociateImageBlockList.
|
|
// (Their images are identical)
|
|
// Only one entry of them needs to hold AssociateImageBlockList,
|
|
// so let first board be the master entry, the others are slaves point to the master.
|
|
// Or we can say, they share the same AssociateImageBlockList.
|
|
//
|
|
|
|
//
|
|
// Set first board as master.
|
|
//
|
|
MasterBoardId = AssociateBoardsBlock->Boards[0];
|
|
//
|
|
// Find target entry by key(board-id).
|
|
//
|
|
Status = SelectImageEntryWorker (
|
|
*List,
|
|
MasterBoardId,
|
|
&MasterImageTableEntry
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Change entry's identity to master first.
|
|
// Because we only allow master entry to control AssociateImageBlockList.
|
|
//
|
|
MasterImageTableEntry->IsSlaveEntry = FALSE;
|
|
//
|
|
// Let master entry holds this block.
|
|
// Specify a board id, use this id as key to find entry, then append
|
|
// a image block node to this entry.
|
|
//
|
|
Status = AppendImageBlockWorker (
|
|
*List,
|
|
Length,
|
|
Type,
|
|
ImageBlockHeader,
|
|
ImageInstance,
|
|
VirtualImageId,
|
|
MasterBoardId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set pointer of friend entries to master.
|
|
// This procedure runs only when this boards block
|
|
// contains more then one board(Count greater then 1).
|
|
// Index 0 is master.
|
|
//
|
|
// if CurrentSection.TotoalIdCound > 1
|
|
// for Id = CurrentSection.SecondId to CurrentSection.LastId
|
|
// ListObject.ImageEntry[Id].ImageBlockList = ListObject.ImageEntry[CurrentSection.FirstId].ImageBlockList
|
|
//
|
|
for (Index = 1; Index < Count; Index++) {
|
|
CurrentBoardId = AssociateBoardsBlock->Boards[Index];
|
|
Status = SelectImageEntryWorker (
|
|
*List,
|
|
CurrentBoardId,
|
|
&CurrentImageTableEntry
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
OriginalImageBlockList = CurrentImageTableEntry->AssociateImageBlockList;
|
|
//
|
|
// If "AssociateImageBlockList" of this entry is null, then this is entry is ceated first time.
|
|
// Setup where it should point to. If it is not NULL (Allready setup), check its correctness.
|
|
// If the pointer is changed, it could be a violation from caller.
|
|
//
|
|
if (OriginalImageBlockList == NULL) {
|
|
//
|
|
// Make slave entry co use "AssociateImageBlockList" with master entry.
|
|
//
|
|
CurrentImageTableEntry->AssociateImageBlockList = MasterImageTableEntry->AssociateImageBlockList;
|
|
} else if (OriginalImageBlockList != MasterImageTableEntry->AssociateImageBlockList) {
|
|
//
|
|
// Fatal Error!
|
|
// Should not change pointer when its association is set up.
|
|
// Redirection of pointer in any non-NULL entry means boardid
|
|
// is duplicated between boards blocks.
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
//
|
|
// Finally, sync ImageBlockListNodeCount of current slave entry with master.
|
|
//
|
|
CurrentImageTableEntry->ImageBlockListNodeCount = MasterImageTableEntry->ImageBlockListNodeCount;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Insyde multi board image package extension.
|
|
|
|
Find out AssociateImageBlockList specified by board id, and restore its content.
|
|
|
|
Use board id to select image table entry, then get image block list of this entry,
|
|
interate nodes of this list.
|
|
Each node contains pointers that tells the information it is mapping to.
|
|
If the node is a duplicate of other boards, restore info of this node.
|
|
If the node is a duplicate of local board(within same board), node will not be restored.
|
|
Finally, updated the pre-calculated packagesize.
|
|
The restored image block list can be used to build up a image package.
|
|
This is an internal function.
|
|
|
|
@param[in, out] List A pointer to the first entry,
|
|
Funciotn will traverse data struture from this entry.
|
|
@param[in] BoardId A board id to specify which package to restore.
|
|
@param[out] PackageSize Output length of image package data for this board.
|
|
This length does not include package end block.
|
|
|
|
@retval EFI_SUCCESS The specified image block list is successfully restored.
|
|
@retval EFI_INVALID_PARAMETER Argument List is NULL or PackageSize is NULL.
|
|
@retval EFI_UNSUPPORTED The PackageSize calculation is not correct.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RestoreImageBlockWorker (
|
|
IN OUT H2O_HII_IMAGE_TABLE_ENTRY *List,
|
|
IN H2O_BOARD_ID BoardId,
|
|
OUT UINT32 *PackageSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_HII_IMAGE_TABLE_ENTRY *TargetImageTableEntry;
|
|
H2O_HII_IMAGE_BLOCK_NODE *CurrentImageBlockNode;
|
|
LIST_ENTRY *Link;
|
|
LIST_ENTRY *SourceEntry;
|
|
LIST_ENTRY *SourceNode;
|
|
INT32 Index;
|
|
INT32 NodeIndex;
|
|
BOOLEAN IsDuplicateBlockRestored;
|
|
H2O_HII_IMAGE_TABLE_ENTRY *SourceImageTableEntry;
|
|
H2O_HII_IMAGE_BLOCK_NODE *SourceImageBlockNode;
|
|
UINT32 ImagePkgeSizeForThisBoard;
|
|
UINT32 VerifySize;
|
|
|
|
if (List == NULL || PackageSize == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
TargetImageTableEntry = NULL;
|
|
ImagePkgeSizeForThisBoard = 0;
|
|
|
|
//
|
|
// Select entry by board.
|
|
//
|
|
Status = SelectImageEntryWorker (List, BoardId, &TargetImageTableEntry);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Iterate all node of this image block list,
|
|
// Restore node who duplicated with the other board.
|
|
// Local duplicate node should not restored, as they will be in the same package.
|
|
//
|
|
Link = TargetImageTableEntry->AssociateImageBlockList;
|
|
for (Index = 0; Index < TargetImageTableEntry->ImageBlockListNodeCount; Index++) {
|
|
CurrentImageBlockNode = GET_H2O_HII_IMAGE_BLOCK_NODE_FROM_THIS (Link);
|
|
//
|
|
// This "if" clause do all the work of restore duplicate block.
|
|
//
|
|
if (CurrentImageBlockNode->ImageBlockType == EFI_HII_IIBT_DUPLICATE) {
|
|
//
|
|
// Find out duplicated source in other board entries.
|
|
//
|
|
SourceEntry = &List->TableEntry;
|
|
IsDuplicateBlockRestored = FALSE;
|
|
do {
|
|
SourceImageTableEntry = GET_H2O_HII_IMAGE_TABLE_ENTRY_FROM_THIS (SourceEntry);
|
|
//
|
|
// Only search in master entry.
|
|
//
|
|
if (!SourceImageTableEntry->IsSlaveEntry) {
|
|
SourceNode = SourceImageTableEntry->AssociateImageBlockList;
|
|
for (NodeIndex = 0; NodeIndex < SourceImageTableEntry->ImageBlockListNodeCount ; NodeIndex++) {
|
|
SourceImageBlockNode = GET_H2O_HII_IMAGE_BLOCK_NODE_FROM_THIS (SourceNode);
|
|
//
|
|
// Match found, restore content.
|
|
//
|
|
if (SourceImageBlockNode->VirtualImageId == ((EFI_HII_IIBT_DUPLICATE_BLOCK *)(CurrentImageBlockNode->ImageBlock))->ImageId) {
|
|
//
|
|
// NOTE : Compatible with Build Technical Reference 3.23.2.1.
|
|
// H2O_HII_IIBT_IMAGE_32BIT_BLOCK is a ext4 type which contains image instance.
|
|
//
|
|
CurrentImageBlockNode->ImageBlockSize = SourceImageBlockNode->ImageBlockSize;
|
|
CurrentImageBlockNode->ImageBlockType = SourceImageBlockNode->ImageBlockType;
|
|
CurrentImageBlockNode->ImageBlock = SourceImageBlockNode->ImageBlock;
|
|
CurrentImageBlockNode->ImageInstance = SourceImageBlockNode->ImageInstance;
|
|
// Should not update VirtualImageId, it is a key.
|
|
IsDuplicateBlockRestored = TRUE;
|
|
break;
|
|
}
|
|
SourceNode = SourceNode->ForwardLink;
|
|
}
|
|
}
|
|
|
|
if (IsDuplicateBlockRestored) {
|
|
break;
|
|
}
|
|
|
|
SourceEntry = SourceEntry->ForwardLink;
|
|
} while (SourceEntry != &List->TableEntry);
|
|
}
|
|
ImagePkgeSizeForThisBoard += CurrentImageBlockNode->ImageBlockSize;
|
|
Link = Link->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// Verify size.
|
|
//
|
|
VerifySize = 0;
|
|
Link = TargetImageTableEntry->AssociateImageBlockList;
|
|
for (Index = 0; Index < TargetImageTableEntry->ImageBlockListNodeCount; Index++) {
|
|
CurrentImageBlockNode = GET_H2O_HII_IMAGE_BLOCK_NODE_FROM_THIS (Link);
|
|
VerifySize += CurrentImageBlockNode->ImageBlockSize;
|
|
Link = Link->BackLink;
|
|
}
|
|
|
|
if (VerifySize != ImagePkgeSizeForThisBoard) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
*PackageSize = ImagePkgeSizeForThisBoard;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Insyde multi board image package extension.
|
|
|
|
Construct a image package data for one board, the board is specified by caller.
|
|
The output package data is a pure package data without end block.
|
|
This is an internal function.
|
|
|
|
@param[in, out] List A pointer to the first entry.
|
|
Funciotn will traverse data struture start at this entry.
|
|
@param[in] PlatformBoardId A board id to specify which package to restore.
|
|
@param[out] PackageData Update a pointer to a package data with out end block.
|
|
@param[out] PackageDataLength The size of output package data.
|
|
Length is package data specific, not iclude end block.
|
|
@retval EFI_SUCCESS Target image package data is created successfully.
|
|
@retval EFI_INVALID_PARAMETER List is NULL or PackageData is NULL or PackageDataLength
|
|
is NULL.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ConstructImagePkg (
|
|
IN OUT H2O_HII_IMAGE_TABLE_ENTRY *List,
|
|
IN H2O_BOARD_ID PlatformBoardId,
|
|
OUT UINT8 **PackageData,
|
|
OUT UINT32 *PackageDataLength
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_BOARD_ID BoardId;
|
|
UINT32 DataLength;
|
|
UINT8 *BinBuffer;
|
|
H2O_HII_IMAGE_TABLE_ENTRY *CurrentImageTableEntry;
|
|
INT32 Index;
|
|
H2O_HII_IMAGE_BLOCK_NODE *CurrentImageBlockNode;
|
|
LIST_ENTRY *Node;
|
|
UINT32 Offset;
|
|
UINT32 VerifySize;
|
|
UINT32 Length;
|
|
|
|
if (List == NULL || PackageData == NULL || PackageDataLength == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
BoardId = PlatformBoardId;
|
|
DataLength = 0;
|
|
BinBuffer = NULL;
|
|
Offset = 0;
|
|
VerifySize = 0;
|
|
//
|
|
// Pre process target image block list.
|
|
// Use board id to find target list, then restore it,
|
|
// and get real data length.
|
|
//
|
|
Status = RestoreImageBlockWorker (List, BoardId, &DataLength);
|
|
//
|
|
// Add error handling - when input board id not found, use default imgpkg.
|
|
//
|
|
if (Status == EFI_NOT_FOUND) {
|
|
//
|
|
// Use default board value 0 to get info again.
|
|
//
|
|
BoardId = 0x00;
|
|
Status = RestoreImageBlockWorker (List, BoardId, &DataLength);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
*PackageData = NULL;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Create empty buffer. Length equals to real data length.
|
|
//
|
|
BinBuffer = AllocateZeroPool (DataLength);
|
|
if (BinBuffer == NULL) {
|
|
*PackageData = NULL;
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Retrieve the pointer of image table entry according to board id.
|
|
// (We allready restore the image block list for this board.)
|
|
//
|
|
Status = SelectImageEntryWorker (List, BoardId, &CurrentImageTableEntry);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (BinBuffer);
|
|
*PackageData = NULL;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Iterate all nodes in the image block list of the entry we selected.
|
|
// For each node, get mapped data and copy them to new buffer.
|
|
//
|
|
Node = CurrentImageTableEntry->AssociateImageBlockList;
|
|
for (Index = 0; Index < CurrentImageTableEntry->ImageBlockListNodeCount; Index++) {
|
|
CurrentImageBlockNode = GET_H2O_HII_IMAGE_BLOCK_NODE_FROM_THIS (Node);
|
|
//
|
|
// Buffer overflow should not occurred if data length calculated correctly in early stage.
|
|
//
|
|
if (DataLength - Offset < CurrentImageBlockNode->ImageBlockSize) {
|
|
//
|
|
// Not using status EFI_BUFFER_TOO_SMALL
|
|
// because size calculation error means process went wrong in early stage.
|
|
// "Do NOT" handle this error using any re-allocate mamory mechanism.
|
|
//
|
|
FreePool (BinBuffer);
|
|
*PackageData = NULL;
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Following procedure copy data from source separately.
|
|
//
|
|
// Set block header.
|
|
//
|
|
VerifySize += CurrentImageBlockNode->ImageBlockSize;
|
|
CopyMem (BinBuffer + Offset, &CurrentImageBlockNode->ImageBlockType, sizeof (UINT8));
|
|
Offset += sizeof (UINT8);
|
|
//
|
|
// Set block content.
|
|
//
|
|
switch (CurrentImageBlockNode->ImageBlockType) {
|
|
case EFI_HII_IIBT_EXT1:
|
|
case EFI_HII_IIBT_EXT2:
|
|
Length = CurrentImageBlockNode->ImageBlockSize - sizeof (UINT8);
|
|
CopyMem (BinBuffer + Offset, CurrentImageBlockNode->ImageBlock + sizeof (UINT8), Length);
|
|
Offset += Length;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_EXT4:
|
|
//
|
|
// Compatible with Build Technical Reference 3.23.2.1.
|
|
// We already reserved buffer size of a skip block for each H2O_HII_IIBT_IMAGE_32BIT_BLOCK.
|
|
//
|
|
if (((EFI_HII_IIBT_EXT4_BLOCK *)(CurrentImageBlockNode->ImageBlock))->BlockType2 == H2O_HII_IIBT_IMAGE_32BIT) {
|
|
Length = ((EFI_HII_IIBT_EXT4_BLOCK *)(CurrentImageBlockNode->ImageBlock))->Length - sizeof (UINT8);
|
|
// Fatal error checking, incorrect buffer size info from header.
|
|
if (CurrentImageBlockNode->ImageBlockSize - sizeof (EFI_HII_IIBT_SKIP1_BLOCK) - sizeof (UINT8) != Length) {
|
|
DEBUG ((EFI_D_ERROR, "[FatalError]---BlockLength-info-error-when-construct-imgpkg--\n"));
|
|
ASSERT(FALSE);
|
|
}
|
|
CopyMem (BinBuffer + Offset, CurrentImageBlockNode->ImageBlock + sizeof (UINT8), Length);
|
|
Offset += Length;
|
|
//
|
|
// Create a skip1 block. Skip count set to 1.
|
|
//
|
|
// typedef struct _EFI_HII_IIBT_SKIP1_BLOCK {
|
|
// EFI_HII_IMAGE_BLOCK Header;
|
|
// UINT8 SkipCount;
|
|
// } EFI_HII_IIBT_SKIP1_BLOCK;
|
|
//
|
|
*(BinBuffer + Offset) = EFI_HII_IIBT_SKIP1;
|
|
*(BinBuffer + Offset + sizeof (UINT8)) = 1;
|
|
Offset += sizeof (EFI_HII_IIBT_SKIP1_BLOCK);
|
|
} else {
|
|
Length = CurrentImageBlockNode->ImageBlockSize - sizeof (UINT8);
|
|
CopyMem (BinBuffer + Offset, CurrentImageBlockNode->ImageBlock + sizeof (UINT8), Length);
|
|
Offset += Length;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Following case are currently using same procedure,
|
|
// intentionally taer them apart into three groups.
|
|
//
|
|
case EFI_HII_IIBT_IMAGE_1BIT:
|
|
case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
|
|
case EFI_HII_IIBT_IMAGE_4BIT:
|
|
case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
|
|
case EFI_HII_IIBT_IMAGE_8BIT:
|
|
case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
|
|
case EFI_HII_IIBT_IMAGE_24BIT:
|
|
case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
|
|
Length = CurrentImageBlockNode->ImageBlockSize - sizeof (UINT8);
|
|
CopyMem (BinBuffer + Offset, CurrentImageBlockNode->ImageBlock + sizeof (UINT8), Length);
|
|
Offset += Length;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_DUPLICATE:
|
|
case EFI_HII_IIBT_SKIP1:
|
|
case EFI_HII_IIBT_SKIP2:
|
|
Length = CurrentImageBlockNode->ImageBlockSize - sizeof (UINT8);
|
|
CopyMem (BinBuffer + Offset, CurrentImageBlockNode->ImageBlock + sizeof (UINT8), Length);
|
|
Offset += Length;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_JPEG:
|
|
Length = CurrentImageBlockNode->ImageBlockSize - sizeof (UINT8);
|
|
CopyMem (BinBuffer + Offset, CurrentImageBlockNode->ImageBlock + sizeof (UINT8), Length);
|
|
Offset += Length;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Verify current water level.
|
|
//
|
|
if (VerifySize != Offset) {
|
|
FreePool (BinBuffer);
|
|
*PackageData = NULL;
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Node = Node->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// Finally check size again. This is the total size.
|
|
//
|
|
if (VerifySize != DataLength) {
|
|
FreePool (BinBuffer);
|
|
*PackageData = NULL;
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
*PackageData = BinBuffer;
|
|
*PackageDataLength = DataLength;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Insyde multi board image package extension.
|
|
|
|
This is the "MAIN" function for parsing multi-image package.
|
|
Input a image package(multi), output a image package(single) according to 'PcdH2OBoardId'.
|
|
The output package is a pure package data without "end block".
|
|
If corresponding package not found in source, system will use default package patch it.
|
|
|
|
@param[in] FirstImageBlockHeader A pointer to source image package from package list buffer.
|
|
|
|
@param[out] PackageData Output an address of a new buffer of parsed package data
|
|
if whole progress runs successfully.
|
|
Output a NULL if process failed.
|
|
This buffer should be freed by caller when image package
|
|
installation finished.
|
|
@param[out] PackageDataLength Output a length of new buffer.
|
|
|
|
@retval EFI_SUCCESS EFI_SUCCESS.
|
|
@retval EFI_INVALID_PARAMETER FirstImageBlockHeader is NULL or PackageData is NULL or
|
|
PackageDataLength is NULL.
|
|
@retval EFI_UNSUPPORTED Input source is not a multi image package
|
|
(The first block should be a H2O_HII_IIBT_BOARDS_BLOCK).
|
|
Binary format error or violation occured during the parsing.
|
|
**/
|
|
EFI_STATUS
|
|
ClassifyMultiBoardImageBlock (
|
|
IN CONST UINT8 *FirstImageBlockHeader,
|
|
OUT VOID **PackageData,
|
|
OUT UINT32 *PackageDataLength
|
|
)
|
|
{
|
|
H2O_HII_IMAGE_TABLE_ENTRY *MultiImageEntryList;
|
|
EFI_STATUS Status;
|
|
H2O_BOARD_ID PlatformBoardId;
|
|
UINT8 *CurrentImageBlock;
|
|
UINT32 BlockLength;
|
|
H2O_HII_IIBT_BOARDS_BLOCK DefaultBoardsBlock;
|
|
H2O_HII_IIBT_BOARDS_BLOCK *CurrentBoardsBlock;
|
|
EFI_IMAGE_ID CurrentImageId;
|
|
UINT32 JumpSize;
|
|
EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1Bit;
|
|
EFI_HII_IIBT_IMAGE_4BIT_BLOCK Iibt4Bit;
|
|
EFI_HII_IIBT_IMAGE_8BIT_BLOCK Iibt8Bit;
|
|
EFI_HII_IIBT_IMAGE_24BIT_BLOCK Iibt24Bit;
|
|
UINT16 SkipCount;
|
|
EFI_IMAGE_ID FirstImageIdOfThisBlock;
|
|
|
|
if (FirstImageBlockHeader == NULL || PackageData == NULL || PackageDataLength == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
MultiImageEntryList = NULL;
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
//
|
|
// Let PcdH2OBoardId decide which image package will be used.
|
|
//
|
|
PlatformBoardId = PcdGet64 (PcdH2OBoardId);
|
|
|
|
CurrentImageBlock = (UINT8 *)FirstImageBlockHeader;
|
|
CurrentBoardsBlock = NULL;
|
|
BlockLength = 0;
|
|
CurrentImageId = 1;
|
|
JumpSize = 0;
|
|
|
|
//
|
|
// Compatible with situation that fisrt block is not a boards block.
|
|
// Current image buffer "doesn't" have a boards block at the head.
|
|
// This virtual boards block represents the defualt boards block attached at
|
|
// the head of multi image package. See image c array in module's AutoGen.c.
|
|
// This virtual block also maintain the compatibility for Rev 5.2 and 5.3 co-using build.exe.
|
|
//
|
|
DefaultBoardsBlock.Hdr.Header.BlockType = EFI_HII_IIBT_EXT1;
|
|
DefaultBoardsBlock.Hdr.BlockType2 = H2O_HII_IIBT_BOARDS;
|
|
DefaultBoardsBlock.Hdr.Length = 0x06; // sizeof (H2O_HII_IIBT_BOARDS_BLOCK)
|
|
DefaultBoardsBlock.ImageId = 0x00; // Current usage reserved.
|
|
DefaultBoardsBlock.Boards[0] = 0x00; // Default 0x00
|
|
//
|
|
// Set CurrentBoardsBlock to virtual default block first.
|
|
// CurrentBoardsBlock pointer updates whenever
|
|
// boards block has been encountered while parsing image package buffer.
|
|
//
|
|
CurrentBoardsBlock = (H2O_HII_IIBT_BOARDS_BLOCK *)&DefaultBoardsBlock;
|
|
|
|
while (*CurrentImageBlock != EFI_HII_IIBT_END) {
|
|
switch (*CurrentImageBlock) {
|
|
case EFI_HII_IIBT_EXT1:
|
|
BlockLength = ((EFI_HII_IIBT_EXT1_BLOCK *)CurrentImageBlock)->Length;
|
|
//
|
|
// Recored boards block :
|
|
// Following image blocks will associate with this boards info until next
|
|
// boards block found in source buffer.
|
|
// Boards block will not be added to list.
|
|
//
|
|
if (((H2O_HII_IIBT_BOARDS_BLOCK *)CurrentImageBlock)->Hdr.BlockType2 == H2O_HII_IIBT_BOARDS) {
|
|
CurrentBoardsBlock = (H2O_HII_IIBT_BOARDS_BLOCK *)CurrentImageBlock;
|
|
} else {
|
|
//
|
|
// Normal Ext1 block should remain the same.
|
|
// For other Ext1 block who has special usage(future extension),
|
|
// the conditional branch should be added prior to this "else" clause.
|
|
//
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
EFI_HII_IIBT_EXT1,
|
|
CurrentImageBlock,
|
|
NULL,
|
|
CurrentBoardsBlock,
|
|
0 // Doesnt require image id.
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
}
|
|
JumpSize += BlockLength;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_EXT2:
|
|
BlockLength = ((EFI_HII_IIBT_EXT2_BLOCK *)CurrentImageBlock)->Length;
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
EFI_HII_IIBT_EXT2,
|
|
CurrentImageBlock,
|
|
NULL,
|
|
CurrentBoardsBlock,
|
|
0 // Doesnt require image id.
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_EXT4:
|
|
//
|
|
// NOTE : Compatible with Build Technical Reference 3.23.2.1.
|
|
//
|
|
// When system performs get image in hii data base,
|
|
// H2O_HII_IIBT_IMAGE_32BIT_BLOCK does not increment image id, it will be followed by
|
|
// a skip block to help increace image id.
|
|
//
|
|
// In the data structure under the MultiImageEntryList,
|
|
// the SKIP block right next to H2O_HII_IIBT_IMAGE_32BIT_BLOCK will not be add here
|
|
// to keep the virtual key of this node unique. The CurrentImageId increased 1 as
|
|
// we ignored a SKIP block. This ensures the following block get correct id(global view).
|
|
//
|
|
// When parser performs restore and construct image package method,
|
|
// the skip block will be appended to H2O_HII_IIBT_IMAGE_32BIT_BLOCK.
|
|
//
|
|
// The other normal EXT4 blocks will be added with NULL id.
|
|
//
|
|
if (((H2O_HII_IIBT_IMAGE_32BIT_BLOCK *)CurrentImageBlock)->BlockType2 == H2O_HII_IIBT_IMAGE_32BIT) {
|
|
BlockLength = ((EFI_HII_IIBT_EXT4_BLOCK *)CurrentImageBlock)->Length;
|
|
//
|
|
// This skip block is unique next to H2O_HII_IIBT_IMAGE_32BIT_BLOCK,
|
|
// tools should not mixup this block with the others.
|
|
//
|
|
if (((EFI_HII_IIBT_SKIP1_BLOCK *)(CurrentImageBlock + BlockLength))->SkipCount > 1) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Clean;
|
|
}
|
|
//
|
|
// Jump over a skip block. Total length is incremented by the size of a skip1.
|
|
//
|
|
BlockLength += sizeof (EFI_HII_IIBT_SKIP1_BLOCK);
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
EFI_HII_IIBT_EXT4,
|
|
CurrentImageBlock,
|
|
CurrentImageBlock + sizeof (H2O_HII_IIBT_IMAGE_32BIT_BLOCK) - sizeof (H2O_HII_RGBA_PIXEL),
|
|
CurrentBoardsBlock,
|
|
CurrentImageId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
CurrentImageId++;
|
|
} else {
|
|
BlockLength = ((EFI_HII_IIBT_EXT4_BLOCK *)CurrentImageBlock)->Length;
|
|
//
|
|
// For normal ext block,
|
|
// should not increment CurrentImageId,
|
|
// should not jump over its neighborhood.
|
|
//
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
EFI_HII_IIBT_EXT4,
|
|
CurrentImageBlock,
|
|
NULL,
|
|
CurrentBoardsBlock,
|
|
0 // Doesnt require image id.
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
}
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_1BIT:
|
|
case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
|
|
CopyMem (&Iibt1Bit, CurrentImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
|
|
BlockLength = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) + BITMAP_LEN_1_BIT (Iibt1Bit.Bitmap.Width, Iibt1Bit.Bitmap.Height) - sizeof (UINT8);
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
*CurrentImageBlock,
|
|
CurrentImageBlock,
|
|
CurrentImageBlock + sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8),
|
|
CurrentBoardsBlock,
|
|
CurrentImageId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
CurrentImageId++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_4BIT:
|
|
case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
|
|
CopyMem (&Iibt4Bit, CurrentImageBlock, sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK));
|
|
BlockLength = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) + BITMAP_LEN_4_BIT (Iibt4Bit.Bitmap.Width, Iibt4Bit.Bitmap.Height) - sizeof (UINT8);
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
*CurrentImageBlock,
|
|
CurrentImageBlock,
|
|
CurrentImageBlock + sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8),
|
|
CurrentBoardsBlock,
|
|
CurrentImageId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
CurrentImageId++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_8BIT:
|
|
case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
|
|
CopyMem (&Iibt8Bit, CurrentImageBlock, sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK));
|
|
BlockLength = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) + BITMAP_LEN_8_BIT (Iibt8Bit.Bitmap.Width, Iibt8Bit.Bitmap.Height) - sizeof (UINT8);
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
*CurrentImageBlock,
|
|
CurrentImageBlock,
|
|
CurrentImageBlock + sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8),
|
|
CurrentBoardsBlock,
|
|
CurrentImageId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
CurrentImageId++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_24BIT:
|
|
case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
|
|
CopyMem (&Iibt24Bit, CurrentImageBlock, sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK));
|
|
BlockLength = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) + BITMAP_LEN_24_BIT (Iibt24Bit.Bitmap.Width, Iibt24Bit.Bitmap.Height) - sizeof (EFI_HII_RGB_PIXEL);
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
*CurrentImageBlock,
|
|
CurrentImageBlock,
|
|
CurrentImageBlock + sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL),
|
|
CurrentBoardsBlock,
|
|
CurrentImageId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
CurrentImageId++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_DUPLICATE:
|
|
BlockLength = sizeof (EFI_HII_IIBT_DUPLICATE_BLOCK);
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
EFI_HII_IIBT_DUPLICATE,
|
|
CurrentImageBlock,
|
|
NULL,
|
|
CurrentBoardsBlock,
|
|
CurrentImageId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
CurrentImageId++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_IMAGE_JPEG:
|
|
// Reference:
|
|
// typedef struct _EFI_HII_IIBT_JPEG_BLOCK {
|
|
// EFI_HII_IMAGE_BLOCK Header; // UINT8 BlockType.
|
|
// UINT32 Size; // Image file size alone.
|
|
// UINT8 Data[1]; // First byte of image.
|
|
// } EFI_HII_IIBT_JPEG_BLOCK;
|
|
//
|
|
BlockLength = ((EFI_HII_IIBT_JPEG_BLOCK *)CurrentImageBlock)->Size + sizeof (EFI_HII_IIBT_JPEG_BLOCK) - sizeof (UINT8);
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
EFI_HII_IIBT_IMAGE_JPEG,
|
|
CurrentImageBlock,
|
|
CurrentImageBlock + sizeof (EFI_HII_IIBT_JPEG_BLOCK) - sizeof (UINT8),
|
|
CurrentBoardsBlock,
|
|
CurrentImageId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
CurrentImageId++;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_SKIP1:
|
|
FirstImageIdOfThisBlock = CurrentImageId;
|
|
SkipCount = ((EFI_HII_IIBT_SKIP1_BLOCK *)CurrentImageBlock)->SkipCount;
|
|
BlockLength = sizeof (EFI_HII_IIBT_SKIP1_BLOCK);
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
EFI_HII_IIBT_SKIP1,
|
|
CurrentImageBlock,
|
|
NULL,
|
|
CurrentBoardsBlock,
|
|
FirstImageIdOfThisBlock
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
CurrentImageId = CurrentImageId + SkipCount;
|
|
break;
|
|
|
|
case EFI_HII_IIBT_SKIP2:
|
|
FirstImageIdOfThisBlock = CurrentImageId;
|
|
SkipCount = ((EFI_HII_IIBT_SKIP2_BLOCK *)CurrentImageBlock)->SkipCount;
|
|
BlockLength = sizeof (EFI_HII_IIBT_SKIP2_BLOCK);
|
|
Status = ClassifyImageBlockWorker (
|
|
&MultiImageEntryList,
|
|
BlockLength,
|
|
EFI_HII_IIBT_SKIP2,
|
|
CurrentImageBlock,
|
|
NULL,
|
|
CurrentBoardsBlock,
|
|
FirstImageIdOfThisBlock
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Clean;
|
|
}
|
|
JumpSize += BlockLength;
|
|
CurrentImageId = CurrentImageId + SkipCount;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Should not run to here if data in source buffer is correct.
|
|
//
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Clean;
|
|
//
|
|
// A good habit to add break.
|
|
//
|
|
break;
|
|
}
|
|
CurrentImageBlock = (UINT8 *)FirstImageBlockHeader + JumpSize;
|
|
}
|
|
|
|
//
|
|
// Not found any image, directly return
|
|
//
|
|
if (MultiImageEntryList == NULL) {
|
|
*PackageData = NULL;
|
|
PackageDataLength = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Construct a image package by board.
|
|
//
|
|
Status = ConstructImagePkg (
|
|
MultiImageEntryList,
|
|
PlatformBoardId,
|
|
(UINT8 **)PackageData,
|
|
PackageDataLength
|
|
);
|
|
|
|
Clean:
|
|
BoardImageTableListDestructor (MultiImageEntryList);
|
|
return Status;
|
|
}
|