TinyEMU源码分析之虚拟机初始化,Linux运维开发实战讲解

	// 鼠标
	s->mouse_dev = virtio\_input\_init(vbus,
									 VIRTIO_INPUT_TYPE_TABLET);
	vbus->addr += VIRTIO_SIZE;
}

// 拷贝BIOS和Kernel;手动写入5条指令
copy\_bios(s, p->files[VM_FILE_BIOS].buf, p->files[VM_FILE_BIOS].len,
          p->files[VM_FILE_KERNEL].buf, p->files[VM_FILE_KERNEL].len,
          p->files[VM_FILE_INITRD].buf, p->files[VM_FILE_INITRD].len,
          p->cmdline);

return (VirtMachine \*)s;

}


首先,初始化VirtMachineClass、ram大小、max\_xlen,以及内存映射初始化等。  
 然后,在riscv\_cpu\_init函数中,会完成pc赋初值和TLB初始化(赋值为-1)。



s->pc = 0x1000;
s->cpu_state = riscv_cpu_init(s->mem_map, max_xlen);



> 
> cpu\_state的类型为RISCVCPUState结构,该结构中,包含mstatus、mtvec、mscratch等CSR寄存器定义。
> 
> 
> 


**我们猜测,第一条指令地址,就是0x1000**。


初始化结构参数,其实就是把一些参数,保存到RISCVMachine对象中。


## 2 配置RAM地址空间


我们对本部分代码,进行分析,并结合以下常量定义。



#define LOW_RAM_SIZE 0x00010000 /* 64KB */
#define RAM_BASE_ADDR 0x80000000
#define CLINT_BASE_ADDR 0x02000000
#define CLINT_SIZE 0x000c0000
#define HTIF_BASE_ADDR 0x40008000
#define IDE_BASE_ADDR 0x40009000
#define VIRTIO_BASE_ADDR 0x40010000
#define VIRTIO_SIZE 0x1000
#define VIRTIO_IRQ 1
#define PLIC_BASE_ADDR 0x40100000
#define PLIC_SIZE 0x00400000
#define FRAMEBUFFER_BASE_ADDR 0x41000000


发现代码,构成了,如下的内存地址空间:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c8d3e269796a475ebee31c5f14841a46.png#pic_center)  
 这里,主要是,确定Low Dram、CLINT、HTIF、VBUS、PLIC、High Dram的地址空间范围(申请内存),可以结合上面代码,好好看看,比较简单。


因为,在执行指令时,必须要知道具体的内存空间,是如何分布的,以便正确访问内存。


## 3 初始化设备


初始化console、net device、block device、filesystem、display device、input device。  
 不详述,自己看源码。


## 4 拷贝BIOS和Kernel


在copy\_bios函数中,完成拷贝BIOS和Kernel,其代码如下:



static void copy_bios(RISCVMachine *s, const uint8_t *buf, int buf_len,
const uint8_t *kernel_buf, int kernel_buf_len,
const uint8_t *initrd_buf, int initrd_buf_len,
const char *cmd_line)
{
// 拷贝BIOS到0x80000000
ram_ptr = get_ram_ptr(s, RAM_BASE_ADDR, TRUE);
memcpy(ram_ptr, buf, buf_len);

// 拷贝Kernel到0x80200000
kernel_base = 0;
if (kernel_buf_len > 0) {
    /\* copy the kernel if present \*/
    if (s->max_xlen == 32)
        align = 4 << 20; /\* 4 MB page align \*/
    else
        align = 2 << 20; /\* 2 MB page align \*/
    kernel_base = (buf_len + align - 1) & ~(align - 1);
    memcpy(ram_ptr + kernel_base, kernel_buf, kernel_buf_len);
}

// 创建设备树,并写入内存地址(0x1000+8\*8)处
ram_ptr = get\_ram\_ptr(s, 0, TRUE);
fdt_addr = 0x1000 + 8 \* 8;
riscv\_build\_fdt(s, ram_ptr + fdt_addr,
                RAM_BASE_ADDR + kernel_base, kernel_buf_len,
                RAM_BASE_ADDR + initrd_base, initrd_buf_len,
                cmd_line);

// 手动写入5条指令
/\* jump\_addr = 0x80000000 \*/
q = (uint32\_t \*)(ram_ptr + 0x1000);
q[0] = 0x297 + 0x80000000 - 0x1000; /\* auipc t0, jump\_addr \*/
q[1] = 0x597; /\* auipc a1, dtb \*/
q[2] = 0x58593 + ((fdt_addr - 4) << 20); /\* addi a1, a1, dtb \*/
q[3] = 0xf1402573; /\* csrr a0, mhartid \*/
q[4] = 0x00028067; /\* jalr zero, t0, jump\_addr \*/

}


* 将bios(bbl64.bin)拷贝到0x80000000地址处(物理地址),本例中bbl64.bin长度为0xd21a。
* 将kernel(kernel-riscv64.bin)拷贝到0x80200000地址处(物理地址),本例中kernel-riscv64.bin长度为0x3d5324。
* 创建设备树,并写入内存地址(0x1000+8\*8)处(物理地址)。


拷贝BIOS和Kernel的地址,与上图中内存地址空间,一致。


## 5 手动写入5条指令


手动写入的5条指令,翻译过来,就是如下:



/\* jump\_addr = 0x80000000 \*/
// 从物理地址0x1000位置处开始,手动写入5条指令的机器码
q = (uint32\_t \*)(ram_ptr + 0x1000);

// t0=0x80000000
q[0] = 0x297 + 0x80000000 - 0x1000; /\* auipc t0, jump\_addr \*/

// a1=PC
q[1] = 0x597; /\* auipc a1, dtb \*/

// a1=a1+0x3c
q[2] = 0x58593 + ((fdt_addr - 4) << 20); /\* addi a1, a1, dtb \*/

// a0=mhartid
q[3] = 0xf1402573; /\* csrr a0, mhartid \*/

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Linux运维工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Linux运维知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip1024b (备注Linux运维获取)
img

为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!

这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。

本份面试集锦涵盖了

  • 174 道运维工程师面试题
  • 128道k8s面试题
  • 108道shell脚本面试题
  • 200道Linux面试题
  • 51道docker面试题
  • 35道Jenkis面试题
  • 78道MongoDB面试题
  • 17道ansible面试题
  • 60道dubbo面试题
  • 53道kafka面试
  • 18道mysql面试题
  • 40道nginx面试题
  • 77道redis面试题
  • 28道zookeeper

总计 1000+ 道面试题, 内容 又全含金量又高

  • 174道运维工程师面试题

1、什么是运维?

2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?

3、现在给你三百台服务器,你怎么对他们进行管理?

4、简述raid0 raid1raid5二种工作模式的工作原理及特点

5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?

6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

7、Tomcat和Resin有什么区别,工作中你怎么选择?

8、什么是中间件?什么是jdk?

9、讲述一下Tomcat8005、8009、8080三个端口的含义?

10、什么叫CDN?

11、什么叫网站灰度发布?

12、简述DNS进行域名解析的过程?

13、RabbitMQ是什么东西?

14、讲一下Keepalived的工作原理?

15、讲述一下LVS三种模式的工作过程?

16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

17、如何重置mysql root密码?

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

15、讲述一下LVS三种模式的工作过程?

16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

17、如何重置mysql root密码?

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-if0e1EzO-1713024642716)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值