diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index ad600a4..ddd3b5f 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -2,24 +2,45 @@ name: check on: [push, pull_request] jobs: build: - name: cargo build runs-on: ubuntu-latest + strategy: + matrix: + arch: + - x86_64 + - aarch64 + env: + TARGET_ARCH: "${{ matrix.arch }}" + name: cargo build ${{ matrix.arch }} steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - run: ./hack/ci/install-deps.sh - run: ./hack/build/cargo.sh build test: - name: cargo test runs-on: ubuntu-latest + strategy: + matrix: + arch: + - x86_64 + - aarch64 + env: + TARGET_ARCH: "${{ matrix.arch }}" + name: cargo test ${{ matrix.arch }} steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - run: ./hack/ci/install-deps.sh - run: ./hack/build/cargo.sh test clippy: - name: cargo clippy runs-on: ubuntu-latest + strategy: + matrix: + arch: + - x86_64 + - aarch64 + env: + TARGET_ARCH: "${{ matrix.arch }}" + name: cargo clippy ${{ matrix.arch }} steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable @@ -27,6 +48,23 @@ jobs: components: clippy - run: ./hack/ci/install-deps.sh - run: ./hack/build/cargo.sh clippy + initrd: + runs-on: ubuntu-latest + strategy: + matrix: + arch: + - x86_64 + - aarch64 + env: + TARGET_ARCH: "${{ matrix.arch }}" + name: initrd ${{ matrix.arch }} + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: "${{ matrix.arch }}-unknown-linux-gnu,${{ matrix.arch }}-unknown-linux-musl" + - run: ./hack/ci/install-deps.sh + - run: ./hack/initrd/build.sh fmt: name: cargo fmt runs-on: ubuntu-latest @@ -37,16 +75,6 @@ jobs: components: rustfmt - run: ./hack/ci/install-deps.sh - run: ./hack/build/cargo.sh fmt --all -- --check - initrd: - name: initrd - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - with: - targets: "x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl" - - run: ./hack/ci/install-deps.sh - - run: ./hack/initrd/build.sh shellcheck: name: shellcheck runs-on: ubuntu-latest diff --git a/.github/workflows/kernel.yml b/.github/workflows/kernel.yml index c5d0a17..b913e13 100644 --- a/.github/workflows/kernel.yml +++ b/.github/workflows/kernel.yml @@ -10,10 +10,18 @@ on: - "hack/ci/**" jobs: build: - name: build runs-on: ubuntu-latest + strategy: + matrix: + arch: + - x86_64 + - aarch64 + env: + TARGET_ARCH: "${{ matrix.arch }}" + name: build ${{ matrix.arch }} steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable - run: ./hack/ci/install-deps.sh - run: ./hack/kernel/build.sh env: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 9037f72..de7d1be 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -5,43 +5,50 @@ on: - cron: "0 10 * * *" jobs: build: - name: build runs-on: ubuntu-latest + strategy: + matrix: + arch: + - x86_64 + - aarch64 + env: + TARGET_ARCH: "${{ matrix.arch }}" + name: build ${{ matrix.arch }} steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: - targets: "x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl" + targets: "${{ matrix.arch }}-unknown-linux-gnu,${{ matrix.arch }}-unknown-linux-musl" - run: ./hack/ci/install-deps.sh - run: ./hack/dist/bundle.sh env: KRATA_KERNEL_BUILD_JOBS: "5" - uses: actions/upload-artifact@v4 with: - name: krata-bundle-systemd-x86_64 - path: "target/dist/bundle-systemd.tgz" + name: krata-bundle-systemd-${{ matrix.arch }} + path: "target/dist/bundle-systemd-${{ matrix.arch }}.tgz" compression-level: 0 - run: ./hack/dist/deb.sh env: KRATA_KERNEL_BUILD_SKIP: "1" - uses: actions/upload-artifact@v4 with: - name: krata-debian-x86_64 - path: "target/dist/*_amd64.deb" + name: krata-debian-${{ matrix.arch }} + path: "target/dist/*.deb" compression-level: 0 - run: ./hack/dist/apk.sh env: KRATA_KERNEL_BUILD_SKIP: "1" - uses: actions/upload-artifact@v4 with: - name: krata-alpine-x86_64 - path: "target/dist/*_x86_64.apk" + name: krata-alpine-${{ matrix.arch }} + path: "target/dist/*_${{ matrix.arch }}.apk" compression-level: 0 - run: ./hack/os/build.sh env: KRATA_KERNEL_BUILD_SKIP: "1" - uses: actions/upload-artifact@v4 with: - name: krata-os-x86_64 - path: "target/os/krata.qcow2" + name: krata-os-${{ matrix.arch }} + path: "target/os/krata-${{ matrix.arch }}.qcow2" compression-level: 0 diff --git a/.github/workflows/os.yml b/.github/workflows/os.yml index 6e1cf69..e12c0ad 100644 --- a/.github/workflows/os.yml +++ b/.github/workflows/os.yml @@ -12,19 +12,26 @@ on: - "hack/ci/**" jobs: build: - name: build runs-on: ubuntu-latest + strategy: + matrix: + arch: + - x86_64 + - aarch64 + env: + TARGET_ARCH: "${{ matrix.arch }}" + name: build ${{ matrix.arch }} steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: - targets: "x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl" + targets: "${{ matrix.arch }}-unknown-linux-gnu,${{ matrix.arch }}-unknown-linux-musl" - run: ./hack/ci/install-deps.sh - run: ./hack/os/build.sh env: KRATA_KERNEL_BUILD_JOBS: "5" - uses: actions/upload-artifact@v4 with: - name: krata-os-x86_64 - path: "target/os/krata.qcow2" + name: krata-os-${{ matrix.arch }} + path: "target/os/krata-${{ matrix.arch }}.qcow2" compression-level: 0 diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 0000000..c3bf740 --- /dev/null +++ b/Cross.toml @@ -0,0 +1,19 @@ +[target.aarch64-unknown-linux-gnu] +pre-build = [ + "apt-get update && apt-get --assume-yes install protobuf-compiler" +] + +[target.aarch64-unknown-linux-musl] +pre-build = [ + "apt-get update && apt-get --assume-yes install protobuf-compiler" +] + +[target.x86_64-unknown-linux-gnu] +pre-build = [ + "apt-get update && apt-get --assume-yes install protobuf-compiler" +] + +[target.x86_64-unknown-linux-musl] +pre-build = [ + "apt-get update && apt-get --assume-yes install protobuf-compiler" +] diff --git a/DEV.md b/DEV.md index 0ad16b9..aa063e6 100644 --- a/DEV.md +++ b/DEV.md @@ -18,7 +18,7 @@ it's corresponding code path from the above table. | Component | Specification | Notes | | ------------- | ------------- | --------------------------------------------------------------------------------- | -| Architecture | x86_64 | aarch64 support requires minimal effort, but limited to x86 for research phase | +| Architecture | x86_64 | aarch64 support is still in development | | Memory | At least 6GB | dom0 will need to be configured will lower memory limit to give krata guests room | | Xen | 4.17 | Temporary due to hardcoded interface version constants | | Debian | stable / sid | Debian is recommended due to the ease of Xen setup | diff --git a/crates/xen/xenclient/src/arm64.rs b/crates/xen/xenclient/src/arm64.rs index 8a3ad70..0ad9d0c 100644 --- a/crates/xen/xenclient/src/arm64.rs +++ b/crates/xen/xenclient/src/arm64.rs @@ -137,7 +137,7 @@ impl Arm64BootSetup { &mut extents, )?; if allocsz == 0 { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("allocsz is zero")); } } @@ -154,6 +154,10 @@ impl ArchBootSetup for Arm64BootSetup { ARM_PAGE_SHIFT } + fn needs_early_kernel(&mut self) -> bool { + true + } + fn setup_shared_info(&mut self, _: &mut BootSetup, _: u64) -> Result<()> { Ok(()) } @@ -166,9 +170,12 @@ impl ArchBootSetup for Arm64BootSetup { &mut self, setup: &mut BootSetup, total_pages: u64, - kernel_segment: &DomainSegment, + kernel_segment: &Option, initrd_segment: &Option, ) -> Result<()> { + let kernel_segment = kernel_segment + .as_ref() + .ok_or(Error::MemorySetupFailed("kernel_segment missing"))?; setup.call.claim_pages(setup.domid, total_pages)?; let mut ramsize = total_pages << XEN_PAGE_SHIFT; @@ -218,7 +225,7 @@ impl ArchBootSetup for Arm64BootSetup { } else if kernbase - bankbase[0] > modsize { kernbase - modsize } else { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("unable to determine modbase")); }; setup.call.claim_pages(setup.domid, 0)?; Ok(()) diff --git a/crates/xen/xenclient/src/boot.rs b/crates/xen/xenclient/src/boot.rs index dcd61a9..114fb30 100644 --- a/crates/xen/xenclient/src/boot.rs +++ b/crates/xen/xenclient/src/boot.rs @@ -88,7 +88,7 @@ impl BootSetup<'_> { &mut self, arch: &mut dyn ArchBootSetup, total_pages: u64, - kernel_segment: &DomainSegment, + kernel_segment: &Option, initrd_segment: &Option, ) -> Result<()> { self.call.set_address_size(self.domid, 64)?; @@ -119,15 +119,24 @@ impl BootSetup<'_> { let image_info = image_loader.parse()?; debug!("initialize image_info={:?}", image_info); - let kernel_segment = self.load_kernel_segment(arch, image_loader, &image_info)?; + let mut kernel_segment: Option = None; let mut initrd_segment: Option = None; if !image_info.unmapped_initrd { initrd_segment = Some(self.alloc_module(arch, initrd)?); } + + if arch.needs_early_kernel() { + kernel_segment = Some(self.load_kernel_segment(arch, image_loader, &image_info)?); + } + let total_pages = mem_mb << (20 - arch.page_shift()); self.initialize_memory(arch, total_pages, &kernel_segment, &initrd_segment)?; - self.virt_alloc_end = image_info.virt_base; + + if kernel_segment.is_none() { + kernel_segment = Some(self.load_kernel_segment(arch, image_loader, &image_info)?); + } + let mut p2m_segment: Option = None; if image_info.virt_p2m_base >= image_info.virt_base || (image_info.virt_p2m_base & ((1 << arch.page_shift()) - 1)) != 0 @@ -158,6 +167,10 @@ impl BootSetup<'_> { let initrd_segment = initrd_segment.unwrap(); let store_evtchn = self.call.evtchn_alloc_unbound(self.domid, 0)?; let console_evtchn = self.call.evtchn_alloc_unbound(self.domid, 0)?; + + let kernel_segment = + kernel_segment.ok_or(Error::MemorySetupFailed("kernel_segment missing"))?; + let state = BootState { kernel_segment, start_info_segment, @@ -317,11 +330,11 @@ impl BootSetup<'_> { fn alloc_padding_pages(&mut self, arch: &mut dyn ArchBootSetup, boundary: u64) -> Result<()> { if (boundary & (arch.page_size() - 1)) != 0 { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("boundary is incorrect")); } if boundary < self.virt_alloc_end { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("boundary is below allocation end")); } let pages = (boundary - self.virt_alloc_end) / arch.page_size(); self.chk_alloc_pages(arch, pages)?; @@ -333,7 +346,7 @@ impl BootSetup<'_> { || self.pfn_alloc_end > self.total_pages || pages > self.total_pages - self.pfn_alloc_end { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("no more pages left")); } self.pfn_alloc_end += pages; @@ -346,6 +359,8 @@ pub trait ArchBootSetup { fn page_size(&mut self) -> u64; fn page_shift(&mut self) -> u64; + fn needs_early_kernel(&mut self) -> bool; + fn alloc_p2m_segment( &mut self, setup: &mut BootSetup, @@ -373,7 +388,7 @@ pub trait ArchBootSetup { &mut self, setup: &mut BootSetup, total_pages: u64, - kernel_segment: &DomainSegment, + kernel_segment: &Option, initrd_segment: &Option, ) -> Result<()>; fn bootlate(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>; diff --git a/crates/xen/xenclient/src/error.rs b/crates/xen/xenclient/src/error.rs index fa5215e..d6886b7 100644 --- a/crates/xen/xenclient/src/error.rs +++ b/crates/xen/xenclient/src/error.rs @@ -24,8 +24,8 @@ pub enum Error { MmapFailed, #[error("munmap failed")] UnmapFailed, - #[error("memory setup failed")] - MemorySetupFailed, + #[error("memory setup failed: {0}")] + MemorySetupFailed(&'static str), #[error("populate physmap failed: wanted={0}, received={1}, input_extents={2}")] PopulatePhysmapFailed(usize, usize, usize), #[error("unknown elf compression method")] diff --git a/crates/xen/xenclient/src/mem.rs b/crates/xen/xenclient/src/mem.rs index cd99e0f..0f4238c 100644 --- a/crates/xen/xenclient/src/mem.rs +++ b/crates/xen/xenclient/src/mem.rs @@ -57,7 +57,7 @@ impl PhysicalPages<'_> { } if pfn < page.pfn || (pfn + count) > page.pfn + page.count { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("pfn is out of range")); } } else { if pfn < page.pfn { @@ -73,7 +73,7 @@ impl PhysicalPages<'_> { } if count == 0 { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("page count is zero")); } self.pfn_alloc(pfn, count) @@ -166,7 +166,7 @@ impl PhysicalPages<'_> { pub fn unmap(&mut self, pfn: u64) -> Result<()> { let page = self.pages.iter().enumerate().find(|(_, x)| x.pfn == pfn); if page.is_none() { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("cannot unmap missing page")); } let (i, page) = page.unwrap(); diff --git a/crates/xen/xenclient/src/x86.rs b/crates/xen/xenclient/src/x86.rs index 948e84a..93fe98b 100644 --- a/crates/xen/xenclient/src/x86.rs +++ b/crates/xen/xenclient/src/x86.rs @@ -116,7 +116,6 @@ pub struct SharedInfo { pub wc_sec: u32, pub wc_nsec: u32, pub wc_sec_hi: u32, - // arch shared info pub max_pfn: u64, pub pfn_to_mfn_frame_list_list: u64, @@ -201,19 +200,19 @@ impl X86BootSetup { ) -> Result { debug!("counting pgtables from={} to={} pfn={}", from, to, pfn); if self.table.mappings_count == X86_PAGE_TABLE_MAX_MAPPINGS { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("max page table count reached")); } let m = self.table.mappings_count; let pfn_end = pfn + ((to - from) >> X86_PAGE_SHIFT); if pfn_end >= setup.phys.p2m_size() { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("pfn_end greater than p2m size")); } for idx in 0..self.table.mappings_count { if from < self.table.mappings[idx].area.to && to > self.table.mappings[idx].area.from { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("page table calculation failed")); } } let mut map = PageTableMapping::default(); @@ -285,6 +284,10 @@ impl ArchBootSetup for X86BootSetup { X86_PAGE_SHIFT } + fn needs_early_kernel(&mut self) -> bool { + false + } + fn alloc_p2m_segment( &mut self, setup: &mut BootSetup, @@ -347,7 +350,10 @@ impl ArchBootSetup for X86BootSetup { } fn setup_page_tables(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> { - let p2m_segment = state.p2m_segment.as_ref().ok_or(Error::MemorySetupFailed)?; + let p2m_segment = state + .p2m_segment + .as_ref() + .ok_or(Error::MemorySetupFailed("p2m_segment missing"))?; let p2m_guest = unsafe { slice::from_raw_parts_mut(p2m_segment.addr as *mut u64, setup.phys.p2m_size() as usize) }; @@ -416,8 +422,11 @@ impl ArchBootSetup for X86BootSetup { let page_table_segment = state .page_table_segment .as_ref() - .ok_or(Error::MemorySetupFailed)?; - let p2m_segment = state.p2m_segment.as_ref().ok_or(Error::MemorySetupFailed)?; + .ok_or(Error::MemorySetupFailed("page_table_segment missing"))?; + let p2m_segment = state + .p2m_segment + .as_ref() + .ok_or(Error::MemorySetupFailed("p2m_segment missing"))?; unsafe { for (i, c) in X86_GUEST_MAGIC.chars().enumerate() { (*info).magic[i] = c as c_char; @@ -467,7 +476,7 @@ impl ArchBootSetup for X86BootSetup { &mut self, setup: &mut BootSetup, total_pages: u64, - _: &DomainSegment, + _: &Option, _: &Option, ) -> Result<()> { setup.call.claim_pages(setup.domid, total_pages)?; @@ -487,7 +496,7 @@ impl ArchBootSetup for X86BootSetup { } if total != total_pages { - return Err(Error::MemorySetupFailed); + return Err(Error::MemorySetupFailed("total pages mismatch")); } setup.total_pages = total; @@ -576,11 +585,14 @@ impl ArchBootSetup for X86BootSetup { } fn bootlate(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> { - let p2m_segment = state.p2m_segment.as_ref().ok_or(Error::MemorySetupFailed)?; + let p2m_segment = state + .p2m_segment + .as_ref() + .ok_or(Error::MemorySetupFailed("p2m_segment missing"))?; let page_table_segment = state .page_table_segment .as_ref() - .ok_or(Error::MemorySetupFailed)?; + .ok_or(Error::MemorySetupFailed("page_table_segment missing"))?; let pg_pfn = page_table_segment.pfn; let pg_mfn = setup.phys.p2m[pg_pfn as usize]; setup.phys.unmap(pg_pfn)?; @@ -595,7 +607,7 @@ impl ArchBootSetup for X86BootSetup { let page_table_segment = state .page_table_segment .as_ref() - .ok_or(Error::MemorySetupFailed)?; + .ok_or(Error::MemorySetupFailed("page_table_segment missing"))?; let pg_pfn = page_table_segment.pfn; let pg_mfn = setup.phys.p2m[pg_pfn as usize]; let mut vcpu = VcpuGuestContext::default(); diff --git a/hack/build/cargo.sh b/hack/build/cargo.sh index 7440348..1372ed1 100755 --- a/hack/build/cargo.sh +++ b/hack/build/cargo.sh @@ -3,11 +3,22 @@ set -e TOOLS_DIR="$(dirname "${0}")" RUST_TARGET="$("${TOOLS_DIR}/target.sh")" +CROSS_COMPILE="$("${TOOLS_DIR}/cross-compile.sh")" -if [ "${RUST_LIBC}" = "musl" ] && [ -f "/etc/alpine-release" ] +if [ "${TARGET_LIBC}" = "musl" ] && [ -f "/etc/alpine-release" ] then export RUSTFLAGS="-Ctarget-feature=-crt-static" fi +if [ -z "${CARGO}" ] +then + if [ "${CROSS_COMPILE}" = "1" ] && command -v cross > /dev/null + then + CARGO="cross" + else + CARGO="cargo" + fi +fi + export CARGO_BUILD_TARGET="${RUST_TARGET}" -exec cargo "${@}" +exec "${CARGO}" "${@}" diff --git a/hack/build/cross-compile.sh b/hack/build/cross-compile.sh new file mode 100755 index 0000000..e8cdbae --- /dev/null +++ b/hack/build/cross-compile.sh @@ -0,0 +1,15 @@ +#!/bin/sh +set -e + +TOOLS_DIR="$(dirname "${0}")" + +RUST_TARGET="$("${TOOLS_DIR}/target.sh")" +TARGET_ARCH="$(echo "${RUST_TARGET}" | awk -F '-' '{print $1}')" +HOST_ARCH="$(uname -m)" + +if [ "${HOST_ARCH}" != "${TARGET_ARCH}" ] +then + echo "1" +else + echo "0" +fi diff --git a/hack/build/target.sh b/hack/build/target.sh index 943b7fa..d21840e 100755 --- a/hack/build/target.sh +++ b/hack/build/target.sh @@ -1,29 +1,57 @@ #!/bin/sh set -e -if [ -z "${RUST_LIBC}" ] +if [ -z "${TARGET_LIBC}" ] || [ "${KRATA_TARGET_IGNORE_LIBC}" = "1" ] then - RUST_LIBC="gnu" + TARGET_LIBC="gnu" +fi + +if [ -z "${TARGET_ARCH}" ] +then + TARGET_ARCH="$(uname -m)" fi if [ -z "${RUST_TARGET}" ] then - HOST_ARCH="$(uname -m)" - if [ "${HOST_ARCH}" = "x86_64" ] + if [ "${TARGET_ARCH}" = "x86_64" ] then - RUST_TARGET="x86_64-unknown-linux-${RUST_LIBC}" + RUST_TARGET="x86_64-unknown-linux-${TARGET_LIBC}" fi - if [ "${HOST_ARCH}" = "aarch64" ] + if [ "${TARGET_ARCH}" = "aarch64" ] then - RUST_TARGET="aarch64-unknown-linux-${RUST_LIBC}" + RUST_TARGET="aarch64-unknown-linux-${TARGET_LIBC}" fi fi -if [ -z "${RUST_TARGET}" ] +if [ -z "${C_TARGET}" ] then - echo "ERROR: Unable to determine RUST_TARGET, your architecture may not be supported by krata." > /dev/stderr - exit 1 + if [ "${TARGET_ARCH}" = "x86_64" ] + then + C_TARGET="x86_64-linux-${TARGET_LIBC}" + fi + + if [ "${TARGET_ARCH}" = "aarch64" ] + then + C_TARGET="aarch64-linux-${TARGET_LIBC}" + fi fi -echo "${RUST_TARGET}" +if [ "${KRATA_TARGET_C_MODE}" = "1" ] +then + if [ -z "${C_TARGET}" ] + then + echo "ERROR: Unable to determine C_TARGET, your architecture may not be supported by krata." > /dev/stderr + exit 1 + fi + + echo "${C_TARGET}" +else + if [ -z "${RUST_TARGET}" ] + then + echo "ERROR: Unable to determine RUST_TARGET, your architecture may not be supported by krata." > /dev/stderr + exit 1 + fi + + echo "${RUST_TARGET}" +fi diff --git a/hack/ci/install-deps.sh b/hack/ci/install-deps.sh index 29c04f8..139eca8 100755 --- a/hack/ci/install-deps.sh +++ b/hack/ci/install-deps.sh @@ -6,3 +6,4 @@ sudo apt-get install -y \ build-essential libssl-dev libelf-dev musl-dev \ flex bison bc protobuf-compiler musl-tools qemu-utils sudo gem install --no-document fpm +cargo install cross diff --git a/hack/dist/apk.sh b/hack/dist/apk.sh index b772e46..3402332 100755 --- a/hack/dist/apk.sh +++ b/hack/dist/apk.sh @@ -4,7 +4,7 @@ set -e # shellcheck source-path=SCRIPTDIR source=common.sh . "$(dirname "${0}")/common.sh" -export RUST_LIBC="musl" +export TARGET_LIBC="musl" KRATA_SYSTAR_OPENRC=1 "${KRATA_DIR}/hack/dist/systar.sh" KRATA_VERSION="$("${KRATA_DIR}/hack/dist/version.sh")" @@ -22,4 +22,4 @@ fpm -s tar -t apk \ --description "Krata Hypervisor" \ --url "https://krata.dev" \ --maintainer "Edera Team " \ - "${OUTPUT_DIR}/system-openrc.tgz" + "${OUTPUT_DIR}/system-openrc-${TARGET_ARCH}.tgz" diff --git a/hack/dist/bundle.sh b/hack/dist/bundle.sh index c2dc0c0..b9b3b75 100755 --- a/hack/dist/bundle.sh +++ b/hack/dist/bundle.sh @@ -9,15 +9,18 @@ then KRATA_KERNEL_BUILD_JOBS="2" fi -BUNDLE_TAR="${OUTPUT_DIR}/bundle-systemd.tgz" +TARGET_ARCH="$("${KRATA_DIR}/hack/build/arch.sh")" +BUNDLE_TAR="${OUTPUT_DIR}/bundle-systemd-${TARGET_ARCH}.tgz" rm -f "${BUNDLE_TAR}" BUNDLE_DIR="$(mktemp -d /tmp/krata-bundle.XXXXXXXXXXXXX)" BUNDLE_DIR="${BUNDLE_DIR}/krata" mkdir -p "${BUNDLE_DIR}" + +./hack/build/cargo.sh build --release --bin kratad --bin kratanet --bin kratactl + +RUST_TARGET="$(./hack/build/target.sh)" for X in kratad kratanet kratactl do - ./hack/build/cargo.sh build --release --bin "${X}" - RUST_TARGET="$(./hack/build/target.sh)" cp "${KRATA_DIR}/target/${RUST_TARGET}/release/${X}" "${BUNDLE_DIR}/${X}" done ./hack/initrd/build.sh @@ -28,8 +31,8 @@ fi cd "${BUNDLE_DIR}" -cp "${KRATA_DIR}/target/initrd/initrd" initrd -cp "${KRATA_DIR}/target/kernel/kernel" kernel +cp "${KRATA_DIR}/target/initrd/initrd-${TARGET_ARCH}" initrd +cp "${KRATA_DIR}/target/kernel/kernel-${TARGET_ARCH}" kernel cp "${KRATA_DIR}/resources/systemd/kratad.service" kratad.service cp "${KRATA_DIR}/resources/systemd/kratanet.service" kratanet.service cp "${KRATA_DIR}/resources/bundle/install.sh" install.sh diff --git a/hack/dist/deb.sh b/hack/dist/deb.sh index eb80b89..db2c107 100755 --- a/hack/dist/deb.sh +++ b/hack/dist/deb.sh @@ -7,18 +7,19 @@ set -e "${KRATA_DIR}/hack/dist/systar.sh" KRATA_VERSION="$("${KRATA_DIR}/hack/dist/version.sh")" -TARGET_ARCH="$(KRATA_ARCH_ALT_NAME=1 "${KRATA_DIR}/hack/build/arch.sh")" +TARGET_ARCH_STANDARD="$(KRATA_ARCH_ALT_NAME=0 "${KRATA_DIR}/hack/build/arch.sh")" +TARGET_ARCH_DEBIAN="$(KRATA_ARCH_ALT_NAME=1 "${KRATA_DIR}/hack/build/arch.sh")" cd "${OUTPUT_DIR}" -rm -f "krata_${KRATA_VERSION}_${TARGET_ARCH}.deb" +rm -f "krata_${KRATA_VERSION}_${TARGET_ARCH_DEBIAN}.deb" fpm -s tar -t deb \ --name krata \ --license agpl3 \ --version "${KRATA_VERSION}" \ - --architecture "${TARGET_ARCH}" \ - --depends "xen-system-${TARGET_ARCH}" \ + --architecture "${TARGET_ARCH_DEBIAN}" \ + --depends "xen-system-${TARGET_ARCH_DEBIAN}" \ --description "Krata Hypervisor" \ --url "https://krata.dev" \ --maintainer "Edera Team " \ @@ -27,4 +28,4 @@ fpm -s tar -t deb \ --deb-systemd "${KRATA_DIR}/resources/systemd/kratanet.service" \ --deb-systemd-enable \ --deb-systemd-auto-start \ - "${OUTPUT_DIR}/system-systemd.tgz" + "${OUTPUT_DIR}/system-systemd-${TARGET_ARCH_STANDARD}.tgz" diff --git a/hack/dist/systar.sh b/hack/dist/systar.sh index e4ac6d3..22337d3 100755 --- a/hack/dist/systar.sh +++ b/hack/dist/systar.sh @@ -12,11 +12,12 @@ then SYSTAR_VARIANT="openrc" fi -SYSTAR="${OUTPUT_DIR}/system-${SYSTAR_VARIANT}.tgz" +TARGET_ARCH="$("${KRATA_DIR}/hack/build/arch.sh")" +SYSTAR="${OUTPUT_DIR}/system-${SYSTAR_VARIANT}-${TARGET_ARCH}.tgz" rm -f "${SYSTAR}" SYSTAR_DIR="$(mktemp -d /tmp/krata-systar.XXXXXXXXXXXXX)" cd "${SYSTAR_DIR}" -tar xf "${OUTPUT_DIR}/bundle-systemd.tgz" +tar xf "${OUTPUT_DIR}/bundle-systemd-${TARGET_ARCH}.tgz" mkdir sys cd sys diff --git a/hack/initrd/build.sh b/hack/initrd/build.sh index 6d985e1..81d1815 100755 --- a/hack/initrd/build.sh +++ b/hack/initrd/build.sh @@ -6,7 +6,9 @@ cd "$(dirname "${REAL_SCRIPT}")/../.." KRATA_DIR="${PWD}" cd "${KRATA_DIR}" -export RUST_LIBC="musl" +TARGET_ARCH="$(./hack/build/arch.sh)" + +export TARGET_LIBC="musl" RUST_TARGET="$(./hack/build/target.sh)" export RUSTFLAGS="-Ctarget-feature=+crt-static" @@ -16,5 +18,5 @@ cp "target/${RUST_TARGET}/release/krataguest" "${INITRD_DIR}/init" chmod +x "${INITRD_DIR}/init" cd "${INITRD_DIR}" mkdir -p "${KRATA_DIR}/target/initrd" -find . | cpio -R 0:0 --ignore-devno --renumber-inodes -o -H newc --quiet > "${KRATA_DIR}/target/initrd/initrd" +find . | cpio -R 0:0 --ignore-devno --renumber-inodes -o -H newc --quiet > "${KRATA_DIR}/target/initrd/initrd-${TARGET_ARCH}" rm -rf "${INITRD_DIR}" diff --git a/hack/kernel/build.sh b/hack/kernel/build.sh index 822b763..121d2b6 100755 --- a/hack/kernel/build.sh +++ b/hack/kernel/build.sh @@ -8,9 +8,21 @@ KERNEL_DIR="${KRATA_DIR}/kernel" cd "${KRATA_DIR}" +TARGET_ARCH_STANDARD="$(KRATA_ARCH_KERNEL_NAME=0 ./hack/build/arch.sh)" +TARGET_ARCH_KERNEL="$(KRATA_ARCH_KERNEL_NAME=1 ./hack/build/arch.sh)" +C_TARGET="$(KRATA_TARGET_C_MODE=1 KRATA_TARGET_IGNORE_LIBC=1 ./hack/build/target.sh)" +IS_CROSS_COMPILE="$(./hack/build/cross-compile.sh)" + +if [ "${IS_CROSS_COMPILE}" = "1" ] +then + CROSS_COMPILE_MAKE="CROSS_COMPILE=${C_TARGET}-" +else + CROSS_COMPILE_MAKE="CROSS_COMPILE=" +fi + # shellcheck source-path=SCRIPTDIR source=../../kernel/config.sh . "${KERNEL_DIR}/config.sh" -KERNEL_SRC="${KERNEL_DIR}/linux-${KERNEL_VERSION}" +KERNEL_SRC="${KERNEL_DIR}/linux-${KERNEL_VERSION}-${TARGET_ARCH_STANDARD}" if [ -z "${KRATA_KERNEL_BUILD_JOBS}" ] then @@ -20,42 +32,45 @@ fi if [ ! -f "${KERNEL_SRC}/Makefile" ] then rm -rf "${KERNEL_SRC}" + mkdir -p "${KERNEL_SRC}" curl --progress-bar -L -o "${KERNEL_SRC}.txz" "${KERNEL_SRC_URL}" - tar xf "${KERNEL_SRC}.txz" -C "${KERNEL_DIR}" + tar xf "${KERNEL_SRC}.txz" --strip-components 1 -C "${KERNEL_SRC}" rm "${KERNEL_SRC}.txz" fi OUTPUT_DIR="${KRATA_DIR}/target/kernel" mkdir -p "${OUTPUT_DIR}" -TARGET_ARCH="$(KRATA_ARCH_KERNEL_NAME=1 ./hack/build/arch.sh)" - -KERNEL_CONFIG_FILE="${KERNEL_DIR}/krata-${TARGET_ARCH}.config" +KERNEL_CONFIG_FILE="${KERNEL_DIR}/krata-${TARGET_ARCH_STANDARD}.config" if [ ! -f "${KERNEL_CONFIG_FILE}" ] then - echo "ERROR: kernel config file not found for ${TARGET_ARCH}" > /dev/stderr + echo "ERROR: kernel config file not found for ${TARGET_ARCH_STANDARD}" > /dev/stderr exit 1 fi cp "${KERNEL_CONFIG_FILE}" "${KERNEL_SRC}/.config" -make -C "${KERNEL_SRC}" ARCH="${TARGET_ARCH}" olddefconfig +make -C "${KERNEL_SRC}" ARCH="${TARGET_ARCH_KERNEL}" "${CROSS_COMPILE_MAKE}" olddefconfig -if [ "${TARGET_ARCH}" = "x86_64" ] +IMAGE_TARGET="bzImage" + +if [ "${TARGET_ARCH_STANDARD}" = "x86_64" ] then - make -C "${KERNEL_SRC}" ARCH="${TARGET_ARCH}" -j"${KRATA_KERNEL_BUILD_JOBS}" bzImage -elif [ "${TARGET_ARCH}" = "arm64" ] + IMAGE_TARGET="bzImage" +elif [ "${TARGET_ARCH_STANDARD}" = "aarch64" ] then - make -C "${KERNEL_SRC}" ARCH="${TARGET_ARCH}" -j"${KRATA_KERNEL_BUILD_JOBS}" Image.gz + IMAGE_TARGET="Image.gz" fi -if [ "${TARGET_ARCH}" = "x86_64" ] +make -C "${KERNEL_SRC}" ARCH="${TARGET_ARCH_KERNEL}" -j"${KRATA_KERNEL_BUILD_JOBS}" "${CROSS_COMPILE_MAKE}" "${IMAGE_TARGET}" + +if [ "${TARGET_ARCH_STANDARD}" = "x86_64" ] then - cp "${KERNEL_SRC}/arch/x86/boot/bzImage" "${OUTPUT_DIR}/kernel" -elif [ "${TARGET_ARCH}" = "arm64" ] + cp "${KERNEL_SRC}/arch/x86/boot/bzImage" "${OUTPUT_DIR}/kernel-${TARGET_ARCH_STANDARD}" +elif [ "${TARGET_ARCH_STANDARD}" = "aarch64" ] then - cp "${KERNEL_SRC}/arch/arm64/boot/Image.gz" "${OUTPUT_DIR}/kernel" + cp "${KERNEL_SRC}/arch/arm64/boot/Image.gz" "${OUTPUT_DIR}/kernel-${TARGET_ARCH_STANDARD}" else - echo "ERROR: unable to determine what file is the vmlinuz for ${TARGET_ARCH}" > /dev/stderr + echo "ERROR: unable to determine what file is the vmlinuz for ${TARGET_ARCH_STANDARD}" > /dev/stderr exit 1 fi diff --git a/hack/kernel/clean.sh b/hack/kernel/clean.sh deleted file mode 100755 index b2eef53..0000000 --- a/hack/kernel/clean.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -set -e - -REAL_SCRIPT="$(realpath "${0}")" -cd "$(dirname "${REAL_SCRIPT}")/../.." -KRATA_DIR="${PWD}" -KERNEL_DIR="${KRATA_DIR}/kernel" - -# shellcheck disable=SC2010 -for ITEM in $(ls "${KERNEL_DIR}" | grep "^linux-") -do - rm -rf "${KERNEL_DIR:?}/${ITEM}" -done diff --git a/hack/os/build.sh b/hack/os/build.sh index f4c73c8..3d8f883 100755 --- a/hack/os/build.sh +++ b/hack/os/build.sh @@ -7,20 +7,31 @@ cd "$(dirname "${REAL_SCRIPT}")/../.." ./hack/dist/apk.sh KRATA_VERSION="$(./hack/dist/version.sh)" TARGET_ARCH="$(./hack/build/arch.sh)" +TARGET_ARCH_ALT="$(KRATA_ARCH_KERNEL_NAME=1 ./hack/build/arch.sh)" +CROSS_COMPILE="$(./hack/build/cross-compile.sh)" TARGET_DIR="${PWD}/target" TARGET_OS_DIR="${TARGET_DIR}/os" mkdir -p "${TARGET_OS_DIR}" -cp "${TARGET_DIR}/dist/krata_${KRATA_VERSION}_${TARGET_ARCH}.apk" "${TARGET_OS_DIR}/krata.apk" +cp "${TARGET_DIR}/dist/krata_${KRATA_VERSION}_${TARGET_ARCH}.apk" "${TARGET_OS_DIR}/krata-${TARGET_ARCH}.apk" -DOCKER_INTERACTIVE_FLAGS="" +DOCKER_FLAGS="" if [ -t 0 ] then - DOCKER_INTERACTIVE_FLAGS="-it" + DOCKER_FLAGS="-it" fi -docker run --rm --privileged -v "${PWD}:/mnt" ${DOCKER_INTERACTIVE_FLAGS} alpine:latest "/mnt/os/internal/stage1.sh" -sudo chown "${USER}:${GROUP}" "${TARGET_OS_DIR}/rootfs.tar" +if [ "${CROSS_COMPILE}" = "1" ] +then + DOCKER_FLAGS="${DOCKER_FLAGS} --platform linux/${TARGET_ARCH_ALT}" + docker run --privileged --rm tonistiigi/binfmt --install all +fi + +ROOTFS="${TARGET_OS_DIR}/rootfs-${TARGET_ARCH}.tar" + +# shellcheck disable=SC2086 +docker run --rm --privileged -v "${PWD}:/mnt" ${DOCKER_FLAGS} alpine:latest "/mnt/os/internal/stage1.sh" "${TARGET_ARCH}" +sudo chown "${USER}:${GROUP}" "${ROOTFS}" sudo modprobe nbd next_nbd_device() { @@ -42,10 +53,10 @@ then exit 1 fi -OS_IMAGE="${TARGET_OS_DIR}/krata.qcow2" +OS_IMAGE="${TARGET_OS_DIR}/krata-${TARGET_ARCH}.qcow2" EFI_PART="${NBD_DEVICE}p1" ROOT_PART="${NBD_DEVICE}p2" -ROOT_DIR="${TARGET_OS_DIR}/root" +ROOT_DIR="${TARGET_OS_DIR}/root-${TARGET_ARCH}" EFI_DIR="${ROOT_DIR}/boot/efi" cleanup() { @@ -58,7 +69,7 @@ cleanup() { } rm -f "${OS_IMAGE}" -qemu-img create -f qcow2 "${TARGET_OS_DIR}/krata.qcow2" "2G" +qemu-img create -f qcow2 "${OS_IMAGE}" "2G" trap cleanup EXIT HUP INT TERM sudo qemu-nbd --connect="${NBD_DEVICE}" --cache=writeback -f qcow2 "${OS_IMAGE}" @@ -75,7 +86,7 @@ sudo mount -t ext4 "${ROOT_PART}" "${ROOT_DIR}" sudo mkdir -p "${EFI_DIR}" sudo mount -t vfat "${EFI_PART}" "${EFI_DIR}" -sudo tar xf "${TARGET_OS_DIR}/rootfs.tar" -C "${ROOT_DIR}" +sudo tar xf "${ROOTFS}" -C "${ROOT_DIR}" ROOT_UUID="$(sudo blkid "${ROOT_PART}" | sed -En 's/.*\bUUID="([^"]+)".*/\1/p')" EFI_UUID="$(sudo blkid "${EFI_PART}" | sed -En 's/.*\bUUID="([^"]+)".*/\1/p')" echo "${ROOT_UUID}" @@ -89,7 +100,7 @@ sudo mount --make-private "${ROOT_DIR}/sys" sudo cp "${PWD}/os/internal/stage2.sh" "${ROOT_DIR}/stage2.sh" echo "${ROOT_UUID}" | sudo tee "${ROOT_DIR}/root-uuid" > /dev/null -sudo chroot "${ROOT_DIR}" /bin/sh -c "/stage2.sh" +sudo chroot "${ROOT_DIR}" /bin/sh -c "/stage2.sh ${TARGET_ARCH} ${TARGET_ARCH_ALT}" sudo rm -f "${ROOT_DIR}/stage2.sh" sudo rm -f "${ROOT_DIR}/root-uuid" @@ -101,6 +112,6 @@ sudo rm -f "${ROOT_DIR}/root-uuid" cleanup -OS_SMALL_IMAGE="${TARGET_OS_DIR}/krata.small.qcow2" +OS_SMALL_IMAGE="${TARGET_OS_DIR}/krata-${TARGET_ARCH}.small.qcow2" qemu-img convert -O qcow2 "${OS_IMAGE}" "${OS_SMALL_IMAGE}" mv -f "${OS_SMALL_IMAGE}" "${OS_IMAGE}" diff --git a/kernel/config.sh b/kernel/config.sh index a4b064a..6c53b56 100644 --- a/kernel/config.sh +++ b/kernel/config.sh @@ -1,3 +1,3 @@ #!/bin/sh -KERNEL_VERSION="6.7.8" +KERNEL_VERSION="6.8.1" KERNEL_SRC_URL="https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${KERNEL_VERSION}.tar.xz" diff --git a/kernel/krata-arm64.config b/kernel/krata-aarch64.config similarity index 100% rename from kernel/krata-arm64.config rename to kernel/krata-aarch64.config diff --git a/os/internal/stage1.sh b/os/internal/stage1.sh index 0deae1a..83e238a 100755 --- a/os/internal/stage1.sh +++ b/os/internal/stage1.sh @@ -1,12 +1,13 @@ #!/bin/sh set -e +TARGET_ARCH="${1}" apk add --update-cache alpine-base \ linux-lts linux-firmware-none \ mkinitfs dosfstools e2fsprogs \ tzdata chrony -apk add --allow-untrusted /mnt/target/os/krata.apk +apk add --allow-untrusted "/mnt/target/os/krata-${TARGET_ARCH}.apk" for SERVICE in kratad kratanet do @@ -74,7 +75,7 @@ rm -rf /var/cache/apk/* rm -rf /.dockerenv cd / -rm -f /mnt/target/os/rootfs.tar -tar cf /mnt/target/os/rootfs.tar --numeric-owner \ +rm -f "/mnt/target/os/rootfs-${TARGET_ARCH}.tar" +tar cf "/mnt/target/os/rootfs-${TARGET_ARCH}.tar" --numeric-owner \ --exclude 'mnt/**' --exclude 'proc/**' \ --exclude 'sys/**' --exclude 'dev/**' . diff --git a/os/internal/stage2.sh b/os/internal/stage2.sh index bccf72f..3cc8a7d 100755 --- a/os/internal/stage2.sh +++ b/os/internal/stage2.sh @@ -1,9 +1,20 @@ #!/bin/sh set -e +TARGET_ARCH="${1}" +TARGET_ARCH_ALT="${2}" apk add --update-cache grub-efi -grub-install --target=x86_64-efi --efi-directory=/boot/efi --no-nvram --skip-fs-probe --bootloader-id=BOOT -mv /boot/efi/EFI/BOOT/grubx64.efi /boot/efi/EFI/BOOT/BOOTX64.efi +grub-install --target="${TARGET_ARCH_ALT}-efi" --efi-directory=/boot/efi --no-nvram --skip-fs-probe --bootloader-id=BOOT + +FROM_EFI_FILE="grubx64.efi" +TO_EFI_FILE="BOOTX64.efi" +if [ "${TARGET_ARCH}" = "aarch64" ] +then + FROM_EFI_FILE="grubaa64.efi" + TO_EFI_FILE="BOOTA64.efi" +fi + +mv "/boot/efi/EFI/BOOT/${FROM_EFI_FILE}" "/boot/efi/EFI/BOOT/${TO_EFI_FILE}" ROOT_UUID="$(cat /root-uuid)"