Example #1
0
func Loop(
	vm *platform.Vm,
	vcpu *platform.Vcpu,
	model *machine.Model,
	tracer *loader.Tracer) error {

	// It's not really kosher to switch threads constantly when running a
	// KVM VCPU. So we simply lock this goroutine to a single system
	// thread. That way we know it won't be bouncing around.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	log.Printf("Vcpu[%d] running.", vcpu.Id)

	for {
		// Enter the guest.
		err := vcpu.Run()

		// Trace if requested.
		trace_err := tracer.Trace(vcpu, vcpu.IsStepping())
		if trace_err != nil {
			return trace_err
		}

		// No reason for exit?
		if err == nil {
			return ExitWithoutReason
		}

		// Handle the error.
		switch err.(type) {
		case *platform.ExitPio:
			err = model.HandlePio(vm, err.(*platform.ExitPio))

		case *platform.ExitMmio:
			err = model.HandleMmio(vm, err.(*platform.ExitMmio))

		case *platform.ExitDebug:
			err = nil

		case *platform.ExitShutdown:
			// Vcpu shutdown.
			return nil
		}

		// Error handling the exit.
		if err != nil {
			return err
		}
	}

	// Unreachable.
	return nil
}
Example #2
0
func (tracer *Tracer) toPaddr(
	vcpu *platform.Vcpu,
	reg platform.RegisterValue) string {

	phys_addr, valid, _, _, err := vcpu.Translate(platform.Vaddr(reg))
	if err != nil {
		return "%x->??"
	}

	if valid {
		return fmt.Sprintf("%x->%x", reg, phys_addr)
	}

	return fmt.Sprintf("%x", reg)
}
Example #3
0
func (tracer *Tracer) Trace(vcpu *platform.Vcpu, step bool) error {

	// Are we on?
	if !tracer.enabled {
		return nil
	}

	// Get the current instruction.
	addr, err := vcpu.GetRegister(tracer.convention.instruction)
	if err != nil {
		return err
	}

	// Skip duplicates (only if stepping is on).
	if step && platform.Vaddr(addr) == tracer.last_addr {
		return nil
	}

	// Lookup the current instruction.
	var fname string
	var offset uint64
	if tracer.sysmap != nil {
		fname, offset = tracer.sysmap.Lookup(platform.Vaddr(addr))
	}

	// Get the stack depth.
	stack, err := vcpu.GetRegister(tracer.convention.stack)
	if err != nil {
		return err
	}

	// Print the return value if applicable.
	if step &&
		fname != tracer.last_fname &&
		tracer.last_addr != 0 {

		rval, err := vcpu.GetRegister(tracer.convention.rvalue)
		if err != nil {
			return err
		}
		log.Printf("  trace: [%08x] %s => %s ?",
			stack,
			tracer.last_fname,
			tracer.toPaddr(vcpu, rval))

		// Save the current.
		tracer.last_fname = fname
	}

	// Get a physical address string.
	rip_phys_str := tracer.toPaddr(vcpu, addr)

	if fname != "" {
		if offset == 0 {
			num_args := len(tracer.convention.arguments)
			arg_vals := make([]string, num_args, num_args)
			for i, reg := range tracer.convention.arguments {
				reg_val, err := vcpu.GetRegister(reg)
				if err != nil {
					arg_vals[i] = fmt.Sprintf("??")
					continue
				}
				arg_vals[i] = tracer.toPaddr(vcpu, reg_val)
			}
			log.Printf("  trace: [%08x] %s:%s(%s)",
				stack,
				fname,
				rip_phys_str,
				strings.Join(arg_vals, ","))
		} else {
			log.Printf("  trace: [%08x] %s:%s ... +%x",
				stack,
				fname,
				rip_phys_str,
				offset)
		}
	} else {
		log.Printf("  trace: ??:%s", rip_phys_str)
	}

	// We're okay.
	tracer.last_addr = platform.Vaddr(addr)
	return nil
}
Example #4
0
func SetupLinux(
	vcpu *platform.Vcpu,
	model *machine.Model,
	orig_boot_data []byte,
	entry_point uint64,
	is_64bit bool,
	initrd_addr platform.Paddr,
	initrd_len uint64,
	cmdline_addr platform.Paddr) error {

	// Copy in the GDT table.
	// These match the segments below.
	gdt_addr, gdt, err := model.Allocate(
		machine.MemoryTypeUser,
		0,                 // Start.
		model.Max(),       // End.
		platform.PageSize, // Size.
		false)             // From bottom.
	if err != nil {
		return err
	}
	if is_64bit {
		C.build_64bit_gdt(unsafe.Pointer(&gdt[0]))
	} else {
		C.build_32bit_gdt(unsafe.Pointer(&gdt[0]))
	}

	BootGdt := platform.DescriptorValue{
		Base:  uint64(gdt_addr),
		Limit: uint16(platform.PageSize),
	}
	err = vcpu.SetDescriptor(platform.GDT, BootGdt, true)
	if err != nil {
		return err
	}

	// Set a null IDT.
	BootIdt := platform.DescriptorValue{
		Base:  0,
		Limit: 0,
	}
	err = vcpu.SetDescriptor(platform.IDT, BootIdt, true)
	if err != nil {
		return err
	}

	// Enable protected-mode.
	// This does not set any flags (e.g. paging) beyond the
	// protected mode flag. This is according to Linux entry
	// protocol for 32-bit protected mode.
	cr0, err := vcpu.GetControlRegister(platform.CR0)
	if err != nil {
		return err
	}
	cr0 = cr0 | (1 << 0) // Protected mode.
	err = vcpu.SetControlRegister(platform.CR0, cr0, true)
	if err != nil {
		return err
	}

	// Always have the PAE bit set.
	cr4, err := vcpu.GetControlRegister(platform.CR4)
	if err != nil {
		return err
	}
	cr4 = cr4 | (1 << 5) // PAE enabled.
	err = vcpu.SetControlRegister(platform.CR4, cr4, true)
	if err != nil {
		return err
	}

	// For 64-bit kernels, we need to enable long mode,
	// and load an identity page table. This will require
	// only a page of pages, as we use huge page sizes.
	if is_64bit {
		// Create our page tables.
		pde_addr, pde, err := model.Allocate(
			machine.MemoryTypeUser,
			0,                 // Start.
			model.Max(),       // End.
			platform.PageSize, // Size.
			false)             // From bottom.
		if err != nil {
			return err
		}
		pgd_addr, pgd, err := model.Allocate(
			machine.MemoryTypeUser,
			0,                 // Start.
			model.Max(),       // End.
			platform.PageSize, // Size.
			false)             // From bottom.
		if err != nil {
			return err
		}
		pml4_addr, pml4, err := model.Allocate(
			machine.MemoryTypeUser,
			0,                 // Start.
			model.Max(),       // End.
			platform.PageSize, // Size.
			false)             // From bottom.
		if err != nil {
			return err
		}

		C.build_pde(unsafe.Pointer(&pde[0]), platform.PageSize)
		C.build_pgd(unsafe.Pointer(&pgd[0]), C.__u64(pde_addr), platform.PageSize)
		C.build_pml4(unsafe.Pointer(&pml4[0]), C.__u64(pgd_addr), platform.PageSize)

		log.Printf("loader: Created PDE @ %08x.", pde_addr)
		log.Printf("loader: Created PGD @ %08x.", pgd_addr)
		log.Printf("loader: Created PML4 @ %08x.", pml4_addr)

		// Set our newly build page table.
		err = vcpu.SetControlRegister(
			platform.CR3,
			platform.ControlRegisterValue(pml4_addr),
			true)
		if err != nil {
			return err
		}

		// Enable long mode.
		efer, err := vcpu.GetControlRegister(platform.EFER)
		if err != nil {
			return err
		}
		efer = efer | (1 << 8) // Long-mode enable.
		err = vcpu.SetControlRegister(platform.EFER, efer, true)
		if err != nil {
			return err
		}

		// Enable paging.
		cr0, err = vcpu.GetControlRegister(platform.CR0)
		if err != nil {
			return err
		}
		cr0 = cr0 | (1 << 31) // Paging enable.
		err = vcpu.SetControlRegister(platform.CR0, cr0, true)
		if err != nil {
			return err
		}
	}

	// NOTE: For 64-bit kernels, we need to enable
	// real 64-bit mode. This means that the L bit in
	// the segments must be one, the Db bit must be
	// zero, and we set the LME bit in EFER (above).
	var lVal uint8
	var dVal uint8
	if is_64bit {
		lVal = 1
		dVal = 0
	} else {
		lVal = 0
		dVal = 1
	}

	// Load the VMCS segments.
	//
	// NOTE: These values are loaded into the VMCS
	// registers and are expected to match the descriptors
	// we've used above. Unfortunately the API format doesn't
	// match, so we need to duplicate some work here. Ah, well
	// at least the below serves as an explanation for what
	// the magic numbers in GDT_ENTRY() above mean.
	BootCs := platform.SegmentValue{
		Base:     0,
		Limit:    0xffffffff,
		Selector: uint16(C.BootCsSelector), // @ 0x10
		Dpl:      0,                        // Privilege level (kernel).
		Db:       dVal,                     // 32-bit segment?
		G:        1,                        // Granularity (page).
		S:        1,                        // As per BOOT_CS (code/data).
		L:        lVal,                     // 64-bit extension.
		Type:     0xb,                      // As per BOOT_CS (access must be set).
		Present:  1,
	}
	BootDs := platform.SegmentValue{
		Base:     0,
		Limit:    0xffffffff,
		Selector: uint16(C.BootDsSelector), // @ 0x18
		Dpl:      0,                        // Privilege level (kernel).
		Db:       1,                        // 32-bit segment?
		G:        1,                        // Granularity (page).
		S:        1,                        // As per BOOT_DS (code/data).
		L:        0,                        // 64-bit extension.
		Type:     0x3,                      // As per BOOT_DS (access must be set).
		Present:  1,
	}
	BootTr := platform.SegmentValue{
		Base:     0,
		Limit:    0xffffffff,
		Selector: uint16(C.BootTrSelector), // @ 0x20
		Dpl:      0,                        // Privilege level (kernel).
		Db:       1,                        // 32-bit segment?
		G:        1,                        // Granularity (page).
		S:        0,                        // As per BOOT_TR (system).
		L:        0,                        // 64-bit extension.
		Type:     0xb,                      // As per BOOT_TR.
		Present:  1,
	}

	err = vcpu.SetSegment(platform.CS, BootCs, true)
	if err != nil {
		return err
	}

	err = vcpu.SetSegment(platform.DS, BootDs, true)
	if err != nil {
		return err
	}

	err = vcpu.SetSegment(platform.ES, BootDs, true)
	if err != nil {
		return err
	}

	err = vcpu.SetSegment(platform.FS, BootDs, true)
	if err != nil {
		return err
	}

	err = vcpu.SetSegment(platform.GS, BootDs, true)
	if err != nil {
		return err
	}

	err = vcpu.SetSegment(platform.SS, BootDs, true)
	if err != nil {
		return err
	}

	err = vcpu.SetSegment(platform.TR, BootTr, true)
	if err != nil {
		return err
	}

	// Create our boot parameters.
	boot_addr, boot_data, err := model.Allocate(
		machine.MemoryTypeUser,
		0,                 // Start.
		model.Max(),       // End.
		platform.PageSize, // Size.
		false)             // From bottom.
	if err != nil {
		return err
	}
	err = SetupLinuxBootParams(
		model,
		boot_data,
		orig_boot_data,
		cmdline_addr,
		initrd_addr,
		initrd_len)
	if err != nil {
		return err
	}

	// Set our registers.
	// This is according to the Linux 32-bit boot protocol.
	log.Printf("loader: boot_params @ %08x.", boot_addr)
	err = vcpu.SetRegister(platform.RSI, platform.RegisterValue(boot_addr))
	if err != nil {
		return err
	}

	err = vcpu.SetRegister(platform.RBP, 0)
	if err != nil {
		return err
	}

	err = vcpu.SetRegister(platform.RDI, 0)
	if err != nil {
		return err
	}

	err = vcpu.SetRegister(platform.RBX, 0)
	if err != nil {
		return err
	}

	// Jump to our entry point.
	err = vcpu.SetRegister(platform.RIP, platform.RegisterValue(entry_point))
	if err != nil {
		return err
	}

	// Make sure interrupts are disabled.
	// This will actually clear out all other flags.
	rflags, err := vcpu.GetRegister(platform.RFLAGS)
	if err != nil {
		return err
	}
	rflags = rflags &^ (1 << 9) // Interrupts off.
	rflags = rflags | (1 << 1)  // Reserved 1.
	err = vcpu.SetRegister(
		platform.RFLAGS,
		platform.RegisterValue(rflags))
	if err != nil {
		return err
	}

	// We're done.
	return nil
}