-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Christopher Meis <[email protected]>
- Loading branch information
Showing
6 changed files
with
313 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package device | ||
|
||
import ( | ||
"encoding/binary" | ||
"time" | ||
) | ||
|
||
type ACPIPMTimer struct { | ||
Start time.Time | ||
} | ||
|
||
const ( | ||
pmTimerFreqHz uint64 = 3_579_545 | ||
nanosPerSecond uint64 = 1_000_000_000 | ||
) | ||
|
||
func NewACPIPMTimer() *ACPIPMTimer { | ||
return &ACPIPMTimer{ | ||
Start: time.Now(), | ||
} | ||
} | ||
|
||
func (a *ACPIPMTimer) Read(base uint64, data []byte) error { | ||
if len(data) != 4 { | ||
return errDataLenInvalid | ||
} | ||
|
||
since := time.Since(a.Start) | ||
nanos := since.Nanoseconds() | ||
counter := (nanos * int64(pmTimerFreqHz)) / int64(nanosPerSecond) | ||
counter32 := uint32(counter & 0xFFFF_FFFF) | ||
counterbyte := make([]byte, 4) | ||
|
||
binary.LittleEndian.PutUint32(counterbyte, counter32) | ||
|
||
copy(data[0:], counterbyte) | ||
|
||
return nil | ||
} | ||
|
||
func (a *ACPIPMTimer) Write(base uint64, data []byte) error { | ||
return nil | ||
} | ||
|
||
func (a *ACPIPMTimer) IOPort() uint64 { | ||
return 0x608 | ||
} | ||
|
||
func (a *ACPIPMTimer) Size() uint64 { | ||
return 0x4 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package device | ||
|
||
import "log" | ||
|
||
// This device is used by EDK2/CloudHv to let the host know about a shutdown. | ||
// No implementation of handling the event on host side yet. | ||
// See: https://github.com/cloud-hypervisor/edk2/blob/ch/OvmfPkg/Include/IndustryStandard/CloudHv.h | ||
|
||
const ( | ||
ACPIShutDownDevPort = uint64(0x600) | ||
) | ||
|
||
type ACPIShutDownDevice struct { | ||
Port uint64 | ||
// ExitEvent chan int | ||
// ResetEvent chan int | ||
} | ||
|
||
func NewACPIShutDownEvent() *ACPIShutDownDevice { | ||
return &ACPIShutDownDevice{ | ||
Port: ACPIShutDownDevPort, | ||
} | ||
} | ||
|
||
func (a *ACPIShutDownDevice) Read(base uint64, data []byte) error { | ||
data[0] = 0 | ||
|
||
return nil | ||
} | ||
|
||
func (a *ACPIShutDownDevice) Write(base uint64, data []byte) error { | ||
if data[0] == 1 { | ||
// Send 1 to ResetEvent | ||
// a.ResetEvent <- 1 | ||
log.Println("ACPI Reboot signaled") | ||
} | ||
// The ACPI DSDT table specifies the S5 sleep state (shutdown) as value 5 | ||
S5SleepVal := uint8(5) | ||
SleepStatusENBit := uint8(5) | ||
SleepValBit := uint8(2) | ||
|
||
if data[0] == (S5SleepVal<<SleepValBit)|(1<<SleepStatusENBit) { | ||
// a.ExitEvent <- 1 | ||
log.Println("ACPI Shutdown signalled") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (a *ACPIShutDownDevice) IOPort() uint64 { | ||
return a.Port | ||
} | ||
|
||
func (a *ACPIShutDownDevice) Size() uint64 { | ||
return 0x8 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package device | ||
|
||
import ( | ||
"time" | ||
) | ||
|
||
const ( | ||
indexMask = uint8(0x7F) | ||
indexOffset = uint64(0x70) | ||
dataOffset = uint64(0x71) | ||
dataLen = uint64(128) | ||
) | ||
|
||
type CMOS struct { | ||
Index uint8 | ||
Data []uint8 | ||
} | ||
|
||
func NewCMOS(memBelow4G, memAbove4G uint64) *CMOS { | ||
cmos := &CMOS{ | ||
Index: 0, | ||
Data: make([]uint8, dataLen), | ||
} | ||
|
||
// We assume 3G RAM at all times for now..... | ||
extMem := uint16(0xBC00) | ||
|
||
cmos.Data[0x34] = uint8(extMem) | ||
cmos.Data[0x35] = uint8(extMem >> 8) | ||
|
||
// Only valid for PVH boot of firmware with 3G RAM fixed..... | ||
cmos.Data[0x5b] = 0 | ||
cmos.Data[0x5c] = 0 | ||
cmos.Data[0x5d] = 0 | ||
|
||
return cmos | ||
} | ||
|
||
func (c *CMOS) Read(base uint64, data []byte) error { | ||
if len(data) != 1 { | ||
return errDataLenInvalid | ||
} | ||
|
||
var d uint8 | ||
|
||
// Reading CMOS RAM also requires two steps: | ||
// 1. OUT to port hex 70 with the CMOS address that is to be read from. | ||
// 2. IN from port hex 71, and the data read is returned in the AL register. | ||
// Ref: http://bitsavers.trailing-edge.com/pdf/ibm/pc/at/1502494_PC_AT_Technical_Reference_Mar84.pdf | ||
switch base { | ||
case indexOffset: | ||
data[0] = c.Index | ||
case dataOffset: | ||
dt := time.Now() | ||
secs := dt.Second() | ||
min := dt.Minute() | ||
hour := dt.Hour() | ||
weekd := dt.Weekday() | ||
day := dt.Day() | ||
month := dt.Month() | ||
year := dt.Year() | ||
|
||
switch c.Index { | ||
case 0x00: | ||
d = toBCD(uint8(secs)) | ||
case 0x02: | ||
d = toBCD(uint8(min)) | ||
case 0x04: | ||
d = toBCD(uint8(hour)) | ||
case 0x06: | ||
d = toBCD(uint8(weekd)) | ||
case 0x07: | ||
d = toBCD(uint8(day)) | ||
case 0x08: | ||
d = toBCD(uint8(month)) | ||
case 0x09: | ||
d = toBCD(uint8(year % 100)) | ||
case 0x0A: | ||
d = 1<<5 | 0<<7 // 32kHz Clock and we assume no update in progress | ||
case 0x0D: | ||
d = 1 << 7 | ||
case 0x32: | ||
d = toBCD((uint8(year+1900) / 100)) | ||
default: | ||
d = c.Data[c.Index&indexMask] | ||
} | ||
|
||
data[0] = d | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (c *CMOS) Write(base uint64, data []byte) error { | ||
if len(data) != 1 { | ||
return errDataLenInvalid | ||
} | ||
|
||
// Writing to CMOS RAM involves two steps: | ||
// 1. OUT to port hex 70 with the CMOS address that will be written to. | ||
// 2. OUT to port hex 71 with the data to be written. | ||
// Ref: http://bitsavers.trailing-edge.com/pdf/ibm/pc/at/1502494_PC_AT_Technical_Reference_Mar84.pdf | ||
switch base { | ||
case indexOffset: | ||
c.Index = data[0] | ||
case dataOffset: | ||
if c.Index == 0x8F && data[0] == 0 { | ||
// CMOS reset - we ignore for now | ||
} else { | ||
c.Data[c.Index&indexMask] = data[0] | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func toBCD(v uint8) uint8 { | ||
return ((v / 100) << 4) | (v % 10) | ||
} | ||
|
||
func (c *CMOS) IOPort() uint64 { | ||
return 0x70 | ||
} | ||
|
||
func (c *CMOS) Size() uint64 { | ||
return 0x2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package device | ||
|
||
import "errors" | ||
|
||
var errDataLenInvalid = errors.New("invalid data size on port") | ||
|
||
// IODevice describes the interface a IO-Port device must implement regardless of the | ||
// bus it is attached to. | ||
// Clean up and unifying pci.Device and IODevice of this package will be required. | ||
type IODevice interface { | ||
Read(uint64, []byte) error | ||
Write(uint64, []byte) error | ||
IOPort() uint64 | ||
Size() uint64 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package device | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
type FWDebugDevice struct{} | ||
|
||
func (f *FWDebugDevice) Read(port uint64, data []byte) error { | ||
if len(data) == 1 { | ||
// This magic value is read from the Port to indicate the availablity of the debug port. | ||
// See: https://github.com/cloud-hypervisor/edk2/blob/ch/OvmfPkg/Library/PlatformDebugLibIoPort/DebugIoPortQemu.c | ||
data[0] = 0xE9 | ||
} else { | ||
return errDataLenInvalid | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (f *FWDebugDevice) Write(port uint64, data []byte) error { | ||
if len(data) == 1 { | ||
if data[0] == '\000' { | ||
fmt.Printf("\r\n") | ||
} else { | ||
fmt.Printf("%c", data[0]) | ||
} | ||
} else { | ||
return errDataLenInvalid | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (f *FWDebugDevice) IOPort() uint64 { | ||
// https://github.com/tianocore/edk2/commit/bf23b44d926982dfc9ecc7785cea17e0889a9297 | ||
return 0x402 | ||
} | ||
|
||
func (f *FWDebugDevice) Size() uint64 { | ||
return 0x1 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package device | ||
|
||
type NoopDevice struct { | ||
Port uint64 | ||
Psize uint64 | ||
} | ||
|
||
func (n *NoopDevice) Read(port uint64, data []byte) error { | ||
return nil | ||
} | ||
|
||
func (n *NoopDevice) Write(port uint64, data []byte) error { | ||
return nil | ||
} | ||
|
||
func (n *NoopDevice) IOPort() uint64 { | ||
return n.Port | ||
} | ||
|
||
func (n *NoopDevice) Size() uint64 { | ||
return n.Psize | ||
} |