Skip to content

Commit

Permalink
Merge pull request #8 from nmi/add_serial
Browse files Browse the repository at this point in the history
Add serial
  • Loading branch information
bobuhiro11 authored Feb 11, 2021
2 parents 7a4e506 + 95a61ba commit 3abfc53
Show file tree
Hide file tree
Showing 14 changed files with 307 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ busybox
initrd
bzImage
linux-*.tar.xz
linux.tar.xz

# Test binary, built with `go test -c`
*.test
Expand Down
23 changes: 16 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,30 @@ golangci-lint:
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh \
| sh -s -- -b . $(GOLANGCI_LINT_VERSION)

initrd:
busybox.tar.bz2:
curl https://busybox.net/downloads/busybox-$(BUSYBOX_VERSION).tar.bz2 -o busybox.tar.bz2

initrd: busybox.config busybox.tar.bz2 busybox.inittab busybox.passwd busybox.rcS
tar -xf busybox.tar.bz2
cp busybox.config busybox-$(BUSYBOX_VERSION)/.config
make -C busybox-$(BUSYBOX_VERSION) install
mkdir -p busybox-$(BUSYBOX_VERSION)/_install/etc
cp inittab busybox-$(BUSYBOX_VERSION)/_install/etc/inittab
mkdir -p busybox-$(BUSYBOX_VERSION)/_install/etc/init.d
mkdir -p busybox-$(BUSYBOX_VERSION)/_install/proc
mkdir -p busybox-$(BUSYBOX_VERSION)/_install/sys
cp busybox.inittab busybox-$(BUSYBOX_VERSION)/_install/etc/inittab
cp busybox.passwd busybox-$(BUSYBOX_VERSION)/_install/etc/passwd
cp busybox.rcS busybox-$(BUSYBOX_VERSION)/_install/etc/init.d/rcS
cd busybox-$(BUSYBOX_VERSION)/_install && find . | cpio -o --format=newc > ../../initrd
rm -rf busybox-$(BUSYBOX_VERSION)

bzImage:
curl https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.12.tar.xz \
-o linux-$(LINUX_VERSION).tar.xz
tar Jxf ./linux-5.10.12.tar.xz
linux.tar.xz:
curl https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-$(LINUX_VERSION).tar.xz \
-o linux.tar.xz

bzImage: linux.config linux.tar.xz
tar Jxf ./linux.tar.xz
cp linux.config linux-$(LINUX_VERSION)/.config
cd linux-$(LINUX_VERSION) && patch -p1 < ../linux-5.10.12-patch-0000-enable-serial-debug-autoconf.patch
make -C linux-$(LINUX_VERSION)
cp linux-$(LINUX_VERSION)/arch/x86/boot/bzImage .
rm -rf linux-$(LINUX_VERSION)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ kvm.LinuxRun(bzImagePath, initrdPath, ioportHandler)
- [The Linux/x86 Boot Protocol, kernel.org](https://www.kernel.org/doc/html/latest/x86/boot.html)
- [Build and run minimal Linux / Busybox systems in Qemu](https://gist.github.com/chrisdone/02e165a0004be33734ac2334f215380e)
- [kvm_cost.go, google/gvisor](https://github.com/google/gvisor/blob/master/pkg/sentry/platform/kvm/kvm_const.go)
- [Serial UART information, www.lammertbies.nl](https://www.lammertbies.nl/comm/info/serial-uart)
2 changes: 1 addition & 1 deletion inittab → busybox.inittab
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
# this yourself...
#
# Start an "askfirst" shell on the console (whatever that may be)
::askfirst:-/bin/sh
#::askfirst:-/bin/sh
# Start an "askfirst" shell on /dev/tty2-4
#tty2::askfirst:-/bin/sh
#tty3::askfirst:-/bin/sh
Expand Down
1 change: 1 addition & 0 deletions busybox.passwd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root::0:0::/:/bin/sh
3 changes: 3 additions & 0 deletions busybox.rcS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/nmi/gokvm

go 1.13

require golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
76 changes: 72 additions & 4 deletions kvm/kvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"unsafe"

"github.com/nmi/gokvm/bootproto"
"github.com/nmi/gokvm/serial"
)

const (
Expand All @@ -28,6 +29,7 @@ const (
kvmCreatePIT2 = 0x4040AE77
kvmGetSupportedCPUID = 0xC008AE05
kvmSetCPUID2 = 0x4008AE90
kvmIRQLine = 0xc008ae67

EXITUNKNOWN = 0
EXITEXCEPTION = 1
Expand Down Expand Up @@ -238,6 +240,22 @@ func SetIdentityMapAddr(vmFd uintptr) error {
return err
}

type IRQLevel struct {
IRQ uint32
Level uint32
}

func IRQLine(vmFd uintptr, irq, level uint32) error {
irqLevel := IRQLevel{
IRQ: irq,
Level: level,
}

_, err := ioctl(vmFd, kvmIRQLine, uintptr(unsafe.Pointer(&irqLevel)))

return err
}

func CreateIRQChip(vmFd uintptr) error {
_, err := ioctl(vmFd, kvmCreateIRQChip, 0)

Expand Down Expand Up @@ -339,6 +357,7 @@ type LinuxGuest struct {
kvmFd, vmFd, vcpuFd uintptr
mem []byte
run *RunData
serial *serial.Serial
}

func NewLinuxGuest(bzImagePath, initPath string) (*LinuxGuest, error) {
Expand Down Expand Up @@ -470,9 +489,29 @@ func NewLinuxGuest(bzImagePath, initPath string) (*LinuxGuest, error) {
return g, err
}

serialIRQCallback := func(irq, level uint32) {
err := IRQLine(g.vmFd, irq, level)
if err != nil {
panic(err)
}
}

if g.serial, err = serial.New(serialIRQCallback); err != nil {
return g, err
}

return g, nil
}

func (g *LinuxGuest) GetInputChan() chan<- byte {
return g.serial.GetInputChan()
}

func (g *LinuxGuest) InjectSerialIRQ() {
g.serial.InjectIRQ(0)
g.serial.InjectIRQ(1)
}

func (g *LinuxGuest) initRegs() error {
regs, err := GetRegs(g.vcpuFd)
if err != nil {
Expand Down Expand Up @@ -568,14 +607,43 @@ func (g *LinuxGuest) RunOnce() (bool, error) {
return false, nil
case EXITIO:
direction, size, port, count, offset := g.run.IO()
if direction == EXITIOOUT && size == 1 && port == 0x3f8 && count == 1 {
p := uintptr(unsafe.Pointer(g.run))
c := *(*byte)(unsafe.Pointer(p + uintptr(offset)))
fmt.Printf("%c", c)
bytes := (*(*[100]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(g.run)) + uintptr(offset))))[0:size]

for i := 0; i < int(count); i++ {
if err := g.handleExitIO(direction, port, bytes); err != nil {
return false, err
}
}

return true, nil
default:
return false, fmt.Errorf("%w: %d", ErrorUnexpectedEXITReason, g.run.ExitReason)
}
}

func (g *LinuxGuest) handleExitIO(direction, port uint64, bytes []byte) error {
switch {
case 0x3c0 <= port && port <= 0x3da:
return nil // VGA
case 0x60 <= port && port <= 0x6F:
return nil // PS/2 Keyboard (Always 8042 Chip)
case 0x70 <= port && port <= 0x71:
return nil // CMOS clock
case 0x80 <= port && port <= 0x9F:
return nil // DMA Page Registers (Commonly 74L612 Chip)
case 0x2f8 <= port && port <= 0x2FF:
return nil // Serial port 2
case 0x3e8 <= port && port <= 0x3ef:
return nil // Serial port 3
case 0x2e8 <= port && port <= 0x2ef:
return nil // Serial port 4
case serial.COM1Addr <= port && port < serial.COM1Addr+8:
if direction == EXITIOIN {
return g.serial.In(port, bytes)
}

return g.serial.Out(port, bytes)
default:
return fmt.Errorf("%w: unexpected io port 0x%x", ErrorUnexpectedEXITReason, port)
}
}
2 changes: 1 addition & 1 deletion kvm/kvm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ func TestNewLinuxGuest(t *testing.T) {
t.Fatal(err)
}

for i := 0; i < 1000; i++ {
for i := 0; i < 10; i++ {
isContinue, err := g.RunOnce()
if err != nil {
t.Fatal(err)
Expand Down
11 changes: 11 additions & 0 deletions linux-5.10.12-patch-0000-enable-serial-debug-autoconf.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- linux-5.10.12/drivers/tty/serial/8250/8250_port.c 2021-02-09 00:14:11.470906210 +0900
+++ linux-5.10.12/drivers/tty/serial/8250/8250_port.c.orig 2021-02-09 00:14:03.514875736 +0900
@@ -44,7 +44,7 @@
/*
* Debugging.
*/
-#if 0
+#if 1
#define DEBUG_AUTOCONF(fmt...) printk(fmt)
#else
#define DEBUG_AUTOCONF(fmt...) do { } while (0)
26 changes: 22 additions & 4 deletions linux.config
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ CONFIG_TINY_SRCU=y
# end of RCU Subsystem

# CONFIG_IKCONFIG is not set
# CONFIG_IKHEADERS is not set
CONFIG_LOG_BUF_SHIFT=17
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
Expand All @@ -119,6 +120,7 @@ CONFIG_ARCH_SUPPORTS_INT128=y
# CONFIG_CGROUPS is not set
# CONFIG_CHECKPOINT_RESTORE is not set
# CONFIG_SCHED_AUTOGROUP is not set
# CONFIG_SYSFS_DEPRECATED is not set
# CONFIG_RELAY is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
Expand All @@ -133,6 +135,7 @@ CONFIG_RD_ZSTD=y
# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_LD_ORPHAN_WARN=y
CONFIG_SYSCTL=y
CONFIG_HAVE_UID16=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_HAVE_PCSPKR_PLATFORM=y
Expand Down Expand Up @@ -221,7 +224,7 @@ CONFIG_CC_HAS_SANE_STACKPROTECTOR=y
#
# CONFIG_ZONE_DMA is not set
# CONFIG_SMP is not set
# CONFIG_X86_FEATURE_NAMES is not set
CONFIG_X86_FEATURE_NAMES=y
CONFIG_X86_MPPARSE=y
# CONFIG_GOLDFISH is not set
# CONFIG_RETPOLINE is not set
Expand All @@ -242,6 +245,7 @@ CONFIG_X86_CMOV=y
CONFIG_X86_MINIMUM_CPU_FAMILY=64
CONFIG_X86_DEBUGCTLMSR=y
CONFIG_IA32_FEAT_CTL=y
CONFIG_X86_VMX_FEATURE_NAMES=y
# CONFIG_PROCESSOR_SELECT is not set
CONFIG_CPU_SUP_INTEL=y
CONFIG_CPU_SUP_AMD=y
Expand Down Expand Up @@ -358,6 +362,7 @@ CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
#
# CONFIG_EDD is not set
# CONFIG_FIRMWARE_MEMMAP is not set
# CONFIG_FW_CFG_SYSFS is not set
# CONFIG_GOOGLE_FIRMWARE is not set

#
Expand Down Expand Up @@ -519,6 +524,7 @@ CONFIG_NEED_PER_CPU_KM=y
# CONFIG_ZBUD is not set
# CONFIG_ZSMALLOC is not set
CONFIG_GENERIC_EARLY_IOREMAP=y
# CONFIG_IDLE_PAGE_TRACKING is not set
CONFIG_ARCH_HAS_PTE_DEVMAP=y
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
CONFIG_ARCH_HAS_PKEYS=y
Expand All @@ -543,7 +549,8 @@ CONFIG_HAVE_PCI=y
# Generic Driver Options
#
# CONFIG_UEVENT_HELPER is not set
# CONFIG_DEVTMPFS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set

Expand Down Expand Up @@ -944,6 +951,7 @@ CONFIG_VIRTIO=y
#
# end of Microsoft Hyper-V guest support

# CONFIG_GREYBUS is not set
# CONFIG_STAGING is not set
# CONFIG_X86_PLATFORM_DEVICES is not set
# CONFIG_CHROME_PLATFORMS is not set
Expand Down Expand Up @@ -1101,9 +1109,14 @@ CONFIG_DCACHE_WORD_ACCESS=y
#
# Pseudo filesystems
#
# CONFIG_PROC_FS is not set
CONFIG_PROC_FS=y
# CONFIG_PROC_KCORE is not set
CONFIG_PROC_SYSCTL=y
CONFIG_PROC_PAGE_MONITOR=y
# CONFIG_PROC_CHILDREN is not set
# CONFIG_SYSFS is not set
CONFIG_PROC_PID_ARCH_STATUS=y
CONFIG_KERNFS=y
CONFIG_SYSFS=y
# CONFIG_HUGETLBFS is not set
CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
# CONFIG_CONFIGFS_FS is not set
Expand Down Expand Up @@ -1226,6 +1239,8 @@ CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
CONFIG_CONSOLE_LOGLEVEL_QUIET=15
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_DYNAMIC_DEBUG is not set
# CONFIG_DYNAMIC_DEBUG_CORE is not set
# CONFIG_SYMBOLIC_ERRNAME is not set
# end of printk and dmesg options

Expand Down Expand Up @@ -1325,6 +1340,8 @@ CONFIG_WQ_WATCHDOG=y
#
# Scheduler Debugging
#
CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
# end of Scheduler Debugging

# CONFIG_DEBUG_TIMEKEEPING is not set
Expand Down Expand Up @@ -1375,6 +1392,7 @@ CONFIG_STACKTRACE=y
# end of RCU Debugging

# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
# CONFIG_LATENCYTOP is not set
CONFIG_USER_STACKTRACE_SUPPORT=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
Expand Down
Loading

0 comments on commit 3abfc53

Please sign in to comment.