Skip to content

Commit

Permalink
add tamago/amd64 support, microvm target (#45)
Browse files Browse the repository at this point in the history
* WiP tamago/amd64 support

* add CPU initialization functions

* tidying

* add amd64 memory initialization

* tidying

* tidying

* initial amd64 cpuinit (LM with 2MB map)

* working amd64 long mode

* enable SSE

* add basic COM1 support

* increase RAM size

* tidying

* halt and catch fire

* package rename riscv -> riscv64 for consistency with GOARCH

* working 16550A UART driver

* triple-fault on microvm exit

* map page entries to cover ramStart+ramSize

* set stack offset

* add IsSet function

* amd64 TSC support

* microvm kvmclock support

* microvm MC146818A RTC driver

* tidying

* tidying

* typo fix

* typo fix

* URL update

* documentation update

* tidying

* tidying

* tidying

* fix and simplify amd64 TLBs, reserve I/O area

* tidying

* initial import of WiP VirtIO driver

* tidying

* move VirtIO device driver outside tamago

* update qemu settings

* tidying

* add IsSet64 function

* improve VirtIO driver

* improve VirtIO driver

* improve VirtIO driver

* improve VirtIO driver

* improve VirtIO driver

* improve VirtIO driver

* improve VirtIO driver

* improve VirtIO driver

* tidying

* bump release

* tidying
  • Loading branch information
abarisani authored Jan 20, 2025
1 parent 1cacaac commit f6dbdd8
Show file tree
Hide file tree
Showing 89 changed files with 1,800 additions and 128 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ Current release level
[![GitHub release](https://img.shields.io/github/v/release/usbarmory/tamago-go)](https://github.com/usbarmory/tamago-go/tree/latest) [![Build Status](https://github.com/usbarmory/tamago-go/workflows/Build%20Go%20compiler/badge.svg)](https://github.com/usbarmory/tamago-go/actions)

The current release for the [TamaGo modified Go distribution](https://github.com/usbarmory/tamago-go) is
[tamago1.23.4](https://github.com/usbarmory/tamago-go/tree/tamago1.23.4),
which [adds](https://github.com/golang/go/compare/go1.23.4...usbarmory:tamago1.23.4)
`GOOS=tamago` support to go1.23.4.
[tamago1.23.5](https://github.com/usbarmory/tamago-go/tree/tamago1.23.5),
which [adds](https://github.com/golang/go/compare/go1.23.5...usbarmory:tamago1.23.5)
`GOOS=tamago` support to go1.23.5.

Binary releases for amd64 and armv7l Linux hosts [are available](https://github.com/usbarmory/tamago-go/releases/latest).

Expand Down Expand Up @@ -90,10 +90,9 @@ The following table summarizes currently supported RISC-V SoCs and boards
Supported AMD64 targets
=======================

The support for an actual target is work-in-progress, the
[testing environment](https://github.com/usbarmory/tamago-go/blob/tamago1.23.4/src/testing/testing_tamago.go)
is supported and all Go standard library packages are supported and
[tested using original distribution tests](https://github.com/usbarmory/tamago/wiki/Compatibility).
| CPU | Board | CPU package | Board package |
|------------------|----------------------------------------------------------------------|----------------------------------------------------------------|------------------------------------------------------------------------------------|
| AMD/Intel 64-bit | [microvm](https://www.qemu.org/docs/master/system/i386/microvm.html) | [amd64](https://github.com/usbarmory/tamago/tree/master/amd64) | [qemu/microvm](https://github.com/usbarmory/tamago/tree/master/board/qemu/microvm) |

Userspace targets
=================
Expand Down Expand Up @@ -125,7 +124,7 @@ Compiling
=========

Go applications are simply required to import, the relevant board package to
ensure that hardware initialization and runtime support takes place:
ensure that hardware initialization and runtime support take place:

```golang
import (
Expand Down Expand Up @@ -154,6 +153,9 @@ GOOS=tamago GOARM=7 GOARCH=arm ${TAMAGO} build -ldflags "-T 0x80010000 -R 0x1000
# Example for QEMU RISC-V sifive_u
GOOS=tamago GOARCH=riscv64 ${TAMAGO} build -ldflags "-T 0x80010000 -R 0x1000" main.go
# Example for QEMU AMD64 sifive_u
GOOS=tamago GOARCH=amd64 ${TAMAGO} build -ldflags "-T 0x10010000 -R 0x1000" main.go
# Example for Linux userspace
GOOS=tamago ${TAMAGO} build main.go
```
Expand Down
60 changes: 60 additions & 0 deletions amd64/amd64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// x86-64 processor support
// https://github.com/usbarmory/tamago
//
// Copyright (c) WithSecure Corporation
// https://foundry.withsecure.com
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

// Package amd64 provides support for AMD64 architecture specific operations.
//
// The following architectures/cores are supported/tested:
// - AMD64 (single-core)
//
// This package is only meant to be used with `GOOS=tamago GOARCH=amd64` as
// supported by the TamaGo framework for bare metal Go, see
// https://github.com/usbarmory/tamago.
package amd64

import (
"runtime"
_ "unsafe"
)

//go:linkname ramStackOffset runtime.ramStackOffset
var ramStackOffset uint64 = 0x100000 // 1 MB

// CPU instance
type CPU struct {
// features
invariant bool
kvm bool
kvmclock uint32

// Timer multiplier
TimerMultiplier float64
// Timer offset in nanoseconds
TimerOffset int64
// Timer function
TimerFn func() uint64
}

// defined in amd64.s
func halt(int32)

// Fault generates a triple fault.
func Fault()

// Init performs initialization of an AMD64 core instance.
func (cpu *CPU) Init() {
runtime.Exit = halt

cpu.initFeatures()
cpu.initTimers()
}

// Name returns the CPU identifier.
func (cpu *CPU) Name() string {
return runtime.CPU()
}
22 changes: 22 additions & 0 deletions amd64/amd64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// x86-64 processor support
// https://github.com/usbarmory/tamago
//
// Copyright (c) WithSecure Corporation
// https://foundry.withsecure.com
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

// func Fault()
TEXT ·Fault(SB),$0
CLI
XORL AX, AX
LGDT (AX)
HLT

// func halt(int32)
TEXT ·halt(SB),$0-8
CLI
halt:
HLT
JMP halt
92 changes: 92 additions & 0 deletions amd64/features.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// x86-64 processor support
// https://github.com/usbarmory/tamago
//
// Copyright (c) WithSecure Corporation
// https://foundry.withsecure.com
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

package amd64

import (
"github.com/usbarmory/tamago/bits"
)

// CPUID function numbers
//
// (Intel® Architecture Instruction Set Extensions
// and Future Features Programming Reference
// 1.5 CPUID INSTRUCTION).
const (
CPUID_TSC_CCC = 0x15

CPUID_APM = 0x80000007
APM_TSC_INVARIANT = 8
)

// KVM CPUID function numbers
//
// (https://docs.kernel.org/virt/kvm/x86/cpuid.html)
const (
KVM_CPUID_SIGNATURE = 0x40000000
KVM_SIGNATURE = 0x4b4d564b // "KVMK"

KVM_CPUID_FEATURES = 0x40000001
FEATURES_CLOCKSOURCE = 0
FEATURES_CLOCKSOURCE2 = 3

KVM_CPUID_TSC_KHZ = 0x40000010
)

// kvmclock MSRs
const (
MSR_KVM_SYSTEM_TIME = 0x12
MSR_KVM_SYSTEM_TIME_NEW = 0x4b564d01
)

// defined in features.s
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)

func (cpu *CPU) initFeatures() {
_, _, _, apmFeatures := cpuid(CPUID_APM, 0x00)
cpu.invariant = bits.IsSet(&apmFeatures, APM_TSC_INVARIANT)

_, kvmk, _, _ := cpuid(KVM_CPUID_SIGNATURE, 0x00)
cpu.kvm = kvmk == KVM_SIGNATURE

if !cpu.kvm {
return
}

kvmFeatures, _, _, _ := cpuid(KVM_CPUID_FEATURES, 0x00)

if bits.IsSet(&kvmFeatures, FEATURES_CLOCKSOURCE) {
cpu.kvmclock = 0x12
}

if bits.IsSet(&kvmFeatures, FEATURES_CLOCKSOURCE2) {
cpu.kvmclock = 0x4b564d01
}
}

// Features represents the processor capabilities detected through the CPUID
// instruction.
type Features struct {
// InvariantTSC indicates whether the Time Stamp Counter is guaranteed
// to be at constant rate.
InvariantTSC bool
// KVM indicates whether a Kernel-base Virtual Machine is detected.
KVM bool
// KVMClockMSR returns the kvmclock Model Specific Register.
KVMClockMSR uint32
}

// Features returns the processor capabilities.
func (cpu *CPU) Features() *Features {
return &Features{
InvariantTSC: cpu.invariant,
KVM: cpu.kvm,
KVMClockMSR: cpu.kvmclock,
}
}
21 changes: 21 additions & 0 deletions amd64/features.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// x86-64 processor support
// https://github.com/usbarmory/tamago
//
// Copyright (c) WithSecure Corporation
// https://foundry.withsecure.com
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

#include "textflag.h"

// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
TEXT ·cpuid(SB),NOSPLIT,$0-24
MOVL eaxArg+0(FP), AX
MOVL ecxArg+4(FP), CX
CPUID
MOVL AX, eax+8(FP)
MOVL BX, ebx+12(FP)
MOVL CX, ecx+16(FP)
MOVL DX, edx+20(FP)
RET
113 changes: 113 additions & 0 deletions amd64/init.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// x86-64 processor support
// https://github.com/usbarmory/tamago
//
// Copyright (c) WithSecure Corporation
// https://foundry.withsecure.com
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

#include "textflag.h"

#define MSR_EFER 0xc0000080

#define PML4T 0x1000 // Page Map Level 4 Table (512GB entries)
#define PDPT 0x2000 // Page Directory Pointer Table (1GB entries)
#define PDT 0x3000 // Page Directory Table (2MB entries)
#define PT 0x4000 // Page Table (4kB entries)

// Global Descriptor Table
DATA gdt<>+0x00(SB)/8, $0x0000000000000000 // null descriptor
DATA gdt<>+0x08(SB)/8, $0x00209a0000000000 // code descriptor (x/r)
DATA gdt<>+0x10(SB)/8, $0x0000920000000000 // data descriptor (r/w)
GLOBL gdt<>(SB),8,$24

DATA gdtptr<>+0x00(SB)/2, $0x1800 // GDT Limit
DATA gdtptr<>+0x02(SB)/8, $gdt<>(SB) // GDT Base Address
GLOBL gdtptr<>(SB),8,$10

TEXT cpuinit(SB),NOSPLIT|NOFRAME,$0
// Disable interrupts
CLI

// Set up paging
//
// AMD64 Architecture Programmer’s Manual
// Volume 2 - 5.3 Long-Mode Page Translation
//
// Intel® 64 and IA-32 Architectures Software Developer’s Manual
// Volume 3A - 4.5 IA-32E PAGING

// Clear tables
XORL AX, AX // value
MOVL $PML4T, DI // to
MOVL $0x5000, CX // n
MOVL DI, CR3
REP; STOSB

// PML4T[0] = PDPT
MOVL $PML4T, DI
MOVL $(PDPT | 1<<1 | 1<<0), (DI) // set R/W, P

// Configure Long-Mode Page Translation as follows:
// 0x00000000 - 0x3ffffffff (1GB) cacheable physical page
// 0x40000000 - 0x7ffffffff (1GB) cacheable physical page
// 0x80000000 - 0xbffffffff (1GB) cacheable physical page
// 0xc0000000 - 0xfffffffff (1GB) uncacheable physical page
MOVL $PDPT, DI
MOVQ $(0 << 30 | 1<<7 | 1<<1 | 1<<0), (DI) // set PS, R/W, P
ADDL $8, DI
MOVQ $(1 << 30 | 1<<7 | 1<<1 | 1<<0), (DI) // set PS, R/W, P
ADDL $8, DI
MOVQ $(2 << 30 | 1<<7 | 1<<1 | 1<<0), (DI) // set PS, R/W, P
ADDL $8, DI
MOVQ $(3 << 30 | 1<<7 | 1<<4 | 1<<1 | 1<<0), (DI) // set PS, PCD, R/W, P

// Enter long mode

MOVL $(1<<7 | 1<<5), AX // set CR4.(PGE|PAE)
MOVL AX, CR4

MOVL $MSR_EFER, CX
RDMSR
ORL $(1<<8), AX // set MSR_EFER.LME
WRMSR

MOVL CR0, AX
ORL $(1<<31 | 1<<0), AX // set CR0.(PG|PE)
MOVL AX, CR0

// Set Global Descriptor Table

CALL ·getPC<>(SB)
MOVL $gdtptr<>(SB), BX // 32-bit mode: only PC offset is copied
ADDL $6, AX
ADDL BX, AX
LGDT (AX)

CALL ·getPC<>(SB)
MOVL $·start<>(SB), BX // 32-bit mode: only PC offset is copied
ADDL $6, AX
ADDL BX, AX

PUSHQ $0x08
PUSHQ AX
RETFQ

TEXT ·start<>(SB),NOSPLIT|NOFRAME,$0
MOVL CR0, AX
MOVL CR4, BX

// Enable SSE
ANDL $~(1<<2), AX // clear CR0.EM
ORL $(1<<1), AX // set CR0.MP
ORL $(1<<10 | 1<<9), BX // set CR4.(OSXMMEXCPT|OSFXSR)

MOVL AX, CR0
MOVL BX, CR4

JMP _rt0_tamago_start(SB)

TEXT ·getPC<>(SB),NOSPLIT|NOFRAME,$0
POPQ AX
CALL AX
19 changes: 19 additions & 0 deletions amd64/mem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// x86-64 processor support
// https://github.com/usbarmory/tamago
//
// Copyright (c) WithSecure Corporation
// https://foundry.withsecure.com
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

//go:build !linkramstart

package amd64

import (
_ "unsafe"
)

//go:linkname ramStart runtime.ramStart
var ramStart uint64 = 0x10000000
Loading

0 comments on commit f6dbdd8

Please sign in to comment.