Skip to content

Commit 6d293a9

Browse files
committed
bug fix for Serial IO; start preliminary support for IPv4 / SNP
1 parent 280bd26 commit 6d293a9

File tree

5 files changed

+363
-2
lines changed

5 files changed

+363
-2
lines changed

src/machine/uefi/dhcpv4.go

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package uefi
2+
3+
import (
4+
"unsafe"
5+
)
6+
7+
//---------------------------------------------------------------------------
8+
// GUIDs
9+
//---------------------------------------------------------------------------
10+
11+
// EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID — §29.2.1
12+
var EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID = EFI_GUID{
13+
0x9d9a39d8, 0xbd42, 0x4a73,
14+
[8]uint8{0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80},
15+
}
16+
17+
// EFI_DHCP4_PROTOCOL_GUID — §29.2.2
18+
var EFI_DHCP4_PROTOCOL_GUID = EFI_GUID{
19+
0x8a219718, 0x4ef5, 0x4761,
20+
[8]uint8{0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56},
21+
}
22+
23+
//---------------------------------------------------------------------------
24+
// Enums / States
25+
//---------------------------------------------------------------------------
26+
27+
// EFI_DHCP4_STATE — DHCP state machine §29.2.3
28+
const (
29+
Dhcp4Stopped = iota
30+
Dhcp4Init
31+
Dhcp4Selecting
32+
Dhcp4Requesting
33+
Dhcp4Bound
34+
Dhcp4Renewing
35+
Dhcp4Rebinding
36+
Dhcp4InitReboot
37+
Dhcp4Rebooting
38+
)
39+
40+
// EFI_DHCP4_EVENT tracks events in the DHCP process. §29.2.4
41+
const (
42+
Dhcp4SendDiscover = iota + 1
43+
Dhcp4RcvdOffer
44+
Dhcp4SelectOffer
45+
Dhcp4SendRequest
46+
Dhcp4RcvdAck
47+
Dhcp4RcvdNak
48+
Dhcp4SendDecline
49+
Dhcp4BoundCompleted
50+
Dhcp4EnterRenewing
51+
Dhcp4EnterRebinding
52+
Dhcp4AddressLost
53+
Dhcp4Fail
54+
)
55+
56+
// EFI_DHCP4_PACKET_OPTION 29.2.4
57+
type EFI_DHCP4_PACKET_OPTION struct {
58+
OpCode uint8
59+
Length uint8
60+
Data [1]uint8
61+
}
62+
63+
//---------------------------------------------------------------------------
64+
// EFI_DHCP4_SERVICE_BINDING_PROTOCOL
65+
//---------------------------------------------------------------------------
66+
67+
type EFI_DHCP4_SERVICE_BINDING_PROTOCOL struct {
68+
createChild uintptr // (*this, *childHandle)
69+
destroyChild uintptr // (*this, childHandle)
70+
}
71+
72+
func (p *EFI_DHCP4_SERVICE_BINDING_PROTOCOL) CreateChild(childHandle *EFI_HANDLE) EFI_STATUS {
73+
return UefiCall2(
74+
p.createChild,
75+
uintptr(unsafe.Pointer(p)),
76+
uintptr(unsafe.Pointer(childHandle)),
77+
)
78+
}
79+
80+
func (p *EFI_DHCP4_SERVICE_BINDING_PROTOCOL) DestroyChild(childHandle EFI_HANDLE) EFI_STATUS {
81+
return UefiCall2(
82+
p.destroyChild,
83+
uintptr(unsafe.Pointer(p)),
84+
uintptr(childHandle),
85+
)
86+
}
87+
88+
//---------------------------------------------------------------------------
89+
// EFI_DHCP4_PROTOCOL
90+
//---------------------------------------------------------------------------
91+
92+
// EFI_DHCP4_CONFIG_DATA is for configuring a DHCP request. §29.2.4
93+
type EFI_DHCP4_CONFIG_DATA struct {
94+
DiscoverTryCount uint32
95+
DiscoverTimeout *uint32
96+
RequestTryCount uint32
97+
RequestTimeout *uint32
98+
ClientAddress EFI_IPv4_ADDRESS
99+
Dhcp4Callback EFI_DHCP4_CALLBACK
100+
CallbackContext unsafe.Pointer // not sure about this
101+
OptionCount uint32
102+
OptionList **EFI_DHCP4_PACKET_OPTION
103+
}
104+
105+
// EFI_DHCP4_CALLBACK is not yet supported. Needs a PE+ -> SysV trampoline.
106+
type EFI_DHCP4_CALLBACK uintptr
107+
108+
type EFI_DHCP4_MODE_DATA struct {
109+
State uint32
110+
ConfigData EFI_DHCP4_CONFIG_DATA
111+
ClientAddress EFI_IPv4_ADDRESS
112+
ClientMac EFI_MAC_ADDRESS
113+
ServerAddress EFI_IPv4_ADDRESS
114+
RouterAddress EFI_IPv4_ADDRESS
115+
SubnetMask EFI_IPv4_ADDRESS
116+
}
117+
118+
// EFI_DHCP4_PROTOCOL function table §29.2.2
119+
type EFI_DHCP4_PROTOCOL struct {
120+
getModeData uintptr
121+
configure uintptr
122+
start uintptr
123+
renewRebind uintptr
124+
release uintptr
125+
stop uintptr
126+
build uintptr
127+
transmitReceive uintptr
128+
parse uintptr
129+
}
130+
131+
func (p *EFI_DHCP4_PROTOCOL) GetModeData(modeData *EFI_DHCP4_MODE_DATA) EFI_STATUS {
132+
return UefiCall2(
133+
p.getModeData,
134+
uintptr(unsafe.Pointer(p)),
135+
uintptr(unsafe.Pointer(modeData)),
136+
)
137+
}
138+
139+
func (p *EFI_DHCP4_PROTOCOL) Configure(cfg *EFI_DHCP4_CONFIG_DATA) EFI_STATUS {
140+
return UefiCall2(
141+
p.configure,
142+
uintptr(unsafe.Pointer(p)),
143+
uintptr(unsafe.Pointer(cfg)),
144+
)
145+
}
146+
147+
func (p *EFI_DHCP4_PROTOCOL) Start(asyncEvent *EFI_EVENT) EFI_STATUS {
148+
return UefiCall2(
149+
p.start,
150+
uintptr(unsafe.Pointer(p)),
151+
uintptr(unsafe.Pointer(asyncEvent)),
152+
)
153+
}
154+
155+
func (p *EFI_DHCP4_PROTOCOL) RenewRebind(asyncEvent *EFI_EVENT) EFI_STATUS {
156+
return UefiCall2(p.renewRebind, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(asyncEvent)))
157+
}
158+
159+
func (p *EFI_DHCP4_PROTOCOL) Release(asyncEvent *EFI_EVENT) EFI_STATUS {
160+
return UefiCall2(p.release, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(asyncEvent)))
161+
}
162+
163+
func (p *EFI_DHCP4_PROTOCOL) Stop() EFI_STATUS {
164+
return UefiCall1(p.stop, uintptr(unsafe.Pointer(p)))
165+
}
166+
167+
func (p *EFI_DHCP4_PROTOCOL) Build(packetBuffer unsafe.Pointer) EFI_STATUS {
168+
return UefiCall2(p.build, uintptr(unsafe.Pointer(p)), uintptr(packetBuffer))
169+
}
170+
171+
func (p *EFI_DHCP4_PROTOCOL) TransmitReceive(token unsafe.Pointer) EFI_STATUS {
172+
return UefiCall2(p.transmitReceive, uintptr(unsafe.Pointer(p)), uintptr(token))
173+
}
174+
175+
func (p *EFI_DHCP4_PROTOCOL) Parse(packetBuffer unsafe.Pointer, parseResult unsafe.Pointer) EFI_STATUS {
176+
return UefiCall3(p.parse, uintptr(unsafe.Pointer(p)), uintptr(packetBuffer), uintptr(parseResult))
177+
}
178+
179+
// DHCPv4 wraps EFI_DHCP4_PROTOCOL to provide a more go idiomatic API for handling DHCPv4.
180+
type DHCPv4 struct {
181+
*EFI_DHCP4_PROTOCOL
182+
}
183+
184+
func EnumerateDHCPv4() ([]*DHCPv4, error) {
185+
var (
186+
handleCount UINTN
187+
handleBuffer *EFI_HANDLE
188+
)
189+
status := BS().LocateHandleBuffer(ByProtocol, &EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID, nil, &handleCount, &handleBuffer)
190+
if status != EFI_SUCCESS {
191+
return nil, StatusError(status)
192+
}
193+
// if none were found, we should have gotten EFI_NOT_FOUND
194+
195+
//turn handleBuffer into a slice of EFI_HANDLEs
196+
handleSlice := unsafe.Slice((*EFI_HANDLE)(unsafe.Pointer(handleBuffer)), int(handleCount))
197+
198+
dhcpv4s := make([]*DHCPv4, 0, int(handleCount))
199+
200+
// Turn Binding handles into Protocol
201+
for i := range handleSlice {
202+
var binding *EFI_DHCP4_SERVICE_BINDING_PROTOCOL
203+
status := BS().HandleProtocol(
204+
handleSlice[i],
205+
&EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID,
206+
unsafe.Pointer(&binding),
207+
)
208+
if status != EFI_SUCCESS {
209+
// just skip, or error out entirely?? Hmm..
210+
continue
211+
}
212+
var bindChild EFI_HANDLE
213+
// TODO: track and clean up after the children
214+
status = binding.CreateChild(&bindChild)
215+
if status != EFI_SUCCESS {
216+
continue
217+
}
218+
var dhcpp *EFI_DHCP4_PROTOCOL
219+
status = BS().HandleProtocol(
220+
bindChild,
221+
&EFI_DHCP4_PROTOCOL_GUID,
222+
unsafe.Pointer(&dhcpp),
223+
)
224+
if status != EFI_SUCCESS {
225+
continue
226+
}
227+
dhcpv4s = append(dhcpv4s, &DHCPv4{EFI_DHCP4_PROTOCOL: dhcpp})
228+
}
229+
230+
return dhcpv4s, nil
231+
}

src/machine/uefi/efidef.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ type EFI_LBA uint64
66
type EFI_TPL UINTN
77
type EFI_HANDLE uintptr
88
type EFI_EVENT uintptr
9+
type EFI_MAC_ADDRESS [32]uint8
10+
type EFI_IPv4_ADDRESS [4]uint8
11+
type EFI_IPv6_ADDRESS [16]uint8
12+
type EFI_IP_ADDRESS [16]uint8
913

1014
type CHAR16 uint16
1115
type BOOLEAN bool

src/machine/uefi/ip.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package uefi

src/machine/uefi/serial_io_protocol.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ func (sp *SerialPort) Init() error {
205205
status = sp.SetAttributes(
206206
115200, // BaudRate
207207
0, // ReceiveFifoDepth (0 = default)
208-
0, // Timeout (0 = default)
208+
1, // Timeout (0 = default)
209209
ParityNone, // EFI_PARITY_TYPE (1 = none)
210210
8, // DataBits
211211
StopBits1, // StopBits (1)
@@ -223,8 +223,8 @@ func (sp *SerialPort) Init() error {
223223
// flow control, RTS is set and cleared accordingly.
224224
func (sp *SerialPort) Read(buf []byte) (n int, err error) {
225225
var controlBits uint32
226-
sp.GetControl(&controlBits)
227226
for {
227+
sp.GetControl(&controlBits)
228228
bufLen := UINTN(len(buf))
229229
// assert RTS and DTR; should be no harm to set/clear these even if hardware flow control
230230
// is not in use.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package uefi
2+
3+
import "unsafe"
4+
5+
//---------------------------------------------------------------------------
6+
// GUID
7+
//---------------------------------------------------------------------------
8+
9+
// {A19832B9-AC25-11D3-9A2D-0090273FC14D}
10+
var EFI_SIMPLE_NETWORK_PROTOCOL_GUID = EFI_GUID{
11+
0xA19832B9, 0xAC25, 0x11D3,
12+
[8]uint8{0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D},
13+
}
14+
15+
//---------------------------------------------------------------------------
16+
// Enums and Constants – §10.4
17+
//---------------------------------------------------------------------------
18+
19+
const (
20+
EFI_SIMPLE_NETWORK_STOPPED = 0
21+
EFI_SIMPLE_NETWORK_STARTED = 1
22+
EFI_SIMPLE_NETWORK_INITIALIZED = 2
23+
)
24+
25+
// ---------------------------------------------------------------------------
26+
//
27+
// Types – §10.4.3
28+
//
29+
// ---------------------------------------------------------------------------
30+
type EFI_SIMPLE_NETWORK_MODE struct {
31+
State uint32
32+
HwAddressSize uint32
33+
MediaHeaderSize uint32
34+
MaxPacketSize uint32
35+
NvRamSize uint32
36+
NvRamAccessSize uint32
37+
ReceiveFilterMask uint32
38+
ReceiveFilterSetting uint32
39+
MaxMCastFilterCount uint32
40+
MCastFilterCount uint32
41+
MCastFilter [32]EFI_MAC_ADDRESS
42+
CurrentAddress EFI_MAC_ADDRESS
43+
BroadcastAddress EFI_MAC_ADDRESS
44+
PermanentAddress EFI_MAC_ADDRESS
45+
IfType uint8
46+
MacAddressChangeable bool
47+
MultipleTxSupported bool
48+
MediaPresentSupported bool
49+
MediaPresent bool
50+
}
51+
52+
//---------------------------------------------------------------------------
53+
// Protocol – §10.4.2
54+
//---------------------------------------------------------------------------
55+
56+
type EFI_SIMPLE_NETWORK_PROTOCOL struct {
57+
Revision uint64
58+
start uintptr // (this)
59+
stop uintptr // (this)
60+
initialize uintptr // (this)
61+
reset uintptr // (this, extVerify)
62+
shutdown uintptr // (this)
63+
receiveFilters uintptr // (this, enable, disable, resetMCast, mCastCount, mCastFilter)
64+
stationAddress uintptr // (this, reset, newAddress)
65+
statistics uintptr // (this, reset, statsSize, stats)
66+
mCastIpToMac uintptr // (this, ipv4, ipv6, mac)
67+
nvData uintptr // (this, readWrite, offset, bufferSize, buffer)
68+
getStatus uintptr // (this, intStatus, txBuf)
69+
transmit uintptr // (this, headerSize, bufferSize, buffer, srcAddr, dstAddr, proto)
70+
receive uintptr // (this, headerSize, bufferSize, buffer, srcAddr, dstAddr, proto)
71+
WaitForPacket EFI_EVENT
72+
Mode *EFI_SIMPLE_NETWORK_MODE
73+
}
74+
75+
func (snp *EFI_SIMPLE_NETWORK_PROTOCOL) Start() EFI_STATUS {
76+
return UefiCall1(snp.start, uintptr(unsafe.Pointer(snp)))
77+
}
78+
79+
func (snp *EFI_SIMPLE_NETWORK_PROTOCOL) Stop() EFI_STATUS {
80+
return UefiCall1(snp.stop, uintptr(unsafe.Pointer(snp)))
81+
}
82+
83+
func (snp *EFI_SIMPLE_NETWORK_PROTOCOL) Initialize() EFI_STATUS {
84+
return UefiCall1(snp.initialize, uintptr(unsafe.Pointer(snp)))
85+
}
86+
87+
func (snp *EFI_SIMPLE_NETWORK_PROTOCOL) Shutdown() EFI_STATUS {
88+
return UefiCall1(snp.shutdown, uintptr(unsafe.Pointer(snp)))
89+
}
90+
91+
type SimpleNetworkProtocol struct {
92+
*EFI_SIMPLE_NETWORK_PROTOCOL
93+
}
94+
95+
func EnumerateSNP() (snps []*SimpleNetworkProtocol, err error) {
96+
var (
97+
handleCount UINTN
98+
handleBuffer *EFI_HANDLE
99+
)
100+
status := BS().LocateHandleBuffer(ByProtocol, &EFI_SIMPLE_NETWORK_PROTOCOL_GUID, nil, &handleCount, &handleBuffer)
101+
if status != EFI_SUCCESS {
102+
return nil, StatusError(status)
103+
}
104+
// if none were found, we should have gotten EFI_NOT_FOUND
105+
106+
//turn handleBuffer into a slice of EFI_HANDLEs
107+
handleSlice := unsafe.Slice((*EFI_HANDLE)(unsafe.Pointer(handleBuffer)), int(handleCount))
108+
109+
for i := range handleSlice {
110+
BS().ConnectController(handleSlice[i], nil, nil, true)
111+
var snp *EFI_SIMPLE_NETWORK_PROTOCOL
112+
status := BS().HandleProtocol(
113+
handleSlice[i],
114+
&EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID,
115+
unsafe.Pointer(&snp),
116+
)
117+
if status != EFI_SUCCESS {
118+
// just skip, or error out entirely?? Hmm..
119+
continue
120+
}
121+
snps = append(snps, &SimpleNetworkProtocol{EFI_SIMPLE_NETWORK_PROTOCOL: snp})
122+
}
123+
124+
return snps, nil
125+
}

0 commit comments

Comments
 (0)