簡單來說,如果很久以前曾在 Linux or Unix 下寫過 socket 程式,那我想這就不是一件很難的事,只要注意一些 header 檔案的位置跟傳統的不一樣即可。

從上圖可以得知,要在 UEFI Shell 下使用網路,需具備 4 要件:
1. 要有網卡。
2. 要有 UNDI driver。
3. 載入 Simple Network Protocol。
4. 載入 TCP / IP Stack。
註:從 Intel 的文件 "UEFI Driver Development Guide for Network Boot Devices" 來看,SNP 和 TCP / IP Stack 中間似乎還有一層 MNP ( Managed Network Protocol ),不過這邊我們可以先忽略它。
以我的小電腦來說,除了 Simple Network Protocol 以外,其餘皆已內建,故我從 UDK2014 code base 中 build 出此 driver 即可﹝C:\edk2-UDK2014\MdeModulePkg\Universal\Network﹞,接著開機時,使用 "load" command 載入 driver,便可以順利使用 "ifconfig" command 取得 IP。
再來就是跟以前撰寫 socket 程式一樣,呼叫 socket, connect, send, close 等函式完成想要完成的工作,底下為 Client 端發送封包的例子。
2025/06/14 更新
拿掉之前的測試程式,因為只是範例,連 main 都沒有。
TCPClient.c
//#include <Uefi.h>
//#include <Library/UefiLib.h>
//#include <Library/ShellCEntryLib.h>
#include <netinet/in.h>
#include <sys/EfiSysCall.h>
//#include <sys/endian.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
testTCPSocket (
IN unsigned long serverIP,
IN int serverPort
)
{
int rc;
int sock;
struct sockaddr_in v4;
char data[1024];
size_t sent_bytes;
size_t sendstrlen;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_TCP);
if (sock == -1)
{
printf("init socket error\n");
return -1;
}
memset(&v4, 0x00, sizeof(v4));
v4.sin_len = sizeof(v4);
v4.sin_family = AF_INET;
v4.sin_addr.s_addr = serverIP;
v4.sin_port = htons(serverPort);
rc = connect(sock, (struct sockaddr*)&v4, sizeof(v4));
if (rc == -1)
{
printf("connect() failed (%d)\n", rc);
//return -1;
}
printf("input string to send or 'q' to exit connection\n");
while (1)
{
memset(data, 0x00, sizeof(data));
//scanf("%s", data);
fgets(data, sizeof(data) - 1, stdin);
if (data[0] == 'q')
{
printf("ready to exit connection\n");
break;
}
sendstrlen = strlen(data);
if (sendstrlen > 0 && sendstrlen < 1023)
{
sent_bytes = send(sock, data, sendstrlen, 0);
printf("\t !!! Sent data: %s(%d) --- \n", data, sent_bytes);
}
}
close(sock);
return 0;
}
unsigned long
getServerIP (
IN int Argc,
IN char **Argv
)
{
UINT32 ip[4];
int rc;
unsigned long serverIP;
int i;
if (Argc < 2)
{
return 0;
}
rc = sscanf(Argv[1], "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
if (rc != 4)
{
return 0;
}
for (i = 0; i < 4; i++)
{
if (ip[i] > 255 || ip[i] < 0)
{
return 0;
}
}
serverIP = (ip[3] << 24)
| (ip[2] << 16)
| (ip[1] << 8)
| ip[0];
return serverIP;
}
int
main (
IN int Argc,
IN char **Argv
)
{
unsigned long serverIP;
int serverPort;
int rc;
if (Argc != 3)
{
printf("error argv \n");
printf("TCPClient 127.0.0.1 8080\n");
return 0;
}
serverIP = inet_addr(Argv[1]);
//serverIP = getServerIP(Argc, Argv);
serverPort = atoi(Argv[2]);
printf("TCPClient Start \n");
rc = testTCPSocket(serverIP, serverPort);
printf("Send Socket (%d)\n", rc);
return 0;
}
TCPClient.inf
## @file
# A simple, basic, application showing how the Hello application could be
# built using the "Standard C Libraries" from StdLib.
#
# Copyright (c) 2010 - 2011, 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.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = TCPClient
FILE_GUID = 60a0b517-eb12-444d-8792-f6368622f9cb
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = ShellCEntryLib
#
# VALID_ARCHITECTURES = IA32 X64 IPF
#
[Sources]
TCPClient.c
[Packages]
StdLib/StdLib.dec
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
[LibraryClasses]
BsdSocketLib
EfiSocketLib
LibC
LibNetUtil
[Protocols]
[BuildOptions]
INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
MSFT:*_*_*_CC_FLAGS = /Od
GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
4 則留言:
你好,請教一下,您有這支code的inf檔案嗎,我試著build它 但一直遇到以下的build error
LibCMin.lib(Main.obj) : error LNK2005: ShellAppMain already defined in SocketClient.lib(SocketClient.obj)
Generating code
LibString.lib(Copying.obj) : error LNK2001: unresolved external symbol memset
LibGdtoa.lib(misc.obj) : error LNK2001: unresolved external symbol memset
LibString.lib(Searching.obj) : error LNK2001: unresolved external symbol memset
您好,
我原本的例子連 main 都沒有,不知道你的錯誤是因為這樣嗎?
不過看起來是 ShellAPPMain 重複定義了,以及 memset 找不到。
附上我電腦的備份檔,不過,因為我已經換工作了,故現在也沒有辦法測試是否沒問題,但我剛才稍微 review,看起來應該是沒問題的。
嗯嗯, main的部份我有補上 主要是memset它DEBUG_MODE才能build過 release mode build不過 我加了/Od也一樣 目前是有build過了 但在shell執行起來它會出現一行
ERROR Initializing Standard IO: No Error Detected.
Success
不曉得您當初有沒有遇到
如果沒有的話 就算了 我再試試看其他的方法
謝謝!!
抱歉,這個問題我沒遇過,我只記得如果要用網路等功能,用的UEFI 那包,跟 BIOS 的 code 好像要 match,不然會有問題。
現在已經不在當初部門,可能也沒什麼好建議了。
張貼留言