diff --git a/.buildkite/hooks/post-checkout b/.buildkite/hooks/post-checkout new file mode 100644 index 00000000..d6806995 --- /dev/null +++ b/.buildkite/hooks/post-checkout @@ -0,0 +1,20 @@ +#!/bin/bash + +DEB_NAME="linux-image-4.9.0-9-amd64_4.9.168-1_amd64.deb" +DEB_URL="http://ftp.debian.org/debian/pool/main/l/linux/${DEB_NAME}" + +REPO_PATH="${BUILDKITE_BUILD_CHECKOUT_PATH}" +DEB_PATH="${REPO_PATH}/${DEB_NAME}" +EXTRACT_PATH="${REPO_PATH}/src/bzimage-archive" +BZIMAGE_PATH="${EXTRACT_PATH}/boot/vmlinuz-4.9.0-9-amd64" + +mkdir -p ${EXTRACT_PATH} + +wget $DEB_URL -P ${REPO_PATH} +dpkg-deb -x ${DEB_PATH} ${EXTRACT_PATH} + + +mv ${BZIMAGE_PATH} ${REPO_PATH}/src/loader/bzimage +rm -r ${EXTRACT_PATH} +rm -f ${DEB_PATH} + diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml new file mode 100644 index 00000000..74264c5a --- /dev/null +++ b/.buildkite/pipeline.yml @@ -0,0 +1,26 @@ +# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +steps: + - label: "build-gnu-x86-bzimage" + commands: + - cargo build --release --features bzimage + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + image: "rustvmm/dev:v2" + always-pull: true + + - label: "build-musl-x86-bzimage" + commands: + - cargo build --release --features bzimage --target x86_64-unknown-linux-musl + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + image: "rustvmm/dev:v2" + always-pull: true diff --git a/.buildkite/rust-vmm-ci-pipeline.yml b/.buildkite/rust-vmm-ci-pipeline.yml new file mode 100644 index 00000000..39d19757 --- /dev/null +++ b/.buildkite/rust-vmm-ci-pipeline.yml @@ -0,0 +1,176 @@ +# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +steps: + - label: "build-gnu-x86" + commands: + - cargo build --release + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + image: "rustvmm/dev:v2" + always-pull: true + + - label: "build-gnu-arm" + commands: + - cargo build --release + retry: + automatic: false + agents: + platform: arm.metal + plugins: + - docker#v3.0.1: + image: "rustvmm/dev:v2" + always-pull: true + + - label: "build-musl-x86" + commands: + - cargo build --release --target x86_64-unknown-linux-musl + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + image: "rustvmm/dev:v2" + always-pull: true + + - label: "build-musl-arm" + commands: + - cargo build --release --target aarch64-unknown-linux-musl + retry: + automatic: false + agents: + platform: arm.metal + plugins: + - docker#v3.0.1: + image: "rustvmm/dev:v2" + always-pull: true + + - label: "style" + command: cargo fmt --all -- --check + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + image: "rustvmm/dev:v2" + always-pull: true + + - label: "unittests-gnu-x86" + commands: + - cargo test --all-features + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + privileged: true + image: "rustvmm/dev:v2" + always-pull: true + + - label: "unittests-gnu-arm" + commands: + - cargo test --all-features + retry: + automatic: false + agents: + platform: arm.metal + plugins: + - docker#v3.0.1: + privileged: true + image: "rustvmm/dev:v2" + always-pull: true + + - label: "unittests-musl-x86" + command: + - cargo test --all-features --target x86_64-unknown-linux-musl + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + privileged: true + image: "rustvmm/dev:v2" + always-pull: true + + - label: "unittests-musl-arm" + command: + - cargo test --all-features --target aarch64-unknown-linux-musl + retry: + automatic: false + agents: + platform: arm.metal + plugins: + - docker#v3.0.1: + privileged: true + image: "rustvmm/dev:v2" + always-pull: true + + - label: "clippy-x86" + commands: + - cargo clippy --all -- -D warnings + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + image: "rustvmm/dev:v2" + always-pull: true + + - label: "clippy-arm" + commands: + - cargo clippy --all -- -D warnings + retry: + automatic: false + agents: + platform: arm.metal + plugins: + - docker#v3.0.1: + image: "rustvmm/dev:v2" + always-pull: true + + - label: "check-warnings-x86" + commands: + - RUSTFLAGS="-D warnings" cargo check --all-targets + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + privileged: true + image: "rustvmm/dev:v2" + always-pull: true + + - label: "check-warnings-arm" + command: + - RUSTFLAGS="-D warnings" cargo check --all-targets + retry: + automatic: false + agents: + platform: arm.metal + plugins: + - docker#v3.0.1: + privileged: true + image: "rustvmm/dev:v2" + always-pull: true + + - label: "coverage-x86" + commands: + - pytest tests/test_coverage.py + retry: + automatic: false + agents: + platform: x86_64.metal + plugins: + - docker#v3.0.1: + privileged: true + image: "rustvmm/dev:v2" + always-pull: true diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 00000000..ba63e46b --- /dev/null +++ b/.cargo/config @@ -0,0 +1,3 @@ +[target.aarch64-unknown-linux-musl] +rustflags = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc" ] + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..19df3f5c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "linux-loader" +version = "0.1.0" +authors = ["Cathy Zhang "] +edition = "2018" +license = "Apache-2.0 AND BSD-3-Clause" + +[features] +default = ["elf"] +elf = [] +bzimage = [] + +[dependencies.vm-memory] +git = "https://github.com/alexandruag/vm-memory" +branch = "file_backed_regions" +features = ["backend-mmap"] diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 00000000..c6203ae2 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,92 @@ +# ELF Image parsing and loading + +The boot process is explained from the following two sides. + +## Loader side + +It follows ELF standard which is specified in elf.rs. +The entry header and program headers will be inerpreted, and PT_LOAD segments +will be loaded into guest memory. + +### Where kernel is loaded + +There are two ways on deciding where the program segments will be loaded. + +- One way is to provide an option and allow vmm to specify where to load the + image, considering its memory layout. + +- The other way is to load image into phdr.p_paddr by default. + +## VMM side + +### Construct zero page + +According to the 64-bit boot protocol, the boot parameters (traditionally known +as "zero page") should be setup, including setup_header, e820 table and other +stuff. However, ELF has no setup_header, nothing returned from ELF loader could +be used to fill boot parameters, vmm is totally responsible for the construction. + +### Configure vCPU + +- RIP, the start offset of guest memory where kernel is loaded, which is + returned from loader + +- 64 bit mode with paging enabled + +- GDT must be configured and loaded + +# bzImage + +The boot process is also explained from the following two sides. + +## Loader side + +### What will be returned from loader + +bzImage includes two parts, the setup and the compressed kernel. The compressed +kernel part will be loaded into guest memory, and the following three parts +will be returned to the VMM by the loader. + +- The start address of loaded kernel + +- The offset of memory where kernel is end of loading + +- The setup header begin at the offset 0x01f1 of bzImage, this one is an extra + compared to the return of ELF loader. + +### Where kernel is loaded + +The same as ELF image loader, there are two ways for deciding where the +compressed kernel will be loaded. + +- VMM specify where to load kernel image. + +- Load into code32_start (Boot load address) by default. + +### Additional checking + +As what the boot protocol said, the kernel is a bzImage kernel if the +protocol >= 2.00 and the 0x01 bit(LOAD_HIGH) is the loadflags field is set. Add +this checking to validate the bzImage. + +## VMM side + +### Construct zero page + +While vmm build "zero page" with e820 table and other stuff, bzImage loader will +return the setup header to fill the boot parameters. Meanwhile, +setup_header.init_size is a must to be filled into zero page, which will be used +during head_64.S boot process. + +### Configure vCPU + +- RIP, the start address of loaded 64-bit kernel returned from loader + 0x200. + Regarding to the 64-bit boot protocol, kernel is started by jumping to the + 64-bit kernel entry point, which is the start address of loaded 64-bit kernel + plus 0x200. + +- 64 bit mode with paging enabled + +- GDT must be configured and loaded + + diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 00000000..6f756351 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE-BSD-3-Clause b/LICENSE-BSD-3-Clause new file mode 100644 index 00000000..8bafca30 --- /dev/null +++ b/LICENSE-BSD-3-Clause @@ -0,0 +1,27 @@ +// Copyright 2017 The Chromium OS Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..0fae1780 --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ +# Linux-loader + +## Short-description + +* Parsing and loading vmlinux (raw ELF image) and bzImage images +* Linux command line parsing and generation +* Definitions and helpers for the Linux boot protocol + +## How to build + +``` +cd linux-loader +cargo build +``` + +## Tests + +Our Continuous Integration (CI) pipeline is implemented on top of +[Buildkite](https://buildkite.com/). +For the complete list of tests, check our +[CI pipeline](https://buildkite.com/rust-vmm/vm-virtio-ci). + +Each individual test runs in a container. To reproduce a test locally, you can +use the dev-container on both x86 and arm64. + +```bash +docker run -it \ + --security-opt seccomp=unconfined \ + --volume $(pwd):/linux-loader \ + rustvmm/dev:v2 +cd linux-loader/ +cargo test +``` + +### Test Profiles + +The integration tests support two test profiles: +- **devel**: this is the recommended profile for running the integration tests + on a local development machine. +- **ci** (default option): this is the profile used when running the + integration tests as part of the the Continuous Integration (CI). + +The test profiles are applicable to tests that run using pytest. Currently only +the [coverage test](tests/test_coverage.py) follows this model as all the other +integration tests are run using the +[Buildkite pipeline](https://buildkite.com/rust-vmm/vm-virtio-ci). + +The difference between is declaring tests as passed or failed: +- with the **devel** profile the coverage test passes if the current coverage + is equal or higher than the upstream coverage value. In case the current + coverage is higher, the coverage file is updated to the new coverage value. +- with the **ci** profile the coverage test passes only if the current coverage + is equal to the upstream coverage value. + +Further details about the coverage test can be found in the +[Adaptive Coverage](#adaptive-coverage) section. + +### Adaptive Coverage + +The line coverage is saved in [tests/coverage](tests/coverage). To update the +coverage before submitting a PR, run the coverage test: + +```bash +docker run -it \ + --security-opt seccomp=unconfined \ + --volume $(pwd):/linux-loader \ + rustvmm/dev:v2 +cd linux-loader/ +pytest --profile=devel tests/test_coverage.py +``` + +If the PR coverage is higher than the upstream coverage, the coverage file +needs to be manually added to the commit before submitting the PR: + +```bash +git add tests/coverage +``` + +Failing to do so will generate a fail on the CI pipeline when publishing the +PR. + +**NOTE:** The coverage file is only updated in the `devel` test profile. In +the `ci` profile the coverage test will fail if the current coverage is higher +than the coverage reported in [tests/coverage](tests/coverage). + +### bzImage test + +As we don't want to distribute an entire kernel bzImage, the `load_bzImage` test is ignored by +default. In order to test the bzImage support, one needs to locally build a bzImage, copy it +to the `src/loader` directory and run cargo test: + +```shell +# Assuming your linux-loader and linux-stable are both under $LINUX_LOADER +$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git $LINUX_LOADER/linux-stable +$ cd linux-stable +$ make bzImage +$ cp linux-stable/arch/x86/boot/bzImage $LINUX_LOADER/linux-loader/src/loader/ +$ cd $LINUX_LOADER/linux-loader +$ docker run -it \ + --security-opt seccomp=unconfined \ + --volume $(pwd):/linux-loader \ + rustvmm/dev:v2 +$ cd linux-loader/ +$ cargo test +``` diff --git a/src/cmdline/mod.rs b/src/cmdline/mod.rs new file mode 100644 index 00000000..d9991f69 --- /dev/null +++ b/src/cmdline/mod.rs @@ -0,0 +1,235 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Portions Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-BSD-3-Clause file. +// +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause +// +//! Helper for creating valid kernel command line strings. + +use std::fmt; +use std::result; + +/// The error type for command line building operations. +#[derive(PartialEq, Debug)] +pub enum Error { + /// Operation would have resulted in a non-printable ASCII character. + InvalidAscii, + /// Key/Value Operation would have had a space in it. + HasSpace, + /// Key/Value Operation would have had an equals sign in it. + HasEquals, + /// Operation would have made the command line too large. + TooLarge, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}", + match *self { + Error::InvalidAscii => "string contains non-printable ASCII character", + Error::HasSpace => "string contains a space", + Error::HasEquals => "string contains an equals sign", + Error::TooLarge => "inserting string would make command line too long", + } + ) + } +} + +/// Specialized Result type for command line operations. +pub type Result = result::Result; + +fn valid_char(c: char) -> bool { + match c { + ' '...'~' => true, + _ => false, + } +} + +fn valid_str(s: &str) -> Result<()> { + if s.chars().all(valid_char) { + Ok(()) + } else { + Err(Error::InvalidAscii) + } +} + +fn valid_element(s: &str) -> Result<()> { + if !s.chars().all(valid_char) { + Err(Error::InvalidAscii) + } else if s.contains(' ') { + Err(Error::HasSpace) + } else if s.contains('=') { + Err(Error::HasEquals) + } else { + Ok(()) + } +} + +/// A builder for a kernel command line string that validates the string as its being built. A +/// `CString` can be constructed from this directly using `CString::new`. +#[derive(Clone)] +pub struct Cmdline { + line: String, + capacity: usize, +} + +impl Cmdline { + /// Constructs an empty Cmdline with the given capacity, which includes the nul terminator. + /// Capacity must be greater than 0. + pub fn new(capacity: usize) -> Cmdline { + assert_ne!(capacity, 0); + Cmdline { + line: String::with_capacity(capacity), + capacity, + } + } + + fn has_capacity(&self, more: usize) -> Result<()> { + let needs_space = if self.line.is_empty() { 0 } else { 1 }; + if self.line.len() + more + needs_space < self.capacity { + Ok(()) + } else { + Err(Error::TooLarge) + } + } + + fn start_push(&mut self) { + if !self.line.is_empty() { + self.line.push(' '); + } + } + + fn end_push(&mut self) { + // This assert is always true because of the `has_capacity` check that each insert method + // uses. + assert!(self.line.len() < self.capacity); + } + + /// Validates and inserts a key value pair into this command line + pub fn insert>(&mut self, key: T, val: T) -> Result<()> { + let k = key.as_ref(); + let v = val.as_ref(); + + valid_element(k)?; + valid_element(v)?; + self.has_capacity(k.len() + v.len() + 1)?; + + self.start_push(); + self.line.push_str(k); + self.line.push('='); + self.line.push_str(v); + self.end_push(); + + Ok(()) + } + + /// Validates and inserts a string to the end of the current command line + pub fn insert_str>(&mut self, slug: T) -> Result<()> { + let s = slug.as_ref(); + valid_str(s)?; + + self.has_capacity(s.len())?; + + self.start_push(); + self.line.push_str(s); + self.end_push(); + + Ok(()) + } + + /// Returns the cmdline in progress without nul termination + pub fn as_str(&self) -> &str { + self.line.as_str() + } +} + +impl Into> for Cmdline { + fn into(self) -> Vec { + self.line.into_bytes() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::ffi::CString; + + #[test] + fn insert_hello_world() { + let mut cl = Cmdline::new(100); + assert_eq!(cl.as_str(), ""); + assert!(cl.insert("hello", "world").is_ok()); + assert_eq!(cl.as_str(), "hello=world"); + + let s = CString::new(cl).expect("failed to create CString from Cmdline"); + assert_eq!(s, CString::new("hello=world").unwrap()); + } + + #[test] + fn insert_multi() { + let mut cl = Cmdline::new(100); + assert!(cl.insert("hello", "world").is_ok()); + assert!(cl.insert("foo", "bar").is_ok()); + assert_eq!(cl.as_str(), "hello=world foo=bar"); + } + + #[test] + fn insert_space() { + let mut cl = Cmdline::new(100); + assert_eq!(cl.insert("a ", "b"), Err(Error::HasSpace)); + assert_eq!(cl.insert("a", "b "), Err(Error::HasSpace)); + assert_eq!(cl.insert("a ", "b "), Err(Error::HasSpace)); + assert_eq!(cl.insert(" a", "b"), Err(Error::HasSpace)); + assert_eq!(cl.as_str(), ""); + } + + #[test] + fn insert_equals() { + let mut cl = Cmdline::new(100); + assert_eq!(cl.insert("a=", "b"), Err(Error::HasEquals)); + assert_eq!(cl.insert("a", "b="), Err(Error::HasEquals)); + assert_eq!(cl.insert("a=", "b "), Err(Error::HasEquals)); + assert_eq!(cl.insert("=a", "b"), Err(Error::HasEquals)); + assert_eq!(cl.insert("a", "=b"), Err(Error::HasEquals)); + assert_eq!(cl.as_str(), ""); + } + + #[test] + fn insert_emoji() { + let mut cl = Cmdline::new(100); + assert_eq!(cl.insert("heart", "💖"), Err(Error::InvalidAscii)); + assert_eq!(cl.insert("💖", "love"), Err(Error::InvalidAscii)); + assert_eq!(cl.as_str(), ""); + } + + #[test] + fn insert_string() { + let mut cl = Cmdline::new(13); + assert_eq!(cl.as_str(), ""); + assert!(cl.insert_str("noapic").is_ok()); + assert_eq!(cl.as_str(), "noapic"); + assert!(cl.insert_str("nopci").is_ok()); + assert_eq!(cl.as_str(), "noapic nopci"); + } + + #[test] + fn insert_too_large() { + let mut cl = Cmdline::new(4); + assert_eq!(cl.insert("hello", "world"), Err(Error::TooLarge)); + assert_eq!(cl.insert("a", "world"), Err(Error::TooLarge)); + assert_eq!(cl.insert("hello", "b"), Err(Error::TooLarge)); + assert!(cl.insert("a", "b").is_ok()); + assert_eq!(cl.insert("a", "b"), Err(Error::TooLarge)); + assert_eq!(cl.insert_str("a"), Err(Error::TooLarge)); + assert_eq!(cl.as_str(), "a=b"); + + let mut cl = Cmdline::new(10); + assert!(cl.insert("ab", "ba").is_ok()); // adds 5 length + assert_eq!(cl.insert("c", "da"), Err(Error::TooLarge)); // adds 5 (including space) length + assert!(cl.insert("c", "d").is_ok()); // adds 4 (including space) length + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..fadbd490 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,32 @@ +// Copyright (c) 2019 Intel Corporation. All rights reserved. +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-BSD-3-Clause file. +// +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause + +#![deny(missing_docs)] + +//! A Linux kernel image loading crate. +//! +//! This crate offers support for loading raw ELF (vmlinux) and compressed +//! big zImage (bzImage) kernel images. +//! Support for any other kernel image format can be added by implementing +//! the KernelLoader. +//! +//! # Platform support +//! +//! - x86_64 +//! +//! This crates only supports x86_64 platforms because it implements support +//! for kernel image formats (vmlinux and bzImage) that are x86 specific. +//! +//! Extending it to support other kernel image formats (e.g. ARM's Image) +//! will make it consumable by other platforms. + +pub mod cmdline; +pub mod loader; + +extern crate vm_memory; diff --git a/src/loader/bootparam.rs b/src/loader/bootparam.rs new file mode 100644 index 00000000..f19663ff --- /dev/null +++ b/src/loader/bootparam.rs @@ -0,0 +1,3870 @@ +// Copyright (c) 2019 Intel Corporation. All rights reserved. +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Portions Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-BSD-3-Clause file. +// +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause + +/* + * automatically generated by rust-bindgen + * From upstream linux bootparam.h at commit: + * 806276b7f07a39a1cc3f38bb1ef5c573d4594a38 + */ + +#[repr(C)] +#[derive(Default)] +pub struct __IncompleteArrayField(::std::marker::PhantomData); +impl __IncompleteArrayField { + #[inline] + pub fn new() -> Self { + __IncompleteArrayField(::std::marker::PhantomData) + } + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { + ::std::mem::transmute(self) + } + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ::std::mem::transmute(self) + } + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::std::slice::from_raw_parts(self.as_ptr(), len) + } + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } +} +impl ::std::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } +} +impl ::std::clone::Clone for __IncompleteArrayField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } +} +impl ::std::marker::Copy for __IncompleteArrayField {} +#[repr(C)] +pub struct __BindgenUnionField(::std::marker::PhantomData); +impl __BindgenUnionField { + #[inline] + pub fn new() -> Self { + __BindgenUnionField(::std::marker::PhantomData) + } + #[inline] + pub unsafe fn as_ref(&self) -> &T { + ::std::mem::transmute(self) + } + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + ::std::mem::transmute(self) + } +} +impl ::std::default::Default for __BindgenUnionField { + #[inline] + fn default() -> Self { + Self::new() + } +} +impl ::std::clone::Clone for __BindgenUnionField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } +} +impl ::std::marker::Copy for __BindgenUnionField {} +impl ::std::fmt::Debug for __BindgenUnionField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fmt.write_str("__BindgenUnionField") + } +} +pub const SETUP_NONE: ::std::os::raw::c_uint = 0; +pub const SETUP_E820_EXT: ::std::os::raw::c_uint = 1; +pub const SETUP_DTB: ::std::os::raw::c_uint = 2; +pub const SETUP_PCI: ::std::os::raw::c_uint = 3; +pub const SETUP_EFI: ::std::os::raw::c_uint = 4; +pub const RAMDISK_IMAGE_START_MASK: ::std::os::raw::c_uint = 2047; +pub const RAMDISK_PROMPT_FLAG: ::std::os::raw::c_uint = 32768; +pub const RAMDISK_LOAD_FLAG: ::std::os::raw::c_uint = 16384; +pub const LOADED_HIGH: ::std::os::raw::c_uint = 1; +pub const QUIET_FLAG: ::std::os::raw::c_uint = 32; +pub const KEEP_SEGMENTS: ::std::os::raw::c_uint = 64; +pub const CAN_USE_HEAP: ::std::os::raw::c_uint = 128; +pub const XLF_KERNEL_64: ::std::os::raw::c_uint = 1; +pub const XLF_CAN_BE_LOADED_ABOVE_4G: ::std::os::raw::c_uint = 2; +pub const XLF_EFI_HANDOVER_32: ::std::os::raw::c_uint = 4; +pub const XLF_EFI_HANDOVER_64: ::std::os::raw::c_uint = 8; +pub const XLF_EFI_KEXEC: ::std::os::raw::c_uint = 16; +pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64; +pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024; +pub const VIDEO_TYPE_MDA: ::std::os::raw::c_uint = 16; +pub const VIDEO_TYPE_CGA: ::std::os::raw::c_uint = 17; +pub const VIDEO_TYPE_EGAM: ::std::os::raw::c_uint = 32; +pub const VIDEO_TYPE_EGAC: ::std::os::raw::c_uint = 33; +pub const VIDEO_TYPE_VGAC: ::std::os::raw::c_uint = 34; +pub const VIDEO_TYPE_VLFB: ::std::os::raw::c_uint = 35; +pub const VIDEO_TYPE_PICA_S3: ::std::os::raw::c_uint = 48; +pub const VIDEO_TYPE_MIPS_G364: ::std::os::raw::c_uint = 49; +pub const VIDEO_TYPE_SGI: ::std::os::raw::c_uint = 51; +pub const VIDEO_TYPE_TGAC: ::std::os::raw::c_uint = 64; +pub const VIDEO_TYPE_SUN: ::std::os::raw::c_uint = 80; +pub const VIDEO_TYPE_SUNPCI: ::std::os::raw::c_uint = 81; +pub const VIDEO_TYPE_PMAC: ::std::os::raw::c_uint = 96; +pub const VIDEO_TYPE_EFI: ::std::os::raw::c_uint = 112; +pub const VIDEO_FLAGS_NOCURSOR: ::std::os::raw::c_uint = 1; +pub const VIDEO_CAPABILITY_SKIP_QUIRKS: ::std::os::raw::c_uint = 1; +pub const APM_STATE_READY: ::std::os::raw::c_uint = 0; +pub const APM_STATE_STANDBY: ::std::os::raw::c_uint = 1; +pub const APM_STATE_SUSPEND: ::std::os::raw::c_uint = 2; +pub const APM_STATE_OFF: ::std::os::raw::c_uint = 3; +pub const APM_STATE_BUSY: ::std::os::raw::c_uint = 4; +pub const APM_STATE_REJECT: ::std::os::raw::c_uint = 5; +pub const APM_STATE_OEM_SYS: ::std::os::raw::c_uint = 32; +pub const APM_STATE_OEM_DEV: ::std::os::raw::c_uint = 64; +pub const APM_STATE_DISABLE: ::std::os::raw::c_uint = 0; +pub const APM_STATE_ENABLE: ::std::os::raw::c_uint = 1; +pub const APM_STATE_DISENGAGE: ::std::os::raw::c_uint = 0; +pub const APM_STATE_ENGAGE: ::std::os::raw::c_uint = 1; +pub const APM_SYS_STANDBY: ::std::os::raw::c_uint = 1; +pub const APM_SYS_SUSPEND: ::std::os::raw::c_uint = 2; +pub const APM_NORMAL_RESUME: ::std::os::raw::c_uint = 3; +pub const APM_CRITICAL_RESUME: ::std::os::raw::c_uint = 4; +pub const APM_LOW_BATTERY: ::std::os::raw::c_uint = 5; +pub const APM_POWER_STATUS_CHANGE: ::std::os::raw::c_uint = 6; +pub const APM_UPDATE_TIME: ::std::os::raw::c_uint = 7; +pub const APM_CRITICAL_SUSPEND: ::std::os::raw::c_uint = 8; +pub const APM_USER_STANDBY: ::std::os::raw::c_uint = 9; +pub const APM_USER_SUSPEND: ::std::os::raw::c_uint = 10; +pub const APM_STANDBY_RESUME: ::std::os::raw::c_uint = 11; +pub const APM_CAPABILITY_CHANGE: ::std::os::raw::c_uint = 12; +pub const APM_USER_HIBERNATION: ::std::os::raw::c_uint = 13; +pub const APM_HIBERNATION_RESUME: ::std::os::raw::c_uint = 14; +pub const APM_SUCCESS: ::std::os::raw::c_uint = 0; +pub const APM_DISABLED: ::std::os::raw::c_uint = 1; +pub const APM_CONNECTED: ::std::os::raw::c_uint = 2; +pub const APM_NOT_CONNECTED: ::std::os::raw::c_uint = 3; +pub const APM_16_CONNECTED: ::std::os::raw::c_uint = 5; +pub const APM_16_UNSUPPORTED: ::std::os::raw::c_uint = 6; +pub const APM_32_CONNECTED: ::std::os::raw::c_uint = 7; +pub const APM_32_UNSUPPORTED: ::std::os::raw::c_uint = 8; +pub const APM_BAD_DEVICE: ::std::os::raw::c_uint = 9; +pub const APM_BAD_PARAM: ::std::os::raw::c_uint = 10; +pub const APM_NOT_ENGAGED: ::std::os::raw::c_uint = 11; +pub const APM_BAD_FUNCTION: ::std::os::raw::c_uint = 12; +pub const APM_RESUME_DISABLED: ::std::os::raw::c_uint = 13; +pub const APM_NO_ERROR: ::std::os::raw::c_uint = 83; +pub const APM_BAD_STATE: ::std::os::raw::c_uint = 96; +pub const APM_NO_EVENTS: ::std::os::raw::c_uint = 128; +pub const APM_NOT_PRESENT: ::std::os::raw::c_uint = 134; +pub const APM_DEVICE_BIOS: ::std::os::raw::c_uint = 0; +pub const APM_DEVICE_ALL: ::std::os::raw::c_uint = 1; +pub const APM_DEVICE_DISPLAY: ::std::os::raw::c_uint = 256; +pub const APM_DEVICE_STORAGE: ::std::os::raw::c_uint = 512; +pub const APM_DEVICE_PARALLEL: ::std::os::raw::c_uint = 768; +pub const APM_DEVICE_SERIAL: ::std::os::raw::c_uint = 1024; +pub const APM_DEVICE_NETWORK: ::std::os::raw::c_uint = 1280; +pub const APM_DEVICE_PCMCIA: ::std::os::raw::c_uint = 1536; +pub const APM_DEVICE_BATTERY: ::std::os::raw::c_uint = 32768; +pub const APM_DEVICE_OEM: ::std::os::raw::c_uint = 57344; +pub const APM_DEVICE_OLD_ALL: ::std::os::raw::c_uint = 65535; +pub const APM_DEVICE_CLASS: ::std::os::raw::c_uint = 255; +pub const APM_DEVICE_MASK: ::std::os::raw::c_uint = 65280; +pub const APM_MAX_BATTERIES: ::std::os::raw::c_uint = 2; +pub const APM_CAP_GLOBAL_STANDBY: ::std::os::raw::c_uint = 1; +pub const APM_CAP_GLOBAL_SUSPEND: ::std::os::raw::c_uint = 2; +pub const APM_CAP_RESUME_STANDBY_TIMER: ::std::os::raw::c_uint = 4; +pub const APM_CAP_RESUME_SUSPEND_TIMER: ::std::os::raw::c_uint = 8; +pub const APM_CAP_RESUME_STANDBY_RING: ::std::os::raw::c_uint = 16; +pub const APM_CAP_RESUME_SUSPEND_RING: ::std::os::raw::c_uint = 32; +pub const APM_CAP_RESUME_STANDBY_PCMCIA: ::std::os::raw::c_uint = 64; +pub const APM_CAP_RESUME_SUSPEND_PCMCIA: ::std::os::raw::c_uint = 128; +pub const _IOC_NRBITS: ::std::os::raw::c_uint = 8; +pub const _IOC_TYPEBITS: ::std::os::raw::c_uint = 8; +pub const _IOC_SIZEBITS: ::std::os::raw::c_uint = 14; +pub const _IOC_DIRBITS: ::std::os::raw::c_uint = 2; +pub const _IOC_NRMASK: ::std::os::raw::c_uint = 255; +pub const _IOC_TYPEMASK: ::std::os::raw::c_uint = 255; +pub const _IOC_SIZEMASK: ::std::os::raw::c_uint = 16383; +pub const _IOC_DIRMASK: ::std::os::raw::c_uint = 3; +pub const _IOC_NRSHIFT: ::std::os::raw::c_uint = 0; +pub const _IOC_TYPESHIFT: ::std::os::raw::c_uint = 8; +pub const _IOC_SIZESHIFT: ::std::os::raw::c_uint = 16; +pub const _IOC_DIRSHIFT: ::std::os::raw::c_uint = 30; +pub const _IOC_NONE: ::std::os::raw::c_uint = 0; +pub const _IOC_WRITE: ::std::os::raw::c_uint = 1; +pub const _IOC_READ: ::std::os::raw::c_uint = 2; +pub const IOC_IN: ::std::os::raw::c_uint = 1073741824; +pub const IOC_OUT: ::std::os::raw::c_uint = 2147483648; +pub const IOC_INOUT: ::std::os::raw::c_uint = 3221225472; +pub const IOCSIZE_MASK: ::std::os::raw::c_uint = 1073676288; +pub const IOCSIZE_SHIFT: ::std::os::raw::c_uint = 16; +pub const EDDNR: ::std::os::raw::c_uint = 489; +pub const EDDBUF: ::std::os::raw::c_uint = 3328; +pub const EDDMAXNR: ::std::os::raw::c_uint = 6; +pub const EDDEXTSIZE: ::std::os::raw::c_uint = 8; +pub const EDDPARMSIZE: ::std::os::raw::c_uint = 74; +pub const CHECKEXTENSIONSPRESENT: ::std::os::raw::c_uint = 65; +pub const GETDEVICEPARAMETERS: ::std::os::raw::c_uint = 72; +pub const LEGACYGETDEVICEPARAMETERS: ::std::os::raw::c_uint = 8; +pub const EDDMAGIC1: ::std::os::raw::c_uint = 21930; +pub const EDDMAGIC2: ::std::os::raw::c_uint = 43605; +pub const READ_SECTORS: ::std::os::raw::c_uint = 2; +pub const EDD_MBR_SIG_OFFSET: ::std::os::raw::c_uint = 440; +pub const EDD_MBR_SIG_BUF: ::std::os::raw::c_uint = 656; +pub const EDD_MBR_SIG_MAX: ::std::os::raw::c_uint = 16; +pub const EDD_MBR_SIG_NR_BUF: ::std::os::raw::c_uint = 490; +pub const EDD_EXT_FIXED_DISK_ACCESS: ::std::os::raw::c_uint = 1; +pub const EDD_EXT_DEVICE_LOCKING_AND_EJECTING: ::std::os::raw::c_uint = 2; +pub const EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT: ::std::os::raw::c_uint = 4; +pub const EDD_EXT_64BIT_EXTENSIONS: ::std::os::raw::c_uint = 8; +pub const EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT: ::std::os::raw::c_uint = 1; +pub const EDD_INFO_GEOMETRY_VALID: ::std::os::raw::c_uint = 2; +pub const EDD_INFO_REMOVABLE: ::std::os::raw::c_uint = 4; +pub const EDD_INFO_WRITE_VERIFY: ::std::os::raw::c_uint = 8; +pub const EDD_INFO_MEDIA_CHANGE_NOTIFICATION: ::std::os::raw::c_uint = 16; +pub const EDD_INFO_LOCKABLE: ::std::os::raw::c_uint = 32; +pub const EDD_INFO_NO_MEDIA_PRESENT: ::std::os::raw::c_uint = 64; +pub const EDD_INFO_USE_INT13_FN50: ::std::os::raw::c_uint = 128; +pub const E820MAP: ::std::os::raw::c_uint = 720; +pub const E820MAX: ::std::os::raw::c_uint = 128; +pub const E820_X_MAX: ::std::os::raw::c_uint = 128; +pub const E820NR: ::std::os::raw::c_uint = 488; +pub const E820_RAM: ::std::os::raw::c_uint = 1; +pub const E820_RESERVED: ::std::os::raw::c_uint = 2; +pub const E820_ACPI: ::std::os::raw::c_uint = 3; +pub const E820_NVS: ::std::os::raw::c_uint = 4; +pub const E820_UNUSABLE: ::std::os::raw::c_uint = 5; +pub const E820_RESERVED_KERN: ::std::os::raw::c_uint = 128; +pub const ISA_START_ADDRESS: ::std::os::raw::c_uint = 655360; +pub const ISA_END_ADDRESS: ::std::os::raw::c_uint = 1048576; +pub const BIOS_BEGIN: ::std::os::raw::c_uint = 655360; +pub const BIOS_END: ::std::os::raw::c_uint = 1048576; +pub const BIOS_ROM_BASE: ::std::os::raw::c_uint = 4292870144; +pub const BIOS_ROM_END: ::std::os::raw::c_uint = 4294967295; +pub type __s8 = ::std::os::raw::c_schar; +pub type __u8 = ::std::os::raw::c_uchar; +pub type __s16 = ::std::os::raw::c_short; +pub type __u16 = ::std::os::raw::c_ushort; +pub type __s32 = ::std::os::raw::c_int; +pub type __u32 = ::std::os::raw::c_uint; +pub type __s64 = ::std::os::raw::c_longlong; +pub type __u64 = ::std::os::raw::c_ulonglong; +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct __kernel_fd_set { + pub fds_bits: [::std::os::raw::c_ulong; 16usize], +} +#[test] +fn bindgen_test_layout___kernel_fd_set() { + assert_eq!( + ::std::mem::size_of::<__kernel_fd_set>(), + 128usize, + concat!("Size of: ", stringify!(__kernel_fd_set)) + ); + assert_eq!( + ::std::mem::align_of::<__kernel_fd_set>(), + 8usize, + concat!("Alignment of ", stringify!(__kernel_fd_set)) + ); + assert_eq!( + unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(__kernel_fd_set), + "::", + stringify!(fds_bits) + ) + ); +} +impl Clone for __kernel_fd_set { + fn clone(&self) -> Self { + *self + } +} +pub type __kernel_sighandler_t = + ::std::option::Option; +pub type __kernel_key_t = ::std::os::raw::c_int; +pub type __kernel_mqd_t = ::std::os::raw::c_int; +pub type __kernel_old_uid_t = ::std::os::raw::c_ushort; +pub type __kernel_old_gid_t = ::std::os::raw::c_ushort; +pub type __kernel_old_dev_t = ::std::os::raw::c_ulong; +pub type __kernel_long_t = ::std::os::raw::c_long; +pub type __kernel_ulong_t = ::std::os::raw::c_ulong; +pub type __kernel_ino_t = __kernel_ulong_t; +pub type __kernel_mode_t = ::std::os::raw::c_uint; +pub type __kernel_pid_t = ::std::os::raw::c_int; +pub type __kernel_ipc_pid_t = ::std::os::raw::c_int; +pub type __kernel_uid_t = ::std::os::raw::c_uint; +pub type __kernel_gid_t = ::std::os::raw::c_uint; +pub type __kernel_suseconds_t = __kernel_long_t; +pub type __kernel_daddr_t = ::std::os::raw::c_int; +pub type __kernel_uid32_t = ::std::os::raw::c_uint; +pub type __kernel_gid32_t = ::std::os::raw::c_uint; +pub type __kernel_size_t = __kernel_ulong_t; +pub type __kernel_ssize_t = __kernel_long_t; +pub type __kernel_ptrdiff_t = __kernel_long_t; +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct __kernel_fsid_t { + pub val: [::std::os::raw::c_int; 2usize], +} +#[test] +fn bindgen_test_layout___kernel_fsid_t() { + assert_eq!( + ::std::mem::size_of::<__kernel_fsid_t>(), + 8usize, + concat!("Size of: ", stringify!(__kernel_fsid_t)) + ); + assert_eq!( + ::std::mem::align_of::<__kernel_fsid_t>(), + 4usize, + concat!("Alignment of ", stringify!(__kernel_fsid_t)) + ); + assert_eq!( + unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(__kernel_fsid_t), + "::", + stringify!(val) + ) + ); +} +impl Clone for __kernel_fsid_t { + fn clone(&self) -> Self { + *self + } +} +pub type __kernel_off_t = __kernel_long_t; +pub type __kernel_loff_t = ::std::os::raw::c_longlong; +pub type __kernel_time_t = __kernel_long_t; +pub type __kernel_clock_t = __kernel_long_t; +pub type __kernel_timer_t = ::std::os::raw::c_int; +pub type __kernel_clockid_t = ::std::os::raw::c_int; +pub type __kernel_caddr_t = *mut ::std::os::raw::c_char; +pub type __kernel_uid16_t = ::std::os::raw::c_ushort; +pub type __kernel_gid16_t = ::std::os::raw::c_ushort; +pub type __le16 = __u16; +pub type __be16 = __u16; +pub type __le32 = __u32; +pub type __be32 = __u32; +pub type __le64 = __u64; +pub type __be64 = __u64; +pub type __sum16 = __u16; +pub type __wsum = __u32; +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct screen_info { + pub orig_x: __u8, + pub orig_y: __u8, + pub ext_mem_k: __u16, + pub orig_video_page: __u16, + pub orig_video_mode: __u8, + pub orig_video_cols: __u8, + pub flags: __u8, + pub unused2: __u8, + pub orig_video_ega_bx: __u16, + pub unused3: __u16, + pub orig_video_lines: __u8, + pub orig_video_isVGA: __u8, + pub orig_video_points: __u16, + pub lfb_width: __u16, + pub lfb_height: __u16, + pub lfb_depth: __u16, + pub lfb_base: __u32, + pub lfb_size: __u32, + pub cl_magic: __u16, + pub cl_offset: __u16, + pub lfb_linelength: __u16, + pub red_size: __u8, + pub red_pos: __u8, + pub green_size: __u8, + pub green_pos: __u8, + pub blue_size: __u8, + pub blue_pos: __u8, + pub rsvd_size: __u8, + pub rsvd_pos: __u8, + pub vesapm_seg: __u16, + pub vesapm_off: __u16, + pub pages: __u16, + pub vesa_attributes: __u16, + pub capabilities: __u32, + pub _reserved: [__u8; 6usize], +} +#[test] +fn bindgen_test_layout_screen_info() { + assert_eq!( + ::std::mem::size_of::(), + 64usize, + concat!("Size of: ", stringify!(screen_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(screen_info)) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).orig_x as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(orig_x) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).orig_y as *const _ as usize }, + 1usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(orig_y) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).ext_mem_k as *const _ as usize }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(ext_mem_k) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).orig_video_page as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(orig_video_page) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).orig_video_mode as *const _ as usize }, + 6usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(orig_video_mode) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).orig_video_cols as *const _ as usize }, + 7usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(orig_video_cols) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).flags as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).unused2 as *const _ as usize }, + 9usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(unused2) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).orig_video_ega_bx as *const _ as usize }, + 10usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(orig_video_ega_bx) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).unused3 as *const _ as usize }, + 12usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(unused3) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).orig_video_lines as *const _ as usize }, + 14usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(orig_video_lines) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).orig_video_isVGA as *const _ as usize }, + 15usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(orig_video_isVGA) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).orig_video_points as *const _ as usize }, + 16usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(orig_video_points) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).lfb_width as *const _ as usize }, + 18usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(lfb_width) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).lfb_height as *const _ as usize }, + 20usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(lfb_height) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).lfb_depth as *const _ as usize }, + 22usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(lfb_depth) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).lfb_base as *const _ as usize }, + 24usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(lfb_base) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).lfb_size as *const _ as usize }, + 28usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(lfb_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).cl_magic as *const _ as usize }, + 32usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(cl_magic) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).cl_offset as *const _ as usize }, + 34usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(cl_offset) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).lfb_linelength as *const _ as usize }, + 36usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(lfb_linelength) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).red_size as *const _ as usize }, + 38usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(red_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).red_pos as *const _ as usize }, + 39usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(red_pos) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).green_size as *const _ as usize }, + 40usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(green_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).green_pos as *const _ as usize }, + 41usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(green_pos) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).blue_size as *const _ as usize }, + 42usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(blue_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).blue_pos as *const _ as usize }, + 43usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(blue_pos) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).rsvd_size as *const _ as usize }, + 44usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(rsvd_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).rsvd_pos as *const _ as usize }, + 45usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(rsvd_pos) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).vesapm_seg as *const _ as usize }, + 46usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(vesapm_seg) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).vesapm_off as *const _ as usize }, + 48usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(vesapm_off) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).pages as *const _ as usize }, + 50usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(pages) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).vesa_attributes as *const _ as usize }, + 52usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(vesa_attributes) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info)).capabilities as *const _ as usize }, + 54usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(capabilities) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const screen_info))._reserved as *const _ as usize }, + 58usize, + concat!( + "Alignment of field: ", + stringify!(screen_info), + "::", + stringify!(_reserved) + ) + ); +} +impl Clone for screen_info { + fn clone(&self) -> Self { + *self + } +} +pub type apm_event_t = ::std::os::raw::c_ushort; +pub type apm_eventinfo_t = ::std::os::raw::c_ushort; +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct apm_bios_info { + pub version: __u16, + pub cseg: __u16, + pub offset: __u32, + pub cseg_16: __u16, + pub dseg: __u16, + pub flags: __u16, + pub cseg_len: __u16, + pub cseg_16_len: __u16, + pub dseg_len: __u16, +} +#[test] +fn bindgen_test_layout_apm_bios_info() { + assert_eq!( + ::std::mem::size_of::(), + 20usize, + concat!("Size of: ", stringify!(apm_bios_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(apm_bios_info)) + ); + assert_eq!( + unsafe { &(*(0 as *const apm_bios_info)).version as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(apm_bios_info), + "::", + stringify!(version) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const apm_bios_info)).cseg as *const _ as usize }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(apm_bios_info), + "::", + stringify!(cseg) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const apm_bios_info)).offset as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(apm_bios_info), + "::", + stringify!(offset) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const apm_bios_info)).cseg_16 as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(apm_bios_info), + "::", + stringify!(cseg_16) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const apm_bios_info)).dseg as *const _ as usize }, + 10usize, + concat!( + "Alignment of field: ", + stringify!(apm_bios_info), + "::", + stringify!(dseg) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const apm_bios_info)).flags as *const _ as usize }, + 12usize, + concat!( + "Alignment of field: ", + stringify!(apm_bios_info), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const apm_bios_info)).cseg_len as *const _ as usize }, + 14usize, + concat!( + "Alignment of field: ", + stringify!(apm_bios_info), + "::", + stringify!(cseg_len) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const apm_bios_info)).cseg_16_len as *const _ as usize }, + 16usize, + concat!( + "Alignment of field: ", + stringify!(apm_bios_info), + "::", + stringify!(cseg_16_len) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const apm_bios_info)).dseg_len as *const _ as usize }, + 18usize, + concat!( + "Alignment of field: ", + stringify!(apm_bios_info), + "::", + stringify!(dseg_len) + ) + ); +} +impl Clone for apm_bios_info { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params { + pub length: __u16, + pub info_flags: __u16, + pub num_default_cylinders: __u32, + pub num_default_heads: __u32, + pub sectors_per_track: __u32, + pub number_of_sectors: __u64, + pub bytes_per_sector: __u16, + pub dpte_ptr: __u32, + pub key: __u16, + pub device_path_info_length: __u8, + pub reserved2: __u8, + pub reserved3: __u16, + pub host_bus_type: [__u8; 4usize], + pub interface_type: [__u8; 8usize], + pub interface_path: edd_device_params__bindgen_ty_1, + pub device_path: edd_device_params__bindgen_ty_2, + pub reserved4: __u8, + pub checksum: __u8, +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_1 { + pub isa: __BindgenUnionField, + pub pci: __BindgenUnionField, + pub ibnd: __BindgenUnionField, + pub xprs: __BindgenUnionField, + pub htpt: __BindgenUnionField, + pub unknown: __BindgenUnionField, + pub bindgen_union_field: [u8; 8usize], +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_1__bindgen_ty_1 { + pub base_address: __u16, + pub reserved1: __u16, + pub reserved2: __u32, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_1__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_1)).base_address as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(base_address) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_1)).reserved1 as *const _ + as usize + }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(reserved1) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_1)).reserved2 as *const _ + as usize + }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(reserved2) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_1__bindgen_ty_1 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_1__bindgen_ty_2 { + pub bus: __u8, + pub slot: __u8, + pub function: __u8, + pub channel: __u8, + pub reserved: __u32, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_1__bindgen_ty_2() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_2) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_2) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_2)).bus as *const _ as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_2), + "::", + stringify!(bus) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_2)).slot as *const _ + as usize + }, + 1usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_2), + "::", + stringify!(slot) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_2)).function as *const _ + as usize + }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_2), + "::", + stringify!(function) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_2)).channel as *const _ + as usize + }, + 3usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_2), + "::", + stringify!(channel) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_2)).reserved as *const _ + as usize + }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_2), + "::", + stringify!(reserved) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_1__bindgen_ty_2 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_1__bindgen_ty_3 { + pub reserved: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_1__bindgen_ty_3() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_3) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_3) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_3)).reserved as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_3), + "::", + stringify!(reserved) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_1__bindgen_ty_3 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_1__bindgen_ty_4 { + pub reserved: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_1__bindgen_ty_4() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_4) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_4) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_4)).reserved as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_4), + "::", + stringify!(reserved) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_1__bindgen_ty_4 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_1__bindgen_ty_5 { + pub reserved: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_1__bindgen_ty_5() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_5) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_5) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_5)).reserved as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_5), + "::", + stringify!(reserved) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_1__bindgen_ty_5 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_1__bindgen_ty_6 { + pub reserved: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_1__bindgen_ty_6() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_6) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_6) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_1__bindgen_ty_6)).reserved as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1__bindgen_ty_6), + "::", + stringify!(reserved) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_1__bindgen_ty_6 { + fn clone(&self) -> Self { + *self + } +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(edd_device_params__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(edd_device_params__bindgen_ty_1)) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_1)).isa as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1), + "::", + stringify!(isa) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_1)).pci as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1), + "::", + stringify!(pci) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_1)).ibnd as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1), + "::", + stringify!(ibnd) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_1)).xprs as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1), + "::", + stringify!(xprs) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_1)).htpt as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1), + "::", + stringify!(htpt) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_1)).unknown as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_1), + "::", + stringify!(unknown) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_1 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2 { + pub ata: __BindgenUnionField, + pub atapi: __BindgenUnionField, + pub scsi: __BindgenUnionField, + pub usb: __BindgenUnionField, + pub i1394: __BindgenUnionField, + pub fibre: __BindgenUnionField, + pub i2o: __BindgenUnionField, + pub raid: __BindgenUnionField, + pub sata: __BindgenUnionField, + pub unknown: __BindgenUnionField, + pub bindgen_union_field: [u8; 16usize], +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_1 { + pub device: __u8, + pub reserved1: __u8, + pub reserved2: __u16, + pub reserved3: __u32, + pub reserved4: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_1) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_1) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_1)).device as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_1), + "::", + stringify!(device) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_1)).reserved1 as *const _ + as usize + }, + 1usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_1), + "::", + stringify!(reserved1) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_1)).reserved2 as *const _ + as usize + }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_1), + "::", + stringify!(reserved2) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_1)).reserved3 as *const _ + as usize + }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_1), + "::", + stringify!(reserved3) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_1)).reserved4 as *const _ + as usize + }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_1), + "::", + stringify!(reserved4) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_1 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_2 { + pub device: __u8, + pub lun: __u8, + pub reserved1: __u8, + pub reserved2: __u8, + pub reserved3: __u32, + pub reserved4: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_2() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_2) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_2) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_2)).device as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_2), + "::", + stringify!(device) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_2)).lun as *const _ as usize + }, + 1usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_2), + "::", + stringify!(lun) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_2)).reserved1 as *const _ + as usize + }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_2), + "::", + stringify!(reserved1) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_2)).reserved2 as *const _ + as usize + }, + 3usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_2), + "::", + stringify!(reserved2) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_2)).reserved3 as *const _ + as usize + }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_2), + "::", + stringify!(reserved3) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_2)).reserved4 as *const _ + as usize + }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_2), + "::", + stringify!(reserved4) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_2 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_3 { + pub id: __u16, + pub lun: __u64, + pub reserved1: __u16, + pub reserved2: __u32, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_3() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_3) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_3) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_3)).id as *const _ as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_3), + "::", + stringify!(id) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_3)).lun as *const _ as usize + }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_3), + "::", + stringify!(lun) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_3)).reserved1 as *const _ + as usize + }, + 10usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_3), + "::", + stringify!(reserved1) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_3)).reserved2 as *const _ + as usize + }, + 12usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_3), + "::", + stringify!(reserved2) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_3 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_4 { + pub serial_number: __u64, + pub reserved: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_4() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_4) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_4) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_4)).serial_number + as *const _ as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_4), + "::", + stringify!(serial_number) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_4)).reserved as *const _ + as usize + }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_4), + "::", + stringify!(reserved) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_4 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_5 { + pub eui: __u64, + pub reserved: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_5() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_5) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_5) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_5)).eui as *const _ as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_5), + "::", + stringify!(eui) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_5)).reserved as *const _ + as usize + }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_5), + "::", + stringify!(reserved) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_5 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_6 { + pub wwid: __u64, + pub lun: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_6() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_6) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_6) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_6)).wwid as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_6), + "::", + stringify!(wwid) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_6)).lun as *const _ as usize + }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_6), + "::", + stringify!(lun) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_6 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_7 { + pub identity_tag: __u64, + pub reserved: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_7() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_7) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_7) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_7)).identity_tag as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_7), + "::", + stringify!(identity_tag) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_7)).reserved as *const _ + as usize + }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_7), + "::", + stringify!(reserved) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_7 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_8 { + pub array_number: __u32, + pub reserved1: __u32, + pub reserved2: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_8() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_8) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_8) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_8)).array_number as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_8), + "::", + stringify!(array_number) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_8)).reserved1 as *const _ + as usize + }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_8), + "::", + stringify!(reserved1) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_8)).reserved2 as *const _ + as usize + }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_8), + "::", + stringify!(reserved2) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_8 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_9 { + pub device: __u8, + pub reserved1: __u8, + pub reserved2: __u16, + pub reserved3: __u32, + pub reserved4: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_9() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_9) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_9) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_9)).device as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_9), + "::", + stringify!(device) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_9)).reserved1 as *const _ + as usize + }, + 1usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_9), + "::", + stringify!(reserved1) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_9)).reserved2 as *const _ + as usize + }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_9), + "::", + stringify!(reserved2) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_9)).reserved3 as *const _ + as usize + }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_9), + "::", + stringify!(reserved3) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_9)).reserved4 as *const _ + as usize + }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_9), + "::", + stringify!(reserved4) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_9 { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_device_params__bindgen_ty_2__bindgen_ty_10 { + pub reserved1: __u64, + pub reserved2: __u64, +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2__bindgen_ty_10() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!( + "Size of: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_10) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_10) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_10)).reserved1 as *const _ + as usize + }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_10), + "::", + stringify!(reserved1) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const edd_device_params__bindgen_ty_2__bindgen_ty_10)).reserved2 as *const _ + as usize + }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2__bindgen_ty_10), + "::", + stringify!(reserved2) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2__bindgen_ty_10 { + fn clone(&self) -> Self { + *self + } +} +#[test] +fn bindgen_test_layout_edd_device_params__bindgen_ty_2() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(edd_device_params__bindgen_ty_2)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(edd_device_params__bindgen_ty_2)) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).ata as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(ata) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).atapi as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(atapi) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).scsi as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(scsi) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).usb as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(usb) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).i1394 as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(i1394) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).fibre as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(fibre) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).i2o as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(i2o) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).raid as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(raid) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).sata as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(sata) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params__bindgen_ty_2)).unknown as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params__bindgen_ty_2), + "::", + stringify!(unknown) + ) + ); +} +impl Clone for edd_device_params__bindgen_ty_2 { + fn clone(&self) -> Self { + *self + } +} +#[test] +fn bindgen_test_layout_edd_device_params() { + assert_eq!( + ::std::mem::size_of::(), + 74usize, + concat!("Size of: ", stringify!(edd_device_params)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(edd_device_params)) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).length as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(length) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).info_flags as *const _ as usize }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(info_flags) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).num_default_cylinders as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(num_default_cylinders) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).num_default_heads as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(num_default_heads) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).sectors_per_track as *const _ as usize }, + 12usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(sectors_per_track) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).number_of_sectors as *const _ as usize }, + 16usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(number_of_sectors) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).bytes_per_sector as *const _ as usize }, + 24usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(bytes_per_sector) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).dpte_ptr as *const _ as usize }, + 26usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(dpte_ptr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).key as *const _ as usize }, + 30usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(key) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).device_path_info_length as *const _ as usize }, + 32usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(device_path_info_length) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).reserved2 as *const _ as usize }, + 33usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(reserved2) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).reserved3 as *const _ as usize }, + 34usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(reserved3) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).host_bus_type as *const _ as usize }, + 36usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(host_bus_type) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).interface_type as *const _ as usize }, + 40usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(interface_type) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).interface_path as *const _ as usize }, + 48usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(interface_path) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).device_path as *const _ as usize }, + 56usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(device_path) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).reserved4 as *const _ as usize }, + 72usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(reserved4) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_device_params)).checksum as *const _ as usize }, + 73usize, + concat!( + "Alignment of field: ", + stringify!(edd_device_params), + "::", + stringify!(checksum) + ) + ); +} +impl Clone for edd_device_params { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct edd_info { + pub device: __u8, + pub version: __u8, + pub interface_support: __u16, + pub legacy_max_cylinder: __u16, + pub legacy_max_head: __u8, + pub legacy_sectors_per_track: __u8, + pub params: edd_device_params, +} +#[test] +fn bindgen_test_layout_edd_info() { + assert_eq!( + ::std::mem::size_of::(), + 82usize, + concat!("Size of: ", stringify!(edd_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(edd_info)) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_info)).device as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd_info), + "::", + stringify!(device) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_info)).version as *const _ as usize }, + 1usize, + concat!( + "Alignment of field: ", + stringify!(edd_info), + "::", + stringify!(version) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_info)).interface_support as *const _ as usize }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(edd_info), + "::", + stringify!(interface_support) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_info)).legacy_max_cylinder as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(edd_info), + "::", + stringify!(legacy_max_cylinder) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_info)).legacy_max_head as *const _ as usize }, + 6usize, + concat!( + "Alignment of field: ", + stringify!(edd_info), + "::", + stringify!(legacy_max_head) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_info)).legacy_sectors_per_track as *const _ as usize }, + 7usize, + concat!( + "Alignment of field: ", + stringify!(edd_info), + "::", + stringify!(legacy_sectors_per_track) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd_info)).params as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(edd_info), + "::", + stringify!(params) + ) + ); +} +impl Clone for edd_info { + fn clone(&self) -> Self { + *self + } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct edd { + pub mbr_signature: [::std::os::raw::c_uint; 16usize], + pub edd_info: [edd_info; 6usize], + pub mbr_signature_nr: ::std::os::raw::c_uchar, + pub edd_info_nr: ::std::os::raw::c_uchar, +} +#[test] +fn bindgen_test_layout_edd() { + assert_eq!( + ::std::mem::size_of::(), + 560usize, + concat!("Size of: ", stringify!(edd)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(edd)) + ); + assert_eq!( + unsafe { &(*(0 as *const edd)).mbr_signature as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edd), + "::", + stringify!(mbr_signature) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd)).edd_info as *const _ as usize }, + 64usize, + concat!( + "Alignment of field: ", + stringify!(edd), + "::", + stringify!(edd_info) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd)).mbr_signature_nr as *const _ as usize }, + 556usize, + concat!( + "Alignment of field: ", + stringify!(edd), + "::", + stringify!(mbr_signature_nr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const edd)).edd_info_nr as *const _ as usize }, + 557usize, + concat!( + "Alignment of field: ", + stringify!(edd), + "::", + stringify!(edd_info_nr) + ) + ); +} +impl Clone for edd { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct e820entry { + pub addr: __u64, + pub size: __u64, + pub type_: __u32, +} +#[test] +fn bindgen_test_layout_e820entry() { + assert_eq!( + ::std::mem::size_of::(), + 20usize, + concat!("Size of: ", stringify!(e820entry)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(e820entry)) + ); + assert_eq!( + unsafe { &(*(0 as *const e820entry)).addr as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(e820entry), + "::", + stringify!(addr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const e820entry)).size as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(e820entry), + "::", + stringify!(size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const e820entry)).type_ as *const _ as usize }, + 16usize, + concat!( + "Alignment of field: ", + stringify!(e820entry), + "::", + stringify!(type_) + ) + ); +} +impl Clone for e820entry { + fn clone(&self) -> Self { + *self + } +} +#[repr(C)] +pub struct e820map { + pub nr_map: __u32, + pub map: [e820entry; 128usize], +} +#[test] +fn bindgen_test_layout_e820map() { + assert_eq!( + ::std::mem::size_of::(), + 2564usize, + concat!("Size of: ", stringify!(e820map)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(e820map)) + ); + assert_eq!( + unsafe { &(*(0 as *const e820map)).nr_map as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(e820map), + "::", + stringify!(nr_map) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const e820map)).map as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(e820map), + "::", + stringify!(map) + ) + ); +} +impl Default for e820map { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct ist_info { + pub signature: __u32, + pub command: __u32, + pub event: __u32, + pub perf_level: __u32, +} +#[test] +fn bindgen_test_layout_ist_info() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(ist_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(ist_info)) + ); + assert_eq!( + unsafe { &(*(0 as *const ist_info)).signature as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ist_info), + "::", + stringify!(signature) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ist_info)).command as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(ist_info), + "::", + stringify!(command) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ist_info)).event as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(ist_info), + "::", + stringify!(event) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ist_info)).perf_level as *const _ as usize }, + 12usize, + concat!( + "Alignment of field: ", + stringify!(ist_info), + "::", + stringify!(perf_level) + ) + ); +} +impl Clone for ist_info { + fn clone(&self) -> Self { + *self + } +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct edid_info { + pub dummy: [::std::os::raw::c_uchar; 128usize], +} +#[test] +fn bindgen_test_layout_edid_info() { + assert_eq!( + ::std::mem::size_of::(), + 128usize, + concat!("Size of: ", stringify!(edid_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(edid_info)) + ); + assert_eq!( + unsafe { &(*(0 as *const edid_info)).dummy as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(edid_info), + "::", + stringify!(dummy) + ) + ); +} +impl Default for edid_info { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct setup_data { + pub next: __u64, + pub type_: __u32, + pub len: __u32, + pub data: __IncompleteArrayField<__u8>, +} +#[test] +fn bindgen_test_layout_setup_data() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(setup_data)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(setup_data)) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_data)).next as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(setup_data), + "::", + stringify!(next) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_data)).type_ as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(setup_data), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_data)).len as *const _ as usize }, + 12usize, + concat!( + "Alignment of field: ", + stringify!(setup_data), + "::", + stringify!(len) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_data)).data as *const _ as usize }, + 16usize, + concat!( + "Alignment of field: ", + stringify!(setup_data), + "::", + stringify!(data) + ) + ); +} +impl Clone for setup_data { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub struct setup_header { + pub setup_sects: __u8, + pub root_flags: __u16, + pub syssize: __u32, + pub ram_size: __u16, + pub vid_mode: __u16, + pub root_dev: __u16, + pub boot_flag: __u16, + pub jump: __u16, + pub header: __u32, + pub version: __u16, + pub realmode_swtch: __u32, + pub start_sys: __u16, + pub kernel_version: __u16, + pub type_of_loader: __u8, + pub loadflags: __u8, + pub setup_move_size: __u16, + pub code32_start: __u32, + pub ramdisk_image: __u32, + pub ramdisk_size: __u32, + pub bootsect_kludge: __u32, + pub heap_end_ptr: __u16, + pub ext_loader_ver: __u8, + pub ext_loader_type: __u8, + pub cmd_line_ptr: __u32, + pub initrd_addr_max: __u32, + pub kernel_alignment: __u32, + pub relocatable_kernel: __u8, + pub min_alignment: __u8, + pub xloadflags: __u16, + pub cmdline_size: __u32, + pub hardware_subarch: __u32, + pub hardware_subarch_data: __u64, + pub payload_offset: __u32, + pub payload_length: __u32, + pub setup_data: __u64, + pub pref_address: __u64, + pub init_size: __u32, + pub handover_offset: __u32, +} +#[test] +fn bindgen_test_layout_setup_header() { + assert_eq!( + ::std::mem::size_of::(), + 119usize, + concat!("Size of: ", stringify!(setup_header)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(setup_header)) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).setup_sects as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(setup_sects) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).root_flags as *const _ as usize }, + 1usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(root_flags) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).syssize as *const _ as usize }, + 3usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(syssize) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).ram_size as *const _ as usize }, + 7usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(ram_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).vid_mode as *const _ as usize }, + 9usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(vid_mode) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).root_dev as *const _ as usize }, + 11usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(root_dev) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).boot_flag as *const _ as usize }, + 13usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(boot_flag) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).jump as *const _ as usize }, + 15usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(jump) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).header as *const _ as usize }, + 17usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(header) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).version as *const _ as usize }, + 21usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(version) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).realmode_swtch as *const _ as usize }, + 23usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(realmode_swtch) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).start_sys as *const _ as usize }, + 27usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(start_sys) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).kernel_version as *const _ as usize }, + 29usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(kernel_version) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).type_of_loader as *const _ as usize }, + 31usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(type_of_loader) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).loadflags as *const _ as usize }, + 32usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(loadflags) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).setup_move_size as *const _ as usize }, + 33usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(setup_move_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).code32_start as *const _ as usize }, + 35usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(code32_start) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).ramdisk_image as *const _ as usize }, + 39usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(ramdisk_image) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).ramdisk_size as *const _ as usize }, + 43usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(ramdisk_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).bootsect_kludge as *const _ as usize }, + 47usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(bootsect_kludge) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).heap_end_ptr as *const _ as usize }, + 51usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(heap_end_ptr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).ext_loader_ver as *const _ as usize }, + 53usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(ext_loader_ver) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).ext_loader_type as *const _ as usize }, + 54usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(ext_loader_type) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).cmd_line_ptr as *const _ as usize }, + 55usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(cmd_line_ptr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).initrd_addr_max as *const _ as usize }, + 59usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(initrd_addr_max) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).kernel_alignment as *const _ as usize }, + 63usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(kernel_alignment) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).relocatable_kernel as *const _ as usize }, + 67usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(relocatable_kernel) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).min_alignment as *const _ as usize }, + 68usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(min_alignment) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).xloadflags as *const _ as usize }, + 69usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(xloadflags) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).cmdline_size as *const _ as usize }, + 71usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(cmdline_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).hardware_subarch as *const _ as usize }, + 75usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(hardware_subarch) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).hardware_subarch_data as *const _ as usize }, + 79usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(hardware_subarch_data) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).payload_offset as *const _ as usize }, + 87usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(payload_offset) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).payload_length as *const _ as usize }, + 91usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(payload_length) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).setup_data as *const _ as usize }, + 95usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(setup_data) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).pref_address as *const _ as usize }, + 103usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(pref_address) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).init_size as *const _ as usize }, + 111usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(init_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const setup_header)).handover_offset as *const _ as usize }, + 115usize, + concat!( + "Alignment of field: ", + stringify!(setup_header), + "::", + stringify!(handover_offset) + ) + ); +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct sys_desc_table { + pub length: __u16, + pub table: [__u8; 14usize], +} +#[test] +fn bindgen_test_layout_sys_desc_table() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(sys_desc_table)) + ); + assert_eq!( + ::std::mem::align_of::(), + 2usize, + concat!("Alignment of ", stringify!(sys_desc_table)) + ); + assert_eq!( + unsafe { &(*(0 as *const sys_desc_table)).length as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(sys_desc_table), + "::", + stringify!(length) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const sys_desc_table)).table as *const _ as usize }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(sys_desc_table), + "::", + stringify!(table) + ) + ); +} +impl Clone for sys_desc_table { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Debug, Default, Copy)] +pub struct olpc_ofw_header { + pub ofw_magic: __u32, + pub ofw_version: __u32, + pub cif_handler: __u32, + pub irq_desc_table: __u32, +} +#[test] +fn bindgen_test_layout_olpc_ofw_header() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(olpc_ofw_header)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(olpc_ofw_header)) + ); + assert_eq!( + unsafe { &(*(0 as *const olpc_ofw_header)).ofw_magic as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(olpc_ofw_header), + "::", + stringify!(ofw_magic) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const olpc_ofw_header)).ofw_version as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(olpc_ofw_header), + "::", + stringify!(ofw_version) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const olpc_ofw_header)).cif_handler as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(olpc_ofw_header), + "::", + stringify!(cif_handler) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const olpc_ofw_header)).irq_desc_table as *const _ as usize }, + 12usize, + concat!( + "Alignment of field: ", + stringify!(olpc_ofw_header), + "::", + stringify!(irq_desc_table) + ) + ); +} +impl Clone for olpc_ofw_header { + fn clone(&self) -> Self { + *self + } +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct efi_info { + pub efi_loader_signature: __u32, + pub efi_systab: __u32, + pub efi_memdesc_size: __u32, + pub efi_memdesc_version: __u32, + pub efi_memmap: __u32, + pub efi_memmap_size: __u32, + pub efi_systab_hi: __u32, + pub efi_memmap_hi: __u32, +} +#[test] +fn bindgen_test_layout_efi_info() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(efi_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(efi_info)) + ); + assert_eq!( + unsafe { &(*(0 as *const efi_info)).efi_loader_signature as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(efi_info), + "::", + stringify!(efi_loader_signature) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const efi_info)).efi_systab as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(efi_info), + "::", + stringify!(efi_systab) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const efi_info)).efi_memdesc_size as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(efi_info), + "::", + stringify!(efi_memdesc_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const efi_info)).efi_memdesc_version as *const _ as usize }, + 12usize, + concat!( + "Alignment of field: ", + stringify!(efi_info), + "::", + stringify!(efi_memdesc_version) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const efi_info)).efi_memmap as *const _ as usize }, + 16usize, + concat!( + "Alignment of field: ", + stringify!(efi_info), + "::", + stringify!(efi_memmap) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const efi_info)).efi_memmap_size as *const _ as usize }, + 20usize, + concat!( + "Alignment of field: ", + stringify!(efi_info), + "::", + stringify!(efi_memmap_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const efi_info)).efi_systab_hi as *const _ as usize }, + 24usize, + concat!( + "Alignment of field: ", + stringify!(efi_info), + "::", + stringify!(efi_systab_hi) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const efi_info)).efi_memmap_hi as *const _ as usize }, + 28usize, + concat!( + "Alignment of field: ", + stringify!(efi_info), + "::", + stringify!(efi_memmap_hi) + ) + ); +} +impl Clone for efi_info { + fn clone(&self) -> Self { + *self + } +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct boot_params { + pub screen_info: screen_info, + pub apm_bios_info: apm_bios_info, + pub _pad2: [__u8; 4usize], + pub tboot_addr: __u64, + pub ist_info: ist_info, + pub _pad3: [__u8; 16usize], + pub hd0_info: [__u8; 16usize], + pub hd1_info: [__u8; 16usize], + pub sys_desc_table: sys_desc_table, + pub olpc_ofw_header: olpc_ofw_header, + pub ext_ramdisk_image: __u32, + pub ext_ramdisk_size: __u32, + pub ext_cmd_line_ptr: __u32, + pub _pad4: [__u8; 116usize], + pub edid_info: edid_info, + pub efi_info: efi_info, + pub alt_mem_k: __u32, + pub scratch: __u32, + pub e820_entries: __u8, + pub eddbuf_entries: __u8, + pub edd_mbr_sig_buf_entries: __u8, + pub kbd_status: __u8, + pub _pad5: [__u8; 3usize], + pub sentinel: __u8, + pub _pad6: [__u8; 1usize], + pub hdr: setup_header, + pub _pad7: [__u8; 40usize], + pub edd_mbr_sig_buffer: [__u32; 16usize], + pub e820_map: [e820entry; 128usize], + pub _pad8: [__u8; 48usize], + pub eddbuf: [edd_info; 6usize], + pub _pad9: [__u8; 276usize], +} +#[test] +fn bindgen_test_layout_boot_params() { + assert_eq!( + ::std::mem::size_of::(), + 4096usize, + concat!("Size of: ", stringify!(boot_params)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(boot_params)) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).screen_info as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(screen_info) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).apm_bios_info as *const _ as usize }, + 64usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(apm_bios_info) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params))._pad2 as *const _ as usize }, + 84usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(_pad2) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).tboot_addr as *const _ as usize }, + 88usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(tboot_addr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).ist_info as *const _ as usize }, + 96usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(ist_info) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params))._pad3 as *const _ as usize }, + 112usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(_pad3) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).hd0_info as *const _ as usize }, + 128usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(hd0_info) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).hd1_info as *const _ as usize }, + 144usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(hd1_info) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).sys_desc_table as *const _ as usize }, + 160usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(sys_desc_table) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).olpc_ofw_header as *const _ as usize }, + 176usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(olpc_ofw_header) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).ext_ramdisk_image as *const _ as usize }, + 192usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(ext_ramdisk_image) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).ext_ramdisk_size as *const _ as usize }, + 196usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(ext_ramdisk_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).ext_cmd_line_ptr as *const _ as usize }, + 200usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(ext_cmd_line_ptr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params))._pad4 as *const _ as usize }, + 204usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(_pad4) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).edid_info as *const _ as usize }, + 320usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(edid_info) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).efi_info as *const _ as usize }, + 448usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(efi_info) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).alt_mem_k as *const _ as usize }, + 480usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(alt_mem_k) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).scratch as *const _ as usize }, + 484usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(scratch) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).e820_entries as *const _ as usize }, + 488usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(e820_entries) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).eddbuf_entries as *const _ as usize }, + 489usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(eddbuf_entries) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).edd_mbr_sig_buf_entries as *const _ as usize }, + 490usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(edd_mbr_sig_buf_entries) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).kbd_status as *const _ as usize }, + 491usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(kbd_status) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params))._pad5 as *const _ as usize }, + 492usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(_pad5) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).sentinel as *const _ as usize }, + 495usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(sentinel) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params))._pad6 as *const _ as usize }, + 496usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(_pad6) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).hdr as *const _ as usize }, + 497usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(hdr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params))._pad7 as *const _ as usize }, + 616usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(_pad7) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).edd_mbr_sig_buffer as *const _ as usize }, + 656usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(edd_mbr_sig_buffer) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).e820_map as *const _ as usize }, + 720usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(e820_map) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params))._pad8 as *const _ as usize }, + 3280usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(_pad8) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params)).eddbuf as *const _ as usize }, + 3328usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(eddbuf) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const boot_params))._pad9 as *const _ as usize }, + 3820usize, + concat!( + "Alignment of field: ", + stringify!(boot_params), + "::", + stringify!(_pad9) + ) + ); +} +impl Default for boot_params { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +pub const X86_SUBARCH_PC: _bindgen_ty_1 = 0; +pub const X86_SUBARCH_LGUEST: _bindgen_ty_1 = 1; +pub const X86_SUBARCH_XEN: _bindgen_ty_1 = 2; +pub const X86_SUBARCH_INTEL_MID: _bindgen_ty_1 = 3; +pub const X86_SUBARCH_CE4100: _bindgen_ty_1 = 4; +pub const X86_NR_SUBARCHS: _bindgen_ty_1 = 5; +pub type _bindgen_ty_1 = ::std::os::raw::c_uint; diff --git a/src/loader/elf.rs b/src/loader/elf.rs new file mode 100644 index 00000000..b7d71d7a --- /dev/null +++ b/src/loader/elf.rs @@ -0,0 +1,340 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Portions Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-BSD-3-Clause file. +// +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause + +/* + * automatically generated by rust-bindgen + * From upstream linux include/uapi/linux/elf.h at commit: + * 806276b7f07a39a1cc3f38bb1ef5c573d4594a38 + */ +pub const EI_MAG0: ::std::os::raw::c_uint = 0; +pub const EI_MAG1: ::std::os::raw::c_uint = 1; +pub const EI_MAG2: ::std::os::raw::c_uint = 2; +pub const EI_MAG3: ::std::os::raw::c_uint = 3; +pub const EI_DATA: ::std::os::raw::c_uint = 5; + +pub const ELFMAG0: ::std::os::raw::c_uint = 127; + +pub const ELFDATA2LSB: ::std::os::raw::c_uint = 1; +pub const PT_LOAD: ::std::os::raw::c_uint = 1; + +pub const ELFMAG1: u8 = b'E'; +pub const ELFMAG2: u8 = b'L'; +pub const ELFMAG3: u8 = b'F'; + +type Elf64_Addr = __u64; +type Elf64_Half = __u16; +type Elf64_Off = __u64; +type Elf64_Word = __u32; +type Elf64_Xword = __u64; + +type __s8 = ::std::os::raw::c_schar; +type __u8 = ::std::os::raw::c_uchar; +type __s16 = ::std::os::raw::c_short; +type __u16 = ::std::os::raw::c_ushort; +type __s32 = ::std::os::raw::c_int; +type __u32 = ::std::os::raw::c_uint; +type __s64 = ::std::os::raw::c_longlong; +type __u64 = ::std::os::raw::c_ulonglong; + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct elf64_hdr { + pub e_ident: [::std::os::raw::c_uchar; 16usize], + pub e_type: Elf64_Half, + pub e_machine: Elf64_Half, + pub e_version: Elf64_Word, + pub e_entry: Elf64_Addr, + pub e_phoff: Elf64_Off, + pub e_shoff: Elf64_Off, + pub e_flags: Elf64_Word, + pub e_ehsize: Elf64_Half, + pub e_phentsize: Elf64_Half, + pub e_phnum: Elf64_Half, + pub e_shentsize: Elf64_Half, + pub e_shnum: Elf64_Half, + pub e_shstrndx: Elf64_Half, +} +impl Clone for elf64_hdr { + fn clone(&self) -> Self { + *self + } +} +pub type Elf64_Ehdr = elf64_hdr; + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct elf64_phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, +} + +impl Clone for elf64_phdr { + fn clone(&self) -> Self { + *self + } +} +pub type Elf64_Phdr = elf64_phdr; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bindgen_test_layout_elf64_phdr() { + assert_eq!( + ::std::mem::size_of::(), + 56usize, + concat!("Size of: ", stringify!(elf64_phdr)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(elf64_phdr)) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_phdr)).p_type as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(elf64_phdr), + "::", + stringify!(p_type) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_phdr)).p_flags as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(elf64_phdr), + "::", + stringify!(p_flags) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_phdr)).p_offset as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(elf64_phdr), + "::", + stringify!(p_offset) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_phdr)).p_vaddr as *const _ as usize }, + 16usize, + concat!( + "Alignment of field: ", + stringify!(elf64_phdr), + "::", + stringify!(p_vaddr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_phdr)).p_paddr as *const _ as usize }, + 24usize, + concat!( + "Alignment of field: ", + stringify!(elf64_phdr), + "::", + stringify!(p_paddr) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_phdr)).p_filesz as *const _ as usize }, + 32usize, + concat!( + "Alignment of field: ", + stringify!(elf64_phdr), + "::", + stringify!(p_filesz) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_phdr)).p_memsz as *const _ as usize }, + 40usize, + concat!( + "Alignment of field: ", + stringify!(elf64_phdr), + "::", + stringify!(p_memsz) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_phdr)).p_align as *const _ as usize }, + 48usize, + concat!( + "Alignment of field: ", + stringify!(elf64_phdr), + "::", + stringify!(p_align) + ) + ); + } + + #[test] + fn bindgen_test_layout_elf64_hdr() { + assert_eq!( + ::std::mem::size_of::(), + 64usize, + concat!("Size of: ", stringify!(elf64_hdr)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(elf64_hdr)) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_ident as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_ident) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_type as *const _ as usize }, + 16usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_type) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_machine as *const _ as usize }, + 18usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_machine) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_version as *const _ as usize }, + 20usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_version) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_entry as *const _ as usize }, + 24usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_entry) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_phoff as *const _ as usize }, + 32usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_phoff) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_shoff as *const _ as usize }, + 40usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_shoff) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_flags as *const _ as usize }, + 48usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_flags) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_ehsize as *const _ as usize }, + 52usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_ehsize) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_phentsize as *const _ as usize }, + 54usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_phentsize) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_phnum as *const _ as usize }, + 56usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_phnum) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_shentsize as *const _ as usize }, + 58usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_shentsize) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_shnum as *const _ as usize }, + 60usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_shnum) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const elf64_hdr)).e_shstrndx as *const _ as usize }, + 62usize, + concat!( + "Alignment of field: ", + stringify!(elf64_hdr), + "::", + stringify!(e_shstrndx) + ) + ); + } +} diff --git a/src/loader/mod.rs b/src/loader/mod.rs new file mode 100644 index 00000000..b130113e --- /dev/null +++ b/src/loader/mod.rs @@ -0,0 +1,650 @@ +// Copyright (c) 2019 Intel Corporation. All rights reserved. +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-BSD-3-Clause file. +// +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause + +//! Traits and Structs +//! - [KernelLoader](trait.KernelLoader.html): load kernel image into guest memory +//! - [KernelLoaderResult](struct.KernelLoaderResult.html): the structure which loader +//! returns to VMM to assist zero page construction and boot environment setup +//! - [Elf](struct.Elf.html): elf image loader +//! - [BzImage](struct.BzImage.html): bzImage loader + +extern crate vm_memory; + +use std::error::{self, Error as KernelLoaderError}; +use std::ffi::CStr; +use std::fmt::{self, Display}; +#[cfg(any(feature = "elf", feature = "bzimage"))] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use std::io::SeekFrom; +use std::io::{Read, Seek}; +#[cfg(feature = "elf")] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use std::mem; + +use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestUsize}; + +#[allow(dead_code)] +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[allow(non_upper_case_globals)] +#[allow(missing_docs)] +#[cfg_attr(feature = "cargo-clippy", allow(clippy::all))] +pub mod bootparam; +#[allow(dead_code)] +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[allow(non_upper_case_globals)] +#[cfg_attr(feature = "cargo-clippy", allow(clippy::all))] +mod elf; +#[cfg(any(feature = "elf", feature = "bzimage"))] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod struct_util; + +#[derive(Debug, PartialEq)] +/// Kernel loader errors. +pub enum Error { + /// Loaded big endian binary on a little endian platform. + BigEndianElfOnLittle, + /// Failed writing command line to guest memory. + CommandLineCopy, + /// Command line overflowed guest memory. + CommandLineOverflow, + /// Invalid ELF magic number + InvalidElfMagicNumber, + /// Invalid program header size. + InvalidProgramHeaderSize, + /// Invalid program header offset. + InvalidProgramHeaderOffset, + /// Invalid program header address. + InvalidProgramHeaderAddress, + /// Invalid entry address. + InvalidEntryAddress, + /// Invalid bzImage binary. + InvalidBzImage, + /// Invalid kernel start address. + InvalidKernelStartAddress, + /// Memory to load kernel image is too small. + MemoryOverflow, + /// Unable to read ELF header. + ReadElfHeader, + /// Unable to read kernel image. + ReadKernelImage, + /// Unable to read program header. + ReadProgramHeader, + /// Unable to read bzImage header. + ReadBzImageHeader, + /// Unable to read bzImage compressed image. + ReadBzImageCompressedKernel, + /// Unable to seek to kernel start. + SeekKernelStart, + /// Unable to seek to ELF start. + SeekElfStart, + /// Unable to seek to program header. + SeekProgramHeader, + /// Unable to seek to bzImage end. + SeekBzImageEnd, + /// Unable to seek to bzImage header. + SeekBzImageHeader, + /// Unable to seek to bzImage compressed kernel. + SeekBzImageCompressedKernel, +} + +/// A specialized `Result` type for the kernel loader. +pub type Result = std::result::Result; + +impl error::Error for Error { + fn description(&self) -> &str { + match self { + Error::BigEndianElfOnLittle => { + "Trying to load big-endian binary on little-endian machine" + } + Error::CommandLineCopy => "Failed writing command line to guest memory", + Error::CommandLineOverflow => "Command line overflowed guest memory", + Error::InvalidElfMagicNumber => "Invalid Elf magic number", + Error::InvalidProgramHeaderSize => "Invalid program header size", + Error::InvalidProgramHeaderOffset => "Invalid program header offset", + Error::InvalidProgramHeaderAddress => "Invalid Program Header Address", + Error::InvalidEntryAddress => "Invalid entry address", + Error::InvalidBzImage => "Invalid bzImage", + Error::InvalidKernelStartAddress => "Invalid kernel start address", + Error::MemoryOverflow => "Memory to load kernel image is not enough", + Error::ReadElfHeader => "Unable to read elf header", + Error::ReadKernelImage => "Unable to read kernel image", + Error::ReadProgramHeader => "Unable to read program header", + Error::ReadBzImageHeader => "Unable to read bzImage header", + Error::ReadBzImageCompressedKernel => "Unable to read bzImage compressed kernel", + Error::SeekKernelStart => "Unable to seek to kernel start", + Error::SeekElfStart => "Unable to seek to elf start", + Error::SeekProgramHeader => "Unable to seek to program header", + Error::SeekBzImageEnd => "Unable to seek bzImage end", + Error::SeekBzImageHeader => "Unable to seek bzImage header", + Error::SeekBzImageCompressedKernel => "Unable to seek bzImage compressed kernel", + } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Kernel Loader Error: {}", Error::description(self)) + } +} + +#[derive(Debug, Default, Copy, Clone, PartialEq)] +/// Result of the KernelLoader load() call. +/// +/// This specifies where the kernel is loading and passes additional +/// information for the rest of the boot process to be completed by +/// the VMM. +pub struct KernelLoaderResult { + /// Address in the guest memory where the kernel image starts to be loaded + pub kernel_load: GuestAddress, + /// Offset in guest memory corresponding to the end of kernel image, in case that + /// device tree blob and initrd will be loaded adjacent to kernel image. + pub kernel_end: GuestUsize, + /// This field is only for bzImage following https://www.kernel.org/doc/Documentation/x86/boot.txt + /// VMM should make use of it to fill zero page for bzImage direct boot. + pub setup_header: Option, +} + +/// A kernel image loading support must implement the KernelLoader trait. +/// The only method to be implemented is the load one, returning a KernelLoaderResult structure. +pub trait KernelLoader { + /// How to load a specific kernel image format into the guest memory. + fn load( + guest_mem: &M, + kernel_start: Option, + kernel_image: &mut F, + highmem_start_address: Option, + ) -> Result + where + F: Read + Seek; +} + +#[cfg(feature = "elf")] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +/// Raw ELF (a.k.a. vmlinux) kernel image support. +pub struct Elf; + +#[cfg(feature = "elf")] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl KernelLoader for Elf { + /// Loads a kernel from a vmlinux elf image to a slice + /// + /// kernel is loaded into guest memory at offset phdr.p_paddr specified by elf image. + /// + /// # Arguments + /// + /// * `guest_mem` - The guest memory region the kernel is written to. + /// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel. + /// * `kernel_image` - Input vmlinux image. + /// * `highmem_start_address` - This is the start of the high memory, kernel should above it. + /// + /// # Returns + /// * KernelLoaderResult + fn load( + guest_mem: &M, + kernel_start: Option, + kernel_image: &mut F, + highmem_start_address: Option, + ) -> Result + where + F: Read + Seek, + { + let mut ehdr: elf::Elf64_Ehdr = Default::default(); + kernel_image + .seek(SeekFrom::Start(0)) + .map_err(|_| Error::SeekElfStart)?; + unsafe { + // read_struct is safe when reading a POD struct. It can be used and dropped without issue. + struct_util::read_struct(kernel_image, &mut ehdr).map_err(|_| Error::ReadElfHeader)?; + } + + // Sanity checks + if ehdr.e_ident[elf::EI_MAG0 as usize] != elf::ELFMAG0 as u8 + || ehdr.e_ident[elf::EI_MAG1 as usize] != elf::ELFMAG1 + || ehdr.e_ident[elf::EI_MAG2 as usize] != elf::ELFMAG2 + || ehdr.e_ident[elf::EI_MAG3 as usize] != elf::ELFMAG3 + { + return Err(Error::InvalidElfMagicNumber); + } + if ehdr.e_ident[elf::EI_DATA as usize] != elf::ELFDATA2LSB as u8 { + return Err(Error::BigEndianElfOnLittle); + } + if ehdr.e_phentsize as usize != mem::size_of::() { + return Err(Error::InvalidProgramHeaderSize); + } + if (ehdr.e_phoff as usize) < mem::size_of::() { + return Err(Error::InvalidProgramHeaderOffset); + } + if (highmem_start_address.is_some()) + && ((ehdr.e_entry as u64) < highmem_start_address.unwrap().raw_value()) + { + return Err(Error::InvalidEntryAddress); + } + + let mut loader_result: KernelLoaderResult = Default::default(); + // where the kernel will be start loaded. + loader_result.kernel_load = match kernel_start { + Some(start) => GuestAddress(start.raw_value() + (ehdr.e_entry as u64)), + None => GuestAddress(ehdr.e_entry as u64), + }; + + kernel_image + .seek(SeekFrom::Start(ehdr.e_phoff)) + .map_err(|_| Error::SeekProgramHeader)?; + let phdrs: Vec = unsafe { + // Reading the structs is safe for a slice of POD structs. + struct_util::read_struct_slice(kernel_image, ehdr.e_phnum as usize) + .map_err(|_| Error::ReadProgramHeader)? + }; + + // Read in each section pointed to by the program headers. + for phdr in &phdrs { + if phdr.p_type != elf::PT_LOAD || phdr.p_filesz == 0 { + continue; + } + + kernel_image + .seek(SeekFrom::Start(phdr.p_offset)) + .map_err(|_| Error::SeekKernelStart)?; + + // if the vmm does not specify where the kernel should be loaded, just + // load it to the physical address p_paddr for each segment. + let mem_offset = match kernel_start { + Some(start) => start + .checked_add(phdr.p_paddr as u64) + .ok_or(Error::InvalidProgramHeaderAddress)?, + None => GuestAddress(phdr.p_paddr as u64), + }; + + guest_mem + .read_exact_from(mem_offset, kernel_image, phdr.p_filesz as usize) + .map_err(|_| Error::ReadKernelImage)?; + + loader_result.kernel_end = mem_offset + .raw_value() + .checked_add(phdr.p_memsz as GuestUsize) + .ok_or(Error::MemoryOverflow)?; + } + + // elf image has no setup_header which is defined for bzImage + loader_result.setup_header = None; + + Ok(loader_result) + } +} + +#[cfg(feature = "bzimage")] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +/// Big zImage (bzImage) kernel image support. +pub struct BzImage; + +#[cfg(feature = "bzimage")] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl KernelLoader for BzImage { + /// Loads a bzImage + /// + /// kernel is loaded into guest memory at code32_start the default load address + /// stored in bzImage setup header. + /// + /// # Arguments + /// + /// * `guest_mem` - The guest memory where the kernel image is loaded. + /// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel. + /// * `kernel_image` - Input bzImage image. + /// * `highmem_start_address` - This is the start of the high memory, kernel should above it. + /// + /// # Returns + /// * KernelLoaderResult + fn load( + guest_mem: &M, + kernel_start: Option, + kernel_image: &mut F, + highmem_start_address: Option, + ) -> Result + where + F: Read + Seek, + { + let mut kernel_size = kernel_image + .seek(SeekFrom::End(0)) + .map_err(|_| Error::SeekBzImageEnd)? as usize; + let mut boot_header: bootparam::setup_header = Default::default(); + kernel_image + .seek(SeekFrom::Start(0x1F1)) + .map_err(|_| Error::SeekBzImageHeader)?; + unsafe { + // read_struct is safe when reading a POD struct. It can be used and dropped without issue. + struct_util::read_struct(kernel_image, &mut boot_header) + .map_err(|_| Error::ReadBzImageHeader)?; + } + + // if the HdrS magic number is not found at offset 0x202, the boot protocol version is "old", + // the image type is assumed as zImage, not bzImage. + if boot_header.header != 0x5372_6448 { + return Err(Error::InvalidBzImage); + } + + // follow section of loading the rest of the kernel in linux boot protocol + if (boot_header.version < 0x0200) || ((boot_header.loadflags & 0x1) == 0x0) { + return Err(Error::InvalidBzImage); + } + + let mut setup_size = boot_header.setup_sects as usize; + if setup_size == 0 { + setup_size = 4; + } + setup_size = (setup_size + 1) * 512; + kernel_size -= setup_size; + + // verify bzImage validation by checking if code32_start, the defaults to the address of + // the kernel is not lower than high memory. + if (highmem_start_address.is_some()) + && (u64::from(boot_header.code32_start) < highmem_start_address.unwrap().raw_value()) + { + return Err(Error::InvalidKernelStartAddress); + } + + let mem_offset = match kernel_start { + Some(start) => start, + None => GuestAddress(u64::from(boot_header.code32_start)), + }; + + boot_header.code32_start = mem_offset.raw_value() as u32; + + let mut loader_result: KernelLoaderResult = Default::default(); + loader_result.setup_header = Some(boot_header); + loader_result.kernel_load = mem_offset; + + //seek the compressed vmlinux.bin and read to memory + kernel_image + .seek(SeekFrom::Start(setup_size as u64)) + .map_err(|_| Error::SeekBzImageCompressedKernel)?; + guest_mem + .read_exact_from(mem_offset, kernel_image, kernel_size) + .map_err(|_| Error::ReadBzImageCompressedKernel)?; + + loader_result.kernel_end = mem_offset + .raw_value() + .checked_add(kernel_size as GuestUsize) + .ok_or(Error::MemoryOverflow)?; + + Ok(loader_result) + } +} + +/// Writes the command line string to the given memory slice. +/// +/// # Arguments +/// +/// * `guest_mem` - A u8 slice that will be partially overwritten by the command line. +/// * `guest_addr` - The address in `guest_mem` at which to load the command line. +/// * `cmdline` - The kernel command line. +pub fn load_cmdline( + guest_mem: &M, + guest_addr: GuestAddress, + cmdline: &CStr, +) -> Result<()> { + let len = cmdline.to_bytes().len(); + if len == 0 { + return Ok(()); + } + + let end = guest_addr + .checked_add(len as u64 + 1) + .ok_or(Error::CommandLineOverflow)?; // Extra for null termination. + if end > guest_mem.end_addr() { + return Err(Error::CommandLineOverflow)?; + } + + guest_mem + .write_slice(cmdline.to_bytes_with_nul(), guest_addr) + .map_err(|_| Error::CommandLineCopy)?; + + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + #[cfg(any(feature = "elf", feature = "bzimage"))] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + use std::io::Cursor; + use vm_memory::{Address, GuestAddress, GuestMemoryMmap}; + + const MEM_SIZE: u64 = 0x1000000; + + fn create_guest_mem() -> GuestMemoryMmap { + GuestMemoryMmap::new(&[(GuestAddress(0x0), (MEM_SIZE as usize))]).unwrap() + } + + #[cfg(feature = "bzimage")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn make_bzimage() -> Vec { + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!("bzimage")); + v + } + + // Elf64 image that prints hello world on x86_64. + #[cfg(feature = "elf")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn make_elf_bin() -> Vec { + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!("test_elf.bin")); + v + } + + #[allow(safe_packed_borrows)] + #[allow(non_snake_case)] + #[test] + #[cfg(feature = "bzimage")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn load_bzImage() { + let gm = create_guest_mem(); + let image = make_bzimage(); + let mut kernel_start = GuestAddress(0x200000); + let mut highmem_start_address = GuestAddress(0x0); + + // load bzImage with good kernel_start and himem_start setting + let mut loader_result = BzImage::load( + &gm, + Some(kernel_start), + &mut Cursor::new(&image), + Some(highmem_start_address), + ) + .unwrap(); + assert_eq!(0x53726448, loader_result.setup_header.unwrap().header); + println!( + "bzImage is loaded at {:8x} \n", + loader_result.kernel_load.raw_value() + ); + println!( + "bzImage version is {:2x} \n", + loader_result.setup_header.unwrap().version + ); + println!( + "bzImage loadflags is {:x} \n", + loader_result.setup_header.unwrap().loadflags + ); + println!( + "bzImage kernel size is {:4x} \n", + (loader_result.kernel_end as u32) + ); + + // load bzImage without kernel_start + loader_result = BzImage::load( + &gm, + None, + &mut Cursor::new(&image), + Some(highmem_start_address), + ) + .unwrap(); + assert_eq!(0x53726448, loader_result.setup_header.unwrap().header); + println!( + "bzImage is loaded at {:8x} \n", + loader_result.kernel_load.raw_value() + ); + + // load bzImage withouth himem_start + loader_result = BzImage::load(&gm, None, &mut Cursor::new(&image), None).unwrap(); + assert_eq!(0x53726448, loader_result.setup_header.unwrap().header); + println!( + "bzImage is loaded at {:8x} \n", + loader_result.kernel_load.raw_value() + ); + + // load bzImage with a bad himem setting + kernel_start = GuestAddress(0x1000); + highmem_start_address = GuestAddress(0x200000); + let x = BzImage::load( + &gm, + Some(kernel_start), + &mut Cursor::new(&image), + Some(highmem_start_address), + ); + assert_eq!(x.is_ok(), false); + println!("load bzImage with bad himem setting \n"); + } + + #[test] + #[cfg(feature = "elf")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn load_elf() { + let gm = create_guest_mem(); + let image = make_elf_bin(); + let kernel_addr = GuestAddress(0x200000); + let mut highmem_start_address = GuestAddress(0x0); + let mut loader_result = Elf::load( + &gm, + Some(kernel_addr), + &mut Cursor::new(&image), + Some(highmem_start_address), + ) + .unwrap(); + println!( + "load elf at address {:8x} \n", + loader_result.kernel_load.raw_value() + ); + + loader_result = Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&image), None).unwrap(); + println!( + "load elf at address {:8x} \n", + loader_result.kernel_load.raw_value() + ); + + loader_result = Elf::load( + &gm, + None, + &mut Cursor::new(&image), + Some(highmem_start_address), + ) + .unwrap(); + println!( + "load elf at address {:8x} \n", + loader_result.kernel_load.raw_value() + ); + + highmem_start_address = GuestAddress(0xa00000); + assert_eq!( + Err(Error::InvalidEntryAddress), + Elf::load( + &gm, + None, + &mut Cursor::new(&image), + Some(highmem_start_address) + ) + ); + } + + #[test] + fn cmdline_overflow() { + let gm = create_guest_mem(); + let cmdline_address = GuestAddress(MEM_SIZE - 5); + assert_eq!( + Err(Error::CommandLineOverflow), + load_cmdline( + &gm, + cmdline_address, + CStr::from_bytes_with_nul(b"12345\0").unwrap() + ) + ); + } + + #[test] + fn cmdline_write_end() { + let gm = create_guest_mem(); + let mut cmdline_address = GuestAddress(45); + assert_eq!( + Ok(()), + load_cmdline( + &gm, + cmdline_address, + CStr::from_bytes_with_nul(b"1234\0").unwrap() + ) + ); + let val: u8 = gm.read_obj(cmdline_address).unwrap(); + assert_eq!(val, '1' as u8); + cmdline_address = cmdline_address.unchecked_add(1); + let val: u8 = gm.read_obj(cmdline_address).unwrap(); + assert_eq!(val, '2' as u8); + cmdline_address = cmdline_address.unchecked_add(1); + let val: u8 = gm.read_obj(cmdline_address).unwrap(); + assert_eq!(val, '3' as u8); + cmdline_address = cmdline_address.unchecked_add(1); + let val: u8 = gm.read_obj(cmdline_address).unwrap(); + assert_eq!(val, '4' as u8); + cmdline_address = cmdline_address.unchecked_add(1); + let val: u8 = gm.read_obj(cmdline_address).unwrap(); + assert_eq!(val, '\0' as u8); + } + + #[cfg(feature = "elf")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + #[test] + fn bad_magic() { + let gm = create_guest_mem(); + let kernel_addr = GuestAddress(0x0); + let mut bad_image = make_elf_bin(); + bad_image[0x1] = 0x33; + assert_eq!( + Err(Error::InvalidElfMagicNumber), + Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&bad_image), None) + ); + } + + #[cfg(feature = "elf")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + #[test] + fn bad_endian() { + // Only little endian is supported + let gm = create_guest_mem(); + let kernel_addr = GuestAddress(0x0); + let mut bad_image = make_elf_bin(); + bad_image[0x5] = 2; + assert_eq!( + Err(Error::BigEndianElfOnLittle), + Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&bad_image), None) + ); + } + + #[cfg(feature = "elf")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + #[test] + fn bad_phoff() { + // program header has to be past the end of the elf header + let gm = create_guest_mem(); + let kernel_addr = GuestAddress(0x0); + let mut bad_image = make_elf_bin(); + bad_image[0x20] = 0x10; + assert_eq!( + Err(Error::InvalidProgramHeaderOffset), + Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&bad_image), None) + ); + } +} diff --git a/src/loader/struct_util.rs b/src/loader/struct_util.rs new file mode 100644 index 00000000..716282c4 --- /dev/null +++ b/src/loader/struct_util.rs @@ -0,0 +1,154 @@ +// Copyright (c) 2019 Intel Corporation. All rights reserved. +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Portions Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-BSD-3-Clause file. +// +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause + +use std; +use std::io::Read; +use std::mem; + +#[derive(Debug)] +pub enum Error { + ReadStruct, +} +pub type Result = std::result::Result; + +/// Reads a struct from an input buffer. +/// This is unsafe because the struct is initialized to unverified data read from the input. +/// `read_struct` should only be called to fill plain old data structs. It is not endian safe. +/// +/// # Arguments +/// +/// * `f` - The input to read from. Often this is a file. +/// * `out` - The struct to fill with data read from `f`. +pub unsafe fn read_struct(f: &mut F, out: &mut T) -> Result<()> { + let out_slice = std::slice::from_raw_parts_mut(out as *mut T as *mut u8, mem::size_of::()); + f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?; + Ok(()) +} + +/// Reads an array of structs from an input buffer. Returns a Vec of structs initialized with data +/// from the specified input. +/// This is unsafe because the structs are initialized to unverified data read from the input. +/// `read_struct_slice` should only be called for plain old data structs. It is not endian safe. +/// +/// # Arguments +/// +/// * `f` - The input to read from. Often this is a file. +/// * `len` - The number of structs to fill with data read from `f`. +#[cfg(feature = "elf")] +pub unsafe fn read_struct_slice(f: &mut F, len: usize) -> Result> { + let mut out: Vec = Vec::with_capacity(len); + out.set_len(len); + let out_slice = std::slice::from_raw_parts_mut( + out.as_ptr() as *mut T as *mut u8, + mem::size_of::() * len, + ); + f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?; + Ok(out) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Cursor; + use std::mem; + + #[derive(Clone, Copy, Debug, Default, PartialEq)] + struct TestRead { + a: u64, + b: u8, + c: u8, + d: u8, + e: u8, + } + + #[test] + fn struct_basic_read() { + let orig = TestRead { + a: 0x7766554433221100, + b: 0x88, + c: 0x99, + d: 0xaa, + e: 0xbb, + }; + let source = unsafe { + // Don't worry it's a test + std::slice::from_raw_parts( + &orig as *const _ as *const u8, + std::mem::size_of::(), + ) + }; + assert_eq!(mem::size_of::(), mem::size_of_val(&source)); + let mut tr: TestRead = Default::default(); + unsafe { + read_struct(&mut Cursor::new(source), &mut tr).unwrap(); + } + assert_eq!(orig, tr); + } + + #[test] + fn struct_read_past_end() { + let orig = TestRead { + a: 0x7766554433221100, + b: 0x88, + c: 0x99, + d: 0xaa, + e: 0xbb, + }; + let source = unsafe { + // Don't worry it's a test + std::slice::from_raw_parts( + &orig as *const _ as *const u8, + std::mem::size_of::() - 1, + ) + }; + let mut tr: TestRead = Default::default(); + unsafe { + assert!(read_struct(&mut Cursor::new(source), &mut tr).is_err()); + format!("{:?}", read_struct(&mut Cursor::new(source), &mut tr)); + } + } + + #[test] + #[cfg(feature = "elf")] + fn struct_slice_read() { + let orig = vec![ + TestRead { + a: 0x7766554433221100, + b: 0x88, + c: 0x99, + d: 0xaa, + e: 0xbb, + }, + TestRead { + a: 0x7867564534231201, + b: 0x02, + c: 0x13, + d: 0x24, + e: 0x35, + }, + TestRead { + a: 0x7a69584736251403, + b: 0x04, + c: 0x15, + d: 0x26, + e: 0x37, + }, + ]; + let source = unsafe { + // Don't worry it's a test + std::slice::from_raw_parts( + orig.as_ptr() as *const u8, + std::mem::size_of::() * 3, + ) + }; + + let tr: Vec = unsafe { read_struct_slice(&mut Cursor::new(source), 3).unwrap() }; + assert_eq!(orig, tr); + } +} diff --git a/src/loader/test_elf.bin b/src/loader/test_elf.bin new file mode 100644 index 00000000..2e75f639 Binary files /dev/null and b/src/loader/test_elf.bin differ diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..58aef2d7 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,28 @@ +import pytest + + +PROFILE_CI="ci" +PROFILE_DEVEL="devel" + + +def pytest_addoption(parser): + parser.addoption( + "--profile", + default=PROFILE_CI, + choices=[PROFILE_CI, PROFILE_DEVEL], + help="Profile for running the test: {} or {}".format( + PROFILE_CI, + PROFILE_DEVEL + ) + ) + + +@pytest.fixture +def profile(request): + return request.config.getoption("--profile") + + +# This is used for defining global variables in pytest. +def pytest_configure(): + pytest.profile_ci = PROFILE_CI + pytest.profile_devel = PROFILE_DEVEL diff --git a/tests/coverage b/tests/coverage new file mode 100644 index 00000000..82645f51 --- /dev/null +++ b/tests/coverage @@ -0,0 +1 @@ +83.6 diff --git a/tests/test_coverage.py b/tests/test_coverage.py new file mode 100644 index 00000000..f94d74fa --- /dev/null +++ b/tests/test_coverage.py @@ -0,0 +1,110 @@ +# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause +"""Test the coverage and update the threshold when coverage is increased.""" + +import os, re, shutil, subprocess +import pytest + +def _get_current_coverage(): + """Helper function that returns the coverage computed with kcov.""" + kcov_ouput_dir = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "kcov_output" + ) + + # By default the build output for kcov and unit tests are both in the debug + # directory. This causes some linker errors that I haven't investigated. + # Error: error: linking with `cc` failed: exit code: 1 + # An easy fix is to have separate build directories for kcov & unit tests. + kcov_build_dir = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "kcov_build" + ) + + # Remove kcov output and build directory to be sure we are always working + # on a clean environment. + shutil.rmtree(kcov_ouput_dir, ignore_errors=True) + shutil.rmtree(kcov_build_dir, ignore_errors=True) + + exclude_pattern = ( + '${CARGO_HOME:-$HOME/.cargo/},' + 'usr/lib/,' + 'lib/,' + 'bootparam.rs,' + 'elf.rs' + ) + exclude_region = "'mod tests {'" + + kcov_cmd = "CARGO_TARGET_DIR={} cargo kcov --all --features=elf,bzimage " \ + "--output {} -- " \ + "--exclude-region={} " \ + "--exclude-pattern={} " \ + "--verify".format( + kcov_build_dir, + kcov_ouput_dir, + exclude_region, + exclude_pattern + ) + + subprocess.run(kcov_cmd, shell=True, check=True) + + # Read the coverage reported by kcov. + coverage_file = os.path.join(kcov_ouput_dir, 'index.js') + with open(coverage_file) as cov_output: + coverage = float(re.findall( + r'"covered":"(\d+\.\d)"', + cov_output.read() + )[0]) + + # Remove coverage related directories. + shutil.rmtree(kcov_ouput_dir, ignore_errors=True) + shutil.rmtree(kcov_build_dir, ignore_errors=True) + + return coverage + + +def _get_previous_coverage(): + """Helper function that returns the last reported coverage.""" + coverage_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'coverage' + ) + + # The first and only line of the file contains the coverage. + with open(coverage_path) as f: + coverage = f.readline() + return float(coverage.strip()) + +def _update_coverage(cov_value): + """Updates the coverage in the coverage file.""" + coverage_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'coverage' + ) + + with open(coverage_path, "w") as f: + f.write(str(cov_value)) + +def test_coverage(profile): + current_coverage = _get_current_coverage() + previous_coverage = _get_previous_coverage() + if previous_coverage < current_coverage: + if profile == pytest.profile_ci: + # In the CI Profile we expect the coverage to be manually updated. + assert False, "Coverage is increased from {} to {}. " \ + "Please update the coverage in " \ + "tests/coverage.".format( + previous_coverage, + current_coverage + ) + elif profile == pytest.profile_devel: + _update_coverage(current_coverage) + else: + # This should never happen because pytest should only accept + # the valid test profiles specified with `choices` in + # `pytest_addoption`. + assert False, "Invalid test profile." + elif previous_coverage > current_coverage: + diff = float(previous_coverage - current_coverage) + assert False, "Coverage drops by {:.2f}%. Please add unit tests for" \ + "the uncovered lines.".format(diff)