Merge remote-tracking branch 'rcore-os/master' into exception

This commit is contained in:
Ben Pig Chu 2020-08-04 23:49:38 +08:00
commit 9b256d0568
41 changed files with 1354 additions and 302 deletions

View File

@ -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

View File

@ -11,6 +11,7 @@ members = [
]
exclude = [
"zircon-user",
"zCore",
"rboot",
]

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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
}
}

View File

@ -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(());
}

View File

@ -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)?;
}

BIN
prebuilt/zircon/x64/Scrt1.o (Stored with Git LFS) Normal file

Binary file not shown.

BIN
prebuilt/zircon/x64/libc.so (Stored with Git LFS) Normal file

Binary file not shown.

BIN
prebuilt/zircon/x64/libfdio.so (Stored with Git LFS) Normal file

Binary file not shown.

BIN
prebuilt/zircon/x64/libunwind.so (Stored with Git LFS) Normal file

Binary file not shown.

BIN
prebuilt/zircon/x64/zbi-linux (Stored with Git LFS) Executable file

Binary file not shown.

BIN
prebuilt/zircon/x64/zbi-macos (Stored with Git LFS) Executable file

Binary file not shown.

View File

@ -1 +1 @@
nightly-2020-06-04
nightly-2020-06-04

View File

@ -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"

View File

@ -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

View File

@ -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()`.

View File

@ -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!(

View File

@ -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"] }

View File

@ -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)
}
}
}

View File

@ -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)
}
}

View File

@ -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())
}
}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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())
);
}
}

View File

@ -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));
}
}

View File

@ -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)
);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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()),

View File

@ -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>;

View File

@ -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"

View File

@ -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(())
}
}

View File

@ -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)

View File

@ -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(())

View File

@ -0,0 +1,7 @@
[build]
target = "x86_64-fuchsia"
[target.x86_64-fuchsia]
rustflags = [
"-L", "../prebuilt/zircon/x64",
]

9
zircon-user/Cargo.toml Normal file
View File

@ -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]

33
zircon-user/Makefile Normal file
View File

@ -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 $@

View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, zCore!");
}