Phase1:Cache

  1. 阅读实验手册后,根据任务1中描述的性质实现cache,创建cache.h,定义块大小,位数,以及缓存相应的结构体

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #define BLOCK_SIZE 64
    #define STORAGE_SIZE_L1 64*1024
    #define STORAGE_SIZE_L2 4*1024*1024
    #define EIGHT_WAY 8
    #define SIXTEEN_WAY 16

    void init_cache();

    struct Cache
    {
    bool valid;
    int tag;
    uint8_t data[BLOCK_SIZE];
    }cache[STORAGE_SIZE_L1/BLOCK_SIZE];
    struct SecondaryCache
    {
    bool valid,dirty;
    int tag;
    uint8_t data[BLOCK_SIZE];
    }cache2[STORAGE_SIZE_L2/BLOCK_SIZE];
  2. 构造cache初始化函数init_cache(),代码如下

    根据要求把给valid,tag以及dirty赋值并在monitor.c文件中的restart()函数中添加相应代码对缓存进行初始化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    void init_cache()
    {
    int i;
    for (i = 0;i < STORAGE_SIZE_L1/BLOCK_SIZE;i ++)
    {
    cache[i].valid = false;
    cache[i].tag = 0;
    memset (cache[i].data,0,BLOCK_SIZE);
    }
    for (i = 0;i < STORAGE_SIZE_L2/BLOCK_SIZE;i ++)
    {
    cache2[i].valid = false;
    cache2[i].dirty = false;
    cache2[i].tag = 0;
    memset (cache2[i].data,0,BLOCK_SIZE);
    }
    }
  3. 修改memory.c中的hwaddr_read()和hwaddr_write()函数,实现读写cache的功能,并当cache缺失时才读写DRAM

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    uint32_t hwaddr_read(hwaddr_t addr, size_t len) {
    int index = is_mmio(addr);
    if ( index >= 0)
    {
    return mmio_read(addr, len, index);
    }
    uint32_t offset = addr & (BLOCK_SIZE - 1); // inside addr
    uint32_t block = cache_read(addr);
    uint8_t temp[4];
    memset (temp,0,sizeof (temp));

    if (offset + len >= BLOCK_SIZE)
    {
    uint32_t _block = cache_read(addr + len);
    memcpy(temp,cache[block].data + offset, BLOCK_SIZE - offset);
    memcpy(temp + BLOCK_SIZE - offset,cache[_block].data, len - (BLOCK_SIZE - offset));
    }
    else
    {
    memcpy(temp,cache[block].data + offset,len);
    }
    int zero = 0;
    uint32_t tmp = unalign_rw(temp + zero, 4) & (~0u >> ((4 - len) << 3));
    return tmp;
    }

    void hwaddr_write(hwaddr_t addr, size_t len, uint32_t data) {
    int index = is_mmio(addr);
    if ( index >= 0)
    {
    mmio_write(addr, len, data, index);
    return ;
    }
    cache_write(addr, len, data);
    }
  4. 至此完成第一阶段。

做第二阶段之前虚拟机发生了一个小小的意外,卡在下图开不了机,只能用新建一个虚拟机重新写第一阶段,再写第二阶段,git log也无法恢复

Damn

Phase2:Segment

  1. 在kernal/include/common.h中定义宏IA32_SEG

    1
    #define IA32_SEG
  2. 修改CPU_state,在reg.h和reg.c文件中增加如下代码,添加并实现GDTR,CR0和各种段寄存器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //reg.h
    #include "../lib-common/x86-inc/cpu.h"//definition of CR0
    enum {R_CS,R_DS,R_ES,R_SS}//R_GS,R_FS
    //在CPU_state中
    //GDTR
    struct GDTR{
    uint32_t base_addr;
    uint16_t seg_limit;
    }gdtr;
    //CR0
    CR0 cr0;
    //registers
    union{
    struct SREG sr[6];
    struct{
    struct SREG cs,ds,es,ss;
    };
    };
    //
    //reg.c
    const char *regss[]={"cs","ds","es","ss"};
  3. 添加 lgdt 指令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //lgdt.h#ifndef __LGDT_H__
    #define __LGDT_H__
    make_helper(lgdt_rm_v);
    #endif
    //lgdt.c
    #include "cpu/exec/helper.h"

    #define DATA_BYTE 2
    #include "lgdt-template.h"
    #undef DATA_BYTE

    #define DATA_BYTE 4
    #include "lgdt-template.h"
    #undef DATA_BYTE

    make_helper_v(lgdt_rm)
  4. 修改swddr_read()和swaddr_write()函数,实现段级地址转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    uint32_t swaddr_read(swaddr_t addr, size_t len) {
    #ifdef DEBUG
    assert(len == 1 || len == 2 || len == 4);
    #endif
    lnaddr_t lnaddr = seg_translate(addr, len, current_sreg);
    return lnaddr_read(lnaddr, len);
    }

    void swaddr_write(swaddr_t addr, size_t len, uint32_t data) {
    #ifdef DEBUG
    assert(len == 1 || len == 2 || len == 4);
    #endif
    lnaddr_t lnaddr = seg_translate(addr, len, current_sreg);
    return lnaddr_write(lnaddr, len, data);
    }
  5. 定义segment.c,实现seg_translate()函数

    1
    2
    3
    4
    5
    6
    7
    #include "nemu.h"

    lnaddr_t seg_translate(swaddr_t addr, size_t len, uint8_t sreg) {
    if (cpu.cr0.protect_enable == 0)return addr;
    Assert(addr+len < cpu.sr[sreg].seg_limit, "cs segment out limit");
    return cpu.sr[sreg].seg_base + addr;
    }
  6. 在Operand结构体中添加成员sreg

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    typedef struct {
    uint32_t type;
    size_t size;
    union {
    uint32_t reg;
    struct {
    swaddr_t addr;
    uint8_t sreg;
    };
    uint32_t imm;
    int32_t simm;
    };
    uint32_t val;
    char str[OP_STR_SIZE];
    } Operand;
  7. 修改read_ModR_M()中的代码, 以确定是和DS, SS中的哪一个进行捆绑, 然后设置 rm->sreg, 这样 swaddr_read()和 swaddr_write()就可以使用正确的 段寄存器了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //nemu/src/cpu/decode/modrm.c
    //read_ModR_M()
    //else
    else
    {
    int instr_len = load_addr(eip, &m, rm);
    if(rm->reg == R_ESP || rm->reg == R_EBP)
    {
    current_sreg = R_SS;
    }
    else
    {
    current_sreg = R_DS;
    }
    rm->val = swaddr_read(rm->addr, rm->size);
    return instr_len;
    }
  8. 出现了报错,重复定义,找了一段时间但是没有解决

    尝试做一下任务3

    Problem

Phase3:Page

  1. 添加CR3寄存器,并相应对CR0寄存器进行初始化

    1
    2
    //reg.h
    CR3 cr3;
  2. 修改lnaddr_read()和lnaddr_write()函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    uint32_t lnaddr_read(lnaddr_t addr, size_t len) {
    #ifdef DEBUG
    assert(len == 1 || len == 2 || len == 4);
    #endif
    size_t max_len = ((~addr) & 0xfff) + 1;
    if (len > max_len)
    {
    uint32_t low = lnaddr_read(addr, max_len);
    uint32_t high = lnaddr_read(addr + max_len, len - max_len);
    return (high << (max_len << 3)) | low;
    }
    hwaddr_t hwaddr = page_translate(addr);
    return hwaddr_read(hwaddr, len);
    }

    void lnaddr_write(lnaddr_t addr, size_t len, uint32_t data) {
    #ifdef DEBUG
    assert(len == 1 || len == 2 || len == 4);
    #endif
    size_t max_len = ((~addr) & 0xfff) + 1;
    if (len > max_len)
    {
    lnaddr_write(addr, max_len, data & ((1 << (max_len << 3)) - 1));
    lnaddr_write(addr + max_len, len - max_len, data >> (max_len << 3));
    return;
    }
    hwaddr_t hwaddr = page_translate(addr);
    hwaddr_write(hwaddr, len, data);
    }
  3. 实现page_translate()函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    //memory.c
    hwaddr_t page_translate(lnaddr_t);
    //新建page.c文件
    //page.c
    #include "nemu.h"

    #define DIR(addr) ((addr)>>22)
    #define PAGE(addr) (((addr)>>12) & 0x3ff)
    #define OFFSET(addr) ((addr) & 0xfff)

    hwaddr_t TLB_read(uint32_t);
    void TLB_write(uint32_t ,uint32_t);

    hwaddr_t page_translate(lnaddr_t addr) {
    PAGE_descriptor dir;
    PAGE_descriptor page;
    hwaddr_t hwaddr;
    if (!cpu.cr0.paging || !cpu.cr0.protect_enable)return addr;
    if ((hwaddr = TLB_read(addr)) != -1)return hwaddr + OFFSET(addr);
    dir.page_val = hwaddr_read((cpu.cr3.page_directory_base<<12)+(DIR(addr)<<2), 4);
    Assert(dir.p, "pagevalue = %x eip = %x", dir.page_val,cpu.eip);
    page.page_val = hwaddr_read((dir.addr<<12)+(PAGE(addr)<<2), 4);
    Assert(page.p, "page do not exist at %x", cpu.eip);
    hwaddr = (page.addr<<12)+OFFSET(addr);
    TLB_write(addr, hwaddr);
    return hwaddr;
    }

Problems

  1. 使用PA2答案做PA3,做完PA1后尝试运行。不知道什么原因,发现kernal无法运行,更改opcode_table中的一些指令后即可运行

From 2021/1/6 to 2120/1/17