【kvm】流程解析学习和实践

今天制作一个简单的kvm模型,并制作个简单的kernel用于执行,主要是了解kvm的io虚拟化,用于学你kvm的工作过程。
kvm是一个经过修改的qemu,kvm利用硬件虚拟化技术为qemu提供加速,主要有cpu虚拟化和内存虚拟化。qemu为kvm提供io的虚拟化
一下就是kvm中几个重要的函数,并且一会儿会用到
kvm_context_t  kvm_init(struct kvm_callbacks   *callbacks,
                        void                   *opaque);

int            kvm_create(kvm_context_t  kvm,
                          unsigned long  phys_mem_bytes,
                          void           **phys_mem);

int            kvm_create_vcpu(kvm_context_t  kvm,
                               int            slot);

void           *kvm_create_phys_mem(kvm_context_t  kvm,
                                    unsigned long  phys_start,
                                    unsigned long  len,
                                    int            log,
                                    int            writable);

int            kvm_run(kvm_context_t  kvm,
                       int            vcpu);


首先创建一个KVM进程,需要利用kvm_init函数,函数的第一个参数就是kvm_callbacks这是一个回调函数,就是当虚拟机执行了一些特权指令或者io指令是将会执行回调函数中内容。如果是io指令将会退出客户模式进入用户模式的qemu中模拟,并调用相应的函数。函数具体声明在libkvm.h
代码
之后调用kvm_create(),函数第二个参数是RAM大小和加载的程序地址。此时会为虚拟机分配一个vcpu。这个函数调用时并不会分配内存
调用kvm_create_vcpu()创建虚拟cpu。个数0-65。此函数由某线程调用添加vcpu的个数
kvm_create_phys_mem()是为虚拟机分配内存有几种方法之一
之后调用kvm_run启动vcpu和虚拟机,这个函数并不会返回,除非遇到1、io处理程序没有处理成功2、出现了一个kvm和虚拟机都无法处理的情况。
模拟kvm代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libkvm.h>

#ifndef __RUNTIME_H__
#define __RUNTIME_H__

// port to use for general purpose output
#define IO_PORT_PSEUDO_SERIAL  0xf1

#endif /* __RUNTIME_H_ */

/* callback definitions as shown in Listing 2 go here */
static int my_inb(void *opaque, int16_t addr, uint8_t *data)
                     { puts ("inb"); return 0; }

static int my_inw(void *opaque, uint16_t addr, uint16_t *data)
                     { puts ("inw"); return 0; }

static int my_inl(void *opaque, uint16_t addr, uint32_t *data)
                     { puts ("inl"); return 0; }

static int my_outb(void *opaque, uint16_t addr, uint8_t data)
    {
    if (addr == IO_PORT_PSEUDO_SERIAL)
        if (isprint(data) || data == '\n')
            putchar(data);
        else
            putchar('.');
    else
        printf("outb: %x, %d\n", addr, data);
    fflush (NULL);

    return 0;
    }

static int my_outw(void *opaque, uint16_t addr, uint16_t data)
                     { puts ("outw"); return 0; }

static int my_outl (void *opaque, uint16_t addr, uint32_t data)
                     { puts ("outl"); return 0; }

static int my_pre_kvm_run(void *opaque, int vcpu)
                     { return 0; }
static struct kvm_callbacks my_callbacks = {
    .inb                 = my_inb,
    .inw                 = my_inw,
    .inl                 = my_inl,
    .outb                = my_outb,
    .outw                = my_outw,
    .outl                = my_outl,
    .pre_kvm_run         = my_pre_kvm_run,
};
void load_file(void *mem, const char *filename)
{
    int  fd;
    int  nr;

    fd = open(filename, O_RDONLY);
    if (fd == -1) {
        fprintf(stderr, "Cannot open %s", filename);
        perror("open");
        exit(1);
    }
    while ((nr = read(fd, mem, 4096)) != -1  &&  nr != 0)
        mem += nr;

    if (nr == -1) {
        perror("read");
        exit(1);
    }
    close(fd);
}

#define MEMORY_SIZE     (0x1000000)     /* 16 Mb */
#define FIRST_VCPU      (0)

int main(int argc, char *argv[])
{
    kvm_context_t  kvm;
    void           *memory_area;

    /* Second argument is an opaque, we don't use it yet */
    kvm = kvm_init(&my_callbacks, NULL);
    if (!kvm) {
        fprintf(stderr, "KVM init failed");
        exit(1);
    }
    if (kvm_create(kvm, MEMORY_SIZE, &memory_area) != 0) {
        fprintf(stderr, "VM creation failed");
        exit(1);
    }
#ifndef KVM_VERSION_LESS_THAN_65
    if (kvm_create_vcpu(kvm, FIRST_VCPU)) {
        fprintf(stderr, "VCPU creation failed");
        exit(1);
    }
#endif
    memory_area = kvm_create_phys_mem(kvm, 0, MEMORY_SIZE, 0, 1);
    load_file(memory_area + 0xf0000, argv[1]);

    kvm_run(kvm, FIRST_VCPU);

    return 0;
}
连接器代码
OUTPUT_FORMAT(binary)

SECTIONS {
        . = 0;
        .text : { *(.init) *(.text) }
        . = ALIGN(4K);
        .data : { *(.data) }
        . = ALIGN(16);
        .bss : { *(.bss) }
        . = ALIGN(4K);
        .edata = .;
}
制作镜像代码:
#ifndef __RUNTIME_H__
#define __RUNTIME_H__

// port to use for general purpose output
#define IO_PORT_PSEUDO_SERIAL  0xf1

#endif /* __RUNTIME_H_ */
.code16
start:
    mov    $0x48,%al    // H
    outb   %al,$IO_PORT_PSEUDO_SERIAL
    mov    $0x65,%al    // e
    outb   %al,$IO_PORT_PSEUDO_SERIAL
    mov    $0x6c,%al    // l
    outb   %al,$IO_PORT_PSEUDO_SERIAL
    mov    $0x6c,%al    // l
    outb   %al,$IO_PORT_PSEUDO_SERIAL
    mov    $0x6f,%al    // o
    outb   %al,$IO_PORT_PSEUDO_SERIAL
    mov    $0x0a,%al    // new_line
    outb   %al,$IO_PORT_PSEUDO_SERIAL

    hlt                 // halt the processor

. = 0xfff0
    ljmp    $0xf000, $start
Makefile
# If KVM was compiled from sources and you have errors about
# missing asm/kvm*.h files, copy them from
# kvm-XX/kernel/include/asm/* to {prefix}/include/asm/
CC=gcc
KERNEL16_CFLAGS=-nostdlib -ffreestanding -Wl,-T,kernel16.lds

all:    launcher kernel2

launcher: launcher.o
        $(CC) launcher.o /usr/lib/libkvm.a -o launcher

launcher.o:

kernel2: kernel2.S
        $(CC) $(KERNEL16_CFLAGS) kernel2.S -o kernel1

clean:
        rm *.o launcher kernel1
制作内核
gcc -nostdlib -Wl,-T,kernel16.lds kernel1.S -o kernel1
执行
./launcher kernel1





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值