最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
资料预览
给大家整理的视频资料:
给大家整理的电子书资料:
如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
虚拟机的初始化,主要在virt_machine_init函数中完成。
virt_machine_init函数,如下:
static VirtMachine \*riscv\_machine\_init(const VirtMachineParams \*p)
{
RISCVMachine \*s;
VIRTIODevice \*blk_dev;
VIRTIOBusDef vbus_s, \*vbus = &vbus_s;
// 初始化结构参数
s->common.vmc = p->vmc;
s->ram_size = p->ram_size;
s->max_xlen = max_xlen;
s->mem_map = phys\_mem\_map\_init();
s->mem_map->opaque = s;
s->mem_map->flush_tlb_write_range = riscv_flush_tlb_write_range;
s->cpu_state = riscv\_cpu\_init(s->mem_map, max_xlen);
// 配置RAM地址空间
/\* RAM \*/
ram_flags = 0;
cpu\_register\_ram(s->mem_map, RAM_BASE_ADDR, p->ram_size, ram_flags);
cpu\_register\_ram(s->mem_map, 0x00000000, LOW_RAM_SIZE, 0);
cpu\_register\_device(s->mem_map, CLINT_BASE_ADDR, CLINT_SIZE, s,
clint_read, clint_write, DEVIO_SIZE32);
cpu\_register\_device(s->mem_map, PLIC_BASE_ADDR, PLIC_SIZE, s,
plic_read, plic_write, DEVIO_SIZE32);
cpu\_register\_device(s->mem_map, HTIF_BASE_ADDR, 16,
s, htif_read, htif_write, DEVIO_SIZE32);
vbus->addr = VIRTIO_BASE_ADDR;
// 初始化设备
/\* virtio console \*/
if (p->console) {
s->common.console_dev = virtio\_console\_init(vbus, p->console);
vbus->addr += VIRTIO_SIZE;
}
...
if (p->input_device) {
// 键盘
s->keyboard_dev = virtio\_input\_init(vbus,
VIRTIO_INPUT_TYPE_KEYBOARD);
vbus->addr += VIRTIO_SIZE;
// 鼠标
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
发现代码,构成了,如下的内存地址空间:
这里,主要是,确定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);
}
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**