mirror of https://github.com/acidanthera/audk.git
NetworkPkg: Remove a CopyMem to speed up the HTTP boot download.
This patch updates the HTTP boot driver to use the caller provided buffer directly in identity transfer-coding mode, this could save one time CopyMem operation to benefit the download performance. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Zhang Lubo <lubo.zhang@intel.com> Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19482 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
06e5ae774e
commit
7552c24e76
|
@ -456,81 +456,6 @@ HttpBootCreateHttpIo (
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Get the file content from cached data.
|
|
||||||
|
|
||||||
@param[in] Private The pointer to the driver's private data.
|
|
||||||
@param[in] Uri Uri of the file to be retrieved from cache.
|
|
||||||
@param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
|
|
||||||
code of EFI_SUCCESS, the amount of data transferred to
|
|
||||||
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
|
|
||||||
the size of Buffer required to retrieve the requested file.
|
|
||||||
@param[out] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
|
|
||||||
then the size of the requested file is returned in
|
|
||||||
BufferSize.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Successfully created.
|
|
||||||
@retval Others Failed to create HttpIo.
|
|
||||||
|
|
||||||
**/
|
|
||||||
EFI_STATUS
|
|
||||||
HttpBootGetFileFromCache (
|
|
||||||
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
|
||||||
IN CHAR16 *Uri,
|
|
||||||
IN OUT UINTN *BufferSize,
|
|
||||||
OUT UINT8 *Buffer
|
|
||||||
)
|
|
||||||
{
|
|
||||||
LIST_ENTRY *Entry;
|
|
||||||
LIST_ENTRY *Entry2;
|
|
||||||
HTTP_BOOT_CACHE_CONTENT *Cache;
|
|
||||||
HTTP_BOOT_ENTITY_DATA *EntityData;
|
|
||||||
UINTN CopyedSize;
|
|
||||||
|
|
||||||
if (Uri == NULL || BufferSize == 0 || Buffer == NULL) {
|
|
||||||
return EFI_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
NET_LIST_FOR_EACH (Entry, &Private->CacheList) {
|
|
||||||
Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);
|
|
||||||
//
|
|
||||||
// Compare the URI to see whether we already have a cache for this file.
|
|
||||||
//
|
|
||||||
if ((Cache->RequestData != NULL) &&
|
|
||||||
(Cache->RequestData->Url != NULL) &&
|
|
||||||
(StrCmp (Uri, Cache->RequestData->Url) == 0))
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// Hit cache, check buffer size.
|
|
||||||
//
|
|
||||||
if (*BufferSize < Cache->EntityLength) {
|
|
||||||
*BufferSize = Cache->EntityLength;
|
|
||||||
return EFI_BUFFER_TOO_SMALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Fill data to buffer.
|
|
||||||
//
|
|
||||||
CopyedSize = 0;
|
|
||||||
NET_LIST_FOR_EACH (Entry2, &Cache->EntityDataList) {
|
|
||||||
EntityData = NET_LIST_USER_STRUCT (Entry2, HTTP_BOOT_ENTITY_DATA, Link);
|
|
||||||
if (*BufferSize > CopyedSize) {
|
|
||||||
CopyMem (
|
|
||||||
Buffer + CopyedSize,
|
|
||||||
EntityData->DataStart,
|
|
||||||
MIN (EntityData->DataLength, *BufferSize - CopyedSize)
|
|
||||||
);
|
|
||||||
CopyedSize += MIN (EntityData->DataLength, *BufferSize - CopyedSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*BufferSize = CopyedSize;
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return EFI_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Release all the resource of a cache item.
|
Release all the resource of a cache item.
|
||||||
|
|
||||||
|
@ -609,6 +534,91 @@ HttpBootFreeCacheList (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the file content from cached data.
|
||||||
|
|
||||||
|
@param[in] Private The pointer to the driver's private data.
|
||||||
|
@param[in] Uri Uri of the file to be retrieved from cache.
|
||||||
|
@param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
|
||||||
|
code of EFI_SUCCESS, the amount of data transferred to
|
||||||
|
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
|
||||||
|
the size of Buffer required to retrieve the requested file.
|
||||||
|
@param[out] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
|
||||||
|
then the size of the requested file is returned in
|
||||||
|
BufferSize.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successfully created.
|
||||||
|
@retval Others Failed to create HttpIo.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
HttpBootGetFileFromCache (
|
||||||
|
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
||||||
|
IN CHAR16 *Uri,
|
||||||
|
IN OUT UINTN *BufferSize,
|
||||||
|
OUT UINT8 *Buffer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LIST_ENTRY *Entry;
|
||||||
|
LIST_ENTRY *Entry2;
|
||||||
|
HTTP_BOOT_CACHE_CONTENT *Cache;
|
||||||
|
HTTP_BOOT_ENTITY_DATA *EntityData;
|
||||||
|
UINTN CopyedSize;
|
||||||
|
|
||||||
|
if (Uri == NULL || BufferSize == 0 || Buffer == NULL) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Search file in the cache list, the cache entry will be released upon a successful
|
||||||
|
// match.
|
||||||
|
//
|
||||||
|
NET_LIST_FOR_EACH (Entry, &Private->CacheList) {
|
||||||
|
Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);
|
||||||
|
//
|
||||||
|
// Compare the URI to see whether we already have a cache for this file.
|
||||||
|
//
|
||||||
|
if ((Cache->RequestData != NULL) &&
|
||||||
|
(Cache->RequestData->Url != NULL) &&
|
||||||
|
(StrCmp (Uri, Cache->RequestData->Url) == 0))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Hit cache, check buffer size.
|
||||||
|
//
|
||||||
|
if (*BufferSize < Cache->EntityLength) {
|
||||||
|
*BufferSize = Cache->EntityLength;
|
||||||
|
return EFI_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fill data to buffer.
|
||||||
|
//
|
||||||
|
CopyedSize = 0;
|
||||||
|
NET_LIST_FOR_EACH (Entry2, &Cache->EntityDataList) {
|
||||||
|
EntityData = NET_LIST_USER_STRUCT (Entry2, HTTP_BOOT_ENTITY_DATA, Link);
|
||||||
|
if (*BufferSize > CopyedSize) {
|
||||||
|
CopyMem (
|
||||||
|
Buffer + CopyedSize,
|
||||||
|
EntityData->DataStart,
|
||||||
|
MIN (EntityData->DataLength, *BufferSize - CopyedSize)
|
||||||
|
);
|
||||||
|
CopyedSize += MIN (EntityData->DataLength, *BufferSize - CopyedSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*BufferSize = CopyedSize;
|
||||||
|
|
||||||
|
//
|
||||||
|
// On success, free the cached data to release the memory resource.
|
||||||
|
//
|
||||||
|
RemoveEntryList (&Cache->Link);
|
||||||
|
HttpBootFreeCache (Cache);
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A callback function to intercept events during message parser.
|
A callback function to intercept events during message parser.
|
||||||
|
|
||||||
|
@ -719,6 +729,8 @@ HttpBootGetBootFile (
|
||||||
HTTP_BOOT_CACHE_CONTENT *Cache;
|
HTTP_BOOT_CACHE_CONTENT *Cache;
|
||||||
UINT8 *Block;
|
UINT8 *Block;
|
||||||
CHAR16 *Url;
|
CHAR16 *Url;
|
||||||
|
BOOLEAN IdentityMode;
|
||||||
|
UINTN ReceivedSize;
|
||||||
|
|
||||||
ASSERT (Private != NULL);
|
ASSERT (Private != NULL);
|
||||||
ASSERT (Private->HttpCreated);
|
ASSERT (Private->HttpCreated);
|
||||||
|
@ -921,51 +933,94 @@ HttpBootGetBootFile (
|
||||||
//
|
//
|
||||||
Block = NULL;
|
Block = NULL;
|
||||||
if (!HeaderOnly) {
|
if (!HeaderOnly) {
|
||||||
|
//
|
||||||
|
// 3.4.1, check whether we are in identity transfer-coding.
|
||||||
|
//
|
||||||
|
ContentLength = 0;
|
||||||
|
Status = HttpGetEntityLength (Parser, &ContentLength);
|
||||||
|
if (!EFI_ERROR (Status)) {
|
||||||
|
IdentityMode = TRUE;
|
||||||
|
} else {
|
||||||
|
IdentityMode = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 3.4.2, start the message-body download, the identity and chunked transfer-coding
|
||||||
|
// is handled in different path here.
|
||||||
|
//
|
||||||
ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESOPNSE_DATA));
|
ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESOPNSE_DATA));
|
||||||
while (!HttpIsMessageComplete (Parser)) {
|
if (IdentityMode) {
|
||||||
//
|
//
|
||||||
// Allocate a block to hold the message-body, if caller doesn't provide
|
// In identity transfer-coding there is no need to parse the message body,
|
||||||
// a buffer, the block will be cached and we will allocate a new one here.
|
// just download the message body to the user provided buffer directly.
|
||||||
//
|
//
|
||||||
if (Block == NULL || Context.BufferSize == 0) {
|
ReceivedSize = 0;
|
||||||
Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);
|
while (ReceivedSize < ContentLength) {
|
||||||
if (Block == NULL) {
|
ResponseBody.Body = (CHAR8*) Buffer + ReceivedSize;
|
||||||
Status = EFI_OUT_OF_RESOURCES;
|
ResponseBody.BodyLength = *BufferSize - ReceivedSize;
|
||||||
|
Status = HttpIoRecvResponse (
|
||||||
|
&Private->HttpIo,
|
||||||
|
FALSE,
|
||||||
|
&ResponseBody
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
goto ERROR_6;
|
goto ERROR_6;
|
||||||
}
|
}
|
||||||
Context.NewBlock = TRUE;
|
ReceivedSize += ResponseBody.BodyLength;
|
||||||
Context.Block = Block;
|
|
||||||
} else {
|
|
||||||
Context.NewBlock = FALSE;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
ResponseBody.Body = (CHAR8*) Block;
|
|
||||||
ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;
|
|
||||||
Status = HttpIoRecvResponse (
|
|
||||||
&Private->HttpIo,
|
|
||||||
FALSE,
|
|
||||||
&ResponseBody
|
|
||||||
);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
goto ERROR_6;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse the new received block of the message-body, the block will be saved in cache.
|
// In "chunked" transfer-coding mode, so we need to parse the received
|
||||||
|
// data to get the real entity content.
|
||||||
//
|
//
|
||||||
Status = HttpParseMessageBody (
|
Block = NULL;
|
||||||
Parser,
|
while (!HttpIsMessageComplete (Parser)) {
|
||||||
ResponseBody.BodyLength,
|
//
|
||||||
ResponseBody.Body
|
// Allocate a buffer in Block to hold the message-body.
|
||||||
);
|
// If caller provides a buffer, this Block will be reused in every HttpIoRecvResponse().
|
||||||
if (EFI_ERROR (Status)) {
|
// Otherwise a buffer, the buffer in Block will be cached and we should allocate a new before
|
||||||
goto ERROR_6;
|
// every HttpIoRecvResponse().
|
||||||
|
//
|
||||||
|
if (Block == NULL || Context.BufferSize == 0) {
|
||||||
|
Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);
|
||||||
|
if (Block == NULL) {
|
||||||
|
Status = EFI_OUT_OF_RESOURCES;
|
||||||
|
goto ERROR_6;
|
||||||
|
}
|
||||||
|
Context.NewBlock = TRUE;
|
||||||
|
Context.Block = Block;
|
||||||
|
} else {
|
||||||
|
Context.NewBlock = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseBody.Body = (CHAR8*) Block;
|
||||||
|
ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;
|
||||||
|
Status = HttpIoRecvResponse (
|
||||||
|
&Private->HttpIo,
|
||||||
|
FALSE,
|
||||||
|
&ResponseBody
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ERROR_6;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parse the new received block of the message-body, the block will be saved in cache.
|
||||||
|
//
|
||||||
|
Status = HttpParseMessageBody (
|
||||||
|
Parser,
|
||||||
|
ResponseBody.BodyLength,
|
||||||
|
ResponseBody.Body
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto ERROR_6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// 3.5 Message-body receive & parse is completed, get the file size.
|
// 3.5 Message-body receive & parse is completed, we should be able to get the file size now.
|
||||||
//
|
//
|
||||||
Status = HttpGetEntityLength (Parser, &ContentLength);
|
Status = HttpGetEntityLength (Parser, &ContentLength);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
|
|
Loading…
Reference in New Issue