forked from rcore-os/zCore
Merge remote-tracking branch 'rcore-os/master' into exception
This commit is contained in:
commit
9b256d0568
|
@ -6,22 +6,22 @@ jobs:
|
|||
check:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2020-06-04
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
- name: Check code format
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2020-06-04
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
- name: Check code format
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
@ -29,31 +29,26 @@ jobs:
|
|||
matrix:
|
||||
os: [ubuntu-20.04, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodules
|
||||
shell: bash
|
||||
run: |
|
||||
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
|
||||
git submodule sync --recursive
|
||||
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2020-06-04
|
||||
components: rust-src
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --all-features
|
||||
- name: Build zCore
|
||||
run: |
|
||||
cd zCore
|
||||
make build
|
||||
- name: Build docs
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: doc
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2020-06-04
|
||||
components: rust-src
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
- name: Build zCore
|
||||
run: |
|
||||
cd zCore
|
||||
make build
|
||||
- name: Build zCore with hypervisor
|
||||
run: |
|
||||
cd zCore
|
||||
make build hypervisor=1
|
||||
|
||||
build-aarch64:
|
||||
runs-on: ubuntu-20.04
|
||||
|
@ -69,37 +64,56 @@ jobs:
|
|||
with:
|
||||
command: build
|
||||
use-cross: true
|
||||
args: -p zircon-loader --all-features --target aarch64-unknown-linux-gnu
|
||||
args: -p zircon-loader --target aarch64-unknown-linux-gnu
|
||||
|
||||
build-user:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -I prebuilt/zircon/x64/libc.so,prebuilt/zircon/x64/libfdio.so,prebuilt/zircon/x64/libunwind.so,prebuilt/zircon/x64/libzircon.so,prebuilt/zircon/x64/Scrt1.o
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2020-06-04
|
||||
target: x86_64-fuchsia
|
||||
- name: Build Zircon user programs
|
||||
run: |
|
||||
cd zircon-user
|
||||
make build mode=release
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -X prebuilt/zircon/x64/bringup.zbi prebuilt/zircon/x64/core-tests.zbi prebuilt/zircon/arm64
|
||||
- name: Prepare rootfs
|
||||
run: make rootfs
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all-features --no-fail-fast --workspace --exclude zircon-loader
|
||||
env:
|
||||
CARGO_INCREMENTAL: '0'
|
||||
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off'
|
||||
- name: Cache grcov
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cargo/bin/grcov
|
||||
key: ${{ runner.os }}-grcov
|
||||
- name: Gather coverage data
|
||||
id: coverage
|
||||
uses: actions-rs/grcov@v0.1
|
||||
- name: Coveralls upload
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: ${{ steps.coverage.outputs.report }}
|
||||
- uses: actions/checkout@v2
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -I prebuilt/linux/libc-libos.so
|
||||
- name: Prepare rootfs
|
||||
run: make rootfs
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all-features --no-fail-fast --workspace --exclude zircon-loader
|
||||
env:
|
||||
CARGO_INCREMENTAL: '0'
|
||||
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off'
|
||||
- name: Cache grcov
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cargo/bin/grcov
|
||||
key: ${{ runner.os }}-grcov
|
||||
- name: Gather coverage data
|
||||
id: coverage
|
||||
uses: actions-rs/grcov@v0.1
|
||||
- name: Coveralls upload
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: ${{ steps.coverage.outputs.report }}
|
||||
|
||||
bench:
|
||||
runs-on: ubuntu-20.04
|
||||
|
@ -114,14 +128,10 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -X prebuilt/zircon/x64/bringup.zbi prebuilt/zircon/arm64
|
||||
- name: Checkout submodules
|
||||
shell: bash
|
||||
run: |
|
||||
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
|
||||
git submodule sync --recursive
|
||||
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
|
||||
run: git lfs pull -I prebuilt/zircon/x64/core-tests.zbi,prebuilt/zircon/x64/libzircon.so,prebuilt/zircon/x64/userboot.so
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
|
@ -141,3 +151,20 @@ jobs:
|
|||
cd scripts
|
||||
pip3 install pexpect
|
||||
python3 core-tests.py
|
||||
|
||||
doc:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build docs
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: doc
|
||||
args: --no-deps
|
||||
- name: Deploy to Github Pages
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: target/doc
|
||||
|
|
|
@ -11,6 +11,7 @@ members = [
|
|||
]
|
||||
|
||||
exclude = [
|
||||
"zircon-user",
|
||||
"zCore",
|
||||
"rboot",
|
||||
]
|
||||
|
|
11
README.md
11
README.md
|
@ -25,6 +25,7 @@ Clone repo and pull prebuilt fuchsia images:
|
|||
```sh
|
||||
git clone https://github.com/rcore-os/zCore --recursive
|
||||
cd zCore
|
||||
git lfs install
|
||||
git lfs pull
|
||||
```
|
||||
|
||||
|
@ -58,6 +59,16 @@ Run Zircon on bare-metal (zCore):
|
|||
cd zCore && make run mode=release [graphic=on] [accel=1]
|
||||
```
|
||||
|
||||
Build and run your own Zircon user programs:
|
||||
|
||||
```sh
|
||||
# See template in zircon-user
|
||||
cd zircon-user && make zbi mode=release
|
||||
|
||||
# Run your programs in zCore
|
||||
cd zCore && make run mode=release user=1
|
||||
```
|
||||
|
||||
To debug, set `RUST_LOG` environment variable to one of `error`, `warn`, `info`, `debug`, `trace`.
|
||||
|
||||
## Testing
|
||||
|
|
|
@ -23,7 +23,7 @@ uart_16550 = "0.2.6"
|
|||
raw-cpuid = "8.0"
|
||||
pc-keyboard = "0.5"
|
||||
apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" }
|
||||
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "257d695" }
|
||||
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf" }
|
||||
rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "a980897b" }
|
||||
acpi = "1.0.0"
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use super::*;
|
||||
use kernel_hal::{PageTableTrait, PhysAddr, VirtAddr};
|
||||
use riscv::addr::Page;
|
||||
use riscv::paging::{PageTableFlags as PTF, *};
|
||||
use riscv::register::satp;
|
||||
|
@ -27,57 +28,6 @@ impl PageTableImpl {
|
|||
}
|
||||
}
|
||||
|
||||
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
||||
#[export_name = "hal_pt_map"]
|
||||
pub fn map(
|
||||
&mut self,
|
||||
vaddr: riscv::addr::VirtAddr,
|
||||
paddr: riscv::addr::PhysAddr,
|
||||
flags: MMUFlags,
|
||||
) -> Result<(), ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::of_addr(vaddr);
|
||||
let frame = riscv::addr::Frame::of_addr(paddr);
|
||||
pt.map_to(page, frame, flags.to_ptf(), &mut FrameAllocatorImpl)
|
||||
.unwrap()
|
||||
.flush();
|
||||
trace!("map: {:x?} -> {:x?}, flags={:?}", vaddr, paddr, flags);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unmap the page of `vaddr`.
|
||||
#[export_name = "hal_pt_unmap"]
|
||||
pub fn unmap(&mut self, vaddr: riscv::addr::VirtAddr) -> Result<(), ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::of_addr(vaddr);
|
||||
pt.unmap(page).unwrap().1.flush();
|
||||
trace!("unmap: {:x?}", vaddr);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Change the `flags` of the page of `vaddr`.
|
||||
#[export_name = "hal_pt_protect"]
|
||||
pub fn protect(&mut self, vaddr: riscv::addr::VirtAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::of_addr(vaddr);
|
||||
pt.update_flags(page, flags.to_ptf()).unwrap().flush();
|
||||
trace!("protect: {:x?}, flags={:?}", vaddr, flags);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Query the physical address which the page of `vaddr` maps to.
|
||||
#[export_name = "hal_pt_query"]
|
||||
pub fn query(&mut self, vaddr: riscv::addr::VirtAddr) -> Result<riscv::addr::PhysAddr, ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::of_addr(vaddr);
|
||||
let res = pt.ref_entry(page);
|
||||
trace!("query: {:x?} => {:x?}", vaddr, res);
|
||||
match res {
|
||||
Ok(entry) => Ok(entry.addr()),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
fn get(&mut self) -> Rv32PageTable<'_> {
|
||||
let root_vaddr = phys_to_virt(self.root_paddr);
|
||||
|
@ -93,6 +43,60 @@ impl PageTableImpl {
|
|||
}
|
||||
}
|
||||
|
||||
impl PageTableTrait for PageTableImpl {
|
||||
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
||||
#[export_name = "hal_pt_map"]
|
||||
fn map(&mut self, vaddr: VirtAddr, paddr: PhysAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::of_addr(vaddr);
|
||||
let frame = riscv::addr::Frame::of_addr(riscv::addr::PhysAddr::new(paddr));
|
||||
pt.map_to(page, frame, flags.to_ptf(), &mut FrameAllocatorImpl)
|
||||
.unwrap()
|
||||
.flush();
|
||||
trace!("map: {:x?} -> {:x?}, flags={:?}", vaddr, paddr, flags);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unmap the page of `vaddr`.
|
||||
#[export_name = "hal_pt_unmap"]
|
||||
fn unmap(&mut self, vaddr: VirtAddr) -> Result<(), ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
||||
pt.unmap(page).unwrap().1.flush();
|
||||
trace!("unmap: {:x?}", vaddr);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Change the `flags` of the page of `vaddr`.
|
||||
#[export_name = "hal_pt_protect"]
|
||||
fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
||||
pt.update_flags(page, flags.to_ptf()).unwrap().flush();
|
||||
trace!("protect: {:x?}, flags={:?}", vaddr, flags);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Query the physical address which the page of `vaddr` maps to.
|
||||
#[export_name = "hal_pt_query"]
|
||||
fn query(&mut self, vaddr: VirtAddr) -> Result<riscv::addr::PhysAddr, ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
||||
let res = pt.ref_entry(page);
|
||||
trace!("query: {:x?} => {:x?}", vaddr, res);
|
||||
match res {
|
||||
Ok(entry) => Ok(entry.addr()),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the physical address of root page table.
|
||||
#[export_name = "hal_pt_table_phys"]
|
||||
fn table_phys(&self) -> PhysAddr {
|
||||
self.root_paddr
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn set_page_table(vmtoken: usize) {
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
let mode = satp::Mode::Sv32;
|
||||
|
|
|
@ -9,6 +9,7 @@ use {
|
|||
core::ptr::NonNull,
|
||||
core::time::Duration,
|
||||
git_version::git_version,
|
||||
kernel_hal::PageTableTrait,
|
||||
rcore_console::{Console, ConsoleOnGraphic, DrawTarget, Pixel, Rgb888, Size},
|
||||
spin::Mutex,
|
||||
uart_16550::SerialPort,
|
||||
|
@ -52,19 +53,23 @@ impl PageTableImpl {
|
|||
}
|
||||
}
|
||||
|
||||
fn get(&mut self) -> OffsetPageTable<'_> {
|
||||
let root_vaddr = phys_to_virt(self.root_paddr);
|
||||
let root = unsafe { &mut *(root_vaddr as *mut PageTable) };
|
||||
let offset = x86_64::VirtAddr::new(phys_to_virt(0) as u64);
|
||||
unsafe { OffsetPageTable::new(root, offset) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PageTableTrait for PageTableImpl {
|
||||
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
||||
#[export_name = "hal_pt_map"]
|
||||
pub fn map(
|
||||
&mut self,
|
||||
vaddr: x86_64::VirtAddr,
|
||||
paddr: x86_64::PhysAddr,
|
||||
flags: MMUFlags,
|
||||
) -> Result<(), ()> {
|
||||
fn map(&mut self, vaddr: VirtAddr, paddr: PhysAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
let mut pt = self.get();
|
||||
unsafe {
|
||||
pt.map_to_with_table_flags(
|
||||
Page::<Size4KiB>::from_start_address(vaddr).unwrap(),
|
||||
PhysFrame::from_start_address(paddr).unwrap(),
|
||||
Page::<Size4KiB>::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap(),
|
||||
PhysFrame::from_start_address(x86_64::PhysAddr::new(paddr as u64)).unwrap(),
|
||||
flags.to_ptf(),
|
||||
PTF::PRESENT | PTF::WRITABLE | PTF::USER_ACCESSIBLE,
|
||||
&mut FrameAllocatorImpl,
|
||||
|
@ -84,9 +89,10 @@ impl PageTableImpl {
|
|||
|
||||
/// Unmap the page of `vaddr`.
|
||||
#[export_name = "hal_pt_unmap"]
|
||||
pub fn unmap(&mut self, vaddr: x86_64::VirtAddr) -> Result<(), ()> {
|
||||
fn unmap(&mut self, vaddr: VirtAddr) -> Result<(), ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::<Size4KiB>::from_start_address(vaddr).unwrap();
|
||||
let page =
|
||||
Page::<Size4KiB>::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap();
|
||||
// This is a workaround to an issue in the x86-64 crate
|
||||
// A page without PRESENT bit is not unmappable AND mapable
|
||||
// So we add PRESENT bit here
|
||||
|
@ -111,9 +117,10 @@ impl PageTableImpl {
|
|||
|
||||
/// Change the `flags` of the page of `vaddr`.
|
||||
#[export_name = "hal_pt_protect"]
|
||||
pub fn protect(&mut self, vaddr: x86_64::VirtAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
let mut pt = self.get();
|
||||
let page = Page::<Size4KiB>::from_start_address(vaddr).unwrap();
|
||||
let page =
|
||||
Page::<Size4KiB>::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap();
|
||||
if let Ok(flush) = unsafe { pt.update_flags(page, flags.to_ptf()) } {
|
||||
flush.flush();
|
||||
}
|
||||
|
@ -123,18 +130,19 @@ impl PageTableImpl {
|
|||
|
||||
/// Query the physical address which the page of `vaddr` maps to.
|
||||
#[export_name = "hal_pt_query"]
|
||||
pub fn query(&mut self, vaddr: x86_64::VirtAddr) -> Result<x86_64::PhysAddr, ()> {
|
||||
fn query(&mut self, vaddr: VirtAddr) -> Result<PhysAddr, ()> {
|
||||
let pt = self.get();
|
||||
let ret = pt.translate_addr(vaddr).ok_or(());
|
||||
let ret = pt
|
||||
.translate_addr(x86_64::VirtAddr::new(vaddr as u64))
|
||||
.map(|addr| addr.as_u64() as PhysAddr).ok_or(());
|
||||
trace!("query: {:x?} => {:x?}", vaddr, ret);
|
||||
ret
|
||||
}
|
||||
|
||||
fn get(&mut self) -> OffsetPageTable<'_> {
|
||||
let root_vaddr = phys_to_virt(self.root_paddr);
|
||||
let root = unsafe { &mut *(root_vaddr as *mut PageTable) };
|
||||
let offset = x86_64::VirtAddr::new(phys_to_virt(0) as u64);
|
||||
unsafe { OffsetPageTable::new(root, offset) }
|
||||
/// Get the physical address of root page table.
|
||||
#[export_name = "hal_pt_table_phys"]
|
||||
fn table_phys(&self) -> PhysAddr {
|
||||
self.root_paddr
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ use {
|
|||
async_std::task_local,
|
||||
core::{cell::Cell, future::Future, pin::Pin},
|
||||
git_version::git_version,
|
||||
kernel_hal::PageTableTrait,
|
||||
lazy_static::lazy_static,
|
||||
std::fmt::{Debug, Formatter},
|
||||
std::fs::{File, OpenOptions},
|
||||
|
@ -81,10 +82,12 @@ impl PageTable {
|
|||
pub fn new() -> Self {
|
||||
PageTable { table_phys: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl PageTableTrait for PageTable {
|
||||
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
||||
#[export_name = "hal_pt_map"]
|
||||
pub fn map(&mut self, vaddr: VirtAddr, paddr: PhysAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
fn map(&mut self, vaddr: VirtAddr, paddr: PhysAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
debug_assert!(page_aligned(vaddr));
|
||||
debug_assert!(page_aligned(paddr));
|
||||
let prot = flags.to_mmap_prot();
|
||||
|
@ -94,13 +97,13 @@ impl PageTable {
|
|||
|
||||
/// Unmap the page of `vaddr`.
|
||||
#[export_name = "hal_pt_unmap"]
|
||||
pub fn unmap(&mut self, vaddr: VirtAddr) -> Result<(), ()> {
|
||||
fn unmap(&mut self, vaddr: VirtAddr) -> Result<(), ()> {
|
||||
self.unmap_cont(vaddr, 1)
|
||||
}
|
||||
|
||||
/// Change the `flags` of the page of `vaddr`.
|
||||
#[export_name = "hal_pt_protect"]
|
||||
pub fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
debug_assert!(page_aligned(vaddr));
|
||||
let prot = flags.to_mmap_prot();
|
||||
let ret = unsafe { libc::mprotect(vaddr as _, PAGE_SIZE, prot) };
|
||||
|
@ -110,13 +113,19 @@ impl PageTable {
|
|||
|
||||
/// Query the physical address which the page of `vaddr` maps to.
|
||||
#[export_name = "hal_pt_query"]
|
||||
pub fn query(&mut self, vaddr: VirtAddr) -> Result<PhysAddr, ()> {
|
||||
fn query(&mut self, vaddr: VirtAddr) -> Result<PhysAddr, ()> {
|
||||
debug_assert!(page_aligned(vaddr));
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Get the physical address of root page table.
|
||||
#[export_name = "hal_pt_table_phys"]
|
||||
fn table_phys(&self) -> PhysAddr {
|
||||
self.table_phys
|
||||
}
|
||||
|
||||
#[export_name = "hal_pt_unmap_cont"]
|
||||
pub fn unmap_cont(&mut self, vaddr: VirtAddr, pages: usize) -> Result<(), ()> {
|
||||
fn unmap_cont(&mut self, vaddr: VirtAddr, pages: usize) -> Result<(), ()> {
|
||||
if pages == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
@ -47,6 +47,58 @@ pub fn context_run(_context: &mut UserContext) {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
pub trait PageTableTrait: Sync + Send {
|
||||
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
||||
fn map(&mut self, _vaddr: VirtAddr, _paddr: PhysAddr, _flags: MMUFlags) -> Result<(), ()>;
|
||||
|
||||
/// Unmap the page of `vaddr`.
|
||||
fn unmap(&mut self, _vaddr: VirtAddr) -> Result<(), ()>;
|
||||
|
||||
/// Change the `flags` of the page of `vaddr`.
|
||||
fn protect(&mut self, _vaddr: VirtAddr, _flags: MMUFlags) -> Result<(), ()>;
|
||||
|
||||
/// Query the physical address which the page of `vaddr` maps to.
|
||||
fn query(&mut self, _vaddr: VirtAddr) -> Result<PhysAddr, ()>;
|
||||
|
||||
/// Get the physical address of root page table.
|
||||
fn table_phys(&self) -> PhysAddr;
|
||||
|
||||
fn map_many(
|
||||
&mut self,
|
||||
mut vaddr: VirtAddr,
|
||||
paddrs: &[PhysAddr],
|
||||
flags: MMUFlags,
|
||||
) -> Result<(), ()> {
|
||||
for &paddr in paddrs {
|
||||
self.map(vaddr, paddr, flags)?;
|
||||
vaddr += PAGE_SIZE;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn map_cont(
|
||||
&mut self,
|
||||
mut vaddr: VirtAddr,
|
||||
paddr: PhysAddr,
|
||||
pages: usize,
|
||||
flags: MMUFlags,
|
||||
) -> Result<(), ()> {
|
||||
for i in 0..pages {
|
||||
let paddr = paddr + i * PAGE_SIZE;
|
||||
self.map(vaddr, paddr, flags)?;
|
||||
vaddr += PAGE_SIZE;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unmap_cont(&mut self, vaddr: VirtAddr, pages: usize) -> Result<(), ()> {
|
||||
for i in 0..pages {
|
||||
self.unmap(vaddr + i * PAGE_SIZE)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Page Table
|
||||
#[repr(C)]
|
||||
pub struct PageTable {
|
||||
|
@ -68,66 +120,42 @@ impl PageTable {
|
|||
pub fn new() -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl PageTableTrait for PageTable {
|
||||
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
||||
#[linkage = "weak"]
|
||||
#[export_name = "hal_pt_map"]
|
||||
pub fn map(&mut self, _vaddr: VirtAddr, _paddr: PhysAddr, _flags: MMUFlags) -> Result<(), ()> {
|
||||
fn map(&mut self, _vaddr: VirtAddr, _paddr: PhysAddr, _flags: MMUFlags) -> Result<(), ()> {
|
||||
unimplemented!()
|
||||
}
|
||||
/// Unmap the page of `vaddr`.
|
||||
#[linkage = "weak"]
|
||||
#[export_name = "hal_pt_unmap"]
|
||||
pub fn unmap(&mut self, _vaddr: VirtAddr) -> Result<(), ()> {
|
||||
fn unmap(&mut self, _vaddr: VirtAddr) -> Result<(), ()> {
|
||||
unimplemented!()
|
||||
}
|
||||
/// Change the `flags` of the page of `vaddr`.
|
||||
#[linkage = "weak"]
|
||||
#[export_name = "hal_pt_protect"]
|
||||
pub fn protect(&mut self, _vaddr: VirtAddr, _flags: MMUFlags) -> Result<(), ()> {
|
||||
fn protect(&mut self, _vaddr: VirtAddr, _flags: MMUFlags) -> Result<(), ()> {
|
||||
unimplemented!()
|
||||
}
|
||||
/// Query the physical address which the page of `vaddr` maps to.
|
||||
#[linkage = "weak"]
|
||||
#[export_name = "hal_pt_query"]
|
||||
pub fn query(&mut self, _vaddr: VirtAddr) -> Result<PhysAddr, ()> {
|
||||
fn query(&mut self, _vaddr: VirtAddr) -> Result<PhysAddr, ()> {
|
||||
unimplemented!()
|
||||
}
|
||||
/// Get the physical address of root page table.
|
||||
pub fn table_phys(&self) -> PhysAddr {
|
||||
#[linkage = "weak"]
|
||||
#[export_name = "hal_pt_table_phys"]
|
||||
fn table_phys(&self) -> PhysAddr {
|
||||
self.table_phys
|
||||
}
|
||||
|
||||
pub fn map_many(
|
||||
&mut self,
|
||||
mut vaddr: VirtAddr,
|
||||
paddrs: &[PhysAddr],
|
||||
flags: MMUFlags,
|
||||
) -> Result<(), ()> {
|
||||
for &paddr in paddrs {
|
||||
self.map(vaddr, paddr, flags)?;
|
||||
vaddr += PAGE_SIZE;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn map_cont(
|
||||
&mut self,
|
||||
mut vaddr: VirtAddr,
|
||||
paddr: PhysAddr,
|
||||
pages: usize,
|
||||
flags: MMUFlags,
|
||||
) -> Result<(), ()> {
|
||||
for i in 0..pages {
|
||||
let paddr = paddr + i * PAGE_SIZE;
|
||||
self.map(vaddr, paddr, flags)?;
|
||||
vaddr += PAGE_SIZE;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[linkage = "weak"]
|
||||
#[export_name = "hal_pt_unmap_cont"]
|
||||
pub fn unmap_cont(&mut self, vaddr: VirtAddr, pages: usize) -> Result<(), ()> {
|
||||
fn unmap_cont(&mut self, vaddr: VirtAddr, pages: usize) -> Result<(), ()> {
|
||||
for i in 0..pages {
|
||||
self.unmap(vaddr + i * PAGE_SIZE)?;
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
|||
nightly-2020-06-04
|
||||
nightly-2020-06-04
|
||||
|
|
|
@ -10,6 +10,7 @@ edition = "2018"
|
|||
graphic = []
|
||||
zircon = ["zircon-loader"]
|
||||
linux = ["linux-loader", "linux-object", "rcore-fs-sfs"]
|
||||
hypervisor = ["rvm", "zircon", "zircon-object/hypervisor", "zircon-syscall/hypervisor"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
@ -29,7 +30,9 @@ zircon-object = { path = "../zircon-object" }
|
|||
zircon-loader = { path = "../zircon-loader", default-features = false, optional = true }
|
||||
linux-loader = { path = "../linux-loader", default-features = false, optional = true }
|
||||
linux-object = { path = "../linux-object", default-features = false, optional = true }
|
||||
zircon-syscall = { path = "../zircon-syscall", optional = true }
|
||||
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b", optional = true }
|
||||
rvm = { git = "https://github.com/rcore-os/RVM", rev = "4b64355", optional = true }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
x86_64 = "0.11"
|
||||
|
|
|
@ -4,6 +4,8 @@ zbi_file ?= bringup
|
|||
graphic ?=
|
||||
accel ?=
|
||||
linux ?=
|
||||
user ?=
|
||||
hypervisor ?=
|
||||
smp ?= 1
|
||||
test_filter ?= *.*
|
||||
|
||||
|
@ -14,7 +16,7 @@ kernel_img := $(build_path)/zcore.img
|
|||
ESP := $(build_path)/esp
|
||||
OVMF := ../rboot/OVMF.fd
|
||||
qemu := qemu-system-x86_64
|
||||
OBJDUMP := rust-objdump
|
||||
OBJDUMP := rust-objdump -print-imm-hex -x86-asm-syntax=intel
|
||||
VMDISK := $(build_path)/boot.vdi
|
||||
QEMU_DISK := $(build_path)/disk.qcow2
|
||||
|
||||
|
@ -46,6 +48,11 @@ qemu_opts += \
|
|||
-device isa-debug-exit,iobase=0xf4,iosize=0x04
|
||||
endif
|
||||
|
||||
ifeq ($(hypervisor), 1)
|
||||
build_args += --features hypervisor
|
||||
accel = 1
|
||||
endif
|
||||
|
||||
ifeq ($(accel), 1)
|
||||
ifeq ($(shell uname), Darwin)
|
||||
qemu_opts += -accel hvf
|
||||
|
@ -80,12 +87,19 @@ build-test: build
|
|||
|
||||
build: $(kernel_img)
|
||||
|
||||
build-parallel-test: build $(QEMU_DISK)
|
||||
cp ../prebuilt/zircon/x64/core-tests.zbi $(ESP)/EFI/zCore/fuchsia.zbi
|
||||
echo 'cmdline=LOG=warn:userboot=test/core-standalone-test:userboot.shutdown:core-tests=$(test_filter)' >> $(ESP)/EFI/Boot/rboot.conf
|
||||
|
||||
$(kernel_img): kernel bootloader
|
||||
mkdir -p $(ESP)/EFI/zCore $(ESP)/EFI/Boot
|
||||
cp ../rboot/target/x86_64-unknown-uefi/release/rboot.efi $(ESP)/EFI/Boot/BootX64.efi
|
||||
cp rboot.conf $(ESP)/EFI/Boot/rboot.conf
|
||||
ifeq ($(linux), 1)
|
||||
cp x86_64.img $(ESP)/EFI/zCore/fuchsia.zbi
|
||||
else ifeq ($(user), 1)
|
||||
make -C ../zircon-user
|
||||
cp ../zircon-user/target/zcore.zbi $(ESP)/EFI/zCore/fuchsia.zbi
|
||||
else
|
||||
cp ../prebuilt/zircon/x64/$(zbi_file).zbi $(ESP)/EFI/zCore/fuchsia.zbi
|
||||
endif
|
||||
|
|
|
@ -93,6 +93,35 @@ pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) {
|
|||
pt[PHYSICAL_MEMORY_PM4].set_addr(ephysical.addr(), ephysical.flags() | EF::GLOBAL);
|
||||
}
|
||||
|
||||
#[cfg(feature = "hypervisor")]
|
||||
mod rvm_extern_fn {
|
||||
use super::*;
|
||||
|
||||
#[rvm::extern_fn(alloc_frame)]
|
||||
fn rvm_alloc_frame() -> Option<usize> {
|
||||
hal_frame_alloc()
|
||||
}
|
||||
|
||||
#[rvm::extern_fn(dealloc_frame)]
|
||||
fn rvm_dealloc_frame(paddr: usize) {
|
||||
hal_frame_dealloc(&paddr)
|
||||
}
|
||||
|
||||
#[rvm::extern_fn(phys_to_virt)]
|
||||
fn rvm_phys_to_virt(paddr: usize) -> usize {
|
||||
paddr + PHYSICAL_MEMORY_OFFSET
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[rvm::extern_fn(x86_all_traps_handler_addr)]
|
||||
unsafe fn rvm_x86_all_traps_handler_addr() -> usize {
|
||||
extern "C" {
|
||||
fn __alltraps();
|
||||
}
|
||||
__alltraps as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Global heap allocator
|
||||
///
|
||||
/// Available after `memory::init_heap()`.
|
||||
|
|
|
@ -34,6 +34,7 @@ pub fn create_kcounter_vmo() -> (Arc<VmObject>, Arc<VmObject>) {
|
|||
fn kcounters_arena_start();
|
||||
fn kcounters_arena_end();
|
||||
}
|
||||
use kernel_hal::PageTableTrait;
|
||||
let mut pgtable = kernel_hal::PageTable::current();
|
||||
let paddr = pgtable.query(kcounters_arena_start as usize).unwrap();
|
||||
assert_eq!(
|
||||
|
|
|
@ -9,6 +9,7 @@ description = "Zircon kernel objects"
|
|||
|
||||
[features]
|
||||
elf = ["xmas-elf"]
|
||||
hypervisor = ["rvm"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.2"
|
||||
|
@ -23,7 +24,8 @@ xmas-elf = { version = "0.7", optional = true }
|
|||
region-alloc = { git = "https://github.com/rzswh/region-allocator", rev = "122c7a71" }
|
||||
lazy_static = { version = "1.4", features = ["spin_no_std" ] }
|
||||
acpi = "1.0.0"
|
||||
rvm = { git = "https://github.com/rcore-os/RVM", rev = "4b64355", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
kernel-hal-unix = { path = "../kernel-hal-unix" }
|
||||
async-std = { version = "1.5", features = ["attributes"] }
|
||||
async-std = { version = "1.5", features = ["attributes", "unstable"] }
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
use {
|
||||
crate::{
|
||||
object::*,
|
||||
signal::{Port, PortPacket},
|
||||
vm::VmAddressRegion,
|
||||
},
|
||||
alloc::sync::{Arc, Weak},
|
||||
core::convert::{TryFrom, TryInto},
|
||||
rvm::{Guest as GuestInner, RvmError, RvmExitPacket, RvmPort, RvmResult, TrapKind},
|
||||
rvm::{GuestPhysAddr, GuestPhysMemorySetTrait, HostPhysAddr},
|
||||
};
|
||||
|
||||
pub const GUEST_PHYSICAL_ASPACE_BASE: u64 = 0;
|
||||
pub const GUEST_PHYSICAL_ASPACE_SIZE: u64 = 1 << 36;
|
||||
|
||||
pub struct Guest {
|
||||
base: KObjectBase,
|
||||
_counter: CountHelper,
|
||||
gpm: Arc<GuestPhysMemorySet>,
|
||||
inner: Arc<GuestInner>,
|
||||
}
|
||||
|
||||
impl_kobject!(Guest);
|
||||
define_count_helper!(Guest);
|
||||
|
||||
impl Guest {
|
||||
pub fn new() -> ZxResult<Arc<Self>> {
|
||||
if !rvm::check_hypervisor_feature() {
|
||||
return Err(ZxError::NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
let gpm = GuestPhysMemorySet::new();
|
||||
Ok(Arc::new(Guest {
|
||||
base: KObjectBase::new(),
|
||||
_counter: CountHelper::new(),
|
||||
inner: GuestInner::new(gpm.clone())?,
|
||||
gpm,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn set_trap(
|
||||
&self,
|
||||
kind: u32,
|
||||
addr: usize,
|
||||
size: usize,
|
||||
port: Option<Weak<Port>>,
|
||||
key: u64,
|
||||
) -> ZxResult {
|
||||
let rvm_port = port.map(|p| -> Arc<dyn RvmPort> { Arc::new(GuestPort(p)) });
|
||||
self.inner
|
||||
.set_trap(TrapKind::try_from(kind)?, addr, size, rvm_port, key)
|
||||
.map_err(From::from)
|
||||
}
|
||||
|
||||
pub fn vmar(&self) -> Arc<VmAddressRegion> {
|
||||
self.gpm.vmar.clone()
|
||||
}
|
||||
|
||||
pub fn rvm_guest(&self) -> Arc<GuestInner> {
|
||||
self.inner.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GuestPhysMemorySet {
|
||||
vmar: Arc<VmAddressRegion>,
|
||||
}
|
||||
|
||||
impl GuestPhysMemorySet {
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
vmar: VmAddressRegion::new_guest(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GuestPhysMemorySetTrait for GuestPhysMemorySet {
|
||||
/// Physical address space size.
|
||||
fn size(&self) -> u64 {
|
||||
GUEST_PHYSICAL_ASPACE_SIZE
|
||||
}
|
||||
|
||||
/// Add a contiguous guest physical memory region and create mapping,
|
||||
/// with the target host physical address `hpaddr` (optional).
|
||||
fn map(
|
||||
&self,
|
||||
_gpaddr: GuestPhysAddr,
|
||||
_size: usize,
|
||||
_hpaddr: Option<HostPhysAddr>,
|
||||
) -> RvmResult {
|
||||
// All mappings was created by VMAR, should not call this function.
|
||||
Err(RvmError::NotSupported)
|
||||
}
|
||||
|
||||
/// Remove a guest physical memory region, destroy the mapping.
|
||||
fn unmap(&self, gpaddr: GuestPhysAddr, size: usize) -> RvmResult {
|
||||
self.vmar.unmap(gpaddr, size).map_err(From::from)
|
||||
}
|
||||
|
||||
/// Read from guest address space.
|
||||
fn read_memory(&self, gpaddr: GuestPhysAddr, buf: &mut [u8]) -> RvmResult<usize> {
|
||||
self.vmar.read_memory(gpaddr, buf).map_err(From::from)
|
||||
}
|
||||
|
||||
/// Write to guest address space.
|
||||
fn write_memory(&self, gpaddr: GuestPhysAddr, buf: &[u8]) -> RvmResult<usize> {
|
||||
self.vmar.write_memory(gpaddr, buf).map_err(From::from)
|
||||
}
|
||||
|
||||
/// Called when accessed a non-mapped guest physical adderss `gpaddr`.
|
||||
fn handle_page_fault(&self, gpaddr: GuestPhysAddr) -> RvmResult {
|
||||
if let Some(mapping) = self.vmar.find_mapping(gpaddr) {
|
||||
mapping
|
||||
.handle_page_fault(gpaddr, mapping.get_flags())
|
||||
.map_err(From::from)
|
||||
} else {
|
||||
return Err(RvmError::NotFound);
|
||||
}
|
||||
}
|
||||
|
||||
/// Page table base address.
|
||||
fn table_phys(&self) -> HostPhysAddr {
|
||||
self.vmar.table_phys()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GuestPort(Weak<Port>);
|
||||
|
||||
impl RvmPort for GuestPort {
|
||||
fn send(&self, packet: RvmExitPacket) -> RvmResult {
|
||||
let packet: PortPacket = packet.try_into()?;
|
||||
if let Some(port) = self.0.upgrade() {
|
||||
port.push(packet);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RvmError::BadState)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
//! Objects for Virtual Machine Monitor (hypervisor).
|
||||
|
||||
mod guest;
|
||||
mod vcpu;
|
||||
|
||||
use super::ZxError;
|
||||
use kernel_hal::{MMUFlags, PageTableTrait};
|
||||
use rvm::{
|
||||
ArchRvmPageTable, GuestPhysAddr, HostPhysAddr, IntoRvmPageTableFlags, RvmError, RvmPageTable,
|
||||
};
|
||||
|
||||
pub use guest::{Guest, GUEST_PHYSICAL_ASPACE_BASE, GUEST_PHYSICAL_ASPACE_SIZE};
|
||||
pub use rvm::{TrapKind, VcpuIo, VcpuReadWriteKind, VcpuState};
|
||||
pub use vcpu::Vcpu;
|
||||
|
||||
impl From<RvmError> for ZxError {
|
||||
fn from(e: RvmError) -> Self {
|
||||
match e {
|
||||
RvmError::Internal => Self::INTERNAL,
|
||||
RvmError::NotSupported => Self::NOT_SUPPORTED,
|
||||
RvmError::NoMemory => Self::NO_MEMORY,
|
||||
RvmError::InvalidParam => Self::INVALID_ARGS,
|
||||
RvmError::OutOfRange => Self::OUT_OF_RANGE,
|
||||
RvmError::BadState => Self::BAD_STATE,
|
||||
RvmError::NotFound => Self::NOT_FOUND,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ZxError> for RvmError {
|
||||
fn from(e: ZxError) -> Self {
|
||||
match e {
|
||||
ZxError::INTERNAL => Self::Internal,
|
||||
ZxError::NOT_SUPPORTED => Self::NotSupported,
|
||||
ZxError::NO_MEMORY => Self::NoMemory,
|
||||
ZxError::INVALID_ARGS => Self::InvalidParam,
|
||||
ZxError::OUT_OF_RANGE => Self::OutOfRange,
|
||||
ZxError::BAD_STATE => Self::BadState,
|
||||
ZxError::NOT_FOUND => Self::NotFound,
|
||||
_ => Self::BadState,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VmmPageTable(ArchRvmPageTable);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct VmmPageTableFlags(MMUFlags);
|
||||
|
||||
impl VmmPageTable {
|
||||
pub fn new() -> Self {
|
||||
Self(ArchRvmPageTable::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl PageTableTrait for VmmPageTable {
|
||||
fn map(
|
||||
&mut self,
|
||||
gpaddr: GuestPhysAddr,
|
||||
hpaddr: HostPhysAddr,
|
||||
flags: MMUFlags,
|
||||
) -> Result<(), ()> {
|
||||
self.0
|
||||
.map(gpaddr, hpaddr, VmmPageTableFlags(flags))
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
fn unmap(&mut self, gpaddr: GuestPhysAddr) -> Result<(), ()> {
|
||||
self.0.unmap(gpaddr).map_err(|_| ())
|
||||
}
|
||||
|
||||
fn protect(&mut self, gpaddr: GuestPhysAddr, flags: MMUFlags) -> Result<(), ()> {
|
||||
self.0
|
||||
.protect(gpaddr, VmmPageTableFlags(flags))
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
fn query(&mut self, gpaddr: GuestPhysAddr) -> Result<HostPhysAddr, ()> {
|
||||
self.0.query(gpaddr).map_err(|_| ())
|
||||
}
|
||||
|
||||
fn table_phys(&self) -> HostPhysAddr {
|
||||
self.0.table_phys()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRvmPageTableFlags for VmmPageTableFlags {
|
||||
fn is_read(&self) -> bool {
|
||||
self.0.contains(MMUFlags::READ)
|
||||
}
|
||||
fn is_write(&self) -> bool {
|
||||
self.0.contains(MMUFlags::WRITE)
|
||||
}
|
||||
fn is_execute(&self) -> bool {
|
||||
self.0.contains(MMUFlags::EXECUTE)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
use {
|
||||
crate::{
|
||||
hypervisor::{Guest, VcpuIo, VcpuState},
|
||||
object::*,
|
||||
signal::*,
|
||||
task::{Thread, ThreadFlag},
|
||||
},
|
||||
alloc::sync::Arc,
|
||||
core::convert::TryInto,
|
||||
rvm::{self, Vcpu as VcpuInner},
|
||||
spin::Mutex,
|
||||
};
|
||||
|
||||
pub struct Vcpu {
|
||||
base: KObjectBase,
|
||||
_counter: CountHelper,
|
||||
thread: Arc<Thread>,
|
||||
inner: Mutex<VcpuInner>,
|
||||
}
|
||||
|
||||
impl_kobject!(Vcpu);
|
||||
define_count_helper!(Vcpu);
|
||||
|
||||
impl Vcpu {
|
||||
pub fn new(guest: Arc<Guest>, entry: u64, thread: Arc<Thread>) -> ZxResult<Arc<Self>> {
|
||||
if thread.get_flags().contains(ThreadFlag::VCPU) {
|
||||
return Err(ZxError::BAD_STATE);
|
||||
}
|
||||
let inner = Mutex::new(VcpuInner::new(entry, guest.rvm_guest())?);
|
||||
thread.update_flags(|flags| flags.insert(ThreadFlag::VCPU));
|
||||
Ok(Arc::new(Vcpu {
|
||||
base: KObjectBase::new(),
|
||||
_counter: CountHelper::new(),
|
||||
thread,
|
||||
inner,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn same_thread(&self, current_thread: &Arc<Thread>) -> bool {
|
||||
Arc::ptr_eq(&self.thread, current_thread)
|
||||
}
|
||||
|
||||
pub fn virtual_interrupt(&self, vector: u32) -> ZxResult {
|
||||
self.inner
|
||||
.lock()
|
||||
.virtual_interrupt(vector)
|
||||
.map_err(From::from)
|
||||
}
|
||||
|
||||
pub fn resume(&self) -> ZxResult<PortPacket> {
|
||||
self.inner.lock().resume()?.try_into()
|
||||
}
|
||||
|
||||
pub fn read_state(&self) -> ZxResult<VcpuState> {
|
||||
self.inner.lock().read_state().map_err(From::from)
|
||||
}
|
||||
|
||||
pub fn write_state(&self, state: &VcpuState) -> ZxResult {
|
||||
self.inner.lock().write_state(state).map_err(From::from)
|
||||
}
|
||||
|
||||
pub fn write_io_state(&self, state: &VcpuIo) -> ZxResult {
|
||||
self.inner.lock().write_io_state(state).map_err(From::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Vcpu {
|
||||
fn drop(&mut self) {
|
||||
self.thread
|
||||
.update_flags(|flags| flags.remove(ThreadFlag::VCPU));
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rvm::BellPacket> for PacketGuestBell {
|
||||
fn from(bell: rvm::BellPacket) -> Self {
|
||||
Self {
|
||||
addr: bell.addr,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rvm::IoPacket> for PacketGuestIo {
|
||||
fn from(io: rvm::IoPacket) -> Self {
|
||||
Self {
|
||||
port: io.port,
|
||||
access_size: io.access_size,
|
||||
input: io.input,
|
||||
data: io.data,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rvm::MmioPacket> for PacketGuestMem {
|
||||
fn from(mem: rvm::MmioPacket) -> Self {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
Self {
|
||||
addr: mem.addr,
|
||||
inst_len: mem.inst_len,
|
||||
inst_buf: mem.inst_buf,
|
||||
default_operand_size: mem.default_operand_size,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<PortPacket> for rvm::RvmExitPacket {
|
||||
type Error = ZxError;
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
fn try_into(self) -> ZxResult<PortPacket> {
|
||||
use rvm::RvmExitPacketKind;
|
||||
let data = match self.kind {
|
||||
RvmExitPacketKind::GuestBell => {
|
||||
PayloadRepr::GuestBell(unsafe { self.inner.bell.into() })
|
||||
}
|
||||
RvmExitPacketKind::GuestIo => PayloadRepr::GuestIo(unsafe { self.inner.io.into() }),
|
||||
RvmExitPacketKind::GuestMmio => {
|
||||
PayloadRepr::GuestMem(unsafe { self.inner.mmio.into() })
|
||||
}
|
||||
_ => return Err(ZxError::NOT_SUPPORTED),
|
||||
};
|
||||
Ok(PortPacketRepr {
|
||||
key: self.key,
|
||||
status: ZxError::OK,
|
||||
data,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
}
|
|
@ -24,6 +24,8 @@ extern crate std;
|
|||
pub mod debuglog;
|
||||
pub mod dev;
|
||||
mod error;
|
||||
#[cfg(feature = "hypervisor")]
|
||||
pub mod hypervisor;
|
||||
pub mod ipc;
|
||||
pub mod object;
|
||||
pub mod signal;
|
||||
|
|
|
@ -106,3 +106,35 @@ pub struct HandleInfo {
|
|||
rights: u32,
|
||||
unused: u32,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "unknown type")]
|
||||
fn test_ojb_type_unknown() {
|
||||
let obj: Arc<dyn KernelObject> = DummyObject::new();
|
||||
assert_eq!(1, obj_type(&obj));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_info() {
|
||||
let obj = crate::task::Job::root();
|
||||
let handle1 = Handle::new(obj.clone(), Rights::DEFAULT_JOB);
|
||||
let info1 = handle1.get_info();
|
||||
assert_eq!(info1.obj_type, 17);
|
||||
assert_eq!(info1.props, 1);
|
||||
|
||||
let handle_info = handle1.get_handle_info();
|
||||
assert_eq!(handle_info.obj_type, 17);
|
||||
|
||||
let handle2 = Handle::new(obj, Rights::READ);
|
||||
let info2 = handle2.get_info();
|
||||
assert_eq!(info2.props, 0);
|
||||
|
||||
// Let struct lines counted covered.
|
||||
// See https://github.com/mozilla/grcov/issues/450
|
||||
let _ = HandleBasicInfo::default();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,6 +133,8 @@ pub trait KernelObject: DowncastSync + Debug {
|
|||
fn signal(&self) -> Signal;
|
||||
/// Assert `signal`.
|
||||
fn signal_set(&self, signal: Signal);
|
||||
/// Deassert `signal`.
|
||||
fn signal_clear(&self, signal: Signal);
|
||||
/// Change signal status: first `clear` then `set` indicated bits.
|
||||
///
|
||||
/// All signal callbacks will be called.
|
||||
|
@ -205,24 +207,12 @@ impl KObjectBase {
|
|||
|
||||
/// Create a kernel object base with initial `signal`.
|
||||
pub fn with_signal(signal: Signal) -> Self {
|
||||
KObjectBase {
|
||||
id: Self::new_koid(),
|
||||
inner: Mutex::new(KObjectBaseInner {
|
||||
signal,
|
||||
..Default::default()
|
||||
}),
|
||||
}
|
||||
KObjectBase::with(Default::default(), signal)
|
||||
}
|
||||
|
||||
/// Create a kernel object base with `name`.
|
||||
pub fn with_name(name: &str) -> Self {
|
||||
KObjectBase {
|
||||
id: Self::new_koid(),
|
||||
inner: Mutex::new(KObjectBaseInner {
|
||||
name: String::from(name),
|
||||
..Default::default()
|
||||
}),
|
||||
}
|
||||
KObjectBase::with(name, Default::default())
|
||||
}
|
||||
|
||||
/// Create a kernel object base with both signal and name
|
||||
|
@ -290,7 +280,12 @@ impl KObjectBase {
|
|||
/// If true, the function will never be called again.
|
||||
pub fn add_signal_callback(&self, callback: SignalHandler) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.signal_callbacks.push(callback);
|
||||
// Check the callback immediately, in case that a signal arrives just before the call of
|
||||
// `add_signal_callback` (since lock is acquired inside it) and the callback is not triggered
|
||||
// in time.
|
||||
if !callback(inner.signal) {
|
||||
inner.signal_callbacks.push(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,6 +347,7 @@ impl dyn KernelObject {
|
|||
observed: current_signal,
|
||||
count: 1,
|
||||
timestamp: 0,
|
||||
_reserved1: 0,
|
||||
}),
|
||||
});
|
||||
return;
|
||||
|
@ -370,6 +366,7 @@ impl dyn KernelObject {
|
|||
observed: s,
|
||||
count: 1,
|
||||
timestamp: 0,
|
||||
_reserved1: 0,
|
||||
}),
|
||||
});
|
||||
true
|
||||
|
@ -455,6 +452,9 @@ macro_rules! impl_kobject {
|
|||
fn signal_set(&self, signal: Signal) {
|
||||
self.base.signal_set(signal);
|
||||
}
|
||||
fn signal_clear(&self, signal: Signal) {
|
||||
self.base.signal_clear(signal);
|
||||
}
|
||||
fn signal_change(&self, clear: Signal, set: Signal) {
|
||||
self.base.signal_change(clear, set);
|
||||
}
|
||||
|
@ -524,57 +524,56 @@ impl DummyObject {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use async_std::sync::Barrier;
|
||||
use std::time::Duration;
|
||||
|
||||
#[async_std::test]
|
||||
async fn wait() {
|
||||
let object = DummyObject::new();
|
||||
let flag = Arc::new(AtomicU8::new(0));
|
||||
|
||||
let barrier = Arc::new(Barrier::new(2));
|
||||
async_std::task::spawn({
|
||||
let object = object.clone();
|
||||
let flag = flag.clone();
|
||||
let barrier = barrier.clone();
|
||||
async move {
|
||||
flag.store(1, Ordering::SeqCst);
|
||||
object.base.signal_set(Signal::READABLE);
|
||||
async_std::task::sleep(Duration::from_millis(10)).await;
|
||||
async_std::task::sleep(Duration::from_millis(20)).await;
|
||||
|
||||
flag.store(2, Ordering::SeqCst);
|
||||
object.base.signal_set(Signal::WRITABLE);
|
||||
// Assert an irrelevant signal to test the `false` branch of the callback for `READABLE`.
|
||||
object.signal_set(Signal::USER_SIGNAL_0);
|
||||
object.signal_clear(Signal::USER_SIGNAL_0);
|
||||
object.signal_set(Signal::READABLE);
|
||||
barrier.wait().await;
|
||||
|
||||
object.signal_set(Signal::WRITABLE);
|
||||
}
|
||||
});
|
||||
let object: Arc<dyn KernelObject> = object;
|
||||
assert_eq!(flag.load(Ordering::SeqCst), 0);
|
||||
|
||||
let signal = object.wait_signal(Signal::READABLE).await;
|
||||
assert_eq!(signal, Signal::READABLE);
|
||||
assert_eq!(flag.load(Ordering::SeqCst), 1);
|
||||
barrier.wait().await;
|
||||
|
||||
let signal = object.wait_signal(Signal::WRITABLE).await;
|
||||
assert_eq!(signal, Signal::READABLE | Signal::WRITABLE);
|
||||
assert_eq!(flag.load(Ordering::SeqCst), 2);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn wait_many() {
|
||||
let objs = [DummyObject::new(), DummyObject::new()];
|
||||
let flag = Arc::new(AtomicU8::new(0));
|
||||
|
||||
let barrier = Arc::new(Barrier::new(2));
|
||||
async_std::task::spawn({
|
||||
let objs = objs.clone();
|
||||
let flag = flag.clone();
|
||||
let barrier = barrier.clone();
|
||||
async move {
|
||||
flag.store(1, Ordering::SeqCst);
|
||||
objs[0].base.signal_set(Signal::READABLE);
|
||||
async_std::task::sleep(Duration::from_millis(10)).await;
|
||||
async_std::task::sleep(Duration::from_millis(20)).await;
|
||||
|
||||
flag.store(2, Ordering::SeqCst);
|
||||
objs[1].base.signal_set(Signal::WRITABLE);
|
||||
objs[0].signal_set(Signal::READABLE);
|
||||
barrier.wait().await;
|
||||
|
||||
objs[1].signal_set(Signal::WRITABLE);
|
||||
}
|
||||
});
|
||||
let obj0: Arc<dyn KernelObject> = objs[0].clone();
|
||||
let obj1: Arc<dyn KernelObject> = objs[1].clone();
|
||||
assert_eq!(flag.load(Ordering::SeqCst), 0);
|
||||
|
||||
let signals = wait_signal_many(&[
|
||||
(obj0.clone(), Signal::READABLE),
|
||||
|
@ -582,7 +581,7 @@ mod tests {
|
|||
])
|
||||
.await;
|
||||
assert_eq!(signals, [Signal::READABLE, Signal::empty()]);
|
||||
assert_eq!(flag.load(Ordering::SeqCst), 1);
|
||||
barrier.wait().await;
|
||||
|
||||
let signals = wait_signal_many(&[
|
||||
(obj0.clone(), Signal::WRITABLE),
|
||||
|
@ -590,6 +589,27 @@ mod tests {
|
|||
])
|
||||
.await;
|
||||
assert_eq!(signals, [Signal::READABLE, Signal::WRITABLE]);
|
||||
assert_eq!(flag.load(Ordering::SeqCst), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trait_with_dummy() {
|
||||
let dummy = DummyObject::new();
|
||||
assert_eq!(dummy.name(), String::from(""));
|
||||
dummy.set_name("test");
|
||||
assert_eq!(dummy.name(), String::from("test"));
|
||||
dummy.signal_set(Signal::WRITABLE);
|
||||
assert_eq!(dummy.signal(), Signal::WRITABLE);
|
||||
dummy.signal_change(Signal::WRITABLE, Signal::READABLE);
|
||||
assert_eq!(dummy.signal(), Signal::READABLE);
|
||||
|
||||
assert_eq!(dummy.get_child(0).unwrap_err(), ZxError::WRONG_TYPE);
|
||||
assert_eq!(dummy.peer().unwrap_err(), ZxError::NOT_SUPPORTED);
|
||||
assert_eq!(dummy.related_koid(), 0);
|
||||
assert_eq!(dummy.allowed_signals(), Signal::USER_ALL);
|
||||
|
||||
assert_eq!(
|
||||
format!("{:?}", dummy),
|
||||
format!("DummyObject({}, \"test\")", dummy.id())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,6 +152,12 @@ bitflags! {
|
|||
|
||||
/// TRANSFER | PROPERTY | INSPECT
|
||||
const DEFAULT_EXCEPTION = Self::TRANSFER.bits | Self::PROPERTY.bits | Self::INSPECT.bits;
|
||||
|
||||
/// TRANSFER | DUPLICATE | WRITE | INSPECT | MANAGE_PROCESS
|
||||
const DEFAULT_GUEST = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WRITE.bits | Self::INSPECT.bits | Self::MANAGE_PROCESS.bits;
|
||||
|
||||
/// BASIC | IO | EXECUTE | SIGNAL
|
||||
const DEFAULT_VCPU = Self::BASIC.bits | Self::IO.bits | Self::EXECUTE.bits | Self::SIGNAL.bits;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,3 +168,14 @@ impl TryFrom<u32> for Rights {
|
|||
Self::from_bits(x).ok_or(ZxError::INVALID_ARGS)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_try_from() {
|
||||
assert_eq!(Err(ZxError::INVALID_ARGS), Rights::try_from(0xffff_ffff));
|
||||
assert_eq!(Ok(Rights::SAME_RIGHTS), Rights::try_from(1 << 31));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,3 +68,21 @@ impl Signal {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_verify_user_signal() {
|
||||
assert_eq!(
|
||||
Err(ZxError::INVALID_ARGS),
|
||||
Signal::verify_user_signal(Signal::USER_ALL, 1 << 0)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Ok(Signal::USER_SIGNAL_0),
|
||||
Signal::verify_user_signal(Signal::USER_ALL, 1 << 24)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,9 +47,9 @@ impl From<PortInterruptPacket> for PacketInterrupt {
|
|||
fn from(packet: PortInterruptPacket) -> Self {
|
||||
PacketInterrupt {
|
||||
timestamp: packet.timestamp,
|
||||
reserved0: 0,
|
||||
reserved1: 0,
|
||||
reserved2: 0,
|
||||
_reserved0: 0,
|
||||
_reserved1: 0,
|
||||
_reserved2: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ impl Port {
|
|||
self.base.signal_set(Signal::READABLE);
|
||||
}
|
||||
|
||||
/// Push an `User` type `packet` into the port.
|
||||
/// Push a `User` type `packet` into the port.
|
||||
pub fn push_user(&self, packet: impl Into<PortPacket>) -> ZxResult<()> {
|
||||
let mut packet = packet.into();
|
||||
packet.type_ = PacketType::User;
|
||||
|
@ -177,6 +177,7 @@ mod tests {
|
|||
observed: Signal::WRITABLE,
|
||||
count: 1,
|
||||
timestamp: 0,
|
||||
_reserved1: 0,
|
||||
}),
|
||||
};
|
||||
async_std::task::spawn({
|
||||
|
@ -184,6 +185,9 @@ mod tests {
|
|||
let object = object.clone();
|
||||
let packet2 = packet2.clone();
|
||||
async move {
|
||||
// Assert an irrelevant signal to test the `false` branch of the callback for `READABLE`.
|
||||
object.signal_set(Signal::USER_SIGNAL_0);
|
||||
object.signal_clear(Signal::USER_SIGNAL_0);
|
||||
object.signal_set(Signal::READABLE);
|
||||
async_std::task::sleep(Duration::from_millis(1)).await;
|
||||
port.push(packet2);
|
||||
|
@ -191,21 +195,28 @@ mod tests {
|
|||
});
|
||||
|
||||
let packet = port.wait().await;
|
||||
assert_eq!(
|
||||
PortPacketRepr::from(&packet),
|
||||
PortPacketRepr {
|
||||
key: 1,
|
||||
status: ZxError::OK,
|
||||
data: PayloadRepr::Signal(PacketSignal {
|
||||
trigger: Signal::READABLE,
|
||||
observed: Signal::READABLE,
|
||||
count: 1,
|
||||
timestamp: 0,
|
||||
}),
|
||||
}
|
||||
);
|
||||
let packet_repr = PortPacketRepr {
|
||||
key: 1,
|
||||
status: ZxError::OK,
|
||||
data: PayloadRepr::Signal(PacketSignal {
|
||||
trigger: Signal::READABLE,
|
||||
observed: Signal::READABLE,
|
||||
count: 1,
|
||||
timestamp: 0,
|
||||
_reserved1: 0,
|
||||
}),
|
||||
};
|
||||
assert_eq!(PortPacketRepr::from(&packet), packet_repr);
|
||||
|
||||
let packet = port.wait().await;
|
||||
assert_eq!(PortPacketRepr::from(&packet), packet2);
|
||||
|
||||
// Test asserting signal before `send_signal_to_port_async`.
|
||||
let port = Port::new(0);
|
||||
let object = DummyObject::new() as Arc<dyn KernelObject>;
|
||||
object.signal_set(Signal::READABLE);
|
||||
object.send_signal_to_port_async(Signal::READABLE, &port, 1);
|
||||
let packet = port.wait().await;
|
||||
assert_eq!(PortPacketRepr::from(&packet), packet_repr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,16 +10,13 @@ use core::fmt::{Debug, Formatter};
|
|||
pub struct PortPacket {
|
||||
pub key: u64,
|
||||
pub type_: PacketType,
|
||||
exception_num: u8,
|
||||
_padding: u16,
|
||||
pub status: ZxError,
|
||||
pub data: Payload,
|
||||
}
|
||||
|
||||
// reference: zircon/system/public/zircon/syscalls/port.h ZX_PKT_TYPE_*
|
||||
#[repr(u8)]
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[allow(dead_code)]
|
||||
pub enum PacketType {
|
||||
User = 0,
|
||||
SignalOne = 1,
|
||||
|
@ -29,18 +26,23 @@ pub enum PacketType {
|
|||
GuestIo = 5,
|
||||
GuestVcpu = 6,
|
||||
Interrupt = 7,
|
||||
Exception = 8,
|
||||
PageRequest = 9,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union Payload {
|
||||
user: PacketUser,
|
||||
signal: PacketSignal,
|
||||
exception: PacketException,
|
||||
guest_bell: PacketGuestBell,
|
||||
guest_mem: PacketGuestMem,
|
||||
guest_io: PacketGuestIo,
|
||||
guest_vcpu: PacketGuestVcpu,
|
||||
interrupt: PacketInterrupt,
|
||||
user: [u8; 32],
|
||||
// TODO: PacketPageRequest
|
||||
}
|
||||
|
||||
pub type PacketUser = [u8; 32];
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PacketSignal {
|
||||
|
@ -48,23 +50,99 @@ pub struct PacketSignal {
|
|||
pub observed: Signal,
|
||||
pub count: u64,
|
||||
pub timestamp: u64,
|
||||
pub _reserved1: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PacketGuestBell {
|
||||
pub addr: u64,
|
||||
pub _reserved0: u64,
|
||||
pub _reserved1: u64,
|
||||
pub _reserved2: u64,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PacketGuestMem {
|
||||
pub addr: u64,
|
||||
pub inst_len: u8,
|
||||
pub inst_buf: [u8; 15],
|
||||
pub default_operand_size: u8,
|
||||
pub _reserved: [u8; 7],
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PacketGuestMem {
|
||||
pub addr: u64,
|
||||
pub access_size: u8,
|
||||
pub sign_extend: bool,
|
||||
pub xt: u8,
|
||||
pub read: bool,
|
||||
pub _padding1: [u8; 4],
|
||||
pub data: u64,
|
||||
pub _reserved: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PacketGuestIo {
|
||||
pub port: u16,
|
||||
pub access_size: u8,
|
||||
pub input: bool,
|
||||
pub data: [u8; 4],
|
||||
pub _reserved0: u64,
|
||||
pub _reserved1: u64,
|
||||
pub _reserved2: u64,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum PacketGuestVcpuType {
|
||||
VcpuInterrupt = 0,
|
||||
VcpuStartup = 1,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union PacketGuestVcpuData {
|
||||
interrupt: PacketGuestVcpuInterrupt,
|
||||
startup: PacketGuestVcpuStartup,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PacketException {
|
||||
pub pid: KoID,
|
||||
pub tid: KoID,
|
||||
pub num: u8,
|
||||
pub struct PacketGuestVcpuInterrupt {
|
||||
mask: u64,
|
||||
vector: u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PacketGuestVcpuStartup {
|
||||
id: u64,
|
||||
entry: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PacketGuestVcpu {
|
||||
pub data: PacketGuestVcpuData,
|
||||
pub type_: PacketGuestVcpuType,
|
||||
pub _padding1: [u8; 7],
|
||||
pub _reserved: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PacketInterrupt {
|
||||
pub timestamp: i64,
|
||||
pub reserved0: u64,
|
||||
pub reserved1: u64,
|
||||
pub reserved2: u64,
|
||||
pub _reserved0: u64,
|
||||
pub _reserved1: u64,
|
||||
pub _reserved2: u64,
|
||||
}
|
||||
|
||||
// Rust struct: for internal constructing and debugging
|
||||
|
@ -80,46 +158,49 @@ pub struct PortPacketRepr {
|
|||
/// A high-level representation of a packet payload.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum PayloadRepr {
|
||||
User(PacketUser),
|
||||
Signal(PacketSignal),
|
||||
Exception(PacketException),
|
||||
GuestBell(PacketGuestBell),
|
||||
GuestMem(PacketGuestMem),
|
||||
GuestIo(PacketGuestIo),
|
||||
GuestVcpu(PacketGuestVcpu),
|
||||
Interrupt(PacketInterrupt),
|
||||
User([u8; 32]),
|
||||
}
|
||||
|
||||
impl PayloadRepr {
|
||||
fn exception_num(&self) -> u8 {
|
||||
match self {
|
||||
PayloadRepr::Exception(exception) => exception.num,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
fn type_(&self) -> PacketType {
|
||||
match self {
|
||||
PayloadRepr::User(_) => PacketType::User,
|
||||
PayloadRepr::Signal(_) => PacketType::SignalOne,
|
||||
PayloadRepr::Exception(_) => PacketType::Exception,
|
||||
PayloadRepr::GuestBell(_) => PacketType::GuestBell,
|
||||
PayloadRepr::GuestMem(_) => PacketType::GuestMem,
|
||||
PayloadRepr::GuestIo(_) => PacketType::GuestIo,
|
||||
PayloadRepr::GuestVcpu(_) => PacketType::GuestVcpu,
|
||||
PayloadRepr::Interrupt(_) => PacketType::Interrupt,
|
||||
}
|
||||
}
|
||||
fn encode(&self) -> Payload {
|
||||
match *self {
|
||||
PayloadRepr::Signal(signal) => Payload { signal },
|
||||
PayloadRepr::Exception(exception) => Payload { exception },
|
||||
PayloadRepr::Interrupt(interrupt) => Payload { interrupt },
|
||||
PayloadRepr::User(user) => Payload { user },
|
||||
PayloadRepr::Signal(signal) => Payload { signal },
|
||||
PayloadRepr::GuestBell(guest_bell) => Payload { guest_bell },
|
||||
PayloadRepr::GuestMem(guest_mem) => Payload { guest_mem },
|
||||
PayloadRepr::GuestIo(guest_io) => Payload { guest_io },
|
||||
PayloadRepr::GuestVcpu(guest_vcpu) => Payload { guest_vcpu },
|
||||
PayloadRepr::Interrupt(interrupt) => Payload { interrupt },
|
||||
}
|
||||
}
|
||||
#[allow(unsafe_code)]
|
||||
fn decode(type_: PacketType, exception_num: u8, data: &Payload) -> Self {
|
||||
fn decode(type_: PacketType, data: &Payload) -> Self {
|
||||
unsafe {
|
||||
match type_ {
|
||||
PacketType::User => PayloadRepr::User(data.user),
|
||||
PacketType::SignalOne => PayloadRepr::Signal(data.signal),
|
||||
PacketType::SignalRep => PayloadRepr::Signal(data.signal),
|
||||
PacketType::Exception => PayloadRepr::Exception(PacketException {
|
||||
num: exception_num,
|
||||
..data.exception
|
||||
}),
|
||||
PacketType::GuestBell => PayloadRepr::GuestBell(data.guest_bell),
|
||||
PacketType::GuestMem => PayloadRepr::GuestMem(data.guest_mem),
|
||||
PacketType::GuestIo => PayloadRepr::GuestIo(data.guest_io),
|
||||
PacketType::GuestVcpu => PayloadRepr::GuestVcpu(data.guest_vcpu),
|
||||
PacketType::Interrupt => PayloadRepr::Interrupt(data.interrupt),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
@ -132,8 +213,6 @@ impl From<PortPacketRepr> for PortPacket {
|
|||
PortPacket {
|
||||
key: r.key,
|
||||
type_: r.data.type_(),
|
||||
exception_num: r.data.exception_num(),
|
||||
_padding: 0,
|
||||
status: r.status,
|
||||
data: r.data.encode(),
|
||||
}
|
||||
|
@ -145,13 +224,67 @@ impl From<&PortPacket> for PortPacketRepr {
|
|||
PortPacketRepr {
|
||||
key: p.key,
|
||||
status: p.status,
|
||||
data: PayloadRepr::decode(p.type_, p.exception_num, &p.data),
|
||||
data: PayloadRepr::decode(p.type_, &p.data),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for PacketGuestVcpu {
|
||||
#[allow(unsafe_code)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if !self.type_.eq(&other.type_)
|
||||
|| self._padding1.eq(&other._padding1)
|
||||
|| self._reserved.eq(&other._reserved)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
unsafe {
|
||||
match self.type_ {
|
||||
PacketGuestVcpuType::VcpuInterrupt => self.data.interrupt.eq(&other.data.interrupt),
|
||||
PacketGuestVcpuType::VcpuStartup => self.data.startup.eq(&other.data.startup),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for PacketGuestVcpu {}
|
||||
|
||||
impl Debug for PacketGuestVcpu {
|
||||
#[allow(unsafe_code)]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
let mut out = f.debug_struct("PacketGuestVcpu");
|
||||
unsafe {
|
||||
match self.type_ {
|
||||
PacketGuestVcpuType::VcpuInterrupt => out.field("data", &self.data.interrupt),
|
||||
PacketGuestVcpuType::VcpuStartup => out.field("data", &self.data.startup),
|
||||
};
|
||||
}
|
||||
out.field("type_", &self.type_)
|
||||
.field("_padding1", &self._padding1)
|
||||
.field("_reserved", &self._reserved)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PortPacket {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
PortPacketRepr::from(self).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn port_packet_size() {
|
||||
use core::mem::size_of;
|
||||
assert_eq!(size_of::<PacketUser>(), 32);
|
||||
assert_eq!(size_of::<PacketSignal>(), 32);
|
||||
assert_eq!(size_of::<PacketGuestBell>(), 32);
|
||||
assert_eq!(size_of::<PacketGuestMem>(), 32);
|
||||
assert_eq!(size_of::<PacketGuestIo>(), 32);
|
||||
assert_eq!(size_of::<PacketGuestVcpu>(), 32);
|
||||
assert_eq!(size_of::<PacketInterrupt>(), 32);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use {
|
|||
super::*,
|
||||
crate::object::*,
|
||||
alloc::{boxed::Box, sync::Arc},
|
||||
bitflags::bitflags,
|
||||
core::{
|
||||
any::Any,
|
||||
future::Future,
|
||||
|
@ -126,6 +127,7 @@ struct ThreadInner {
|
|||
killed: bool,
|
||||
/// The time this thread has run on cpu
|
||||
time: u128,
|
||||
flags: ThreadFlag,
|
||||
}
|
||||
|
||||
impl ThreadInner {
|
||||
|
@ -157,6 +159,13 @@ impl ThreadInner {
|
|||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct ThreadFlag: usize {
|
||||
const VCPU = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
/// Create a new thread.
|
||||
pub fn create(proc: &Arc<Process>, name: &str, _options: u32) -> ZxResult<Arc<Self>> {
|
||||
|
@ -489,6 +498,17 @@ impl Thread {
|
|||
pub fn get_first_thread(&self) -> bool {
|
||||
self.inner.lock().first_thread
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> ThreadFlag {
|
||||
self.inner.lock().flags
|
||||
}
|
||||
|
||||
pub fn update_flags<F>(&self, f: F)
|
||||
where
|
||||
F: FnOnce(&mut ThreadFlag),
|
||||
{
|
||||
f(&mut self.inner.lock().flags)
|
||||
}
|
||||
}
|
||||
|
||||
impl Task for Thread {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use core::sync::atomic::*;
|
||||
use {
|
||||
super::*, crate::object::*, alloc::sync::Arc, alloc::vec::Vec, bitflags::bitflags,
|
||||
kernel_hal::PageTable, spin::Mutex,
|
||||
kernel_hal::PageTableTrait, spin::Mutex,
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
|
@ -29,7 +29,7 @@ pub struct VmAddressRegion {
|
|||
addr: VirtAddr,
|
||||
size: usize,
|
||||
parent: Option<Arc<VmAddressRegion>>,
|
||||
page_table: Arc<Mutex<PageTable>>,
|
||||
page_table: Arc<Mutex<dyn PageTableTrait>>,
|
||||
/// If inner is None, this region is destroyed, all operations are invalid.
|
||||
inner: Mutex<Option<VmarInner>>,
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ impl VmAddressRegion {
|
|||
inner: Mutex::new(Some(VmarInner::default())),
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a kernel root VMAR.
|
||||
pub fn new_kernel() -> Arc<Self> {
|
||||
let kernel_vmar_base = 0xffff_ff02_0000_0000; // Sorry i hard code because i'm lazy
|
||||
|
@ -78,6 +79,23 @@ impl VmAddressRegion {
|
|||
})
|
||||
}
|
||||
|
||||
/// Create a VMAR for guest physical memory.
|
||||
#[cfg(feature = "hypervisor")]
|
||||
pub fn new_guest() -> Arc<Self> {
|
||||
let guest_vmar_base = crate::hypervisor::GUEST_PHYSICAL_ASPACE_BASE as usize;
|
||||
let guest_vmar_size = crate::hypervisor::GUEST_PHYSICAL_ASPACE_SIZE as usize;
|
||||
Arc::new(VmAddressRegion {
|
||||
flags: VmarFlags::ROOT_FLAGS,
|
||||
base: KObjectBase::new(),
|
||||
_counter: CountHelper::new(),
|
||||
addr: guest_vmar_base,
|
||||
size: guest_vmar_size,
|
||||
parent: None,
|
||||
page_table: Arc::new(Mutex::new(crate::hypervisor::VmmPageTable::new())),
|
||||
inner: Mutex::new(Some(VmarInner::default())),
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a child VMAR at the `offset`.
|
||||
pub fn allocate_at(
|
||||
self: &Arc<Self>,
|
||||
|
@ -466,6 +484,9 @@ impl VmAddressRegion {
|
|||
pub fn handle_page_fault(&self, vaddr: VirtAddr, flags: MMUFlags) -> ZxResult {
|
||||
let guard = self.inner.lock();
|
||||
let inner = guard.as_ref().unwrap();
|
||||
if !self.contains(vaddr) {
|
||||
return Err(ZxError::NOT_FOUND);
|
||||
}
|
||||
if let Some(child) = inner.children.iter().find(|ch| ch.contains(vaddr)) {
|
||||
return child.handle_page_fault(vaddr, flags);
|
||||
}
|
||||
|
@ -524,7 +545,7 @@ impl VmAddressRegion {
|
|||
}
|
||||
|
||||
/// Find mapping of vaddr
|
||||
fn find_mapping(&self, vaddr: usize) -> Option<Arc<VmMapping>> {
|
||||
pub fn find_mapping(&self, vaddr: usize) -> Option<Arc<VmMapping>> {
|
||||
let guard = self.inner.lock();
|
||||
let inner = guard.as_ref().unwrap();
|
||||
if let Some(mapping) = inner.mappings.iter().find(|map| map.contains(vaddr)) {
|
||||
|
@ -558,7 +579,7 @@ impl VmarInner {
|
|||
fn fork_from(
|
||||
&mut self,
|
||||
src: &Arc<VmAddressRegion>,
|
||||
page_table: &Arc<Mutex<PageTable>>,
|
||||
page_table: &Arc<Mutex<dyn PageTableTrait>>,
|
||||
) -> ZxResult {
|
||||
let src_guard = src.inner.lock();
|
||||
let src_inner = src_guard.as_ref().unwrap();
|
||||
|
@ -585,7 +606,7 @@ pub struct VmarInfo {
|
|||
pub struct VmMapping {
|
||||
flags: MMUFlags,
|
||||
vmo: Arc<VmObject>,
|
||||
page_table: Arc<Mutex<PageTable>>,
|
||||
page_table: Arc<Mutex<dyn PageTableTrait>>,
|
||||
inner: Mutex<VmMappingInner>,
|
||||
}
|
||||
|
||||
|
@ -625,7 +646,7 @@ impl VmMapping {
|
|||
vmo: Arc<VmObject>,
|
||||
vmo_offset: usize,
|
||||
flags: MMUFlags,
|
||||
page_table: Arc<Mutex<PageTable>>,
|
||||
page_table: Arc<Mutex<dyn PageTableTrait>>,
|
||||
) -> Arc<Self> {
|
||||
let mapping = Arc::new(VmMapping {
|
||||
inner: Mutex::new(VmMappingInner {
|
||||
|
@ -663,9 +684,12 @@ impl VmMapping {
|
|||
|
||||
fn unmap(&self) {
|
||||
let inner = self.inner.lock();
|
||||
let mut page_table = self.page_table.lock();
|
||||
self.vmo
|
||||
.unmap_from(&mut page_table, inner.addr, inner.vmo_offset, inner.size);
|
||||
let pages = inner.size / PAGE_SIZE;
|
||||
// TODO inner.vmo_offset unused?
|
||||
self.page_table
|
||||
.lock()
|
||||
.unmap_cont(inner.addr, pages)
|
||||
.expect("failed to unmap")
|
||||
}
|
||||
|
||||
fn fill_in_task_status(&self, task_stats: &mut TaskStatsInfo) {
|
||||
|
@ -783,6 +807,10 @@ impl VmMapping {
|
|||
self.inner.lock().end_addr()
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> MMUFlags {
|
||||
self.flags
|
||||
}
|
||||
|
||||
/// Remove WRITE flag from the mappings for Copy-on-Write.
|
||||
pub(super) fn range_change(&self, offset: usize, len: usize, op: RangeChangeOp) {
|
||||
let inner = self.inner.lock();
|
||||
|
@ -803,7 +831,7 @@ impl VmMapping {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_page_fault(&self, vaddr: VirtAddr, flags: MMUFlags) -> ZxResult {
|
||||
pub fn handle_page_fault(&self, vaddr: VirtAddr, flags: MMUFlags) -> ZxResult {
|
||||
if !self.flags.contains(flags) {
|
||||
return Err(ZxError::ACCESS_DENIED);
|
||||
}
|
||||
|
@ -819,7 +847,7 @@ impl VmMapping {
|
|||
}
|
||||
|
||||
/// Clone VMO and map it to a new page table. (For Linux)
|
||||
fn clone_map(&self, page_table: Arc<Mutex<PageTable>>) -> ZxResult<Arc<Self>> {
|
||||
fn clone_map(&self, page_table: Arc<Mutex<dyn PageTableTrait>>) -> ZxResult<Arc<Self>> {
|
||||
let new_vmo = self.vmo.create_child(false, 0, self.vmo.len())?;
|
||||
let mapping = Arc::new(VmMapping {
|
||||
inner: Mutex::new(self.inner.lock().clone()),
|
||||
|
|
|
@ -8,7 +8,7 @@ use {
|
|||
},
|
||||
bitflags::bitflags,
|
||||
core::ops::Deref,
|
||||
kernel_hal::{CachePolicy, PageTable},
|
||||
kernel_hal::CachePolicy,
|
||||
spin::Mutex,
|
||||
};
|
||||
|
||||
|
@ -44,15 +44,6 @@ pub trait VMObjectTrait: Sync + Send {
|
|||
/// Set the size of the content stored in the VMO in bytes.
|
||||
fn set_content_size(&self, size: usize) -> ZxResult;
|
||||
|
||||
/// Unmap physical memory from `page_table`.
|
||||
fn unmap_from(&self, page_table: &mut PageTable, vaddr: VirtAddr, _offset: usize, len: usize) {
|
||||
// TODO _offset unused?
|
||||
let pages = len / PAGE_SIZE;
|
||||
page_table
|
||||
.unmap_cont(vaddr, pages)
|
||||
.expect("failed to unmap")
|
||||
}
|
||||
|
||||
/// Commit a page.
|
||||
fn commit_page(&self, page_idx: usize, flags: MMUFlags) -> ZxResult<PhysAddr>;
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ description = "Zircon syscalls implementation"
|
|||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
hypervisor = ["zircon-object/hypervisor"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
spin = "0.5"
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
use {
|
||||
super::*,
|
||||
core::mem::size_of,
|
||||
zircon_object::{
|
||||
dev::{Resource, ResourceKind},
|
||||
hypervisor::{Guest, Vcpu, VcpuIo, VcpuReadWriteKind, VcpuState},
|
||||
signal::{Port, PortPacket},
|
||||
vm::VmarFlags,
|
||||
},
|
||||
};
|
||||
|
||||
impl Syscall<'_> {
|
||||
pub fn sys_guest_create(
|
||||
&self,
|
||||
resource: HandleValue,
|
||||
options: u32,
|
||||
mut guest_handle: UserOutPtr<HandleValue>,
|
||||
mut vmar_handle: UserOutPtr<HandleValue>,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"hypervisor.guest_create: resource={:#x?}, options={:?}",
|
||||
resource, options
|
||||
);
|
||||
if options != 0 {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
let proc = self.thread.proc();
|
||||
proc.get_object::<Resource>(resource)?
|
||||
.validate(ResourceKind::HYPERVISOR)?;
|
||||
|
||||
let guest = Guest::new()?;
|
||||
let vmar = guest.vmar();
|
||||
let guest_handle_value = proc.add_handle(Handle::new(guest, Rights::DEFAULT_GUEST));
|
||||
guest_handle.write(guest_handle_value)?;
|
||||
|
||||
let vmar_flags = vmar.get_flags();
|
||||
let mut vmar_rights = Rights::DEFAULT_VMAR;
|
||||
if vmar_flags.contains(VmarFlags::CAN_MAP_READ) {
|
||||
vmar_rights.insert(Rights::READ);
|
||||
}
|
||||
if vmar_flags.contains(VmarFlags::CAN_MAP_WRITE) {
|
||||
vmar_rights.insert(Rights::WRITE);
|
||||
}
|
||||
if vmar_flags.contains(VmarFlags::CAN_MAP_EXECUTE) {
|
||||
vmar_rights.insert(Rights::EXECUTE);
|
||||
}
|
||||
let vmar_handle_value = proc.add_handle(Handle::new(vmar, vmar_rights));
|
||||
vmar_handle.write(vmar_handle_value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sys_guest_set_trap(
|
||||
&self,
|
||||
handle: HandleValue,
|
||||
kind: u32,
|
||||
addr: u64,
|
||||
size: u64,
|
||||
port_handle: HandleValue,
|
||||
key: u64,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"hypervisor.guest_set_trap: handle={:#x?}, kind={:#x?}, addr={:#x?}, size={:#x?}, port_handle={:#x?}, key={:#x?}",
|
||||
handle, kind, addr, size, port_handle, key
|
||||
);
|
||||
let proc = self.thread.proc();
|
||||
let guest = proc.get_object_with_rights::<Guest>(handle, Rights::WRITE)?;
|
||||
let port = if port_handle != INVALID_HANDLE {
|
||||
Some(Arc::downgrade(&proc.get_object_with_rights::<Port>(
|
||||
port_handle,
|
||||
Rights::WRITE,
|
||||
)?))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
guest.set_trap(kind, addr as usize, size as usize, port, key)
|
||||
}
|
||||
|
||||
pub fn sys_vcpu_create(
|
||||
&self,
|
||||
guest_handle: HandleValue,
|
||||
options: u32,
|
||||
entry: u64,
|
||||
mut out: UserOutPtr<HandleValue>,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"hypervisor.vcpu_create: guest_handle={:#x?}, options={:?}, entry={:#x?}",
|
||||
guest_handle, options, entry
|
||||
);
|
||||
if options != 0 {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
let proc = self.thread.proc();
|
||||
let guest = proc.get_object_with_rights::<Guest>(guest_handle, Rights::MANAGE_PROCESS)?;
|
||||
let vcpu = Vcpu::new(guest, entry, self.thread.clone())?;
|
||||
let handle_value = proc.add_handle(Handle::new(vcpu, Rights::DEFAULT_VCPU));
|
||||
out.write(handle_value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sys_vcpu_resume(
|
||||
&self,
|
||||
handle: HandleValue,
|
||||
mut user_packet: UserOutPtr<PortPacket>,
|
||||
) -> ZxResult {
|
||||
info!("hypervisor.vcpu_resume: handle={:#x?}", handle);
|
||||
let proc = self.thread.proc();
|
||||
let vcpu = proc.get_object_with_rights::<Vcpu>(handle, Rights::EXECUTE)?;
|
||||
if !vcpu.same_thread(&self.thread) {
|
||||
return Err(ZxError::BAD_STATE);
|
||||
}
|
||||
let packet = vcpu.resume()?;
|
||||
user_packet.write(packet)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sys_vcpu_interrupt(&self, handle: HandleValue, vector: u32) -> ZxResult {
|
||||
info!(
|
||||
"hypervisor.vcpu_interrupt: handle={:#x?}, vector={:?}",
|
||||
handle, vector
|
||||
);
|
||||
let proc = self.thread.proc();
|
||||
let vcpu = proc.get_object_with_rights::<Vcpu>(handle, Rights::SIGNAL)?;
|
||||
vcpu.virtual_interrupt(vector)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sys_vcpu_read_state(
|
||||
&self,
|
||||
handle: HandleValue,
|
||||
kind: u32,
|
||||
mut user_buffer: UserOutPtr<VcpuState>,
|
||||
buffer_size: usize,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"hypervisor.vcpu_read_state: handle={:#x?}, kind={:?}, buffer_size={:?}",
|
||||
handle, kind, buffer_size
|
||||
);
|
||||
if kind != VcpuReadWriteKind::VcpuState as u32 || buffer_size != size_of::<VcpuState>() {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
let proc = self.thread.proc();
|
||||
let vcpu = proc.get_object_with_rights::<Vcpu>(handle, Rights::READ)?;
|
||||
if !vcpu.same_thread(&self.thread) {
|
||||
return Err(ZxError::BAD_STATE);
|
||||
}
|
||||
let state = vcpu.read_state()?;
|
||||
user_buffer.write(state)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sys_vcpu_write_state(
|
||||
&self,
|
||||
handle: HandleValue,
|
||||
kind: u32,
|
||||
user_buffer: usize,
|
||||
buffer_size: usize,
|
||||
) -> ZxResult {
|
||||
info!(
|
||||
"hypervisor.vcpu_write_state: handle={:#x?}, kind={:?}, user_buffer={:#x?}, buffer_size={:?}",
|
||||
handle, kind, user_buffer, buffer_size
|
||||
);
|
||||
let proc = self.thread.proc();
|
||||
let vcpu = proc.get_object_with_rights::<Vcpu>(handle, Rights::WRITE)?;
|
||||
if !vcpu.same_thread(&self.thread) {
|
||||
return Err(ZxError::BAD_STATE);
|
||||
}
|
||||
|
||||
match VcpuReadWriteKind::try_from(kind) {
|
||||
Ok(VcpuReadWriteKind::VcpuState) => {
|
||||
if buffer_size != size_of::<VcpuState>() {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
let state: UserInPtr<VcpuState> = user_buffer.into();
|
||||
vcpu.write_state(&state.read()?)?;
|
||||
}
|
||||
Ok(VcpuReadWriteKind::VcpuIo) => {
|
||||
if buffer_size != size_of::<VcpuIo>() {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
let state: UserInPtr<VcpuIo> = user_buffer.into();
|
||||
vcpu.write_io_state(&state.read()?)?;
|
||||
}
|
||||
Err(_) => return Err(ZxError::INVALID_ARGS),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -32,6 +32,8 @@ mod exception;
|
|||
mod fifo;
|
||||
mod futex;
|
||||
mod handle;
|
||||
#[cfg(feature = "hypervisor")]
|
||||
mod hypervisor;
|
||||
mod object;
|
||||
mod pci;
|
||||
mod port;
|
||||
|
@ -355,6 +357,22 @@ impl Syscall<'_> {
|
|||
warn!("ioports.request: skip");
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "hypervisor")]
|
||||
Sys::GUEST_CREATE => self.sys_guest_create(a0 as _, a1 as _, a2.into(), a3.into()),
|
||||
#[cfg(feature = "hypervisor")]
|
||||
Sys::GUEST_SET_TRAP => {
|
||||
self.sys_guest_set_trap(a0 as _, a1 as _, a2 as _, a3 as _, a4 as _, a5 as _)
|
||||
}
|
||||
#[cfg(feature = "hypervisor")]
|
||||
Sys::VCPU_CREATE => self.sys_vcpu_create(a0 as _, a1 as _, a2 as _, a3.into()),
|
||||
#[cfg(feature = "hypervisor")]
|
||||
Sys::VCPU_RESUME => self.sys_vcpu_resume(a0 as _, a1.into()),
|
||||
#[cfg(feature = "hypervisor")]
|
||||
Sys::VCPU_INTERRUPT => self.sys_vcpu_interrupt(a0 as _, a1 as _),
|
||||
#[cfg(feature = "hypervisor")]
|
||||
Sys::VCPU_READ_STATE => self.sys_vcpu_read_state(a0 as _, a1 as _, a2.into(), a3 as _),
|
||||
#[cfg(feature = "hypervisor")]
|
||||
Sys::VCPU_WRITE_STATE => self.sys_vcpu_write_state(a0 as _, a1 as _, a2, a3 as _),
|
||||
_ => {
|
||||
error!("syscall unimplemented: {:?}", sys_type);
|
||||
Err(ZxError::NOT_SUPPORTED)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#![allow(dead_code)]
|
||||
use {
|
||||
super::*,
|
||||
alloc::boxed::Box,
|
||||
zircon_object::{signal::Event, task::Job},
|
||||
};
|
||||
|
||||
|
@ -21,10 +20,8 @@ impl Syscall<'_> {
|
|||
let proc = self.thread.proc();
|
||||
proc.get_object_with_rights::<Job>(root_job, Rights::MANAGE_PROCESS)?
|
||||
.check_root_job()?;
|
||||
// TODO: out-of-memory event
|
||||
let event = Event::new();
|
||||
event.add_signal_callback(Box::new(|_| {
|
||||
panic!("Out Of Memory!");
|
||||
}));
|
||||
let event_handle = proc.add_handle(Handle::new(event, Rights::DEFAULT_EVENT));
|
||||
out.write(event_handle)?;
|
||||
Ok(())
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[build]
|
||||
target = "x86_64-fuchsia"
|
||||
|
||||
[target.x86_64-fuchsia]
|
||||
rustflags = [
|
||||
"-L", "../prebuilt/zircon/x64",
|
||||
]
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "zircon-user"
|
||||
version = "0.1.0"
|
||||
authors = ["Runji Wang <wangrunji0408@163.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,33 @@
|
|||
mode ?= debug
|
||||
|
||||
ZBI_IN := ../prebuilt/zircon/x64/bringup.zbi
|
||||
ZBI_OUT := target/zcore.zbi
|
||||
BUILD_DIR := target/x86_64-fuchsia/$(mode)
|
||||
BOOTFS := $(BUILD_DIR)/bootfs
|
||||
BINS := $(patsubst src/bin/%.rs, $(BOOTFS)/bin/%, $(wildcard src/bin/*.rs))
|
||||
|
||||
ifeq ($(mode), release)
|
||||
BUILD_ARGS += --release
|
||||
endif
|
||||
|
||||
ifeq ($(shell uname), Darwin)
|
||||
ZBI_CLI := ../prebuilt/zircon/x64/zbi-macos
|
||||
else
|
||||
ZBI_CLI := ../prebuilt/zircon/x64/zbi-linux
|
||||
endif
|
||||
|
||||
.PHONY: zbi
|
||||
|
||||
all: zbi
|
||||
|
||||
zbi: $(ZBI_OUT)
|
||||
|
||||
build:
|
||||
cargo build $(BUILD_ARGS)
|
||||
|
||||
$(BOOTFS)/bin/%: $(BUILD_DIR)/%
|
||||
mkdir -p $(BOOTFS)/bin
|
||||
cp $^ $@
|
||||
|
||||
$(ZBI_OUT): build $(BINS)
|
||||
$(ZBI_CLI) $(ZBI_IN) $(BOOTFS) -o $@
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
println!("Hello, zCore!");
|
||||
}
|
Loading…
Reference in New Issue