Code Monkey home page Code Monkey logo

Comments (3)

bokdeuk-jeong avatar bokdeuk-jeong commented on July 20, 2024 1

https://developer.arm.com/documentation/ddi0615/ad/?lang=en

If execution is using the Realm EL1&0 translation regime, any attempt to execute an instruction fetched from physical memory other than the Realm physical address space causes a stage 2 Permission fault.

Inst abort로 발생한 페이지는 모두 Realm PAS에 매핑해야함. (RMM 구현에 반영되어 있다.)

If the stage 2 translation for a Realm stage 1 translation table walk resolves to an address not in the Realm physical address space, it causes a stage 2 Permission fault.

--> 모든 메모리 페이지에 대해 translation walk했을 때 Realm PAS가 아니면 무조건 permission fault가 발생한다는 뜻인가???
문제가 발생하는 페이지는 ESR_EL2의 EC, DFSC를 decode하면 실제로도 항상 s1ptw=1 (translation walk 중에 발생했다는 뜻)이고 permission fault로 나온다. 하지만, Data page에 대해 모두 NS PAS로 지정하면, fault발생한 instruction으로 resume하면 다시 에러가 발생하지는 않고, VM에서 같은 페이지를 다시 액세스 했을 때 일부 페이지들만 permission fault가 발생한다. 설명과 실제 해 본 결과에 차이가 있어서 확인 중

[ ARM community에 문의]
Realm이 사용하는 S1 테이블도 Realm PAS에 있어야 하는데, 내가 설정한 건 normal world가 공유해주는 (non-sec pas에 있는) 메모리에다 linux realm이 page table 만들도록 해버려서 permission 에러가 난 것. (S2는 RMM이 자기 메모리 영역에다 할당해서 Realm PAS에 있다)
https://community.arm.com/support-forums/f/architectures-and-processors-forum/53883/rme-how-to-share-memory-pages-in-non-sec-pas-with-a-realm/179571

from islet.

bokdeuk-jeong avatar bokdeuk-jeong commented on July 20, 2024

[ realm VM 메모리는 가급적 NS PAS에 매핑 한 채 공유해서 사용하기 정리]

  1. Instruction memory page는 모두 realm PAS에 매핑한다. (RME supplement)
  2. 나머지는 NS PAS에 그대로 두고 realm이 ns 꺼를 share 하도록 S2 pte 설정 (ns bit, bits[55] = 1)
  3. 실행하다가 Data memory page 중에 RMM으로 data abort 발생 한 것 중에 s1ptw bit: 1, permission fault 은 (이미 S2 page table에는 있지만 permission fault가 발생한 것으로) realm PAS로 매핑을 변경해 준다.

2번 s1ptw, permission fault가 발생한 data page는 Realm 커널에서 page table용도로 사용하는 메모리이며, 아래의 요건 때문에 Realm PAS에 존재해야 하는데 NS로 default 설정해 놓아서 permission fault가 발생.

If the stage 2 translation for a Realm stage 1 translation table walk resolves to an address not in the Realm physical address space, it causes a stage 2 Permission fault.

추가로 고려한 것.

  1. Unknown location of page tables: 메모리 중에 realm 커널이 어느 메모리를 page 용도로 사용할 지 알수 없다.
  2. Dyanmic use: 그리고 메모리의 용도가 중간에 변경되기도 한다. 예: user process용 page table을 생성했다가 process가 종료되고 나면 해당 메모리를 다른 용도(예: virtio의 virtqueue)로 할당 할 수 도 있다.

해결 방법:

  1. S1PTW set, permission fault 로 인한 data abort page: Realm에서 발생해서 RMM이 exception 처리하므로, GPT를 realm PAS로 업데이트 한다.
  2. 이미 Realm PAS로 할당해준 메모리를 NS가 접근할 때; (예: Realm에서 page table용으로 사용하던 메모리를 virtque로 할당해서, NS에서 이걸 접근할 때) KVM 또는 QEMU에서 data abort, GPT fault (ISS: 0x24)가 발생해서 NS kernel에서 처리 ==> 커널코드를 수정해서 RMM에게 NS로 다시 돌려달라고 undelegate 요청을 보낸다.

이 때 S2 page table update에도 NS bit을 세팅 해줘야 하는데, qemu process에서 data abort가 발생하면 kvm 자료구조를 얻을 수가 없다. (kvm 자료구조는 /dev/kvm device file 액세스 했을 때 private data로 있어서). 그래서 realm vm 자료 구조를 액세스 하기 복잡해서 IPA를 얻을 수가 없다.

이렇게 되면 메모리는 NS PAS에 있는데 realm VM의 S2 page table에는 여전히 NS bit가 세팅안돼 있어서 Realm PAS에 있는 것처럼 설정이 이상하게 된 채로 남아있다. 이 상태에서 realm에서 메모리를 액세스하려고 시도하다가 translation table walk 가 발생하면 이 불일치 상태로 data abort가 realm kernel 내에서 발생한다. ==> realm kernel의 data abort 처리 루틴을 수정해서 GPT fault로 인한 거면 새로 정의한 RSI 인터페이스로 메모리 페이지를 다시 공유해달라고 RMM에 요청한다.

[코드]
RMM: 0d01ee1
NW linux: https://github.com/Samsung/islet-linux/commit/908551e3103721de3ac6646a9a8aa4a644f96bac
guest linux 패치: islet-project/assets@e18af58

실행한 qemu 커맨드

../qemu-system-aarch64_islet \
        -kernel Image_realmvm \
        -initrd initramfs-busybox-aarch64.cpio.gz \
        -append "earlycon=pl011,mmio,0x1c0a0000 console=ttyAMA0 ssbd=force-off" \
        --enable-kvm \
        -cpu host \
        -smp 1 \
        -M virt,gic-version=3 \
        -device virtio-blk-device,drive=blk0 \
        -drive if=none,id=blk0,file=boot.img,format=raw,file.locking=off \
        -object rng-random,filename=/dev/hwrng,id=rng0 \
        -device virtio-rng-device,rng=rng0 \
        -m 256M \
        -nographic

virtio-blk-pci도 동작하는 것 확인완료

특이사항: virtio-mmio에서도 마찬가지이고 virtio-pci도 동일한 증상인데, deivce status reset reqeust를 qemu에 있는 virtio backend에 전송하면 qemu에서 vcpu를 아예 reset해 버린다. 그래서 device driver(virtio-mmio, virtio-pci-modern 에 reset 요청 하는 부분만 comment out해버림)

from islet.

bokdeuk-jeong avatar bokdeuk-jeong commented on July 20, 2024

[ realm 내 virtio device가 probe 단계에서 virtio status를 reset으로 설정하면 panic 나는 이유 분석 ]

virtio_mmio_probe base()   drivers/virtio/virtio_mmio.c
    - set platform drv data()
    - register_virtio_device()   drivers/virtio/virtio.c
        - device_initailize()
        - ida_alloc()
        - dev_set_name()
        - virtio_device_of_init()
        - dev->vqs initalized()
        - virtio_reset_devie()  drivers/virtio/virtio.c
            - virtio_break_device()
            - virtio_synchronize_cbs()
            - dev->config->reset()
                - vm_reset() drivers/virtio/virtio_mmio.c

static void vm_reset(struct virtio_device *vdev)
{
    struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);

    /* 0 status means a reset. */
    writel(0, vm_dev->base + VIRTIO_MMIO_STATUS);
}

이 reset request로 vcpu context가 reset과 비슷해짐
이 request가 trap돼서 kvm으로 전달하자마자 SetReg RMI가 reg 0 ~ 31번까지 설정이 됐다.
아래는 realm이 vm_reset() 호출후 RMM이 kvm으로 부터 받은 reqeust

[DEBUG]armv9a::rmi::realm -- received VMSetReg Reg[32]=0x400003C5 to VCPU 0 on VM 0
[DEBUG]armv9a::rmi::realm -- received VMSetReg Reg[31]=0x400062C0 to VCPU 0 on VM 0
[DEBUG]armv9a::rmi::realm -- received VMRun VCPU 0 on VM 0 PC_INCR 1

PC (Reg[31]=0x400062C0 )를 설정한 후 PC_INCR 이 true(1) 이니까 위의 커널 패닉 메시지처럼 00000000400062c4 에서 에러가 발생

왜 device reset이 vcpu context 설정을 바꾼건가?

realm에서 writel(0, vm_dev->base + VIRTIO_MMIO_STATUS); 호출 이후 QEMU 내부 처리 시퀀스

virtio_set_status()
    k->set_status() name:virtio-net
        -> virtio_bus_reset()  ./hw/virtio/virtio-bus.c
            -> virtio_reset()  ./hw/virtio/virtio.c
                -> virtio_set_status(vdev, 0) name:virtio-net
                    -> vdev->device_endian = virtio_current_cpu_endian() (LITTLE)
                        -> cpu_virtio_is_big_endian() ./hw/core/cpu-sysemu.c
                            -> cc->sysemu_ops->virtio_is_big_endian()
                            == arm_sysemu_ops->virtio_is_big_endian()
                                -> cpu_synchronize_state()
                                    -> cpus_accel->synchronize_state() ./softmmu/cpus.c
                                    ==
                                    -> kvm_cpu_synchronize_state() ../accel/kvm/kvm-all.c 
                                        -> do_kvm_synchronize_state()
                                            -> do_kvm_cpu_synchronize_state() ./accel/kvm/kvm-all.c:
                                               ->  kvm_arch_get_registers(cpu);  // KVM에서 register 값들을 읽어옴
                                               -> vcpu_dirty = true  // 이부분 때문에 발생
                -> k->reset() 
          ../hw/virtio/virtio.c:virtio_reset() end

MMIO 처리를 마친 후 QEMU kvm run loop에서 vcpu_dirty이면

kvm_cpu_exec() ./accel/kvm/kvm-all.c:
-> if( vcpu_dirty == true) kvm_arch_put_registers(cpu,  KVM_PUT_RUNTIME_STATE) 
     --> ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg); 

각 레지스터 마다 이렇게 부르는데, env에 저장해 둔 레지스터값을 갖고 세팅. 이 값은 사전에 do_kvm_cpu_synchronize_state()에서 kvm ioctl(dev, KVM_GET_ONE_REG, ..)로 미리 받아와 세팅해 둔 값인 듯
우리는 RMM이 normal world로 노출하지 않으니 정상 동작을 할 수 가 없다. 아래는 nw vm 실행했을 때의 값

kvm_arch_put_registers() ../target/arm/kvm64.c
reg[0: id=6030000000100000]=ffffffc008a65014
reg[1:id= 6030000000100002]=0
reg[2:6030000000100004]=0
reg[3:6030000000100006]=0
reg[4:6030000000100008]=c0000e
reg[5:603000000010000a]=410fd0f0
reg[6:603000000010000c]=cc77ac00
reg[7:603000000010000e]=1
reg[8:6030000000100010]=ffffff8000ca09b0
reg[9:6030000000100012]=ffffffc00800b860
                   .... 
reg[30:603000000010003c]=ffffffc0084f5570
sp_el0 reg[603000000010003e]=ffffff8000ca0000
sp_el1 reg[6030000000100044]=ffffffc00800baa0
pstate reg[6030000000100042]=60400005
pc reg[6030000000100040]=ffffffc00840fd10
elr_el1 reg[6030000000100046]=ffffffc0080a4d10
spsr[0]=reg[6030000000100048]=60400005
spsr[1]=reg[603000000010004a]=0
spsr[2]=reg[603000000010004c]=0
spsr[3]=reg[603000000010004e]=0
spsr[4]=reg[6030000000100050]=0
vfp, sve 등도 설정

qemu가 알고 있는 realm의 vcpu context는 realm은 qemu가 초기에 세팅한 값 또는 realm 실행하다 kvm이 처리하면서 알아내거나 업데이트한 값을 갖고 있음

reg[0:6030000000100000]=90
reg[1:6030000000100002]=1001
reg[2:6030000000100004]=1
         ...
reg[30:603000000010003c]=0
sp_el0 reg[603000000010003e]=0
sp_el1 reg[6030000000100044]=0
pstate reg[6030000000100042]=400003c5
pc reg[6030000000100040]=40015cd4
elr_el1 reg[6030000000100046]=0
spsr[0]=reg[6030000000100048]=0
spsr[1]=reg[603000000010004a]=0
spsr[2]=reg[603000000010004c]=0
spsr[3]=reg[603000000010004e]=0
spsr[4]=reg[6030000000100050]=0

처리 방향:

  1. (방안1) realm에서 virtio status update를 reset 단계에는 하지 않는다. : 어차피 부팅할 때 reset을 해놨기 때문에 virtio 장치는 초기화가 돼 있는 상태라, realm 부팅 단계에 또 reset을 하지는 않아도 됨. 단점. realm 커널(realm-linux, realm-android, osv...)마다 수정 필요. reset하면서 vcpu context 이외 virtio쪽 다른 정보 설정 하는 코드도 있으므로 너무 광범위하게 disable하는 셈
  2. (방안2, 채택안) qemu를 수정해서 endianess를 확인하는 부분에서 cpu synchronize를 시키는 함수 호출을 생략 시켜버린다: realm부팅 이후 문제가 되는 부분은 현재 (virtion reset 하면서) endianess check하는 부분이므로 qemu code disable 범위가 적어 최대한 원래 qemu가 동작하는 방식으로 동작.
  3. RMM또는 KVM layer에서 처리: 좀 더 고민이 필요한 부분이므로 향후에 고려

from islet.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.