Ds_handler类
class Ds_handler : public Vmm::Mmio_device { l4::Cap<L4Re::Dataspace> _ds; l4_addr_t _offset;
bool _mergable(cxx::Ref_ptr<Mmio_device> other, l4_addr_t start_other, l4_addr_t start_this) override //相同数据块引用可合并,是不是供KSM功能使用的? { // same device type and same underlying dataspace? auto dsh = dynamic_cast<Ds_handler *>(other.get()); if (!dsh || (_ds != dsh->_ds)) //dah不为空则是相同的设备类型;还需要相同的数据空间才行 return false;
// reference the same part of the data space? return (_offset + (start_other - start_this)) == dsh->_offset; //更进一步,相同的数据空间,还得偏移相同才是可mergable的 }
int access(l4_addr_t pfa, l4_addr_t offset, Vmm::Vcpu_ptr vcpu, l4::Cap<l4::Task> vm_task, l4_addr_t min, l4_addr_t max) { long res; #ifdef MAP_OTHER res = _ds->map(offset + _offset, vcpu.pf_write() ? L4Re::Dataspace::Map_rw : 0, pfa, min, max, vm_task); #else unsigned char ps = get_page_shift(pfa, min, max, offset, _local_start); //获取PAGESHIFT
// TODO Need to make sure that memory is locally mapped. res = L4Re::chksys(vm_task->map(L4Re::This_task, l4_fpage(l4_trunc_size(_local_start + offset, ps), ps, vcpu.pf_write() ? l4_FPAGE_RWX : l4_FPAGE_RX), l4_trunc_size(pfa, ps))); //映射 #endif
if (res < 0) { Err().printf("cannot handle VM memory access @ %lx ip=%lx r=%ld\n", pfa, vcpu->r.ip, res); return res; }
return Vmm::Retry; }
char const *dev_info(char *buf, size_t size) override //设备信息保存在buff中 { #ifndef MAP_OTHER snprintf(buf, size, "mmio ds: [%lx - ?] -> [%lx:%lx - ?]", _local_start, _ds.cap(), _offset); #else snprintf(buf, size, "mmio ds: [? - ?] -> [%lx:%lx - ?]", _ds.cap(), _offset); #endif return buf; }
l4_addr_t _local_start;
public: explicit Ds_handler(l4::Cap<L4Re::Dataspace> ds, l4_addr_t local_start, l4_size_t size, l4_addr_t offset = 0) : _ds(ds), _offset(offset), _local_start(local_start) { assert(size); #ifndef MAP_OTHER if (local_start == 0) //即时映射dataspace到_local_start L4Re::chksys(L4Re::Env::env()->rm()->attach(&_local_start, size, L4Re::Rm::Search_addr | L4Re::Rm::Eager_map, l4::Ipc::make_cap_rw(ds), offset, l4_SUPERPAGESHIFT));
l4_addr_t page_offs = offset & ~l4_PAGEMASK; if (page_offs) //加上偏移 { auto tmp = l4_trunc_page(_local_start) + page_offs; Dbg(Dbg::Mmio, Dbg::Warn) .printf("Region not page aligned, adjusting local_start: %lx -> %lx\n", _local_start, tmp); _local_start = tmp; } #endif }
l4_addr_t local_start() const { return _local_start; } } |
Direct_mmio_handler类
class Direct_mmio_handler : public Vmm::Mmio_device { l4::Cap<L4Re::Dataspace> _ds; l4_addr_t _local_start;
public: explicit Direct_mmio_handler(l4::Cap<L4Re::Dataspace> ds, l4_addr_t local_start, l4_size_t size, l4_addr_t offset) : _ds(ds), _local_start(local_start) { assert(size); //映射 L4Re::chksys(L4Re::Env::env()->rm()->attach(&_local_start, size, L4Re::Rm::Search_addr | L4Re::Rm::Eager_map | L4Re::Rm::Cache_uncached, l4::Ipc::make_cap_rw(ds), offset));
l4_addr_t page_offs = offset & ~l4_PAGEMASK; if (page_offs) //加上偏移 { auto tmp = l4_trunc_page(_local_start) + page_offs; Dbg(Dbg::Mmio, Dbg::Warn) .printf("Region not page aligned, adjusting local_start: %lx -> %lx\n", _local_start, tmp); _local_start = tmp; } }
int access(l4_addr_t pfa, l4_addr_t offset, Vmm::Vcpu_ptr vcpu, l4::Cap<l4::Task>, l4_addr_t, l4_addr_t) { auto insn = vcpu.decode_mmio(pfa); //vcpu解码,返回存储类型(store、load、other)
if (insn.access == Vmm::Mem_access::Other) //解码失败 { Err().printf("cannot decode , try direct map\n");
Dbg(Dbg::Mmio, Dbg::Warn, "mmio"). printf("MMIO access @ 0x%lx: unknown instruction. Ignored.\n",pfa); return -l4_ENXIO; }
Dbg(Dbg::Mmio, Dbg::Trace, "mmio") .printf("MMIO access @ 0x%lx (0x%lx) %s, width: %u\n", pfa, offset, insn.access == Vmm::Mem_access::Load ? "LOAD" : "STORE", (unsigned) insn.width);
do { auto val_bak = insn.value;
vcpu.rep_start(insn); //x86的repeat类指令设置 if ((insn.access == Vmm::Mem_access::Store) || (insn.access == Vmm::Mem_access::Repeat_Store)){ if(insn.width == Vmm::Mem_access::Wd128){ write128(offset, (unsigned char *)&insn.xmm_value); } else{ write(offset, insn.width, insn.value, vcpu.get_vcpu_id()); } } else{ if(insn.width == Vmm::Mem_access::Wd128){ read128(offset, (unsigned char *)&insn.xmm_value); } else insn.value = read(offset, insn.width, vcpu.get_vcpu_id());
vcpu.writeback_mmio(insn); } insn.value = val_bak; vcpu.rep_commit(insn, offset); }while(vcpu.get_rep_cnt(insn) > 0);
return Vmm::Jump_instr; }
l4_uint64_t read(unsigned offset, char width, unsigned cpuid) { (void) cpuid; // must be ignored by this implementation because // we have no CPU-local mappings of our dataspace. if (0) printf("MMIO/RO/DS read: offset=%x (%u) [0x%lx] = %x\n", offset, (unsigned)width, _local_start + offset, *((l4_uint32_t*)(_local_start) + offset));
return Vmm::Mem_access::read_width(_local_start + offset, width); //调用内存读指令 }
l4_uint64_t write(unsigned offset, char width, l4_uint64_t value, unsigned cpuid) { (void) cpuid; // must be ignored by this implementation because // we have no CPU-local mappings of our dataspace. if (0) printf("MMIO/RO/DS read: offset=%x (%u) [0x%lx] = %x\n", offset, (unsigned)width, _local_start + offset, *((l4_uint32_t*)(_local_start + offset)));
return Vmm::Mem_access::write_width(_local_start + offset, value, width); //内存写指令 }
void read128(unsigned offset, unsigned char *value) { memcpy(value, (unsigned char *)(_local_start + offset), 16); }
void write128(unsigned offset, unsigned char *value) { memcpy((unsigned char *)(_local_start + offset), value, 16); }
} |